diff --git a/pkg/kubelet/cm/cpumanager/cpu_assignment_test.go b/pkg/kubelet/cm/cpumanager/cpu_assignment_test.go index 998fab53796..bdfffedb676 100644 --- a/pkg/kubelet/cm/cpumanager/cpu_assignment_test.go +++ b/pkg/kubelet/cm/cpumanager/cpu_assignment_test.go @@ -61,6 +61,24 @@ func TestCPUAccumulatorFreeSockets(t *testing.T) { cpuset.NewCPUSet(0, 2, 3, 4, 5, 6, 7, 8, 9, 11), []int{}, }, + { + "dual socket, multi numa per socket, HT, 2 sockets free", + topoDualSocketMultiNumaPerSocketHT, + mustParseCPUSet(t, "0-79"), + []int{0, 1}, + }, + { + "dual socket, multi numa per socket, HT, 1 sockets free", + topoDualSocketMultiNumaPerSocketHT, + mustParseCPUSet(t, "1-79"), + []int{1}, + }, + { + "dual socket, multi numa per socket, HT, 0 sockets free", + topoDualSocketMultiNumaPerSocketHT, + mustParseCPUSet(t, "1-78"), + []int{}, + }, } for _, tc := range testCases { @@ -75,6 +93,139 @@ func TestCPUAccumulatorFreeSockets(t *testing.T) { } } +func TestCPUAccumulatorFreeNUMANodes(t *testing.T) { + testCases := []struct { + description string + topo *topology.CPUTopology + availableCPUs cpuset.CPUSet + expect []int + }{ + { + "single socket HT, 1 NUMA node free", + topoSingleSocketHT, + cpuset.NewCPUSet(0, 1, 2, 3, 4, 5, 6, 7), + []int{0}, + }, + { + "single socket HT, 0 NUMA Node free", + topoSingleSocketHT, + cpuset.NewCPUSet(1, 2, 3, 4, 5, 6, 7), + []int{}, + }, + { + "dual socket HT, 2 NUMA Node free", + topoDualSocketHT, + cpuset.NewCPUSet(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11), + []int{0, 1}, + }, + { + "dual socket HT, 1 NUMA Node free", + topoDualSocketHT, + cpuset.NewCPUSet(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11), + []int{1}, + }, + { + "dual socket HT, 0 NUMA node free", + topoDualSocketHT, + cpuset.NewCPUSet(0, 2, 3, 4, 5, 6, 7, 8, 9, 11), + []int{}, + }, + { + "dual socket, multi numa per socket, HT, 4 NUMA Node free", + topoDualSocketMultiNumaPerSocketHT, + mustParseCPUSet(t, "0-79"), + []int{0, 1, 2, 3}, + }, + { + "dual socket, multi numa per socket, HT, 3 NUMA node free", + topoDualSocketMultiNumaPerSocketHT, + mustParseCPUSet(t, "1-79"), + []int{1, 2, 3}, + }, + { + "dual socket, multi numa per socket, HT, 2 NUMA node free", + topoDualSocketMultiNumaPerSocketHT, + mustParseCPUSet(t, "1-9,11-79"), + []int{2, 3}, + }, + { + "dual socket, multi numa per socket, HT, 1 NUMA node free", + topoDualSocketMultiNumaPerSocketHT, + mustParseCPUSet(t, "1-9,11-59,61-79"), + []int{3}, + }, + { + "dual socket, multi numa per socket, HT, 0 NUMA node free", + topoDualSocketMultiNumaPerSocketHT, + mustParseCPUSet(t, "1-9,11-59,61-78"), + []int{}, + }, + } + + for _, tc := range testCases { + t.Run(tc.description, func(t *testing.T) { + acc := newCPUAccumulator(tc.topo, tc.availableCPUs, 0) + result := acc.freeNUMANodes() + if !reflect.DeepEqual(result, tc.expect) { + t.Errorf("expected %v to equal %v", result, tc.expect) + } + }) + } +} + +func TestCPUAccumulatorFreeSocketsAndNUMANodes(t *testing.T) { + testCases := []struct { + description string + topo *topology.CPUTopology + availableCPUs cpuset.CPUSet + expectSockets []int + expectNUMANodes []int + }{ + { + "dual socket, multi numa per socket, HT, 2 Socket/4 NUMA Node free", + topoDualSocketMultiNumaPerSocketHT, + mustParseCPUSet(t, "0-79"), + []int{0, 1}, + []int{0, 1, 2, 3}, + }, + { + "dual socket, multi numa per socket, HT, 1 Socket/3 NUMA node free", + topoDualSocketMultiNumaPerSocketHT, + mustParseCPUSet(t, "1-79"), + []int{1}, + []int{1, 2, 3}, + }, + { + "dual socket, multi numa per socket, HT, 1 Socket/ 2 NUMA node free", + topoDualSocketMultiNumaPerSocketHT, + mustParseCPUSet(t, "1-9,11-79"), + []int{1}, + []int{2, 3}, + }, + { + "dual socket, multi numa per socket, HT, 0 Socket/ 2 NUMA node free", + topoDualSocketMultiNumaPerSocketHT, + mustParseCPUSet(t, "1-59,61-79"), + []int{}, + []int{1, 3}, + }, + } + + for _, tc := range testCases { + t.Run(tc.description, func(t *testing.T) { + acc := newCPUAccumulator(tc.topo, tc.availableCPUs, 0) + resultNUMANodes := acc.freeNUMANodes() + if !reflect.DeepEqual(resultNUMANodes, tc.expectNUMANodes) { + t.Errorf("expected NUMA Nodes %v to equal %v", resultNUMANodes, tc.expectNUMANodes) + } + resultSockets := acc.freeSockets() + if !reflect.DeepEqual(resultSockets, tc.expectSockets) { + t.Errorf("expected Sockets %v to equal %v", resultSockets, tc.expectSockets) + } + }) + } +} + func TestCPUAccumulatorFreeCores(t *testing.T) { testCases := []struct { description string @@ -386,6 +537,46 @@ func TestTakeByTopology(t *testing.T) { "", cpuset.NewCPUSet(0, 2, 4, 6, 8, 10), }, + { + "take a socket of cpus from dual socket with multi-numa-per-socket with HT", + topoDualSocketMultiNumaPerSocketHT, + mustParseCPUSet(t, "0-79"), + 40, + "", + mustParseCPUSet(t, "0-19,40-59"), + }, + { + "take a NUMA node of cpus from dual socket with multi-numa-per-socket with HT", + topoDualSocketMultiNumaPerSocketHT, + mustParseCPUSet(t, "0-79"), + 20, + "", + mustParseCPUSet(t, "0-9,40-49"), + }, + { + "take a NUMA node of cpus from dual socket with multi-numa-per-socket with HT, with 1 NUMA node already taken", + topoDualSocketMultiNumaPerSocketHT, + mustParseCPUSet(t, "10-39,50-79"), + 20, + "", + mustParseCPUSet(t, "10-19,50-59"), + }, + { + "take a socket and a NUMA node of cpus from dual socket with multi-numa-per-socket with HT", + topoDualSocketMultiNumaPerSocketHT, + mustParseCPUSet(t, "0-79"), + 60, + "", + mustParseCPUSet(t, "0-29,40-69"), + }, + { + "take a socket and a NUMA node of cpus from dual socket with multi-numa-per-socket with HT, a core taken", + topoDualSocketMultiNumaPerSocketHT, + mustParseCPUSet(t, "1-39,41-79"), // reserve the first (phys) core (0,40) + 60, + "", + mustParseCPUSet(t, "10-39,50-79"), + }, } for _, tc := range testCases { @@ -400,3 +591,11 @@ func TestTakeByTopology(t *testing.T) { }) } } + +func mustParseCPUSet(t *testing.T, s string) cpuset.CPUSet { + cpus, err := cpuset.Parse(s) + if err != nil { + t.Errorf("parsing %q: %v", s, err) + } + return cpus +} diff --git a/pkg/kubelet/cm/cpumanager/policy_test.go b/pkg/kubelet/cm/cpumanager/policy_test.go index 7ce051b2b8f..a106ec6b782 100644 --- a/pkg/kubelet/cm/cpumanager/policy_test.go +++ b/pkg/kubelet/cm/cpumanager/policy_test.go @@ -414,4 +414,105 @@ var ( 282: {CoreID: 55, SocketID: 3, NUMANodeID: 3}, }, } + /* + Topology from dual xeon gold 6230; lscpu excerpt + CPU(s): 80 + On-line CPU(s) list: 0-79 + Thread(s) per core: 2 + Core(s) per socket: 20 + Socket(s): 2 + NUMA node(s): 4 + NUMA node0 CPU(s): 0-9,40-49 + NUMA node1 CPU(s): 10-19,50-59 + NUMA node2 CPU(s): 20-29,60-69 + NUMA node3 CPU(s): 30-39,70-79 + */ + topoDualSocketMultiNumaPerSocketHT = &topology.CPUTopology{ + NumCPUs: 80, + NumSockets: 2, + NumCores: 40, + NumNUMANodes: 4, + CPUDetails: map[int]topology.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}, + }, + } ) diff --git a/pkg/kubelet/cm/cpumanager/topology/topology.go b/pkg/kubelet/cm/cpumanager/topology/topology.go index 37c2f105b7e..c9b0849261f 100644 --- a/pkg/kubelet/cm/cpumanager/topology/topology.go +++ b/pkg/kubelet/cm/cpumanager/topology/topology.go @@ -34,7 +34,8 @@ type CPUDetails map[int]CPUInfo // CPUTopology contains details of node cpu, where : // CPU - logical CPU, cadvisor - thread // Core - physical CPU, cadvisor - Core -// Socket - socket, cadvisor - Node +// Socket - socket, cadvisor - Socket +// NUMA Node - NUMA cell, cadvisor - Node type CPUTopology struct { NumCPUs int NumCores int @@ -254,7 +255,7 @@ func Discover(machineInfo *cadvisorapi.MachineInfo) (*CPUTopology, error) { // getUniqueCoreID computes coreId as the lowest cpuID // for a given Threads []int slice. This will assure that coreID's are -// platform unique (opposite to what cAdvisor reports - socket unique) +// platform unique (opposite to what cAdvisor reports) func getUniqueCoreID(threads []int) (coreID int, err error) { if len(threads) == 0 { return 0, fmt.Errorf("no cpus provided") diff --git a/pkg/kubelet/cm/cpumanager/topology/topology_test.go b/pkg/kubelet/cm/cpumanager/topology/topology_test.go index f28bc800c20..9cc938226e1 100644 --- a/pkg/kubelet/cm/cpumanager/topology/topology_test.go +++ b/pkg/kubelet/cm/cpumanager/topology/topology_test.go @@ -75,6 +75,162 @@ func Test_Discover(t *testing.T) { }, 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, + }, + { name: "DualSocketNoHT", machineInfo: cadvisorapi.MachineInfo{