Skip to content

Commit

Permalink
Podman Stats additional features
Browse files Browse the repository at this point in the history
added Avg Cpu calculation and CPU up time to podman stats. Adding different feature sets in different PRs, CPU first.

resolves #9258

Signed-off-by: cdoern <[email protected]>
  • Loading branch information
cdoern committed Jun 23, 2021
1 parent 2970e35 commit f26fa53
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 2 deletions.
16 changes: 15 additions & 1 deletion cmd/podman/containers/stats.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,9 @@ func stats(cmd *cobra.Command, args []string) error {
func outputStats(reports []define.ContainerStats) error {
headers := report.Headers(define.ContainerStats{}, map[string]string{
"ID": "ID",
"UpTime": "CPU TIME",
"CPUPerc": "CPU %",
"AVGCPU": "Avg CPU %",
"MemUsage": "MEM USAGE / LIMIT",
"MemUsageBytes": "MEM USAGE / LIMIT",
"MemPerc": "MEM %",
Expand All @@ -166,7 +168,7 @@ func outputStats(reports []define.ContainerStats) error {
if report.IsJSON(statsOptions.Format) {
return outputJSON(stats)
}
format := "{{.ID}}\t{{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.MemPerc}}\t{{.NetIO}}\t{{.BlockIO}}\t{{.PIDS}}\n"
format := "{{.ID}}\t{{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.MemPerc}}\t{{.NetIO}}\t{{.BlockIO}}\t{{.PIDS}}\t{{.UpTime}}\t{{.AVGCPU}}\n"
if len(statsOptions.Format) > 0 {
format = report.NormalizeFormat(statsOptions.Format)
}
Expand Down Expand Up @@ -202,6 +204,14 @@ func (s *containerStats) CPUPerc() string {
return floatToPercentString(s.CPU)
}

func (s *containerStats) AVGCPU() string {
return floatToPercentString(s.AvgCPU)
}

func (s *containerStats) Up() string {
return (s.UpTime.String())
}

func (s *containerStats) MemPerc() string {
return floatToPercentString(s.ContainerStats.MemPerc)
}
Expand Down Expand Up @@ -257,7 +267,9 @@ func outputJSON(stats []containerStats) error {
type jstat struct {
Id string `json:"id"` // nolint
Name string `json:"name"`
CPUTime string `json:"cpu_time"`
CpuPercent string `json:"cpu_percent"` // nolint
AverageCPU string `json:"avg_cpu"`
MemUsage string `json:"mem_usage"`
MemPerc string `json:"mem_percent"`
NetIO string `json:"net_io"`
Expand All @@ -269,7 +281,9 @@ func outputJSON(stats []containerStats) error {
jstats = append(jstats, jstat{
Id: j.ID(),
Name: j.Name,
CPUTime: j.Up(),
CpuPercent: j.CPUPerc(),
AverageCPU: j.AVGCPU(),
MemUsage: j.MemUsage(),
MemPerc: j.MemPerc(),
NetIO: j.NetIO(),
Expand Down
10 changes: 9 additions & 1 deletion libpod/define/containerstate.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package define

import "github.com/pkg/errors"
import (
"time"

"github.com/pkg/errors"
)

// ContainerStatus represents the current state of a container
type ContainerStatus int
Expand Down Expand Up @@ -120,12 +124,14 @@ func (s ContainerExecStatus) String() string {

// ContainerStats contains the statistics information for a running container
type ContainerStats struct {
AvgCPU float64
ContainerID string
Name string
PerCPU []uint64
CPU float64
CPUNano uint64
CPUSystemNano uint64
DataPoints int64
SystemNano uint64
MemUsage uint64
MemLimit uint64
Expand All @@ -135,4 +141,6 @@ type ContainerStats struct {
BlockInput uint64
BlockOutput uint64
PIDs uint64
UpTime time.Duration
Duration uint64
}
10 changes: 10 additions & 0 deletions libpod/stats.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,11 @@ func (c *Container) GetContainerStats(previousStats *define.ContainerStats) (*de

previousCPU := previousStats.CPUNano
now := uint64(time.Now().UnixNano())
stats.Duration = cgroupStats.CPU.Usage.Total
stats.UpTime = time.Duration(stats.Duration)
stats.CPU = calculateCPUPercent(cgroupStats, previousCPU, now, previousStats.SystemNano)
stats.AvgCPU = calculateAvgCPU(stats.CPU, previousStats.AvgCPU, previousStats.DataPoints)
stats.DataPoints = previousStats.DataPoints + 1
stats.MemUsage = cgroupStats.Memory.Usage.Usage
stats.MemLimit = getMemLimit(cgroupStats.Memory.Usage.Limit)
stats.MemPerc = (float64(stats.MemUsage) / float64(stats.MemLimit)) * 100
Expand Down Expand Up @@ -127,3 +131,9 @@ func calculateBlockIO(stats *cgroups.Metrics) (read uint64, write uint64) {
}
return
}

// calculateAvgCPU calculates the avg CPU percentage given the previous average and the number of data points.
func calculateAvgCPU(statsCPU float64, prevAvg float64, prevData int64) float64 {
avgPer := ((prevAvg * float64(prevData)) + statsCPU) / (float64(prevData) + 1)
return avgPer
}
11 changes: 11 additions & 0 deletions test/e2e/stats_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,17 @@ var _ = Describe("Podman stats", func() {
Expect(session.ExitCode()).To(Equal(0))
})

It("podman stats only output CPU data", func() {
session := podmanTest.RunTopContainer("")
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
session = podmanTest.Podman([]string{"stats", "--all", "--no-stream", "--format", "\"{{.ID}} {{.UpTime}} {{.AVGCPU}}\""})
session.WaitWithDefaultTimeout()
Expect(session.LineInOutputContains("UpTime")).To(BeTrue())
Expect(session.LineInOutputContains("AVGCPU")).To(BeTrue())
Expect(session.ExitCode()).To(Equal(0))
})

It("podman stats with json output", func() {
var found bool
session := podmanTest.RunTopContainer("")
Expand Down

0 comments on commit f26fa53

Please sign in to comment.