summaryrefslogtreecommitdiff
path: root/libpod/stats_freebsd.go
diff options
context:
space:
mode:
authorOpenShift Merge Robot <openshift-merge-robot@users.noreply.github.com>2022-09-14 14:21:30 +0200
committerGitHub <noreply@github.com>2022-09-14 14:21:30 +0200
commit82651e5974741aec9d9a0b8926c8ff2f715eed8c (patch)
treee326843e191473539f2fa1a3d008af85c9c19ffc /libpod/stats_freebsd.go
parentae20f19351c03398d10ba94a31f21dcf3d86f31c (diff)
parentb47ce9a6e0e9fa8e137c8338a08dffa256081b48 (diff)
downloadpodman-82651e5974741aec9d9a0b8926c8ff2f715eed8c.tar.gz
podman-82651e5974741aec9d9a0b8926c8ff2f715eed8c.tar.bz2
podman-82651e5974741aec9d9a0b8926c8ff2f715eed8c.zip
Merge pull request #15769 from dfr/freebsd-stats
Add support for 'podman stats' on FreeBSD
Diffstat (limited to 'libpod/stats_freebsd.go')
-rw-r--r--libpod/stats_freebsd.go153
1 files changed, 153 insertions, 0 deletions
diff --git a/libpod/stats_freebsd.go b/libpod/stats_freebsd.go
new file mode 100644
index 000000000..53bc3f19a
--- /dev/null
+++ b/libpod/stats_freebsd.go
@@ -0,0 +1,153 @@
+package libpod
+
+import (
+ "fmt"
+ "math"
+ "strings"
+ "time"
+
+ "github.com/containers/common/pkg/cgroups"
+ "github.com/containers/podman/v4/libpod/define"
+ "github.com/containers/podman/v4/pkg/rctl"
+ "github.com/containers/storage/pkg/system"
+ "github.com/sirupsen/logrus"
+)
+
+// getPlatformContainerStats gets the platform-specific running stats
+// for a given container. The previousStats is used to correctly
+// calculate cpu percentages. You should pass nil if there is no
+// previous stat for this container.
+func (c *Container) getPlatformContainerStats(stats *define.ContainerStats, previousStats *define.ContainerStats) error {
+ now := uint64(time.Now().UnixNano())
+
+ jailName := c.ID()
+ if c.state.NetNS != nil {
+ jailName = c.state.NetNS.Name + "." + jailName
+ }
+ entries, err := rctl.GetRacct("jail:" + jailName)
+ if err != nil {
+ return fmt.Errorf("unable to read accounting for %s: %w", jailName, err)
+ }
+
+ // If the current total usage is less than what was previously
+ // recorded then it means the container was restarted and runs
+ // in a new jail
+ if dur, ok := entries["wallclock"]; ok {
+ if previousStats.Duration > dur*1000000000 {
+ previousStats = &define.ContainerStats{}
+ }
+ }
+
+ for key, val := range entries {
+ switch key {
+ case "cputime": // CPU time, in seconds
+ stats.CPUNano = val * 1000000000
+ stats.AvgCPU = calculateCPUPercent(stats.CPUNano, 0, now, uint64(c.state.StartedTime.UnixNano()))
+ case "datasize": // data size, in bytes
+ case "stacksize": // stack size, in bytes
+ case "coredumpsize": // core dump size, in bytes
+ case "memoryuse": // resident set size, in bytes
+ stats.MemUsage = val
+ case "memorylocked": // locked memory, in bytes
+ case "maxproc": // number of processes
+ stats.PIDs = val
+ case "openfiles": // file descriptor table size
+ case "vmemoryuse": // address space limit, in bytes
+ case "pseudoterminals": // number of PTYs
+ case "swapuse": // swap space that may be reserved or used, in bytes
+ case "nthr": // number of threads
+ case "msgqqueued": // number of queued SysV messages
+ case "msgqsize": // SysV message queue size, in bytes
+ case "nmsgq": // number of SysV message queues
+ case "nsem": // number of SysV semaphores
+ case "nsemop": // number of SysV semaphores modified in a single semop(2) call
+ case "nshm": // number of SysV shared memory segments
+ case "shmsize": // SysV shared memory size, in bytes
+ case "wallclock": // wallclock time, in seconds
+ stats.Duration = val * 1000000000
+ stats.UpTime = time.Duration(stats.Duration)
+ case "pcpu": // %CPU, in percents of a single CPU core
+ stats.CPU = float64(val)
+ case "readbps": // filesystem reads, in bytes per second
+ stats.BlockInput = val
+ case "writebps": // filesystem writes, in bytes per second
+ stats.BlockOutput = val
+ case "readiops": // filesystem reads, in operations per second
+ case "writeiops": // filesystem writes, in operations per second
+ }
+ }
+ stats.MemLimit = c.getMemLimit()
+ stats.SystemNano = now
+
+ netStats, err := getContainerNetIO(c)
+ if err != nil {
+ return err
+ }
+
+ // Handle case where the container is not in a network namespace
+ if netStats != nil {
+ stats.NetInput = netStats.TxBytes
+ stats.NetOutput = netStats.RxBytes
+ } else {
+ stats.NetInput = 0
+ stats.NetOutput = 0
+ }
+
+ return nil
+}
+
+// getMemory limit returns the memory limit for a container
+func (c *Container) getMemLimit() uint64 {
+ memLimit := uint64(math.MaxUint64)
+
+ if c.config.Spec.Linux != nil && c.config.Spec.Linux.Resources != nil &&
+ c.config.Spec.Linux.Resources.Memory != nil && c.config.Spec.Linux.Resources.Memory.Limit != nil {
+ memLimit = uint64(*c.config.Spec.Linux.Resources.Memory.Limit)
+ }
+
+ mi, err := system.ReadMemInfo()
+ if err != nil {
+ logrus.Errorf("ReadMemInfo error: %v", err)
+ return 0
+ }
+
+ //nolint:unconvert
+ physicalLimit := uint64(mi.MemTotal)
+
+ if memLimit <= 0 || memLimit > physicalLimit {
+ return physicalLimit
+ }
+
+ return memLimit
+}
+
+// calculateCPUPercent calculates the cpu usage using the latest measurement in stats.
+// previousCPU is the last value of stats.CPU.Usage.Total measured at the time previousSystem.
+//
+// (now - previousSystem) is the time delta in nanoseconds, between the measurement in previousCPU
+//
+// and the updated value in stats.
+func calculateCPUPercent(currentCPU, previousCPU, now, previousSystem uint64) float64 {
+ var (
+ cpuPercent = 0.0
+ cpuDelta = float64(currentCPU - previousCPU)
+ systemDelta = float64(now - previousSystem)
+ )
+ if systemDelta > 0.0 && cpuDelta > 0.0 {
+ // gets a ratio of container cpu usage total, and multiplies that by 100 to get a percentage
+ cpuPercent = (cpuDelta / systemDelta) * 100
+ }
+ return cpuPercent
+}
+
+func calculateBlockIO(stats *cgroups.Metrics) (read uint64, write uint64) {
+ for _, blkIOEntry := range stats.Blkio.IoServiceBytesRecursive {
+ switch strings.ToLower(blkIOEntry.Op) {
+ case "read":
+ read += blkIOEntry.Value
+ case "write":
+ write += blkIOEntry.Value
+ }
+ }
+ return
+}