summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDoug Rabson <dfr@rabson.org>2022-09-02 14:22:02 +0100
committerDoug Rabson <dfr@rabson.org>2022-09-14 08:29:26 +0100
commitb47ce9a6e0e9fa8e137c8338a08dffa256081b48 (patch)
treef22ac57011303713cc802acd78a6db70c3ac55ee
parentb3e978e43b3e01a68e5b8890fe79be64eb976e65 (diff)
downloadpodman-b47ce9a6e0e9fa8e137c8338a08dffa256081b48.tar.gz
podman-b47ce9a6e0e9fa8e137c8338a08dffa256081b48.tar.bz2
podman-b47ce9a6e0e9fa8e137c8338a08dffa256081b48.zip
libpod: Add support for 'podman stats' on FreeBSD
[NO NEW TESTS NEEDED] Signed-off-by: Doug Rabson <dfr@rabson.org>
-rw-r--r--libpod/stats_freebsd.go153
-rw-r--r--libpod/stats_unsupported.go4
2 files changed, 155 insertions, 2 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
+}
diff --git a/libpod/stats_unsupported.go b/libpod/stats_unsupported.go
index b23333c2e..3094e2eaa 100644
--- a/libpod/stats_unsupported.go
+++ b/libpod/stats_unsupported.go
@@ -1,5 +1,5 @@
-//go:build !linux
-// +build !linux
+//go:build !linux && !freebsd
+// +build !linux,!freebsd
package libpod