cpu_top by unit: program path only, pid reuse skipped, cgroup path kept under the root
mesh/delivery merged: source.main moved to novox/mesh-catalog@4915ff5d293f
mesh/check being carried to dd4c53eefb23 on 4915ff5d293f | from 0b2d393b1100

Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
This commit is contained in:
2026-11-03 02:04:43 +01:00
parent 32dc74788e
commit dd4c53eefb
2 changed files with 33 additions and 14 deletions
+16 -3
View File
@@ -191,16 +191,19 @@ func TestCPUTopRanksAUnitsProcesses(t *testing.T) {
f.then("/proc/"+itoa(pid)+"/stat", itoa(pid)+" ("+comm+") S 1 1 1 0 -1 0 0 0 0 0 "+itoa(ticks)+" 0 0 0 20 0 "+itoa(threads)+" 0 1 1 1\n")
}
for pid, c := range map[int][2]string{10: {"firefox", "1"}, 11: {"sh (x)", "1"}, 12: {"gone", "1"}} {
_ = c
f.file("/proc/"+itoa(pid)+"/stat", itoa(pid)+" ("+c[0]+") S 1 1 1 0 -1 0 0 0 0 0 0 0 0 0 20 0 "+c[1]+" 0 1 1 1\n")
}
f.file("/proc/13/stat", "13 (deep) S 1 1 1 0 -1 0 0 0 0 0 0 0 0 0 20 0 4 0 1 1 1\n")
f.file("/proc/10/cmdline", "/usr/bin/firefox\x00--new-window\x00")
f.file("/proc/11/cmdline", "mysql\x00--password\x00hunter2\x00")
st(10, "firefox", 150, 40) // 75 % of one CPU over 2 s
st(11, "sh (x)", 40, 1) // 20 %
st(13, "deep", 10, 4) // 5 %, in the child cgroup
f.then("/sys/fs/cgroup/user.slice/session-c1.scope/cgroup.procs", "10\n11\n14\n")
st(14, "newborn", 500, 1) // not in the first reading: skipped
f.file("/sys/fs/cgroup/user.slice/session-c1.scope/app/cgroup.procs", "13\n15\n")
f.file("/proc/15/stat", "15 (old) S 1 1 1 0 -1 0 0 0 0 0 0 0 0 0 20 0 1 0 1 1 1\n")
f.then("/proc/15/stat", "15 (reused) S 1 1 1 0 -1 0 0 0 0 0 900 0 0 0 20 0 1 0 77 1 1\n") // new starttime: another process
st(14, "newborn", 500, 1) // not in the first reading: skipped
out, err := tool(t, f.machine(), "cpu_top").Run(map[string]any{"unit": "session-c1.scope", "seconds": 2.0, "limit": 3.0})
if err != nil {
@@ -208,9 +211,19 @@ func TestCPUTopRanksAUnitsProcesses(t *testing.T) {
}
top := out.(map[string]any)["top"].([]ProcessCPU)
if len(top) != 3 || top[2].PID != 13 || top[2].CPUPct != 5 || top[0].PID != 10 || top[0].CPUPct != 75 || top[0].SharePct != 75 || top[0].Threads != 40 ||
top[0].Command != "firefox: /usr/bin/firefox --new-window" || top[1].PID != 11 || top[1].CPUPct != 20 || top[1].Command != "sh (x)" {
top[0].Command != "firefox: /usr/bin/firefox" || top[1].PID != 11 || top[1].CPUPct != 20 || top[1].Command != "sh (x): mysql" {
t.Errorf("processes of the unit: %+v", top)
}
for _, p := range top {
if p.PID == 15 || strings.Contains(p.Command, "hunter2") {
t.Errorf("a reused pid was counted, or an argument leaked: %+v", p)
}
}
for _, u := range []string{"../../etc", "/sys/fs/cgroup/../../proc", "user.slice/../.."} {
if _, err := tool(t, f.machine(), "cpu_top").Run(map[string]any{"unit": u}); err == nil {
t.Errorf("cgroup path %q escaping the root was accepted", u)
}
}
if _, err := tool(t, f.machine(), "cpu_top").Run(map[string]any{"unit": "nothing.scope"}); err == nil {
t.Error("an unknown unit was accepted")
}