mirror of
https://github.com/opencontainers/runc.git
synced 2026-07-11 06:03:57 +08:00
10ca66bff5
As per - https://github.com/opencontainers/runtime-spec/pull/1253 - https://github.com/opencontainers/runtime-spec/pull/1261 CPU affinity can be set in two ways: 1. When creating/starting a container, in config.json's Process.ExecCPUAffinity, which is when applied to all execs. 2. When running an exec, in process.json's CPUAffinity, which applied to a given exec and overrides the value from (1). Add some basic tests. Note that older kernels (RHEL8, Ubuntu 20.04) change CPU affinity of a process to that of a container's cgroup, as soon as it is moved to that cgroup, while newer kernels (Ubuntu 24.04, Fedora 41) don't do that. Because of the above, - it's impossible to really test initial CPU affinity without adding debug logging to libcontainer/nsenter; - for older kernels, there can be a brief moment when exec's affinity is different than either initial or final affinity being set; - exec's final CPU affinity, if not specified, can be different depending on the kernel, therefore we don't test it. Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
90 lines
2.2 KiB
Go
90 lines
2.2 KiB
Go
package configs
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"golang.org/x/sys/unix"
|
|
)
|
|
|
|
func TestToCPUSet(t *testing.T) {
|
|
set := func(cpus ...int) *unix.CPUSet {
|
|
r := &unix.CPUSet{}
|
|
for _, cpu := range cpus {
|
|
r.Set(cpu)
|
|
}
|
|
return r
|
|
}
|
|
|
|
testCases := []struct {
|
|
in string
|
|
out *unix.CPUSet
|
|
isErr bool
|
|
}{
|
|
{in: ""}, // Empty means unset.
|
|
|
|
// Valid cases.
|
|
{in: "0", out: &unix.CPUSet{1}},
|
|
{in: "1", out: &unix.CPUSet{2}},
|
|
{in: "0-1", out: &unix.CPUSet{3}},
|
|
{in: "0,1", out: &unix.CPUSet{3}},
|
|
{in: ",0,1,", out: &unix.CPUSet{3}},
|
|
{in: "0-3", out: &unix.CPUSet{0x0f}},
|
|
{in: "0,1,2-3", out: &unix.CPUSet{0x0f}},
|
|
{in: "4-7", out: &unix.CPUSet{0xf0}},
|
|
{in: "0-7", out: &unix.CPUSet{0xff}},
|
|
{in: "0-15", out: &unix.CPUSet{0xffff}},
|
|
{in: "16", out: &unix.CPUSet{0x10000}},
|
|
// Extra whitespace in between ranges are OK.
|
|
{in: "1, 2, 1-2", out: &unix.CPUSet{6}},
|
|
{in: " , 1 , 3 , 5-7, ", out: &unix.CPUSet{0xea}},
|
|
// Somewhat large values. The underlying type in unix.CPUSet
|
|
// can either be uint32 or uint64, so we have to use a helper.
|
|
{in: "0-3,32-33", out: set(0, 1, 2, 3, 32, 33)},
|
|
{in: "127-129, 1", out: set(1, 127, 128, 129)},
|
|
{in: "1023", out: set(1023)},
|
|
|
|
// Error cases.
|
|
{in: "-", isErr: true},
|
|
{in: "1-", isErr: true},
|
|
{in: "-3", isErr: true},
|
|
{in: ",", isErr: true},
|
|
{in: " ", isErr: true},
|
|
// Bad range (start > end).
|
|
{in: "54-53", isErr: true},
|
|
// Extra spaces inside a range is not OK.
|
|
{in: "1 - 2", isErr: true},
|
|
{in: "1024", isErr: true}, // Too big for unix.CPUSet.
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
tc := tc
|
|
t.Run(tc.in, func(t *testing.T) {
|
|
out, err := toCPUSet(tc.in)
|
|
t.Logf("toCPUSet(%q) = %v (error: %v)", tc.in, out, err)
|
|
// Check the error.
|
|
if tc.isErr {
|
|
if err == nil {
|
|
t.Error("want error, got nil")
|
|
}
|
|
return // No more checks.
|
|
}
|
|
if err != nil {
|
|
t.Fatalf("want no error, got %v", err)
|
|
}
|
|
// Check the value.
|
|
if tc.out == nil {
|
|
if out != nil {
|
|
t.Fatalf("want nil, got %v", out)
|
|
}
|
|
return // No more checks.
|
|
}
|
|
if out == nil {
|
|
t.Fatalf("want %v, got nil", tc.out)
|
|
}
|
|
if *out != *tc.out {
|
|
t.Errorf("case %q: want %v, got %v", tc.in, tc.out, out)
|
|
}
|
|
})
|
|
}
|
|
}
|