Review round 2: change A must not slow builds before any slice exists, so a module given no share sets no GOMAXPROCS. The slice's quota bounds the total; threads only size one step, from the node's share over the module's own capacity (shanks: 24 x 50% / 3 = 4). The share is the node-engine's own config.
91 lines
3.5 KiB
Go
91 lines
3.5 KiB
Go
package buildcpu
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"reflect"
|
|
"runtime"
|
|
"testing"
|
|
)
|
|
|
|
// The node's share as a quota, the threads one step is given for its own module's capacity, and the word the composer
|
|
// hands, in one table (ADR 0553, issue 1806).
|
|
func TestShareQuotaAndThreads(t *testing.T) {
|
|
for _, c := range []struct {
|
|
name string
|
|
percent, cores, slots int
|
|
quota, threads int
|
|
}{
|
|
{"shanks: half of 24, three slots", 50, 24, 3, 1200, 4},
|
|
{"ace: three quarters of 24, two slots", 75, 24, 2, 1800, 9},
|
|
{"g14: half of 16, one slot", 50, 16, 1, 800, 8},
|
|
{"one processor at least", 10, 2, 4, 100, 1},
|
|
{"no slots counts as one", 100, 4, 0, 400, 4},
|
|
{"a share out of range is the default", 0, 8, 1, 0, 4},
|
|
} {
|
|
if c.quota != 0 {
|
|
if q := Quota(c.percent, c.cores); q != c.quota {
|
|
t.Errorf("%s: Quota = %d, want %d", c.name, q, c.quota)
|
|
}
|
|
}
|
|
if th := Threads(c.percent, c.cores, c.slots); th != c.threads {
|
|
t.Errorf("%s: Threads = %d, want %d", c.name, th, c.threads)
|
|
}
|
|
}
|
|
l := FromWords(func(k string) string { return map[string]string{ShareWord: "75"}[k] }, 2)
|
|
if l.Percent != 75 || l.From != ShareWord || l.Slots != 2 || l.Threads != Threads(75, runtime.NumCPU(), 2) {
|
|
t.Errorf("from the word: %+v", l)
|
|
}
|
|
// Told nothing usable, a step has no thread limit: nothing in its environment.
|
|
for _, word := range []string{"", "250", "lots"} {
|
|
l := FromWords(func(string) string { return word }, 3)
|
|
if l.Threads != 0 || l.From != "none" || Env(l.Threads) != nil {
|
|
t.Errorf("share %q: %+v, env %v", word, l, Env(l.Threads))
|
|
}
|
|
}
|
|
if got := Env(3); !reflect.DeepEqual(got, []string{"GOMAXPROCS=3", "UV_THREADPOOL_SIZE=3"}) {
|
|
t.Errorf("Env = %q", got)
|
|
}
|
|
}
|
|
|
|
// What the kernel holds a process to is read from its unit's and its slice's cgroup and its stat file, not assumed.
|
|
func TestReadInForce(t *testing.T) {
|
|
dir := t.TempDir()
|
|
cg := filepath.Join(dir, "cg")
|
|
slice := filepath.Join(cg, "meshyield.slice")
|
|
unit := filepath.Join(slice, "mesh-build-go-runtime.service")
|
|
if err := os.MkdirAll(unit, 0o755); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for at, files := range map[string]map[string]string{
|
|
slice: {"cpu.idle": "1\n", "cpu.weight": "0\n", "cpu.max": "1200000 100000\n", "io.weight": "default 1\n"},
|
|
unit: {"cpu.idle": "0\n", "cpu.weight": "100\n", "cpu.max": "max 100000\n", "io.weight": "default 100\n"},
|
|
} {
|
|
for name, v := range files {
|
|
if err := os.WriteFile(filepath.Join(at, name), []byte(v), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
}
|
|
self := filepath.Join(dir, "cgroup")
|
|
stat := filepath.Join(dir, "stat")
|
|
_ = os.WriteFile(self, []byte("0::/meshyield.slice/mesh-build-go-runtime.service\n"), 0o644)
|
|
// A command with a space and a parenthesis in it, then nice 19 in field 19.
|
|
_ = os.WriteFile(stat, []byte("42 (mesh (build) go) S 1 42 42 0 -1 4194560 1 0 0 0 0 0 0 0 39 19 8 0 1 2 3\n"), 0o644)
|
|
cgroupRoot, procSelfCgroup, procSelfStat = cg, self, stat
|
|
t.Cleanup(func() {
|
|
cgroupRoot, procSelfCgroup, procSelfStat = "/sys/fs/cgroup", "/proc/self/cgroup", "/proc/self/stat"
|
|
})
|
|
|
|
got := ReadInForce()
|
|
want := InForce{Nice: 19, Cgroup: "/meshyield.slice/mesh-build-go-runtime.service",
|
|
Unit: Group{Path: "/meshyield.slice/mesh-build-go-runtime.service", CPUIdle: "0", CPUWeight: "100",
|
|
CPUMax: "max 100000", IOWeight: "default 100"},
|
|
Slice: Group{Path: "/meshyield.slice", CPUIdle: "1", CPUWeight: "0", CPUMax: "1200000 100000",
|
|
IOWeight: "default 1"},
|
|
Quota: 1200}
|
|
if !reflect.DeepEqual(got, want) {
|
|
t.Fatalf("ReadInForce = %+v\nwant %+v", got, want)
|
|
}
|
|
}
|