1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
|
package resources
import (
"os"
"path/filepath"
"strconv"
"strings"
resourcestypes "github.com/moby/buildkit/executor/resources/types"
"github.com/pkg/errors"
)
const (
memoryStatFile = "memory.stat"
memoryPressureFile = "memory.pressure"
memoryPeakFile = "memory.peak"
memorySwapCurrentFile = "memory.swap.current"
memoryEventsFile = "memory.events"
)
const (
memoryAnon = "anon"
memoryFile = "file"
memoryKernelStack = "kernel_stack"
memoryPageTables = "pagetables"
memorySock = "sock"
memoryShmem = "shmem"
memoryFileMapped = "file_mapped"
memoryFileDirty = "file_dirty"
memoryFileWriteback = "file_writeback"
memorySlab = "slab"
memoryPgscan = "pgscan"
memoryPgsteal = "pgsteal"
memoryPgfault = "pgfault"
memoryPgmajfault = "pgmajfault"
memoryLow = "low"
memoryHigh = "high"
memoryMax = "max"
memoryOom = "oom"
memoryOomKill = "oom_kill"
)
func getCgroupMemoryStat(path string) (*resourcestypes.MemoryStat, error) {
memoryStat := &resourcestypes.MemoryStat{}
// Parse memory.stat
err := parseKeyValueFile(filepath.Join(path, memoryStatFile), func(key string, value uint64) {
switch key {
case memoryAnon:
memoryStat.Anon = &value
case memoryFile:
memoryStat.File = &value
case memoryKernelStack:
memoryStat.KernelStack = &value
case memoryPageTables:
memoryStat.PageTables = &value
case memorySock:
memoryStat.Sock = &value
case memoryShmem:
memoryStat.Shmem = &value
case memoryFileMapped:
memoryStat.FileMapped = &value
case memoryFileDirty:
memoryStat.FileDirty = &value
case memoryFileWriteback:
memoryStat.FileWriteback = &value
case memorySlab:
memoryStat.Slab = &value
case memoryPgscan:
memoryStat.Pgscan = &value
case memoryPgsteal:
memoryStat.Pgsteal = &value
case memoryPgfault:
memoryStat.Pgfault = &value
case memoryPgmajfault:
memoryStat.Pgmajfault = &value
}
})
if err != nil {
if errors.Is(err, os.ErrNotExist) {
return nil, nil
}
return nil, err
}
pressure, err := parsePressureFile(filepath.Join(path, memoryPressureFile))
if err != nil {
return nil, err
}
if pressure != nil {
memoryStat.Pressure = pressure
}
err = parseKeyValueFile(filepath.Join(path, memoryEventsFile), func(key string, value uint64) {
switch key {
case memoryLow:
memoryStat.LowEvents = value
case memoryHigh:
memoryStat.HighEvents = value
case memoryMax:
memoryStat.MaxEvents = value
case memoryOom:
memoryStat.OomEvents = value
case memoryOomKill:
memoryStat.OomKillEvents = value
}
})
if err != nil {
return nil, err
}
peak, err := parseSingleValueFile(filepath.Join(path, memoryPeakFile))
if err != nil {
if !errors.Is(err, os.ErrNotExist) {
return nil, err
}
} else {
memoryStat.Peak = &peak
}
swap, err := parseSingleValueFile(filepath.Join(path, memorySwapCurrentFile))
if err != nil {
if !errors.Is(err, os.ErrNotExist) {
return nil, err
}
} else {
memoryStat.SwapBytes = &swap
}
return memoryStat, nil
}
func parseKeyValueFile(filePath string, callback func(key string, value uint64)) error {
content, err := os.ReadFile(filePath)
if err != nil {
return errors.Wrapf(err, "failed to read %s", filePath)
}
lines := strings.Split(string(content), "\n")
for _, line := range lines {
if len(strings.TrimSpace(line)) == 0 {
continue
}
fields := strings.Fields(line)
key := fields[0]
valueStr := fields[1]
value, err := strconv.ParseUint(valueStr, 10, 64)
if err != nil {
return errors.Wrapf(err, "failed to parse value for %s", key)
}
callback(key, value)
}
return nil
}
|