
In order to implement the `full-pcpus-only` cpumanager policy option, we leverage the implementation of the algorithm which picks CPUs. By design, CPUs are taken from the biggest chunk available (socket or NUMA zone) to physical cores, down to single cores. Leveraging this, if the requested CPU count is a multiple of the SMT level (commonly 2), we're guaranteed that only full physical cores will be taken. The hidden assumption here is this holds true by construction iff the user reserved CPUs (if any) considering full physical CPUs. IOW, if the user did intentionally or mistakely reserve single threads which are no core siblings[1], then the simple check we implemented is not sufficient. A easy example can probably outline this better. With this setup: cores: [(0, 4), (1, 5), (2, 6), (3, 8)] (in parens: thread siblings). SMT level: 2 (each tuple is 2 elements) Reserved CPUs: 0,1 (explicit pick using `--reserved-cpus`) A container then requests 6 cpus. full-pcpus-only check: 6 % 2 == 0. Passed. The CPU allocator will take first full cores, (2,6) and (3,8), and will then pick the remaining single CPUs. The allocation will succeed, but it's incorrect. We can fix this case with a stricter precheck. We need to additionally consider all the core siblings of the reserved CPUs as unavailable when computing the free cpus, before to start the actual allocation. Doing so, we fall back in the intended behavior, and by construction all possible CPUs allocation whose number is multiple of the SMT level are now correct again. +++ [1] or thread siblings in the linux parlance, in any case: hyperthread siblings of the same physical core Signed-off-by: Francesco Romani <fromani@redhat.com>
1103 lines
32 KiB
Go
1103 lines
32 KiB
Go
/*
|
|
Copyright 2017 The Kubernetes Authors.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
package topology
|
|
|
|
import (
|
|
"reflect"
|
|
"testing"
|
|
|
|
cadvisorapi "github.com/google/cadvisor/info/v1"
|
|
"github.com/google/go-cmp/cmp"
|
|
"k8s.io/kubernetes/pkg/kubelet/cm/cpuset"
|
|
)
|
|
|
|
func Test_Discover(t *testing.T) {
|
|
|
|
tests := []struct {
|
|
name string
|
|
machineInfo cadvisorapi.MachineInfo
|
|
want *CPUTopology
|
|
wantErr bool
|
|
}{
|
|
{
|
|
name: "FailNumCores",
|
|
machineInfo: cadvisorapi.MachineInfo{
|
|
NumCores: 0,
|
|
},
|
|
want: &CPUTopology{},
|
|
wantErr: true,
|
|
},
|
|
{
|
|
name: "OneSocketHT",
|
|
machineInfo: cadvisorapi.MachineInfo{
|
|
NumCores: 8,
|
|
NumSockets: 1,
|
|
Topology: []cadvisorapi.Node{
|
|
{Id: 0,
|
|
Cores: []cadvisorapi.Core{
|
|
{SocketID: 0, Id: 0, Threads: []int{0, 4}},
|
|
{SocketID: 0, Id: 1, Threads: []int{1, 5}},
|
|
{SocketID: 0, Id: 2, Threads: []int{2, 6}},
|
|
{SocketID: 0, Id: 3, Threads: []int{3, 7}},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
want: &CPUTopology{
|
|
NumCPUs: 8,
|
|
NumSockets: 1,
|
|
NumCores: 4,
|
|
NumNUMANodes: 1,
|
|
CPUDetails: map[int]CPUInfo{
|
|
0: {CoreID: 0, SocketID: 0, NUMANodeID: 0},
|
|
1: {CoreID: 1, SocketID: 0, NUMANodeID: 0},
|
|
2: {CoreID: 2, SocketID: 0, NUMANodeID: 0},
|
|
3: {CoreID: 3, SocketID: 0, NUMANodeID: 0},
|
|
4: {CoreID: 0, SocketID: 0, NUMANodeID: 0},
|
|
5: {CoreID: 1, SocketID: 0, NUMANodeID: 0},
|
|
6: {CoreID: 2, SocketID: 0, NUMANodeID: 0},
|
|
7: {CoreID: 3, SocketID: 0, NUMANodeID: 0},
|
|
},
|
|
},
|
|
wantErr: false,
|
|
},
|
|
{
|
|
// dual xeon gold 6230
|
|
name: "DualSocketMultiNumaPerSocketHT",
|
|
machineInfo: cadvisorapi.MachineInfo{
|
|
NumCores: 80,
|
|
NumSockets: 2,
|
|
Topology: []cadvisorapi.Node{
|
|
{Id: 0,
|
|
Cores: []cadvisorapi.Core{
|
|
{SocketID: 0, Id: 0, Threads: []int{0, 40}},
|
|
{SocketID: 0, Id: 1, Threads: []int{1, 41}},
|
|
{SocketID: 0, Id: 2, Threads: []int{2, 42}},
|
|
{SocketID: 0, Id: 8, Threads: []int{3, 43}},
|
|
{SocketID: 0, Id: 9, Threads: []int{4, 44}},
|
|
{SocketID: 0, Id: 16, Threads: []int{5, 45}},
|
|
{SocketID: 0, Id: 17, Threads: []int{6, 46}},
|
|
{SocketID: 0, Id: 18, Threads: []int{7, 47}},
|
|
{SocketID: 0, Id: 24, Threads: []int{8, 48}},
|
|
{SocketID: 0, Id: 25, Threads: []int{9, 49}},
|
|
},
|
|
},
|
|
{Id: 1,
|
|
Cores: []cadvisorapi.Core{
|
|
{SocketID: 0, Id: 3, Threads: []int{10, 50}},
|
|
{SocketID: 0, Id: 4, Threads: []int{11, 51}},
|
|
{SocketID: 0, Id: 10, Threads: []int{12, 52}},
|
|
{SocketID: 0, Id: 11, Threads: []int{13, 53}},
|
|
{SocketID: 0, Id: 12, Threads: []int{14, 54}},
|
|
{SocketID: 0, Id: 19, Threads: []int{15, 55}},
|
|
{SocketID: 0, Id: 20, Threads: []int{16, 56}},
|
|
{SocketID: 0, Id: 26, Threads: []int{17, 57}},
|
|
{SocketID: 0, Id: 27, Threads: []int{18, 58}},
|
|
{SocketID: 0, Id: 28, Threads: []int{19, 59}},
|
|
},
|
|
},
|
|
{Id: 2,
|
|
Cores: []cadvisorapi.Core{
|
|
{SocketID: 1, Id: 0, Threads: []int{20, 60}},
|
|
{SocketID: 1, Id: 1, Threads: []int{21, 61}},
|
|
{SocketID: 1, Id: 2, Threads: []int{22, 62}},
|
|
{SocketID: 1, Id: 8, Threads: []int{23, 63}},
|
|
{SocketID: 1, Id: 9, Threads: []int{24, 64}},
|
|
{SocketID: 1, Id: 16, Threads: []int{25, 65}},
|
|
{SocketID: 1, Id: 17, Threads: []int{26, 66}},
|
|
{SocketID: 1, Id: 18, Threads: []int{27, 67}},
|
|
{SocketID: 1, Id: 24, Threads: []int{28, 68}},
|
|
{SocketID: 1, Id: 25, Threads: []int{29, 69}},
|
|
},
|
|
},
|
|
{Id: 3,
|
|
Cores: []cadvisorapi.Core{
|
|
{SocketID: 1, Id: 3, Threads: []int{30, 70}},
|
|
{SocketID: 1, Id: 4, Threads: []int{31, 71}},
|
|
{SocketID: 1, Id: 10, Threads: []int{32, 72}},
|
|
{SocketID: 1, Id: 11, Threads: []int{33, 73}},
|
|
{SocketID: 1, Id: 12, Threads: []int{34, 74}},
|
|
{SocketID: 1, Id: 19, Threads: []int{35, 75}},
|
|
{SocketID: 1, Id: 20, Threads: []int{36, 76}},
|
|
{SocketID: 1, Id: 26, Threads: []int{37, 77}},
|
|
{SocketID: 1, Id: 27, Threads: []int{38, 78}},
|
|
{SocketID: 1, Id: 28, Threads: []int{39, 79}},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
want: &CPUTopology{
|
|
NumCPUs: 80,
|
|
NumSockets: 2,
|
|
NumCores: 40,
|
|
NumNUMANodes: 4,
|
|
CPUDetails: map[int]CPUInfo{
|
|
0: {CoreID: 0, SocketID: 0, NUMANodeID: 0},
|
|
1: {CoreID: 1, SocketID: 0, NUMANodeID: 0},
|
|
2: {CoreID: 2, SocketID: 0, NUMANodeID: 0},
|
|
3: {CoreID: 3, SocketID: 0, NUMANodeID: 0},
|
|
4: {CoreID: 4, SocketID: 0, NUMANodeID: 0},
|
|
5: {CoreID: 5, SocketID: 0, NUMANodeID: 0},
|
|
6: {CoreID: 6, SocketID: 0, NUMANodeID: 0},
|
|
7: {CoreID: 7, SocketID: 0, NUMANodeID: 0},
|
|
8: {CoreID: 8, SocketID: 0, NUMANodeID: 0},
|
|
9: {CoreID: 9, SocketID: 0, NUMANodeID: 0},
|
|
10: {CoreID: 10, SocketID: 0, NUMANodeID: 1},
|
|
11: {CoreID: 11, SocketID: 0, NUMANodeID: 1},
|
|
12: {CoreID: 12, SocketID: 0, NUMANodeID: 1},
|
|
13: {CoreID: 13, SocketID: 0, NUMANodeID: 1},
|
|
14: {CoreID: 14, SocketID: 0, NUMANodeID: 1},
|
|
15: {CoreID: 15, SocketID: 0, NUMANodeID: 1},
|
|
16: {CoreID: 16, SocketID: 0, NUMANodeID: 1},
|
|
17: {CoreID: 17, SocketID: 0, NUMANodeID: 1},
|
|
18: {CoreID: 18, SocketID: 0, NUMANodeID: 1},
|
|
19: {CoreID: 19, SocketID: 0, NUMANodeID: 1},
|
|
20: {CoreID: 20, SocketID: 1, NUMANodeID: 2},
|
|
21: {CoreID: 21, SocketID: 1, NUMANodeID: 2},
|
|
22: {CoreID: 22, SocketID: 1, NUMANodeID: 2},
|
|
23: {CoreID: 23, SocketID: 1, NUMANodeID: 2},
|
|
24: {CoreID: 24, SocketID: 1, NUMANodeID: 2},
|
|
25: {CoreID: 25, SocketID: 1, NUMANodeID: 2},
|
|
26: {CoreID: 26, SocketID: 1, NUMANodeID: 2},
|
|
27: {CoreID: 27, SocketID: 1, NUMANodeID: 2},
|
|
28: {CoreID: 28, SocketID: 1, NUMANodeID: 2},
|
|
29: {CoreID: 29, SocketID: 1, NUMANodeID: 2},
|
|
30: {CoreID: 30, SocketID: 1, NUMANodeID: 3},
|
|
31: {CoreID: 31, SocketID: 1, NUMANodeID: 3},
|
|
32: {CoreID: 32, SocketID: 1, NUMANodeID: 3},
|
|
33: {CoreID: 33, SocketID: 1, NUMANodeID: 3},
|
|
34: {CoreID: 34, SocketID: 1, NUMANodeID: 3},
|
|
35: {CoreID: 35, SocketID: 1, NUMANodeID: 3},
|
|
36: {CoreID: 36, SocketID: 1, NUMANodeID: 3},
|
|
37: {CoreID: 37, SocketID: 1, NUMANodeID: 3},
|
|
38: {CoreID: 38, SocketID: 1, NUMANodeID: 3},
|
|
39: {CoreID: 39, SocketID: 1, NUMANodeID: 3},
|
|
40: {CoreID: 0, SocketID: 0, NUMANodeID: 0},
|
|
41: {CoreID: 1, SocketID: 0, NUMANodeID: 0},
|
|
42: {CoreID: 2, SocketID: 0, NUMANodeID: 0},
|
|
43: {CoreID: 3, SocketID: 0, NUMANodeID: 0},
|
|
44: {CoreID: 4, SocketID: 0, NUMANodeID: 0},
|
|
45: {CoreID: 5, SocketID: 0, NUMANodeID: 0},
|
|
46: {CoreID: 6, SocketID: 0, NUMANodeID: 0},
|
|
47: {CoreID: 7, SocketID: 0, NUMANodeID: 0},
|
|
48: {CoreID: 8, SocketID: 0, NUMANodeID: 0},
|
|
49: {CoreID: 9, SocketID: 0, NUMANodeID: 0},
|
|
50: {CoreID: 10, SocketID: 0, NUMANodeID: 1},
|
|
51: {CoreID: 11, SocketID: 0, NUMANodeID: 1},
|
|
52: {CoreID: 12, SocketID: 0, NUMANodeID: 1},
|
|
53: {CoreID: 13, SocketID: 0, NUMANodeID: 1},
|
|
54: {CoreID: 14, SocketID: 0, NUMANodeID: 1},
|
|
55: {CoreID: 15, SocketID: 0, NUMANodeID: 1},
|
|
56: {CoreID: 16, SocketID: 0, NUMANodeID: 1},
|
|
57: {CoreID: 17, SocketID: 0, NUMANodeID: 1},
|
|
58: {CoreID: 18, SocketID: 0, NUMANodeID: 1},
|
|
59: {CoreID: 19, SocketID: 0, NUMANodeID: 1},
|
|
60: {CoreID: 20, SocketID: 1, NUMANodeID: 2},
|
|
61: {CoreID: 21, SocketID: 1, NUMANodeID: 2},
|
|
62: {CoreID: 22, SocketID: 1, NUMANodeID: 2},
|
|
63: {CoreID: 23, SocketID: 1, NUMANodeID: 2},
|
|
64: {CoreID: 24, SocketID: 1, NUMANodeID: 2},
|
|
65: {CoreID: 25, SocketID: 1, NUMANodeID: 2},
|
|
66: {CoreID: 26, SocketID: 1, NUMANodeID: 2},
|
|
67: {CoreID: 27, SocketID: 1, NUMANodeID: 2},
|
|
68: {CoreID: 28, SocketID: 1, NUMANodeID: 2},
|
|
69: {CoreID: 29, SocketID: 1, NUMANodeID: 2},
|
|
70: {CoreID: 30, SocketID: 1, NUMANodeID: 3},
|
|
71: {CoreID: 31, SocketID: 1, NUMANodeID: 3},
|
|
72: {CoreID: 32, SocketID: 1, NUMANodeID: 3},
|
|
73: {CoreID: 33, SocketID: 1, NUMANodeID: 3},
|
|
74: {CoreID: 34, SocketID: 1, NUMANodeID: 3},
|
|
75: {CoreID: 35, SocketID: 1, NUMANodeID: 3},
|
|
76: {CoreID: 36, SocketID: 1, NUMANodeID: 3},
|
|
77: {CoreID: 37, SocketID: 1, NUMANodeID: 3},
|
|
78: {CoreID: 38, SocketID: 1, NUMANodeID: 3},
|
|
79: {CoreID: 39, SocketID: 1, NUMANodeID: 3},
|
|
},
|
|
},
|
|
wantErr: false,
|
|
},
|
|
{
|
|
|
|
// FAKE Topology from dual xeon gold 6230
|
|
// (see: dual xeon gold 6230).
|
|
// We flip NUMA cells and Sockets to exercise the code.
|
|
// TODO(fromanirh): replace with a real-world topology
|
|
// once we find a suitable one.
|
|
// Note: this is a fake topology. Thus, there is not a "correct"
|
|
// representation. This one was created following the these concepts:
|
|
// 1. be internally consistent (most important rule)
|
|
// 2. be as close as possible as existing HW topologies
|
|
// 3. if possible, minimize chances wrt existing HW topologies.
|
|
name: "DualNumaMultiSocketPerNumaHT",
|
|
machineInfo: cadvisorapi.MachineInfo{
|
|
NumCores: 80,
|
|
NumSockets: 4,
|
|
Topology: []cadvisorapi.Node{
|
|
{Id: 0,
|
|
Cores: []cadvisorapi.Core{
|
|
{SocketID: 0, Id: 0, Threads: []int{0, 40}},
|
|
{SocketID: 0, Id: 1, Threads: []int{1, 41}},
|
|
{SocketID: 0, Id: 2, Threads: []int{2, 42}},
|
|
{SocketID: 0, Id: 8, Threads: []int{3, 43}},
|
|
{SocketID: 0, Id: 9, Threads: []int{4, 44}},
|
|
{SocketID: 0, Id: 16, Threads: []int{5, 45}},
|
|
{SocketID: 0, Id: 17, Threads: []int{6, 46}},
|
|
{SocketID: 0, Id: 18, Threads: []int{7, 47}},
|
|
{SocketID: 0, Id: 24, Threads: []int{8, 48}},
|
|
{SocketID: 0, Id: 25, Threads: []int{9, 49}},
|
|
{SocketID: 1, Id: 3, Threads: []int{10, 50}},
|
|
{SocketID: 1, Id: 4, Threads: []int{11, 51}},
|
|
{SocketID: 1, Id: 10, Threads: []int{12, 52}},
|
|
{SocketID: 1, Id: 11, Threads: []int{13, 53}},
|
|
{SocketID: 1, Id: 12, Threads: []int{14, 54}},
|
|
{SocketID: 1, Id: 19, Threads: []int{15, 55}},
|
|
{SocketID: 1, Id: 20, Threads: []int{16, 56}},
|
|
{SocketID: 1, Id: 26, Threads: []int{17, 57}},
|
|
{SocketID: 1, Id: 27, Threads: []int{18, 58}},
|
|
{SocketID: 1, Id: 28, Threads: []int{19, 59}},
|
|
},
|
|
},
|
|
{Id: 1,
|
|
Cores: []cadvisorapi.Core{
|
|
{SocketID: 2, Id: 0, Threads: []int{20, 60}},
|
|
{SocketID: 2, Id: 1, Threads: []int{21, 61}},
|
|
{SocketID: 2, Id: 2, Threads: []int{22, 62}},
|
|
{SocketID: 2, Id: 8, Threads: []int{23, 63}},
|
|
{SocketID: 2, Id: 9, Threads: []int{24, 64}},
|
|
{SocketID: 2, Id: 16, Threads: []int{25, 65}},
|
|
{SocketID: 2, Id: 17, Threads: []int{26, 66}},
|
|
{SocketID: 2, Id: 18, Threads: []int{27, 67}},
|
|
{SocketID: 2, Id: 24, Threads: []int{28, 68}},
|
|
{SocketID: 2, Id: 25, Threads: []int{29, 69}},
|
|
{SocketID: 3, Id: 3, Threads: []int{30, 70}},
|
|
{SocketID: 3, Id: 4, Threads: []int{31, 71}},
|
|
{SocketID: 3, Id: 10, Threads: []int{32, 72}},
|
|
{SocketID: 3, Id: 11, Threads: []int{33, 73}},
|
|
{SocketID: 3, Id: 12, Threads: []int{34, 74}},
|
|
{SocketID: 3, Id: 19, Threads: []int{35, 75}},
|
|
{SocketID: 3, Id: 20, Threads: []int{36, 76}},
|
|
{SocketID: 3, Id: 26, Threads: []int{37, 77}},
|
|
{SocketID: 3, Id: 27, Threads: []int{38, 78}},
|
|
{SocketID: 3, Id: 28, Threads: []int{39, 79}},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
want: &CPUTopology{
|
|
NumCPUs: 80,
|
|
NumSockets: 4,
|
|
NumCores: 40,
|
|
NumNUMANodes: 2,
|
|
CPUDetails: map[int]CPUInfo{
|
|
0: {CoreID: 0, SocketID: 0, NUMANodeID: 0},
|
|
1: {CoreID: 1, SocketID: 0, NUMANodeID: 0},
|
|
2: {CoreID: 2, SocketID: 0, NUMANodeID: 0},
|
|
3: {CoreID: 3, SocketID: 0, NUMANodeID: 0},
|
|
4: {CoreID: 4, SocketID: 0, NUMANodeID: 0},
|
|
5: {CoreID: 5, SocketID: 0, NUMANodeID: 0},
|
|
6: {CoreID: 6, SocketID: 0, NUMANodeID: 0},
|
|
7: {CoreID: 7, SocketID: 0, NUMANodeID: 0},
|
|
8: {CoreID: 8, SocketID: 0, NUMANodeID: 0},
|
|
9: {CoreID: 9, SocketID: 0, NUMANodeID: 0},
|
|
10: {CoreID: 10, SocketID: 1, NUMANodeID: 0},
|
|
11: {CoreID: 11, SocketID: 1, NUMANodeID: 0},
|
|
12: {CoreID: 12, SocketID: 1, NUMANodeID: 0},
|
|
13: {CoreID: 13, SocketID: 1, NUMANodeID: 0},
|
|
14: {CoreID: 14, SocketID: 1, NUMANodeID: 0},
|
|
15: {CoreID: 15, SocketID: 1, NUMANodeID: 0},
|
|
16: {CoreID: 16, SocketID: 1, NUMANodeID: 0},
|
|
17: {CoreID: 17, SocketID: 1, NUMANodeID: 0},
|
|
18: {CoreID: 18, SocketID: 1, NUMANodeID: 0},
|
|
19: {CoreID: 19, SocketID: 1, NUMANodeID: 0},
|
|
20: {CoreID: 20, SocketID: 2, NUMANodeID: 1},
|
|
21: {CoreID: 21, SocketID: 2, NUMANodeID: 1},
|
|
22: {CoreID: 22, SocketID: 2, NUMANodeID: 1},
|
|
23: {CoreID: 23, SocketID: 2, NUMANodeID: 1},
|
|
24: {CoreID: 24, SocketID: 2, NUMANodeID: 1},
|
|
25: {CoreID: 25, SocketID: 2, NUMANodeID: 1},
|
|
26: {CoreID: 26, SocketID: 2, NUMANodeID: 1},
|
|
27: {CoreID: 27, SocketID: 2, NUMANodeID: 1},
|
|
28: {CoreID: 28, SocketID: 2, NUMANodeID: 1},
|
|
29: {CoreID: 29, SocketID: 2, NUMANodeID: 1},
|
|
30: {CoreID: 30, SocketID: 3, NUMANodeID: 1},
|
|
31: {CoreID: 31, SocketID: 3, NUMANodeID: 1},
|
|
32: {CoreID: 32, SocketID: 3, NUMANodeID: 1},
|
|
33: {CoreID: 33, SocketID: 3, NUMANodeID: 1},
|
|
34: {CoreID: 34, SocketID: 3, NUMANodeID: 1},
|
|
35: {CoreID: 35, SocketID: 3, NUMANodeID: 1},
|
|
36: {CoreID: 36, SocketID: 3, NUMANodeID: 1},
|
|
37: {CoreID: 37, SocketID: 3, NUMANodeID: 1},
|
|
38: {CoreID: 38, SocketID: 3, NUMANodeID: 1},
|
|
39: {CoreID: 39, SocketID: 3, NUMANodeID: 1},
|
|
40: {CoreID: 0, SocketID: 0, NUMANodeID: 0},
|
|
41: {CoreID: 1, SocketID: 0, NUMANodeID: 0},
|
|
42: {CoreID: 2, SocketID: 0, NUMANodeID: 0},
|
|
43: {CoreID: 3, SocketID: 0, NUMANodeID: 0},
|
|
44: {CoreID: 4, SocketID: 0, NUMANodeID: 0},
|
|
45: {CoreID: 5, SocketID: 0, NUMANodeID: 0},
|
|
46: {CoreID: 6, SocketID: 0, NUMANodeID: 0},
|
|
47: {CoreID: 7, SocketID: 0, NUMANodeID: 0},
|
|
48: {CoreID: 8, SocketID: 0, NUMANodeID: 0},
|
|
49: {CoreID: 9, SocketID: 0, NUMANodeID: 0},
|
|
50: {CoreID: 10, SocketID: 1, NUMANodeID: 0},
|
|
51: {CoreID: 11, SocketID: 1, NUMANodeID: 0},
|
|
52: {CoreID: 12, SocketID: 1, NUMANodeID: 0},
|
|
53: {CoreID: 13, SocketID: 1, NUMANodeID: 0},
|
|
54: {CoreID: 14, SocketID: 1, NUMANodeID: 0},
|
|
55: {CoreID: 15, SocketID: 1, NUMANodeID: 0},
|
|
56: {CoreID: 16, SocketID: 1, NUMANodeID: 0},
|
|
57: {CoreID: 17, SocketID: 1, NUMANodeID: 0},
|
|
58: {CoreID: 18, SocketID: 1, NUMANodeID: 0},
|
|
59: {CoreID: 19, SocketID: 1, NUMANodeID: 0},
|
|
60: {CoreID: 20, SocketID: 2, NUMANodeID: 1},
|
|
61: {CoreID: 21, SocketID: 2, NUMANodeID: 1},
|
|
62: {CoreID: 22, SocketID: 2, NUMANodeID: 1},
|
|
63: {CoreID: 23, SocketID: 2, NUMANodeID: 1},
|
|
64: {CoreID: 24, SocketID: 2, NUMANodeID: 1},
|
|
65: {CoreID: 25, SocketID: 2, NUMANodeID: 1},
|
|
66: {CoreID: 26, SocketID: 2, NUMANodeID: 1},
|
|
67: {CoreID: 27, SocketID: 2, NUMANodeID: 1},
|
|
68: {CoreID: 28, SocketID: 2, NUMANodeID: 1},
|
|
69: {CoreID: 29, SocketID: 2, NUMANodeID: 1},
|
|
70: {CoreID: 30, SocketID: 3, NUMANodeID: 1},
|
|
71: {CoreID: 31, SocketID: 3, NUMANodeID: 1},
|
|
72: {CoreID: 32, SocketID: 3, NUMANodeID: 1},
|
|
73: {CoreID: 33, SocketID: 3, NUMANodeID: 1},
|
|
74: {CoreID: 34, SocketID: 3, NUMANodeID: 1},
|
|
75: {CoreID: 35, SocketID: 3, NUMANodeID: 1},
|
|
76: {CoreID: 36, SocketID: 3, NUMANodeID: 1},
|
|
77: {CoreID: 37, SocketID: 3, NUMANodeID: 1},
|
|
78: {CoreID: 38, SocketID: 3, NUMANodeID: 1},
|
|
79: {CoreID: 39, SocketID: 3, NUMANodeID: 1},
|
|
},
|
|
},
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "DualSocketNoHT",
|
|
machineInfo: cadvisorapi.MachineInfo{
|
|
NumCores: 4,
|
|
NumSockets: 2,
|
|
Topology: []cadvisorapi.Node{
|
|
{Id: 0,
|
|
Cores: []cadvisorapi.Core{
|
|
{SocketID: 0, Id: 0, Threads: []int{0}},
|
|
{SocketID: 0, Id: 2, Threads: []int{2}},
|
|
},
|
|
},
|
|
{Id: 1,
|
|
Cores: []cadvisorapi.Core{
|
|
{SocketID: 1, Id: 1, Threads: []int{1}},
|
|
{SocketID: 1, Id: 3, Threads: []int{3}},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
want: &CPUTopology{
|
|
NumCPUs: 4,
|
|
NumSockets: 2,
|
|
NumCores: 4,
|
|
NumNUMANodes: 2,
|
|
CPUDetails: map[int]CPUInfo{
|
|
0: {CoreID: 0, SocketID: 0, NUMANodeID: 0},
|
|
1: {CoreID: 1, SocketID: 1, NUMANodeID: 1},
|
|
2: {CoreID: 2, SocketID: 0, NUMANodeID: 0},
|
|
3: {CoreID: 3, SocketID: 1, NUMANodeID: 1},
|
|
},
|
|
},
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "DualSocketHT - non unique Core'ID's",
|
|
machineInfo: cadvisorapi.MachineInfo{
|
|
NumCores: 12,
|
|
NumSockets: 2,
|
|
Topology: []cadvisorapi.Node{
|
|
{Id: 0,
|
|
Cores: []cadvisorapi.Core{
|
|
{SocketID: 0, Id: 0, Threads: []int{0, 6}},
|
|
{SocketID: 0, Id: 1, Threads: []int{1, 7}},
|
|
{SocketID: 0, Id: 2, Threads: []int{2, 8}},
|
|
},
|
|
},
|
|
{Id: 1,
|
|
Cores: []cadvisorapi.Core{
|
|
{SocketID: 1, Id: 0, Threads: []int{3, 9}},
|
|
{SocketID: 1, Id: 1, Threads: []int{4, 10}},
|
|
{SocketID: 1, Id: 2, Threads: []int{5, 11}},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
want: &CPUTopology{
|
|
NumCPUs: 12,
|
|
NumSockets: 2,
|
|
NumCores: 6,
|
|
NumNUMANodes: 2,
|
|
CPUDetails: map[int]CPUInfo{
|
|
0: {CoreID: 0, SocketID: 0, NUMANodeID: 0},
|
|
1: {CoreID: 1, SocketID: 0, NUMANodeID: 0},
|
|
2: {CoreID: 2, SocketID: 0, NUMANodeID: 0},
|
|
3: {CoreID: 3, SocketID: 1, NUMANodeID: 1},
|
|
4: {CoreID: 4, SocketID: 1, NUMANodeID: 1},
|
|
5: {CoreID: 5, SocketID: 1, NUMANodeID: 1},
|
|
6: {CoreID: 0, SocketID: 0, NUMANodeID: 0},
|
|
7: {CoreID: 1, SocketID: 0, NUMANodeID: 0},
|
|
8: {CoreID: 2, SocketID: 0, NUMANodeID: 0},
|
|
9: {CoreID: 3, SocketID: 1, NUMANodeID: 1},
|
|
10: {CoreID: 4, SocketID: 1, NUMANodeID: 1},
|
|
11: {CoreID: 5, SocketID: 1, NUMANodeID: 1},
|
|
},
|
|
},
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "OneSocketHT fail",
|
|
machineInfo: cadvisorapi.MachineInfo{
|
|
NumCores: 8,
|
|
NumSockets: 1,
|
|
Topology: []cadvisorapi.Node{
|
|
{Id: 0,
|
|
Cores: []cadvisorapi.Core{
|
|
{SocketID: 0, Id: 0, Threads: []int{0, 4}},
|
|
{SocketID: 0, Id: 1, Threads: []int{1, 5}},
|
|
{SocketID: 0, Id: 2, Threads: []int{2, 2}}, // Wrong case - should fail here
|
|
{SocketID: 0, Id: 3, Threads: []int{3, 7}},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
want: &CPUTopology{},
|
|
wantErr: true,
|
|
},
|
|
{
|
|
name: "OneSocketHT fail",
|
|
machineInfo: cadvisorapi.MachineInfo{
|
|
NumCores: 8,
|
|
NumSockets: 1,
|
|
Topology: []cadvisorapi.Node{
|
|
{Id: 0,
|
|
Cores: []cadvisorapi.Core{
|
|
{SocketID: 0, Id: 0, Threads: []int{0, 4}},
|
|
{SocketID: 0, Id: 1, Threads: []int{1, 5}},
|
|
{SocketID: 0, Id: 2, Threads: []int{2, 6}},
|
|
{SocketID: 0, Id: 3, Threads: []int{}}, // Wrong case - should fail here
|
|
},
|
|
},
|
|
},
|
|
},
|
|
want: &CPUTopology{},
|
|
wantErr: true,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got, err := Discover(&tt.machineInfo)
|
|
if err != nil {
|
|
if tt.wantErr {
|
|
t.Logf("Discover() expected error = %v", err)
|
|
} else {
|
|
t.Errorf("Discover() error = %v, wantErr %v", err, tt.wantErr)
|
|
}
|
|
return
|
|
}
|
|
if diff := cmp.Diff(got, tt.want); diff != "" {
|
|
t.Errorf("Discover() = %v, want %v diff=%s", got, tt.want, diff)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestCPUDetailsKeepOnly(t *testing.T) {
|
|
|
|
var details CPUDetails
|
|
details = map[int]CPUInfo{
|
|
0: {},
|
|
1: {},
|
|
2: {},
|
|
}
|
|
|
|
tests := []struct {
|
|
name string
|
|
cpus cpuset.CPUSet
|
|
want CPUDetails
|
|
}{{
|
|
name: "cpus is in CPUDetails.",
|
|
cpus: cpuset.New(0, 1),
|
|
want: map[int]CPUInfo{
|
|
0: {},
|
|
1: {},
|
|
},
|
|
}, {
|
|
name: "cpus is not in CPUDetails.",
|
|
cpus: cpuset.New(3),
|
|
want: CPUDetails{},
|
|
}}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got := details.KeepOnly(tt.cpus)
|
|
if !reflect.DeepEqual(got, tt.want) {
|
|
t.Errorf("KeepOnly() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestCPUDetailsNUMANodes(t *testing.T) {
|
|
|
|
tests := []struct {
|
|
name string
|
|
details CPUDetails
|
|
want cpuset.CPUSet
|
|
}{{
|
|
name: "Get CPUset of NUMANode IDs",
|
|
details: map[int]CPUInfo{
|
|
0: {NUMANodeID: 0},
|
|
1: {NUMANodeID: 0},
|
|
2: {NUMANodeID: 1},
|
|
3: {NUMANodeID: 1},
|
|
},
|
|
want: cpuset.New(0, 1),
|
|
}}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got := tt.details.NUMANodes()
|
|
if !reflect.DeepEqual(got, tt.want) {
|
|
t.Errorf("NUMANodes() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestCPUDetailsNUMANodesInSockets(t *testing.T) {
|
|
|
|
var details1 CPUDetails
|
|
details1 = map[int]CPUInfo{
|
|
0: {SocketID: 0, NUMANodeID: 0},
|
|
1: {SocketID: 1, NUMANodeID: 0},
|
|
2: {SocketID: 2, NUMANodeID: 1},
|
|
3: {SocketID: 3, NUMANodeID: 1},
|
|
}
|
|
|
|
// poorly designed mainboards
|
|
var details2 CPUDetails
|
|
details2 = map[int]CPUInfo{
|
|
0: {SocketID: 0, NUMANodeID: 0},
|
|
1: {SocketID: 0, NUMANodeID: 1},
|
|
2: {SocketID: 1, NUMANodeID: 2},
|
|
3: {SocketID: 1, NUMANodeID: 3},
|
|
}
|
|
|
|
tests := []struct {
|
|
name string
|
|
details CPUDetails
|
|
ids []int
|
|
want cpuset.CPUSet
|
|
}{{
|
|
name: "Socket IDs is in CPUDetails.",
|
|
details: details1,
|
|
ids: []int{0, 1, 2},
|
|
want: cpuset.New(0, 1),
|
|
}, {
|
|
name: "Socket IDs is not in CPUDetails.",
|
|
details: details1,
|
|
ids: []int{4},
|
|
want: cpuset.New(),
|
|
}, {
|
|
name: "Socket IDs is in CPUDetails. (poorly designed mainboards)",
|
|
details: details2,
|
|
ids: []int{0},
|
|
want: cpuset.New(0, 1),
|
|
}, {
|
|
name: "Socket IDs is not in CPUDetails. (poorly designed mainboards)",
|
|
details: details2,
|
|
ids: []int{3},
|
|
want: cpuset.New(),
|
|
}}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got := tt.details.NUMANodesInSockets(tt.ids...)
|
|
if !reflect.DeepEqual(got, tt.want) {
|
|
t.Errorf("NUMANodesInSockets() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestCPUDetailsSockets(t *testing.T) {
|
|
|
|
tests := []struct {
|
|
name string
|
|
details CPUDetails
|
|
want cpuset.CPUSet
|
|
}{{
|
|
name: "Get CPUset of Socket IDs",
|
|
details: map[int]CPUInfo{
|
|
0: {SocketID: 0},
|
|
1: {SocketID: 0},
|
|
2: {SocketID: 1},
|
|
3: {SocketID: 1},
|
|
},
|
|
want: cpuset.New(0, 1),
|
|
}}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got := tt.details.Sockets()
|
|
if !reflect.DeepEqual(got, tt.want) {
|
|
t.Errorf("Sockets() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestCPUDetailsCPUsInSockets(t *testing.T) {
|
|
|
|
var details CPUDetails
|
|
details = map[int]CPUInfo{
|
|
0: {SocketID: 0},
|
|
1: {SocketID: 0},
|
|
2: {SocketID: 1},
|
|
3: {SocketID: 2},
|
|
}
|
|
|
|
tests := []struct {
|
|
name string
|
|
ids []int
|
|
want cpuset.CPUSet
|
|
}{{
|
|
name: "Socket IDs is in CPUDetails.",
|
|
ids: []int{0, 1},
|
|
want: cpuset.New(0, 1, 2),
|
|
}, {
|
|
name: "Socket IDs is not in CPUDetails.",
|
|
ids: []int{3},
|
|
want: cpuset.New(),
|
|
}}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got := details.CPUsInSockets(tt.ids...)
|
|
if !reflect.DeepEqual(got, tt.want) {
|
|
t.Errorf("CPUsInSockets() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestCPUDetailsSocketsInNUMANodes(t *testing.T) {
|
|
|
|
var details CPUDetails
|
|
details = map[int]CPUInfo{
|
|
0: {NUMANodeID: 0, SocketID: 0},
|
|
1: {NUMANodeID: 0, SocketID: 1},
|
|
2: {NUMANodeID: 1, SocketID: 2},
|
|
3: {NUMANodeID: 2, SocketID: 3},
|
|
}
|
|
|
|
tests := []struct {
|
|
name string
|
|
ids []int
|
|
want cpuset.CPUSet
|
|
}{{
|
|
name: "NUMANodes IDs is in CPUDetails.",
|
|
ids: []int{0, 1},
|
|
want: cpuset.New(0, 1, 2),
|
|
}, {
|
|
name: "NUMANodes IDs is not in CPUDetails.",
|
|
ids: []int{3},
|
|
want: cpuset.New(),
|
|
}}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got := details.SocketsInNUMANodes(tt.ids...)
|
|
if !reflect.DeepEqual(got, tt.want) {
|
|
t.Errorf("SocketsInNUMANodes() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestCPUDetailsCores(t *testing.T) {
|
|
|
|
tests := []struct {
|
|
name string
|
|
details CPUDetails
|
|
want cpuset.CPUSet
|
|
}{{
|
|
name: "Get CPUset of Cores",
|
|
details: map[int]CPUInfo{
|
|
0: {CoreID: 0},
|
|
1: {CoreID: 0},
|
|
2: {CoreID: 1},
|
|
3: {CoreID: 1},
|
|
},
|
|
want: cpuset.New(0, 1),
|
|
}}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got := tt.details.Cores()
|
|
if !reflect.DeepEqual(got, tt.want) {
|
|
t.Errorf("Cores() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestCPUDetailsCoresInNUMANodes(t *testing.T) {
|
|
|
|
var details CPUDetails
|
|
details = map[int]CPUInfo{
|
|
0: {NUMANodeID: 0, CoreID: 0},
|
|
1: {NUMANodeID: 0, CoreID: 1},
|
|
2: {NUMANodeID: 1, CoreID: 2},
|
|
3: {NUMANodeID: 2, CoreID: 3},
|
|
}
|
|
|
|
tests := []struct {
|
|
name string
|
|
ids []int
|
|
want cpuset.CPUSet
|
|
}{{
|
|
name: "NUMANodes IDs is in CPUDetails.",
|
|
ids: []int{0, 1},
|
|
want: cpuset.New(0, 1, 2),
|
|
}, {
|
|
name: "NUMANodes IDs is not in CPUDetails.",
|
|
ids: []int{3},
|
|
want: cpuset.New(),
|
|
}}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got := details.CoresInNUMANodes(tt.ids...)
|
|
if !reflect.DeepEqual(got, tt.want) {
|
|
t.Errorf("CoresInNUMANodes() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestCPUDetailsCoresInSockets(t *testing.T) {
|
|
|
|
var details CPUDetails
|
|
details = map[int]CPUInfo{
|
|
0: {SocketID: 0, CoreID: 0},
|
|
1: {SocketID: 0, CoreID: 1},
|
|
2: {SocketID: 1, CoreID: 2},
|
|
3: {SocketID: 2, CoreID: 3},
|
|
}
|
|
|
|
tests := []struct {
|
|
name string
|
|
ids []int
|
|
want cpuset.CPUSet
|
|
}{{
|
|
name: "Socket IDs is in CPUDetails.",
|
|
ids: []int{0, 1},
|
|
want: cpuset.New(0, 1, 2),
|
|
}, {
|
|
name: "Socket IDs is not in CPUDetails.",
|
|
ids: []int{3},
|
|
want: cpuset.New(),
|
|
}}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got := details.CoresInSockets(tt.ids...)
|
|
if !reflect.DeepEqual(got, tt.want) {
|
|
t.Errorf("CoresInSockets() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestCPUDetailsCPUs(t *testing.T) {
|
|
|
|
tests := []struct {
|
|
name string
|
|
details CPUDetails
|
|
want cpuset.CPUSet
|
|
}{{
|
|
name: "Get CPUset of CPUs",
|
|
details: map[int]CPUInfo{
|
|
0: {},
|
|
1: {},
|
|
},
|
|
want: cpuset.New(0, 1),
|
|
}}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got := tt.details.CPUs()
|
|
if !reflect.DeepEqual(got, tt.want) {
|
|
t.Errorf("CPUs() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestCPUDetailsCPUsInNUMANodes(t *testing.T) {
|
|
|
|
var details CPUDetails
|
|
details = map[int]CPUInfo{
|
|
0: {NUMANodeID: 0},
|
|
1: {NUMANodeID: 0},
|
|
2: {NUMANodeID: 1},
|
|
3: {NUMANodeID: 2},
|
|
}
|
|
|
|
tests := []struct {
|
|
name string
|
|
ids []int
|
|
want cpuset.CPUSet
|
|
}{{
|
|
name: "NUMANode IDs is in CPUDetails.",
|
|
ids: []int{0, 1},
|
|
want: cpuset.New(0, 1, 2),
|
|
}, {
|
|
name: "NUMANode IDs is not in CPUDetails.",
|
|
ids: []int{3},
|
|
want: cpuset.New(),
|
|
}}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got := details.CPUsInNUMANodes(tt.ids...)
|
|
if !reflect.DeepEqual(got, tt.want) {
|
|
t.Errorf("CPUsInNUMANodes() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestCPUDetailsCPUsInCores(t *testing.T) {
|
|
|
|
var details CPUDetails
|
|
details = map[int]CPUInfo{
|
|
0: {CoreID: 0},
|
|
1: {CoreID: 0},
|
|
2: {CoreID: 1},
|
|
3: {CoreID: 2},
|
|
}
|
|
|
|
tests := []struct {
|
|
name string
|
|
ids []int
|
|
want cpuset.CPUSet
|
|
}{{
|
|
name: "Core IDs is in CPUDetails.",
|
|
ids: []int{0, 1},
|
|
want: cpuset.New(0, 1, 2),
|
|
}, {
|
|
name: "Core IDs is not in CPUDetails.",
|
|
ids: []int{3},
|
|
want: cpuset.New(),
|
|
}}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got := details.CPUsInCores(tt.ids...)
|
|
if !reflect.DeepEqual(got, tt.want) {
|
|
t.Errorf("CPUsInCores() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestCPUCoreID(t *testing.T) {
|
|
topoDualSocketHT := &CPUTopology{
|
|
NumCPUs: 12,
|
|
NumSockets: 2,
|
|
NumCores: 6,
|
|
CPUDetails: map[int]CPUInfo{
|
|
0: {CoreID: 0, SocketID: 0, NUMANodeID: 0},
|
|
1: {CoreID: 1, SocketID: 1, NUMANodeID: 1},
|
|
2: {CoreID: 2, SocketID: 0, NUMANodeID: 0},
|
|
3: {CoreID: 3, SocketID: 1, NUMANodeID: 1},
|
|
4: {CoreID: 4, SocketID: 0, NUMANodeID: 0},
|
|
5: {CoreID: 5, SocketID: 1, NUMANodeID: 1},
|
|
6: {CoreID: 0, SocketID: 0, NUMANodeID: 0},
|
|
7: {CoreID: 1, SocketID: 1, NUMANodeID: 1},
|
|
8: {CoreID: 2, SocketID: 0, NUMANodeID: 0},
|
|
9: {CoreID: 3, SocketID: 1, NUMANodeID: 1},
|
|
10: {CoreID: 4, SocketID: 0, NUMANodeID: 0},
|
|
11: {CoreID: 5, SocketID: 1, NUMANodeID: 1},
|
|
},
|
|
}
|
|
|
|
tests := []struct {
|
|
name string
|
|
topo *CPUTopology
|
|
id int
|
|
want int
|
|
wantErr bool
|
|
}{{
|
|
name: "Known Core ID",
|
|
topo: topoDualSocketHT,
|
|
id: 2,
|
|
want: 2,
|
|
}, {
|
|
name: "Known Core ID (core sibling).",
|
|
topo: topoDualSocketHT,
|
|
id: 8,
|
|
want: 2,
|
|
}, {
|
|
name: "Unknown Core ID.",
|
|
topo: topoDualSocketHT,
|
|
id: -2,
|
|
want: -1,
|
|
wantErr: true,
|
|
}}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got, err := tt.topo.CPUCoreID(tt.id)
|
|
gotErr := (err != nil)
|
|
if gotErr != tt.wantErr {
|
|
t.Errorf("CPUCoreID() returned err %v, want %v", gotErr, tt.wantErr)
|
|
}
|
|
if got != tt.want {
|
|
t.Errorf("CPUCoreID() returned %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestCPUSocketID(t *testing.T) {
|
|
topoDualSocketHT := &CPUTopology{
|
|
NumCPUs: 12,
|
|
NumSockets: 2,
|
|
NumCores: 6,
|
|
CPUDetails: map[int]CPUInfo{
|
|
0: {CoreID: 0, SocketID: 0, NUMANodeID: 0},
|
|
1: {CoreID: 1, SocketID: 1, NUMANodeID: 1},
|
|
2: {CoreID: 2, SocketID: 0, NUMANodeID: 0},
|
|
3: {CoreID: 3, SocketID: 1, NUMANodeID: 1},
|
|
4: {CoreID: 4, SocketID: 0, NUMANodeID: 0},
|
|
5: {CoreID: 5, SocketID: 1, NUMANodeID: 1},
|
|
6: {CoreID: 0, SocketID: 0, NUMANodeID: 0},
|
|
7: {CoreID: 1, SocketID: 1, NUMANodeID: 1},
|
|
8: {CoreID: 2, SocketID: 0, NUMANodeID: 0},
|
|
9: {CoreID: 3, SocketID: 1, NUMANodeID: 1},
|
|
10: {CoreID: 4, SocketID: 0, NUMANodeID: 0},
|
|
11: {CoreID: 5, SocketID: 1, NUMANodeID: 1},
|
|
},
|
|
}
|
|
|
|
tests := []struct {
|
|
name string
|
|
topo *CPUTopology
|
|
id int
|
|
want int
|
|
wantErr bool
|
|
}{{
|
|
name: "Known Core ID",
|
|
topo: topoDualSocketHT,
|
|
id: 3,
|
|
want: 1,
|
|
}, {
|
|
name: "Known Core ID (core sibling).",
|
|
topo: topoDualSocketHT,
|
|
id: 9,
|
|
want: 1,
|
|
}, {
|
|
name: "Unknown Core ID.",
|
|
topo: topoDualSocketHT,
|
|
id: 1000,
|
|
want: -1,
|
|
wantErr: true,
|
|
}}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got, err := tt.topo.CPUSocketID(tt.id)
|
|
gotErr := (err != nil)
|
|
if gotErr != tt.wantErr {
|
|
t.Errorf("CPUSocketID() returned err %v, want %v", gotErr, tt.wantErr)
|
|
}
|
|
if got != tt.want {
|
|
t.Errorf("CPUSocketID() returned %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestCPUNUMANodeID(t *testing.T) {
|
|
topoDualSocketHT := &CPUTopology{
|
|
NumCPUs: 12,
|
|
NumSockets: 2,
|
|
NumCores: 6,
|
|
CPUDetails: map[int]CPUInfo{
|
|
0: {CoreID: 0, SocketID: 0, NUMANodeID: 0},
|
|
1: {CoreID: 1, SocketID: 1, NUMANodeID: 1},
|
|
2: {CoreID: 2, SocketID: 0, NUMANodeID: 0},
|
|
3: {CoreID: 3, SocketID: 1, NUMANodeID: 1},
|
|
4: {CoreID: 4, SocketID: 0, NUMANodeID: 0},
|
|
5: {CoreID: 5, SocketID: 1, NUMANodeID: 1},
|
|
6: {CoreID: 0, SocketID: 0, NUMANodeID: 0},
|
|
7: {CoreID: 1, SocketID: 1, NUMANodeID: 1},
|
|
8: {CoreID: 2, SocketID: 0, NUMANodeID: 0},
|
|
9: {CoreID: 3, SocketID: 1, NUMANodeID: 1},
|
|
10: {CoreID: 4, SocketID: 0, NUMANodeID: 0},
|
|
11: {CoreID: 5, SocketID: 1, NUMANodeID: 1},
|
|
},
|
|
}
|
|
|
|
tests := []struct {
|
|
name string
|
|
topo *CPUTopology
|
|
id int
|
|
want int
|
|
wantErr bool
|
|
}{{
|
|
name: "Known Core ID",
|
|
topo: topoDualSocketHT,
|
|
id: 0,
|
|
want: 0,
|
|
}, {
|
|
name: "Known Core ID (core sibling).",
|
|
topo: topoDualSocketHT,
|
|
id: 6,
|
|
want: 0,
|
|
}, {
|
|
name: "Unknown Core ID.",
|
|
topo: topoDualSocketHT,
|
|
id: 1000,
|
|
want: -1,
|
|
wantErr: true,
|
|
}}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got, err := tt.topo.CPUNUMANodeID(tt.id)
|
|
gotErr := (err != nil)
|
|
if gotErr != tt.wantErr {
|
|
t.Errorf("CPUSocketID() returned err %v, want %v", gotErr, tt.wantErr)
|
|
}
|
|
if got != tt.want {
|
|
t.Errorf("CPUSocketID() returned %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|