Skip to content

Commit daede0d

Browse files
committed
add numa_stat for cgroup v2
Signed-off-by: victoryang00 <[email protected]>
1 parent b338acc commit daede0d

File tree

2 files changed

+115
-0
lines changed

2 files changed

+115
-0
lines changed

libcontainer/cgroups/fs2/fs2.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ import (
1313

1414
type parseError = fscommon.ParseError
1515

16+
func malformedLine(path, file, line string) error {
17+
return &parseError{Path: path, File: file, Err: fmt.Errorf("malformed line: %s", line)}
18+
}
19+
1620
type Manager struct {
1721
config *configs.Cgroup
1822
// dirPath is like "/sys/fs/cgroup/user.slice/user-1001.slice/session-1.scope"

libcontainer/cgroups/fs2/memory.go

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,12 @@ func statMemory(dirPath string, stats *cgroups.Stats) error {
102102
// cgroup v2 is always hierarchical.
103103
stats.MemoryStats.UseHierarchy = true
104104

105+
pagesByNUMA, err := getPageUsageByNUMAV2(dirPath)
106+
if err != nil {
107+
return err
108+
}
109+
stats.MemoryStats.PageUsageByNUMA = pagesByNUMA
110+
105111
memoryUsage, err := getMemoryDataV2(dirPath, "")
106112
if err != nil {
107113
if errors.Is(err, unix.ENOENT) && dirPath == UnifiedMountpoint {
@@ -219,3 +225,108 @@ func statsFromMeminfo(stats *cgroups.Stats) error {
219225

220226
return nil
221227
}
228+
229+
func getPageUsageByNUMAV2(path string) (cgroups.PageUsageByNUMA, error) {
230+
const (
231+
maxColumns = math.MaxUint8 + 1
232+
file = "memory.numa_stat"
233+
)
234+
stats := cgroups.PageUsageByNUMA{}
235+
236+
fd, err := cgroups.OpenFile(path, file, os.O_RDONLY)
237+
if os.IsNotExist(err) {
238+
return stats, nil
239+
} else if err != nil {
240+
return stats, err
241+
}
242+
defer fd.Close()
243+
244+
// anon N0=139022336 N1=2760704
245+
// file N0=449581056 N1=0
246+
// kernel_stack N0=3670016 N1=0
247+
// pagetables N0=4116480 N1=0
248+
// sec_pagetables N0=0 N1=0
249+
// shmem N0=0 N1=0
250+
// file_mapped N0=55029760 N1=0
251+
// file_dirty N0=0 N1=0
252+
// file_writeback N0=0 N1=0
253+
// swapcached N0=0 N1=0
254+
// anon_thp N0=0 N1=0
255+
// file_thp N0=0 N1=0
256+
// shmem_thp N0=0 N1=0
257+
// inactive_anon N0=138956800 N1=2752512
258+
// active_anon N0=65536 N1=8192
259+
// inactive_file N0=14770176 N1=0
260+
// active_file N0=434810880 N1=0
261+
// unevictable N0=0 N1=0
262+
// slab_reclaimable N0=2358224 N1=11088
263+
// slab_unreclaimable N0=2672352 N1=544144
264+
// workingset_refault_anon N0=0 N1=0
265+
// workingset_refault_file N0=0 N1=0
266+
// workingset_activate_anon N0=0 N1=0
267+
// workingset_activate_file N0=0 N1=0
268+
// workingset_restore_anon N0=0 N1=0
269+
// workingset_restore_file N0=0 N1=0
270+
// workingset_nodereclaim N0=0 N1=0
271+
272+
scanner := bufio.NewScanner(fd)
273+
for scanner.Scan() {
274+
var field *cgroups.PageStats
275+
276+
line := scanner.Text()
277+
columns := strings.SplitN(line, " ", maxColumns)
278+
for i, column := range columns {
279+
byNode := strings.SplitN(column, "=", 2)
280+
key := byNode[0]
281+
if i == 0 { // First column: key is name, val is total.
282+
field = getNUMAFieldV2(&stats, key)
283+
if field == nil { // unknown field (new kernel?)
284+
break
285+
}
286+
field.Nodes = map[uint8]uint64{}
287+
} else { // Subsequent columns: key is N<id>, val is usage.
288+
val := byNode[1]
289+
if len(key) < 2 || key[0] != 'N' {
290+
// This is definitely an error.
291+
return stats, malformedLine(path, file, line)
292+
}
293+
294+
n, err := strconv.ParseUint(key[1:], 10, 8)
295+
if err != nil {
296+
return stats, &parseError{Path: path, File: file, Err: err}
297+
}
298+
299+
usage, err := strconv.ParseUint(val, 10, 64)
300+
if err != nil {
301+
return stats, &parseError{Path: path, File: file, Err: err}
302+
}
303+
field.Nodes[uint8(n)] += usage
304+
field.Total += usage
305+
}
306+
307+
}
308+
}
309+
if err := scanner.Err(); err != nil {
310+
return cgroups.PageUsageByNUMA{}, &parseError{Path: path, File: file, Err: err}
311+
}
312+
313+
return stats, nil
314+
}
315+
316+
func getNUMAFieldV2(stats *cgroups.PageUsageByNUMA, name string) *cgroups.PageStats {
317+
switch name {
318+
case "pagetables":
319+
return &stats.Total
320+
case "anon":
321+
return &stats.Anon
322+
case "file_mapped":
323+
return &stats.File
324+
case "file_dirty":
325+
return &stats.File
326+
case "file_writeback":
327+
return &stats.File
328+
case "unevictable":
329+
return &stats.Unevictable
330+
}
331+
return nil
332+
}

0 commit comments

Comments
 (0)