Skip to content

Commit

Permalink
support psi for cgroupv2
Browse files Browse the repository at this point in the history
We read output from the following files if they exists:
- cpu.pressure
- memory.pressure
- io.pressure

Each are in format:

```
some avg10=0.00 avg60=0.00 avg300=0.00 total=0
full avg10=0.00 avg60=0.00 avg300=0.00 total=0
```

Signed-off-by: Daniel Dao <dqminh89@gmail.com>
  • Loading branch information
dqminh committed Feb 3, 2022
1 parent eddf35e commit 53f2c48
Show file tree
Hide file tree
Showing 6 changed files with 178 additions and 0 deletions.
13 changes: 13 additions & 0 deletions events.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,13 @@ information is displayed once every 5 seconds.`,
},
}

func convertPSI(from *cgroups.PSIData, to *types.PSIData) {
to.Avg10 = from.Avg10
to.Avg60 = from.Avg60
to.Avg300 = from.Avg300
to.Total = from.Total
}

func convertLibcontainerStats(ls *libcontainer.Stats) *types.Stats {
cg := ls.CgroupStats
if cg == nil {
Expand All @@ -129,6 +136,8 @@ func convertLibcontainerStats(ls *libcontainer.Stats) *types.Stats {
s.CPU.Throttling.Periods = cg.CpuStats.ThrottlingData.Periods
s.CPU.Throttling.ThrottledPeriods = cg.CpuStats.ThrottlingData.ThrottledPeriods
s.CPU.Throttling.ThrottledTime = cg.CpuStats.ThrottlingData.ThrottledTime
convertPSI(&cg.CpuStats.PSI.Some, &s.CPU.PSI.Some)
convertPSI(&cg.CpuStats.PSI.Full, &s.CPU.PSI.Full)

s.CPUSet = types.CPUSet(cg.CPUSetStats)

Expand All @@ -138,6 +147,8 @@ func convertLibcontainerStats(ls *libcontainer.Stats) *types.Stats {
s.Memory.Swap = convertMemoryEntry(cg.MemoryStats.SwapUsage)
s.Memory.Usage = convertMemoryEntry(cg.MemoryStats.Usage)
s.Memory.Raw = cg.MemoryStats.Stats
convertPSI(&cg.MemoryStats.PSI.Some, &s.Memory.PSI.Some)
convertPSI(&cg.MemoryStats.PSI.Full, &s.Memory.PSI.Full)

s.Blkio.IoServiceBytesRecursive = convertBlkioEntry(cg.BlkioStats.IoServiceBytesRecursive)
s.Blkio.IoServicedRecursive = convertBlkioEntry(cg.BlkioStats.IoServicedRecursive)
Expand All @@ -147,6 +158,8 @@ func convertLibcontainerStats(ls *libcontainer.Stats) *types.Stats {
s.Blkio.IoMergedRecursive = convertBlkioEntry(cg.BlkioStats.IoMergedRecursive)
s.Blkio.IoTimeRecursive = convertBlkioEntry(cg.BlkioStats.IoTimeRecursive)
s.Blkio.SectorsRecursive = convertBlkioEntry(cg.BlkioStats.SectorsRecursive)
convertPSI(&cg.BlkioStats.PSI.Some, &s.Blkio.PSI.Some)
convertPSI(&cg.BlkioStats.PSI.Full, &s.Blkio.PSI.Full)

s.Hugetlb = make(map[string]types.Hugetlb)
for k, v := range cg.HugetlbStats {
Expand Down
10 changes: 10 additions & 0 deletions libcontainer/cgroups/fs2/fs2.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,16 @@ func (m *manager) GetStats() (*cgroups.Stats, error) {
if err := statCpu(m.dirPath, st); err != nil && !os.IsNotExist(err) {
errs = append(errs, err)
}
// psi ( since kernel 4.20)
if err := statPSI(m.dirPath, "cpu.pressure", &st.CpuStats.PSI); err != nil && !os.IsNotExist(err) {
errs = append(errs, err)
}
if err := statPSI(m.dirPath, "memory.pressure", &st.MemoryStats.PSI); err != nil && !os.IsNotExist(err) {
errs = append(errs, err)
}
if err := statPSI(m.dirPath, "io.pressure", &st.BlkioStats.PSI); err != nil && !os.IsNotExist(err) {
errs = append(errs, err)
}
// hugetlb (since kernel 5.6)
if err := statHugeTlb(m.dirPath, st); err != nil && !os.IsNotExist(err) {
errs = append(errs, err)
Expand Down
78 changes: 78 additions & 0 deletions libcontainer/cgroups/fs2/psi.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package fs2

import (
"bufio"
"fmt"
"os"
"strconv"
"strings"

"github.com/opencontainers/runc/libcontainer/cgroups"
)

func statPSI(dirPath string, file string, stats *cgroups.PSIStats) error {
f, err := cgroups.OpenFile(dirPath, file, os.O_RDONLY)
if err != nil {
return err
}
defer f.Close()

sc := bufio.NewScanner(f)
for sc.Scan() {
parts := strings.Fields(sc.Text())
switch parts[0] {
case "some":
data, err := parsePSIData(parts[1:])
if err != nil {
return err
}
stats.Some = data
case "full":
data, err := parsePSIData(parts[1:])
if err != nil {
return err
}
stats.Full = data
}
}
if err := sc.Err(); err != nil {
return &parseError{Path: dirPath, File: file, Err: err}
}
return nil
}

func parsePSIData(psi []string) (data cgroups.PSIData, err error) {
for i := 0; i < len(psi); i++ {
kv := strings.SplitN(psi[i], "=", 2)
if len(kv) != 2 {
return data, fmt.Errorf("invalid psi data: %q", psi[i])
}
switch kv[0] {
case "avg10":
v, err := strconv.ParseFloat(kv[1], 64)
if err != nil {
return data, fmt.Errorf("invalid psi value: %q", psi[i])
}
data.Avg10 = v
case "avg60":
v, err := strconv.ParseFloat(kv[1], 64)
if err != nil {
return data, fmt.Errorf("invalid psi value: %q", psi[i])
}
data.Avg60 = v
case "avg300":
v, err := strconv.ParseFloat(kv[1], 64)
if err != nil {
return data, fmt.Errorf("invalid psi value: %q", psi[i])
}
data.Avg300 = v
case "total":
v, err := strconv.ParseUint(kv[1], 10, 64)
if err != nil {
return data, fmt.Errorf("invalid psi value: %q", psi[i])
}
data.Total = v
}
}
return data, nil
}
47 changes: 47 additions & 0 deletions libcontainer/cgroups/fs2/psi_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package fs2

import (
"os"
"path/filepath"
"reflect"
"testing"

"github.com/opencontainers/runc/libcontainer/cgroups"
)

const examplePsiData = `some avg10=1.71 avg60=2.36 avg300=2.57 total=230548833
full avg10=1.00 avg60=1.01 avg300=1.00 total=157622356`

func TestStatCPUPsi(t *testing.T) {
// We're using a fake cgroupfs.
cgroups.TestMode = true

fakeCgroupDir := t.TempDir()
statPath := filepath.Join(fakeCgroupDir, "cpu.pressure")

if err := os.WriteFile(statPath, []byte(examplePsiData), 0o644); err != nil {
t.Fatal(err)
}

var psi cgroups.PSIStats
if err := statPSI(fakeCgroupDir, "cpu.pressure", &psi); err != nil {
t.Error(err)
}

if !reflect.DeepEqual(psi, cgroups.PSIStats{
Some: cgroups.PSIData{
Avg10: 1.71,
Avg60: 2.36,
Avg300: 2.57,
Total: 230548833,
},
Full: cgroups.PSIData{
Avg10: 1.00,
Avg60: 1.01,
Avg300: 1.00,
Total: 157622356,
},
}) {
t.Errorf("unexpected psi result: %+v", psi)
}
}
15 changes: 15 additions & 0 deletions libcontainer/cgroups/stats.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,22 @@ type CpuUsage struct {
UsageInUsermode uint64 `json:"usage_in_usermode"`
}

type PSIData struct {
Avg10 float64 `json:"avg10"`
Avg60 float64 `json:"avg60"`
Avg300 float64 `json:"avg300"`
Total uint64 `json:"total"`
}

type PSIStats struct {
Some PSIData `json:"some,omitempty"`
Full PSIData `json:"full,omitempty"`
}

type CpuStats struct {
CpuUsage CpuUsage `json:"cpu_usage,omitempty"`
ThrottlingData ThrottlingData `json:"throttling_data,omitempty"`
PSI PSIStats `json:"psi,omitempty"`
}

type CPUSetStats struct {
Expand Down Expand Up @@ -89,6 +102,7 @@ type MemoryStats struct {
UseHierarchy bool `json:"use_hierarchy"`

Stats map[string]uint64 `json:"stats,omitempty"`
PSI PSIStats `json:"psi,omitempty"`
}

type PageUsageByNUMA struct {
Expand Down Expand Up @@ -133,6 +147,7 @@ type BlkioStats struct {
IoMergedRecursive []BlkioStatEntry `json:"io_merged_recursive,omitempty"`
IoTimeRecursive []BlkioStatEntry `json:"io_time_recursive,omitempty"`
SectorsRecursive []BlkioStatEntry `json:"sectors_recursive,omitempty"`
PSI PSIStats `json:"psi,omitempty"`
}

type HugetlbStats struct {
Expand Down
15 changes: 15 additions & 0 deletions types/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,18 @@ type Stats struct {
NetworkInterfaces []*NetworkInterface `json:"network_interfaces"`
}

type PSIData struct {
Avg10 float64 `json:"avg10"`
Avg60 float64 `json:"avg60"`
Avg300 float64 `json:"avg300"`
Total uint64 `json:"total"`
}

type PSIStats struct {
Some PSIData `json:"some,omitempty"`
Full PSIData `json:"full,omitempty"`
}

type Hugetlb struct {
Usage uint64 `json:"usage,omitempty"`
Max uint64 `json:"max,omitempty"`
Expand All @@ -43,6 +55,7 @@ type Blkio struct {
IoMergedRecursive []BlkioEntry `json:"ioMergedRecursive,omitempty"`
IoTimeRecursive []BlkioEntry `json:"ioTimeRecursive,omitempty"`
SectorsRecursive []BlkioEntry `json:"sectorsRecursive,omitempty"`
PSI PSIStats `json:"psi,omitempty"`
}

type Pids struct {
Expand All @@ -69,6 +82,7 @@ type CpuUsage struct {
type Cpu struct {
Usage CpuUsage `json:"usage,omitempty"`
Throttling Throttling `json:"throttling,omitempty"`
PSI PSIStats `json:"psi,omitempty"`
}

type CPUSet struct {
Expand Down Expand Up @@ -99,6 +113,7 @@ type Memory struct {
Kernel MemoryEntry `json:"kernel,omitempty"`
KernelTCP MemoryEntry `json:"kernelTCP,omitempty"`
Raw map[string]uint64 `json:"raw,omitempty"`
PSI PSIStats `json:"psi,omitempty"`
}

type L3CacheInfo struct {
Expand Down

0 comments on commit 53f2c48

Please sign in to comment.