package main // Over a stand-in tree holding novox's own files of 2026-10-14 23:25 (read through node-reads for // novox/hq issue 746): the mode, the per-size controls, meminfo's huge page lines, and fail2ban's and // journald's memory.stat and io.stat, cut to the lines the tool reads. import ( "os" "path/filepath" "strings" "testing" ) func tree(t *testing.T, files map[string]string) *Machine { t.Helper() root := t.TempDir() for p, content := range files { full := filepath.Join(root, p) if err := os.MkdirAll(filepath.Dir(full), 0o755); err != nil { t.Fatal(err) } if err := os.WriteFile(full, []byte(content), 0o644); err != nil { t.Fatal(err) } } return &Machine{Root: root} } func novox(t *testing.T) *Machine { thp := "sys/kernel/mm/transparent_hugepage/" cg := "sys/fs/cgroup/system.slice/" files := map[string]string{ thp + "enabled": "[always] madvise never\n", thp + "defrag": "always defer defer+madvise [madvise] never\n", thp + "shmem_enabled": "always within_size [advise] never deny force\n", thp + "hugepages-2048kB/enabled": "always [inherit] madvise never\n", thp + "hugepages-64kB/enabled": "always inherit madvise [never]\n", thp + "hugepages-1024kB/enabled": "always inherit madvise [never]\n", "proc/meminfo": "MemTotal: 65748808 kB\nAnonHugePages: 3579904 kB\nShmemHugePages: 4096 kB\n" + "ShmemPmdMapped: 4096 kB\nFileHugePages: 1693696 kB\nFilePmdMapped: 882688 kB\nHugepagesize: 2048 kB\n", cg + "fail2ban.service/memory.stat": "anon 21815296\nfile 204623872\nfile_mapped 130736128\nfile_dirty 27262976\n" + "file_writeback 4096\nanon_thp 0\nfile_thp 197132288\nthp_fault_alloc 0\nthp_collapse_alloc 550\n", cg + "fail2ban.service/io.stat": "9:0 \n8:16 rbytes=3223552 wbytes=67723415552 rios=240 wios=281159 dbytes=0 dios=0\n" + "8:0 rbytes=6152192 wbytes=67723415552 rios=832 wios=281159 dbytes=0 dios=0\n" + "9:2 rbytes=9375744 wbytes=67723415552 rios=1072 wios=281159 dbytes=0 dios=0\n", cg + "systemd-journald.service/memory.stat": "anon 3227648\nfile 1032015872\nfile_mapped 131928064\nfile_dirty 622592\n" + "file_writeback 159744\nanon_thp 2097152\nfile_thp 379584512\nthp_fault_alloc 0\nthp_collapse_alloc 11741\n", cg + "systemd-journald.service/io.stat": "9:0 \n8:16 rbytes=55209984 wbytes=2498768035840 rios=1317 wios=24719004 dbytes=0 dios=0\n" + "8:0 rbytes=72953856 wbytes=2498768039936 rios=2194 wios=24719005 dbytes=0 dios=0\n" + "9:2 rbytes=128163840 wbytes=2498724843520 rios=3511 wios=24707873 dbytes=0 dios=0\n", cg + "sshd.service/memory.stat": "anon 1000\nfile_thp 0\n", } return tree(t, files) } func TestNovoxBeforeTheChange(t *testing.T) { a, err := novox(t).HugePages(10) if err != nil { t.Fatal(err) } if a.Mode != "always" || a.Defrag != "madvise" || a.Shmem != "advise" { t.Fatalf("modes: %+v", a) } if len(a.PerSize) != 3 || a.PerSize[0].Size != "64kB" || a.PerSize[2].Size != "2048kB" || a.PerSize[2].Enabled != "inherit" || a.PerSize[2].Means != "always" || a.PerSize[0].Means != "never" { t.Fatalf("per size: %+v", a.PerSize) } if a.Meminfo["FileHugePages"] != 1654 || a.Meminfo["FilePmdMapped"] != 862 { t.Fatalf("meminfo: %v", a.Meminfo) } if len(a.Units) != 2 || a.Units[0].Cgroup != "system.slice/systemd-journald.service" || a.Units[1].Cgroup != "system.slice/fail2ban.service" { t.Fatalf("units: %+v", a.Units) } // The mirror and its two members each count the write: the most any one saw, never their sum. if a.Units[1].Written != 67723415552 || a.Units[1].FileTHP != 197132288 || a.Units[1].CollapsedByKhug != 550 { t.Fatalf("fail2ban: %+v", a.Units[1]) } said := strings.Join(a.Said, "\n") for _, want := range []string{"transparent huge pages: always, defrag madvise", "sizes not never: 2048kB always", "file 1654 MiB (mapped at 2 MiB 862 MiB)", "system.slice/fail2ban.service: file in huge folios 188.0 MiB"} { if !strings.Contains(said, want) { t.Errorf("said lacks %q:\n%s", want, said) } } } func TestUnitsAreBoundedAndNoneIsSaid(t *testing.T) { a, err := novox(t).HugePages(1) if err != nil || len(a.Units) != 1 { t.Fatalf("%v %+v", err, a) } b, err := tree(t, map[string]string{"sys/kernel/mm/transparent_hugepage/enabled": "always [madvise] never\n"}).HugePages(10) if err != nil || b.Mode != "madvise" || len(b.Units) != 0 || !strings.Contains(strings.Join(b.Said, "\n"), "no unit holds") { t.Fatalf("%v %+v", err, b) } } func TestAKernelWithoutHugePagesIsAnError(t *testing.T) { if _, err := tree(t, map[string]string{"proc/meminfo": ""}).HugePages(10); err == nil || !strings.Contains(err.Error(), "built without transparent huge pages") { t.Fatalf("%v", err) } } func TestTheArgumentIsBounded(t *testing.T) { if _, err := whole(map[string]any{"units": -1.0}, "units", 10, 0, 100); err == nil { t.Error("a negative count was accepted") } if n, _ := whole(map[string]any{"units": 1000.0}, "units", 10, 0, 100); n != 100 { t.Errorf("not bounded: %d", n) } }