File: memory.go

package info (click to toggle)
singularity-container 4.1.5%2Bds4-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 43,876 kB
  • sloc: asm: 14,840; sh: 3,190; ansic: 1,751; awk: 414; makefile: 413; python: 99
file content (159 lines) | stat: -rw-r--r-- 3,725 bytes parent folder | download | duplicates (3)
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
}