diff --git a/pkg/kubelet/cm/cpumanager/cpu_assignment.go b/pkg/kubelet/cm/cpumanager/cpu_assignment.go index f0efd74e80e0c..72a8b86529930 100644 --- a/pkg/kubelet/cm/cpumanager/cpu_assignment.go +++ b/pkg/kubelet/cm/cpumanager/cpu_assignment.go @@ -125,6 +125,17 @@ func (n *numaFirst) takeFullSecondLevel() { n.acc.takeFullSockets() } +// Sort the UncoreCaches within the NUMA nodes. +func (a *cpuAccumulator) sortAvailableUncoreCaches() []int { + var result []int + for _, numa := range a.sortAvailableNUMANodes() { + uncore := a.details.UncoreInNUMANodes(numa).UnsortedList() + a.sort(uncore, a.details.CPUsInUncoreCaches) + result = append(result, uncore...) + } + return result +} + // If NUMA nodes are higher in the memory hierarchy than sockets, then just // sort the NUMA nodes directly, and return them. func (n *numaFirst) sortAvailableNUMANodes() []int { @@ -238,7 +249,14 @@ func (a *cpuAccumulator) isSocketFree(socketID int) bool { return a.details.CPUsInSockets(socketID).Size() == a.topo.CPUsPerSocket() } -// Returns true if the supplied core is fully available in `topoDetails`. +// Returns true if the supplied UnCoreCache is fully available, +// "fully available" means that all the CPUs in it are free. +func (a *cpuAccumulator) isUncoreCacheFree(uncoreID int) bool { + return a.details.CPUsInUncoreCaches(uncoreID).Size() == a.topo.CPUDetails.CPUsInUncoreCaches(uncoreID).Size() +} + +// Returns true if the supplied core is fully available in `a.details`. +// "fully available" means that all the CPUs in it are free. func (a *cpuAccumulator) isCoreFree(coreID int) bool { return a.details.CPUsInCores(coreID).Size() == a.topo.CPUsPerCore() } @@ -265,6 +283,17 @@ func (a *cpuAccumulator) freeSockets() []int { return free } +// Returns free UncoreCache IDs as a slice sorted by sortAvailableUnCoreCache(). +func (a *cpuAccumulator) freeUncoreCache() []int { + free := []int{} + for _, uncore := range a.sortAvailableUncoreCaches() { + if a.isUncoreCacheFree(uncore) { + free = append(free, uncore) + } + } + return free +} + // Returns free core IDs as a slice sorted by sortAvailableCores(). func (a *cpuAccumulator) freeCores() []int { free := []int{} @@ -358,6 +387,62 @@ func (a *cpuAccumulator) takeFullSockets() { } } +func (a *cpuAccumulator) takeFullUncore() { + for _, uncore := range a.freeUncoreCache() { + cpusInUncore := a.topo.CPUDetails.CPUsInUncoreCaches(uncore) + if !a.needs(cpusInUncore.Size()) { + continue + } + klog.V(4).InfoS("takeFullUncore: claiming uncore", "uncore", uncore) + a.take(cpusInUncore) + } +} + +func (a *cpuAccumulator) takePartialUncore(uncoreID int) { + numCoresNeeded := a.numCPUsNeeded / a.topo.CPUsPerCore() + + // determine the N number of free cores (physical cpus) within the UncoreCache, then + // determine the M number of free cpus (virtual cpus) that correspond with the free cores + freeCores := a.details.CoresNeededInUncoreCache(numCoresNeeded, uncoreID) + freeCPUs := a.details.CPUsInCores(freeCores.UnsortedList()...) + + // claim the cpus if the free cpus within the UncoreCache can satisfy the needed cpus + claimed := (a.numCPUsNeeded == freeCPUs.Size()) + klog.V(4).InfoS("takePartialUncore: trying to claim partial uncore", + "uncore", uncoreID, + "claimed", claimed, + "needed", a.numCPUsNeeded, + "cores", freeCores.String(), + "cpus", freeCPUs.String()) + if !claimed { + return + + } + a.take(freeCPUs) +} + +// First try to take full UncoreCache, if available and need is at least the size of the UncoreCache group. +// Second try to take the partial UncoreCache if available and the request size can fit w/in the UncoreCache. +func (a *cpuAccumulator) takeUncoreCache() { + numCPUsInUncore := a.topo.CPUsPerUncore() + for _, uncore := range a.sortAvailableUncoreCaches() { + // take full UncoreCache if the CPUs needed is greater than free UncoreCache size + if a.needs(numCPUsInUncore) { + a.takeFullUncore() + } + + if a.isSatisfied() { + return + } + + // take partial UncoreCache if the CPUs needed is less than free UncoreCache size + a.takePartialUncore(uncore) + if a.isSatisfied() { + return + } + } +} + func (a *cpuAccumulator) takeFullCores() { for _, core := range a.freeCores() { cpusInCore := a.topo.CPUDetails.CPUsInCores(core) @@ -447,7 +532,7 @@ func (a *cpuAccumulator) iterateCombinations(n []int, k int, f func([]int) LoopC helper(n, k, 0, []int{}, f) } -func takeByTopologyNUMAPacked(topo *topology.CPUTopology, availableCPUs cpuset.CPUSet, numCPUs int) (cpuset.CPUSet, error) { +func takeByTopologyNUMAPacked(topo *topology.CPUTopology, availableCPUs cpuset.CPUSet, numCPUs int, preferAlignByUncoreCache bool) (cpuset.CPUSet, error) { acc := newCPUAccumulator(topo, availableCPUs, numCPUs) if acc.isSatisfied() { return acc.result, nil @@ -470,14 +555,24 @@ func takeByTopologyNUMAPacked(topo *topology.CPUTopology, availableCPUs cpuset.C return acc.result, nil } - // 2. Acquire whole cores, if available and the container requires at least + // 2. If PreferAlignByUncoreCache is enabled, acquire whole UncoreCaches + // if available and the container requires at least a UncoreCache's-worth + // of CPUs. Otherwise, acquire CPUs from the least amount of UncoreCaches. + if preferAlignByUncoreCache { + acc.takeUncoreCache() + if acc.isSatisfied() { + return acc.result, nil + } + } + + // 3. Acquire whole cores, if available and the container requires at least // a core's-worth of CPUs. acc.takeFullCores() if acc.isSatisfied() { return acc.result, nil } - // 3. Acquire single threads, preferring to fill partially-allocated cores + // 4. Acquire single threads, preferring to fill partially-allocated cores // on the same sockets as the whole cores we have already taken in this // allocation. acc.takeRemainingCPUs() @@ -555,8 +650,10 @@ func takeByTopologyNUMADistributed(topo *topology.CPUTopology, availableCPUs cpu // If the number of CPUs requested cannot be handed out in chunks of // 'cpuGroupSize', then we just call out the packing algorithm since we // can't distribute CPUs in this chunk size. + // PreferAlignByUncoreCache feature not implemented here yet and set to false. + // Support for PreferAlignByUncoreCache to be done at beta release. if (numCPUs % cpuGroupSize) != 0 { - return takeByTopologyNUMAPacked(topo, availableCPUs, numCPUs) + return takeByTopologyNUMAPacked(topo, availableCPUs, numCPUs, false) } // Otherwise build an accumulator to start allocating CPUs from. @@ -739,7 +836,7 @@ func takeByTopologyNUMADistributed(topo *topology.CPUTopology, availableCPUs cpu // size 'cpuGroupSize' from 'bestCombo'. distribution := (numCPUs / len(bestCombo) / cpuGroupSize) * cpuGroupSize for _, numa := range bestCombo { - cpus, _ := takeByTopologyNUMAPacked(acc.topo, acc.details.CPUsInNUMANodes(numa), distribution) + cpus, _ := takeByTopologyNUMAPacked(acc.topo, acc.details.CPUsInNUMANodes(numa), distribution, false) acc.take(cpus) } @@ -754,7 +851,7 @@ func takeByTopologyNUMADistributed(topo *topology.CPUTopology, availableCPUs cpu if acc.details.CPUsInNUMANodes(numa).Size() < cpuGroupSize { continue } - cpus, _ := takeByTopologyNUMAPacked(acc.topo, acc.details.CPUsInNUMANodes(numa), cpuGroupSize) + cpus, _ := takeByTopologyNUMAPacked(acc.topo, acc.details.CPUsInNUMANodes(numa), cpuGroupSize, false) acc.take(cpus) remainder -= cpuGroupSize } @@ -778,5 +875,5 @@ func takeByTopologyNUMADistributed(topo *topology.CPUTopology, availableCPUs cpu // If we never found a combination of NUMA nodes that we could properly // distribute CPUs across, fall back to the packing algorithm. - return takeByTopologyNUMAPacked(topo, availableCPUs, numCPUs) + return takeByTopologyNUMAPacked(topo, availableCPUs, numCPUs, false) } diff --git a/pkg/kubelet/cm/cpumanager/cpu_assignment_test.go b/pkg/kubelet/cm/cpumanager/cpu_assignment_test.go index 63b026b1979f2..cf739424268d5 100644 --- a/pkg/kubelet/cm/cpumanager/cpu_assignment_test.go +++ b/pkg/kubelet/cm/cpumanager/cpu_assignment_test.go @@ -655,7 +655,106 @@ func TestTakeByTopologyNUMAPacked(t *testing.T) { for _, tc := range testCases { t.Run(tc.description, func(t *testing.T) { - result, err := takeByTopologyNUMAPacked(tc.topo, tc.availableCPUs, tc.numCPUs) + result, err := takeByTopologyNUMAPacked(tc.topo, tc.availableCPUs, tc.numCPUs, false) + if tc.expErr != "" && err != nil && err.Error() != tc.expErr { + t.Errorf("expected error to be [%v] but it was [%v]", tc.expErr, err) + } + if !result.Equals(tc.expResult) { + t.Errorf("expected result [%s] to equal [%s]", result, tc.expResult) + } + }) + } +} + +type takeByTopologyUncoreTestCase struct { + description string + topo *topology.CPUTopology + opts StaticPolicyOptions + availableCPUs cpuset.CPUSet + numCPUs int + expErr string + expResult cpuset.CPUSet +} + +func TestTakeByTopologyUncore(t *testing.T) { + testCases := []takeByTopologyUncoreTestCase{ + { + "take cpus from two full UncoreCaches and partial from a single UncoreCache", + topoUncoreSingleSocketNoSMT, + StaticPolicyOptions{PreferAlignByUncoreCacheOption: true}, + mustParseCPUSet(t, "1-15"), + 10, + "", + cpuset.New(1, 2, 4, 5, 6, 7, 8, 9, 10, 11), + }, + { + "take one cpu from dual socket with HT - core from Socket 0", + topoDualSocketHT, + StaticPolicyOptions{PreferAlignByUncoreCacheOption: true}, + cpuset.New(1, 2, 3, 4, 5, 7, 8, 9, 10, 11), + 1, + "", + cpuset.New(2), + }, + { + "take first available UncoreCache from first socket", + topoUncoreDualSocketNoSMT, + StaticPolicyOptions{PreferAlignByUncoreCacheOption: true}, + mustParseCPUSet(t, "0-15"), + 4, + "", + cpuset.New(0, 1, 2, 3), + }, + { + "take all available UncoreCache from first socket", + topoUncoreDualSocketNoSMT, + StaticPolicyOptions{PreferAlignByUncoreCacheOption: true}, + mustParseCPUSet(t, "2-15"), + 6, + "", + cpuset.New(2, 3, 4, 5, 6, 7), + }, + { + "take first available UncoreCache from second socket", + topoUncoreDualSocketNoSMT, + StaticPolicyOptions{PreferAlignByUncoreCacheOption: true}, + mustParseCPUSet(t, "8-15"), + 4, + "", + cpuset.New(8, 9, 10, 11), + }, + { + "take first available UncoreCache from available NUMA", + topoUncoreSingleSocketMultiNuma, + StaticPolicyOptions{PreferAlignByUncoreCacheOption: true}, + mustParseCPUSet(t, "3,4-8,12"), + 2, + "", + cpuset.New(4, 5), + }, + { + "take cpus from best available UncoreCache group of multi uncore cache single socket - SMT enabled", + topoUncoreSingleSocketSMT, + StaticPolicyOptions{PreferAlignByUncoreCacheOption: true}, + mustParseCPUSet(t, "2-3,10-11,4-7,12-15"), + 6, + "", + cpuset.New(4, 5, 6, 12, 13, 14), + }, + { + "take cpus from multiple UncoreCache of single socket - SMT enabled", + topoUncoreSingleSocketSMT, + StaticPolicyOptions{PreferAlignByUncoreCacheOption: true}, + mustParseCPUSet(t, "1-7,9-15"), + 10, + "", + mustParseCPUSet(t, "4-7,12-15,1,9"), + }, + } + + for _, tc := range testCases { + t.Run(tc.description, func(t *testing.T) { + result, err := takeByTopologyNUMAPacked(tc.topo, tc.availableCPUs, tc.numCPUs, tc.opts.PreferAlignByUncoreCacheOption) if tc.expErr != "" && err != nil && err.Error() != tc.expErr { t.Errorf("expected error to be [%v] but it was [%v]", tc.expErr, err) } diff --git a/pkg/kubelet/cm/cpumanager/cpu_manager_test.go b/pkg/kubelet/cm/cpumanager/cpu_manager_test.go index f6563bbca2380..6c9f88272921a 100644 --- a/pkg/kubelet/cm/cpumanager/cpu_manager_test.go +++ b/pkg/kubelet/cm/cpumanager/cpu_manager_test.go @@ -651,20 +651,24 @@ func TestCPUManagerGenerate(t *testing.T) { { Cores: []cadvisorapi.Core{ { - Id: 0, - Threads: []int{0}, + Id: 0, + Threads: []int{0}, + UncoreCaches: []cadvisorapi.Cache{{Id: 1}}, }, { - Id: 1, - Threads: []int{1}, + Id: 1, + Threads: []int{1}, + UncoreCaches: []cadvisorapi.Cache{{Id: 1}}, }, { - Id: 2, - Threads: []int{2}, + Id: 2, + Threads: []int{2}, + UncoreCaches: []cadvisorapi.Cache{{Id: 1}}, }, { - Id: 3, - Threads: []int{3}, + Id: 3, + Threads: []int{3}, + UncoreCaches: []cadvisorapi.Cache{{Id: 1}}, }, }, }, diff --git a/pkg/kubelet/cm/cpumanager/policy_options.go b/pkg/kubelet/cm/cpumanager/policy_options.go index 368fc63624fd1..4ce94806f6646 100644 --- a/pkg/kubelet/cm/cpumanager/policy_options.go +++ b/pkg/kubelet/cm/cpumanager/policy_options.go @@ -32,6 +32,7 @@ const ( FullPCPUsOnlyOption string = "full-pcpus-only" DistributeCPUsAcrossNUMAOption string = "distribute-cpus-across-numa" AlignBySocketOption string = "align-by-socket" + PreferAlignByUnCoreCacheOption string = "prefer-align-cpus-by-uncorecache" ) var ( @@ -41,6 +42,7 @@ var ( ) betaOptions = sets.New[string]( FullPCPUsOnlyOption, + PreferAlignByUnCoreCacheOption, ) stableOptions = sets.New[string]() ) @@ -80,6 +82,9 @@ type StaticPolicyOptions struct { // Flag to ensure CPUs are considered aligned at socket boundary rather than // NUMA boundary AlignBySocket bool + // Flag that makes best-effort to align CPUs to a uncorecache boundary + // As long as there are CPUs available, pods will be admitted if the condition is not met. + PreferAlignByUncoreCacheOption bool } // NewStaticPolicyOptions creates a StaticPolicyOptions struct from the user configuration. @@ -109,12 +114,23 @@ func NewStaticPolicyOptions(policyOptions map[string]string) (StaticPolicyOption return opts, fmt.Errorf("bad value for option %q: %w", name, err) } opts.AlignBySocket = optValue + case PreferAlignByUnCoreCacheOption: + optValue, err := strconv.ParseBool(value) + if err != nil { + return opts, fmt.Errorf("bad value for option %q: %w", name, err) + } + opts.PreferAlignByUncoreCacheOption = optValue default: // this should never be reached, we already detect unknown options, // but we keep it as further safety. return opts, fmt.Errorf("unsupported cpumanager option: %q (%s)", name, value) } } + + if opts.PreferAlignByUncoreCacheOption && opts.DistributeCPUsAcrossNUMA { + return opts, fmt.Errorf("static policy options %s and %s can not be used at the same time", PreferAlignByUnCoreCacheOption, DistributeCPUsAcrossNUMAOption) + } + return opts, nil } diff --git a/pkg/kubelet/cm/cpumanager/policy_static.go b/pkg/kubelet/cm/cpumanager/policy_static.go index d4579b9aa7fc6..204c7ad436611 100644 --- a/pkg/kubelet/cm/cpumanager/policy_static.go +++ b/pkg/kubelet/cm/cpumanager/policy_static.go @@ -29,6 +29,7 @@ import ( "k8s.io/kubernetes/pkg/kubelet/cm/cpumanager/topology" "k8s.io/kubernetes/pkg/kubelet/cm/topologymanager" "k8s.io/kubernetes/pkg/kubelet/cm/topologymanager/bitmask" + "k8s.io/kubernetes/pkg/kubelet/llcalign" "k8s.io/kubernetes/pkg/kubelet/managed" "k8s.io/kubernetes/pkg/kubelet/metrics" "k8s.io/kubernetes/pkg/kubelet/types" @@ -138,6 +139,7 @@ func NewStaticPolicy(topology *topology.CPUTopology, numReservedCPUs int, reserv } klog.InfoS("Static policy created with configuration", "options", opts) + klog.InfoS("Static policy created with configuration", "llcAlignment", llcalign.IsEnabled()) policy := &staticPolicy{ topology: topology, @@ -505,7 +507,9 @@ func (p *staticPolicy) takeByTopology(availableCPUs cpuset.CPUSet, numCPUs int) } return takeByTopologyNUMADistributed(p.topology, availableCPUs, numCPUs, cpuGroupSize) } - return takeByTopologyNUMAPacked(p.topology, availableCPUs, numCPUs) + + preferAlignByUncoreCacheOption := isAlignByUncoreCacheEnabled(p.options) + return takeByTopologyNUMAPacked(p.topology, availableCPUs, numCPUs, preferAlignByUncoreCacheOption) } func (p *staticPolicy) GetTopologyHints(s state.State, pod *v1.Pod, container *v1.Container) map[string][]topologymanager.TopologyHint { @@ -717,3 +721,14 @@ func (p *staticPolicy) getAlignedCPUs(numaAffinity bitmask.BitMask, allocatableC return alignedCPUs } + +func isAlignByUncoreCacheEnabled(options StaticPolicyOptions) bool { + if !options.PreferAlignByUncoreCacheOption { + return false + } + if !llcalign.IsEnabled() { + klog.V(4).InfoS("isAlignByUncoreCacheEnabled disabled because missing config file") + return false + } + return true +} diff --git a/pkg/kubelet/cm/cpumanager/policy_test.go b/pkg/kubelet/cm/cpumanager/policy_test.go index 02f0898063a09..dcdeada2f0e32 100644 --- a/pkg/kubelet/cm/cpumanager/policy_test.go +++ b/pkg/kubelet/cm/cpumanager/policy_test.go @@ -38,9 +38,10 @@ var ( } topoDualSocketHT = &topology.CPUTopology{ - NumCPUs: 12, - NumSockets: 2, - NumCores: 6, + NumCPUs: 12, + NumSockets: 2, + NumCores: 6, + NumUncoreCache: 1, CPUDetails: map[int]topology.CPUInfo{ 0: {CoreID: 0, SocketID: 0, NUMANodeID: 0}, 1: {CoreID: 1, SocketID: 1, NUMANodeID: 1}, @@ -57,6 +58,106 @@ var ( }, } + topoUncoreDualSocketNoSMT = &topology.CPUTopology{ + NumCPUs: 16, + NumSockets: 2, + NumCores: 16, + NumUncoreCache: 4, + CPUDetails: map[int]topology.CPUInfo{ + 0: {CoreID: 0, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 0}, + 1: {CoreID: 1, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 0}, + 2: {CoreID: 2, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 0}, + 3: {CoreID: 3, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 0}, + 4: {CoreID: 4, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 1}, + 5: {CoreID: 5, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 1}, + 6: {CoreID: 6, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 1}, + 7: {CoreID: 7, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 1}, + 8: {CoreID: 8, SocketID: 1, NUMANodeID: 0, UncoreCacheID: 2}, + 9: {CoreID: 9, SocketID: 1, NUMANodeID: 0, UncoreCacheID: 2}, + 10: {CoreID: 10, SocketID: 1, NUMANodeID: 0, UncoreCacheID: 2}, + 11: {CoreID: 11, SocketID: 1, NUMANodeID: 0, UncoreCacheID: 2}, + 12: {CoreID: 12, SocketID: 1, NUMANodeID: 0, UncoreCacheID: 3}, + 13: {CoreID: 13, SocketID: 1, NUMANodeID: 0, UncoreCacheID: 3}, + 14: {CoreID: 14, SocketID: 1, NUMANodeID: 0, UncoreCacheID: 3}, + 15: {CoreID: 15, SocketID: 1, NUMANodeID: 0, UncoreCacheID: 3}, + }, + } + + topoUncoreSingleSocketMultiNuma = &topology.CPUTopology{ + NumCPUs: 16, + NumSockets: 1, + NumCores: 16, + NumUncoreCache: 4, + CPUDetails: map[int]topology.CPUInfo{ + 0: {CoreID: 0, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 0}, + 1: {CoreID: 1, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 0}, + 2: {CoreID: 2, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 0}, + 3: {CoreID: 3, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 0}, + 4: {CoreID: 4, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 1}, + 5: {CoreID: 5, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 1}, + 6: {CoreID: 6, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 1}, + 7: {CoreID: 7, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 1}, + 8: {CoreID: 8, SocketID: 0, NUMANodeID: 1, UncoreCacheID: 2}, + 9: {CoreID: 9, SocketID: 0, NUMANodeID: 1, UncoreCacheID: 2}, + 10: {CoreID: 10, SocketID: 0, NUMANodeID: 1, UncoreCacheID: 2}, + 11: {CoreID: 11, SocketID: 0, NUMANodeID: 1, UncoreCacheID: 2}, + 12: {CoreID: 12, SocketID: 0, NUMANodeID: 1, UncoreCacheID: 3}, + 13: {CoreID: 13, SocketID: 0, NUMANodeID: 1, UncoreCacheID: 3}, + 14: {CoreID: 14, SocketID: 0, NUMANodeID: 1, UncoreCacheID: 3}, + 15: {CoreID: 15, SocketID: 0, NUMANodeID: 1, UncoreCacheID: 3}, + }, + } + + topoUncoreSingleSocketSMT = &topology.CPUTopology{ + NumCPUs: 16, + NumSockets: 1, + NumCores: 8, + NumUncoreCache: 2, + CPUDetails: map[int]topology.CPUInfo{ + 0: {CoreID: 0, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 0}, + 1: {CoreID: 1, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 0}, + 2: {CoreID: 2, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 0}, + 3: {CoreID: 3, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 0}, + 4: {CoreID: 4, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 1}, + 5: {CoreID: 5, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 1}, + 6: {CoreID: 6, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 1}, + 7: {CoreID: 7, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 1}, + 8: {CoreID: 0, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 0}, + 9: {CoreID: 1, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 0}, + 10: {CoreID: 2, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 0}, + 11: {CoreID: 3, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 0}, + 12: {CoreID: 4, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 1}, + 13: {CoreID: 5, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 1}, + 14: {CoreID: 6, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 1}, + 15: {CoreID: 7, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 1}, + }, + } + + topoUncoreSingleSocketNoSMT = &topology.CPUTopology{ + NumCPUs: 16, + NumSockets: 1, + NumCores: 16, + NumUncoreCache: 4, + CPUDetails: map[int]topology.CPUInfo{ + 0: {CoreID: 0, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 0}, + 1: {CoreID: 1, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 0}, + 2: {CoreID: 2, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 0}, + 3: {CoreID: 3, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 0}, + 4: {CoreID: 4, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 1}, + 5: {CoreID: 5, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 1}, + 6: {CoreID: 6, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 1}, + 7: {CoreID: 7, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 1}, + 8: {CoreID: 8, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 2}, + 9: {CoreID: 9, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 2}, + 10: {CoreID: 10, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 2}, + 11: {CoreID: 11, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 2}, + 12: {CoreID: 12, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 3}, + 13: {CoreID: 13, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 3}, + 14: {CoreID: 14, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 3}, + 15: {CoreID: 15, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 3}, + }, + } + topoDualSocketNoHT = &topology.CPUTopology{ NumCPUs: 8, NumSockets: 2, diff --git a/pkg/kubelet/cm/cpumanager/topology/topology.go b/pkg/kubelet/cm/cpumanager/topology/topology.go index 62d91a5dee5d0..18b38233666de 100644 --- a/pkg/kubelet/cm/cpumanager/topology/topology.go +++ b/pkg/kubelet/cm/cpumanager/topology/topology.go @@ -36,12 +36,14 @@ type CPUDetails map[int]CPUInfo // Core - physical CPU, cadvisor - Core // Socket - socket, cadvisor - Socket // NUMA Node - NUMA cell, cadvisor - Node +// UncoreCache - Split L3 Cache Topology, cadvisor type CPUTopology struct { - NumCPUs int - NumCores int - NumSockets int - NumNUMANodes int - CPUDetails CPUDetails + NumCPUs int + NumCores int + NumUncoreCache int + NumSockets int + NumNUMANodes int + CPUDetails CPUDetails } // CPUsPerCore returns the number of logical CPUs are associated with @@ -62,6 +64,15 @@ func (topo *CPUTopology) CPUsPerSocket() int { return topo.NumCPUs / topo.NumSockets } +// CPUsPerUncore returns the number of logicial CPUs that are associated with +// each UncoreCache +func (topo *CPUTopology) CPUsPerUncore() int { + if topo.NumUncoreCache == 0 { + return 0 + } + return topo.NumCPUs / topo.NumUncoreCache +} + // CPUCoreID returns the physical core ID which the given logical CPU // belongs to. func (topo *CPUTopology) CPUCoreID(cpu int) (int, error) { @@ -90,11 +101,12 @@ func (topo *CPUTopology) CPUNUMANodeID(cpu int) (int, error) { return info.NUMANodeID, nil } -// CPUInfo contains the NUMA, socket, and core IDs associated with a CPU. +// CPUInfo contains the NUMA, socket, UncoreCache and core IDs associated with a CPU. type CPUInfo struct { - NUMANodeID int - SocketID int - CoreID int + NUMANodeID int + SocketID int + CoreID int + UncoreCacheID int } // KeepOnly returns a new CPUDetails object with only the supplied cpus. @@ -108,6 +120,67 @@ func (d CPUDetails) KeepOnly(cpus cpuset.CPUSet) CPUDetails { return result } +// UncoreCaches returns all the uncorecache Id (L3 Index) associated with the CPUs in this CPUDetails +func (d CPUDetails) UncoreCaches() cpuset.CPUSet { + var numUnCoreIDs []int + for _, info := range d { + numUnCoreIDs = append(numUnCoreIDs, info.UncoreCacheID) + } + return cpuset.New(numUnCoreIDs...) +} + +// UnCoresInNUMANodes returns all of the uncore IDs associated with the given +// NUMANode IDs in this CPUDetails. +func (d CPUDetails) UncoreInNUMANodes(ids ...int) cpuset.CPUSet { + var unCoreIDs []int + for _, id := range ids { + for _, info := range d { + if info.NUMANodeID == id { + unCoreIDs = append(unCoreIDs, info.UncoreCacheID) + } + } + } + return cpuset.New(unCoreIDs...) +} + +// CoresNeededInUncoreCache returns either the full list of all available unique core IDs associated with the given +// UnCoreCache IDs in this CPUDetails or subset that matches the ask. +func (d CPUDetails) CoresNeededInUncoreCache(numCoresNeeded int, ids ...int) cpuset.CPUSet { + coreIDs := d.coresInUncoreCache(ids...) + if coreIDs.Size() <= numCoresNeeded { + return coreIDs + } + tmpCoreIDs := coreIDs.List() + return cpuset.New(tmpCoreIDs[:numCoresNeeded]...) +} + +// Helper function that just gets the cores +func (d CPUDetails) coresInUncoreCache(ids ...int) cpuset.CPUSet { + var coreIDs []int + for _, id := range ids { + for _, info := range d { + if info.UncoreCacheID == id { + coreIDs = append(coreIDs, info.CoreID) + } + } + } + return cpuset.New(coreIDs...) +} + +// CPUsInUncoreCaches returns all the logical CPU IDs associated with the given +// UnCoreCache IDs in this CPUDetails +func (d CPUDetails) CPUsInUncoreCaches(ids ...int) cpuset.CPUSet { + var cpuIDs []int + for _, id := range ids { + for cpu, info := range d { + if info.UncoreCacheID == id { + cpuIDs = append(cpuIDs, cpu) + } + } + } + return cpuset.New(cpuIDs...) +} + // NUMANodes returns all of the NUMANode IDs associated with the CPUs in this // CPUDetails. func (d CPUDetails) NUMANodes() cpuset.CPUSet { @@ -245,6 +318,16 @@ func (d CPUDetails) CPUsInCores(ids ...int) cpuset.CPUSet { return cpuset.New(cpuIDs...) } +func getUncoreCacheID(core cadvisorapi.Core) int { + if len(core.UncoreCaches) < 1 { + // In case cAdvisor is nil, failback to socket alignment since uncorecache is not shared + return core.SocketID + } + // Even though cadvisor API returns a slice, we only expect either 0 or a 1 uncore caches, + // so everything past the first entry should be discarded or ignored + return core.UncoreCaches[0].Id +} + // Discover returns CPUTopology based on cadvisor node info func Discover(machineInfo *cadvisorapi.MachineInfo) (*CPUTopology, error) { if machineInfo.NumCores == 0 { @@ -260,9 +343,10 @@ func Discover(machineInfo *cadvisorapi.MachineInfo) (*CPUTopology, error) { if coreID, err := getUniqueCoreID(core.Threads); err == nil { for _, cpu := range core.Threads { CPUDetails[cpu] = CPUInfo{ - CoreID: coreID, - SocketID: core.SocketID, - NUMANodeID: node.Id, + CoreID: coreID, + SocketID: core.SocketID, + NUMANodeID: node.Id, + UncoreCacheID: getUncoreCacheID(core), } } } else { @@ -273,11 +357,12 @@ func Discover(machineInfo *cadvisorapi.MachineInfo) (*CPUTopology, error) { } return &CPUTopology{ - NumCPUs: machineInfo.NumCores, - NumSockets: machineInfo.NumSockets, - NumCores: numPhysicalCores, - NumNUMANodes: CPUDetails.NUMANodes().Size(), - CPUDetails: CPUDetails, + NumCPUs: machineInfo.NumCores, + NumSockets: machineInfo.NumSockets, + NumCores: numPhysicalCores, + NumNUMANodes: CPUDetails.NUMANodes().Size(), + NumUncoreCache: CPUDetails.UncoreCaches().Size(), + CPUDetails: CPUDetails, }, nil } diff --git a/pkg/kubelet/cm/cpumanager/topology/topology_test.go b/pkg/kubelet/cm/cpumanager/topology/topology_test.go index 37d8f7f01fc54..b4f14547e5aab 100644 --- a/pkg/kubelet/cm/cpumanager/topology/topology_test.go +++ b/pkg/kubelet/cm/cpumanager/topology/topology_test.go @@ -33,6 +33,41 @@ func Test_Discover(t *testing.T) { want *CPUTopology wantErr bool }{ + { + name: "EmptyUncoreCache", + machineInfo: cadvisorapi.MachineInfo{ + NumCores: 8, + NumSockets: 1, + Topology: []cadvisorapi.Node{ + {Id: 0, + Cores: []cadvisorapi.Core{ + {SocketID: 0, Id: 0, Threads: []int{0, 4}, UncoreCaches: []cadvisorapi.Cache{}}, + {SocketID: 0, Id: 1, Threads: []int{1, 5}, UncoreCaches: []cadvisorapi.Cache{}}, + {SocketID: 0, Id: 2, Threads: []int{2, 6}, UncoreCaches: []cadvisorapi.Cache{}}, + {SocketID: 0, Id: 3, Threads: []int{3, 7}, UncoreCaches: []cadvisorapi.Cache{}}, + }, + }, + }, + }, + want: &CPUTopology{ + NumCPUs: 8, + NumSockets: 1, + NumCores: 4, + NumNUMANodes: 1, + NumUncoreCache: 1, + CPUDetails: map[int]CPUInfo{ + 0: {CoreID: 0, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 0}, + 1: {CoreID: 1, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 0}, + 2: {CoreID: 2, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 0}, + 3: {CoreID: 3, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 0}, + 4: {CoreID: 0, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 0}, + 5: {CoreID: 1, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 0}, + 6: {CoreID: 2, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 0}, + 7: {CoreID: 3, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 0}, + }, + }, + wantErr: false, + }, { name: "FailNumCores", machineInfo: cadvisorapi.MachineInfo{ @@ -49,28 +84,29 @@ func Test_Discover(t *testing.T) { 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}}, + {SocketID: 0, Id: 0, Threads: []int{0, 4}, UncoreCaches: []cadvisorapi.Cache{{Id: 0}}}, + {SocketID: 0, Id: 1, Threads: []int{1, 5}, UncoreCaches: []cadvisorapi.Cache{{Id: 0}}}, + {SocketID: 0, Id: 2, Threads: []int{2, 6}, UncoreCaches: []cadvisorapi.Cache{{Id: 0}}}, + {SocketID: 0, Id: 3, Threads: []int{3, 7}, UncoreCaches: []cadvisorapi.Cache{{Id: 0}}}, }, }, }, }, want: &CPUTopology{ - NumCPUs: 8, - NumSockets: 1, - NumCores: 4, - NumNUMANodes: 1, + NumCPUs: 8, + NumSockets: 1, + NumCores: 4, + NumNUMANodes: 1, + NumUncoreCache: 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}, + 0: {CoreID: 0, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 0}, + 1: {CoreID: 1, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 0}, + 2: {CoreID: 2, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 0}, + 3: {CoreID: 3, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 0}, + 4: {CoreID: 0, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 0}, + 5: {CoreID: 1, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 0}, + 6: {CoreID: 2, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 0}, + 7: {CoreID: 3, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 0}, }, }, wantErr: false, @@ -84,148 +120,149 @@ func Test_Discover(t *testing.T) { 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: 0, Id: 0, Threads: []int{0, 40}, UncoreCaches: []cadvisorapi.Cache{{Id: 0}}}, + {SocketID: 0, Id: 1, Threads: []int{1, 41}, UncoreCaches: []cadvisorapi.Cache{{Id: 0}}}, + {SocketID: 0, Id: 2, Threads: []int{2, 42}, UncoreCaches: []cadvisorapi.Cache{{Id: 0}}}, + {SocketID: 0, Id: 8, Threads: []int{3, 43}, UncoreCaches: []cadvisorapi.Cache{{Id: 0}}}, + {SocketID: 0, Id: 9, Threads: []int{4, 44}, UncoreCaches: []cadvisorapi.Cache{{Id: 0}}}, + {SocketID: 0, Id: 16, Threads: []int{5, 45}, UncoreCaches: []cadvisorapi.Cache{{Id: 0}}}, + {SocketID: 0, Id: 17, Threads: []int{6, 46}, UncoreCaches: []cadvisorapi.Cache{{Id: 0}}}, + {SocketID: 0, Id: 18, Threads: []int{7, 47}, UncoreCaches: []cadvisorapi.Cache{{Id: 0}}}, + {SocketID: 0, Id: 24, Threads: []int{8, 48}, UncoreCaches: []cadvisorapi.Cache{{Id: 0}}}, + {SocketID: 0, Id: 25, Threads: []int{9, 49}, UncoreCaches: []cadvisorapi.Cache{{Id: 0}}}, }, }, {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}}, + {SocketID: 0, Id: 3, Threads: []int{10, 50}, UncoreCaches: []cadvisorapi.Cache{{Id: 0}}}, + {SocketID: 0, Id: 4, Threads: []int{11, 51}, UncoreCaches: []cadvisorapi.Cache{{Id: 0}}}, + {SocketID: 0, Id: 10, Threads: []int{12, 52}, UncoreCaches: []cadvisorapi.Cache{{Id: 0}}}, + {SocketID: 0, Id: 11, Threads: []int{13, 53}, UncoreCaches: []cadvisorapi.Cache{{Id: 0}}}, + {SocketID: 0, Id: 12, Threads: []int{14, 54}, UncoreCaches: []cadvisorapi.Cache{{Id: 0}}}, + {SocketID: 0, Id: 19, Threads: []int{15, 55}, UncoreCaches: []cadvisorapi.Cache{{Id: 0}}}, + {SocketID: 0, Id: 20, Threads: []int{16, 56}, UncoreCaches: []cadvisorapi.Cache{{Id: 0}}}, + {SocketID: 0, Id: 26, Threads: []int{17, 57}, UncoreCaches: []cadvisorapi.Cache{{Id: 0}}}, + {SocketID: 0, Id: 27, Threads: []int{18, 58}, UncoreCaches: []cadvisorapi.Cache{{Id: 0}}}, + {SocketID: 0, Id: 28, Threads: []int{19, 59}, UncoreCaches: []cadvisorapi.Cache{{Id: 0}}}, }, }, {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}}, + {SocketID: 1, Id: 0, Threads: []int{20, 60}, UncoreCaches: []cadvisorapi.Cache{{Id: 0}}}, + {SocketID: 1, Id: 1, Threads: []int{21, 61}, UncoreCaches: []cadvisorapi.Cache{{Id: 0}}}, + {SocketID: 1, Id: 2, Threads: []int{22, 62}, UncoreCaches: []cadvisorapi.Cache{{Id: 0}}}, + {SocketID: 1, Id: 8, Threads: []int{23, 63}, UncoreCaches: []cadvisorapi.Cache{{Id: 0}}}, + {SocketID: 1, Id: 9, Threads: []int{24, 64}, UncoreCaches: []cadvisorapi.Cache{{Id: 0}}}, + {SocketID: 1, Id: 16, Threads: []int{25, 65}, UncoreCaches: []cadvisorapi.Cache{{Id: 0}}}, + {SocketID: 1, Id: 17, Threads: []int{26, 66}, UncoreCaches: []cadvisorapi.Cache{{Id: 0}}}, + {SocketID: 1, Id: 18, Threads: []int{27, 67}, UncoreCaches: []cadvisorapi.Cache{{Id: 0}}}, + {SocketID: 1, Id: 24, Threads: []int{28, 68}, UncoreCaches: []cadvisorapi.Cache{{Id: 0}}}, + {SocketID: 1, Id: 25, Threads: []int{29, 69}, UncoreCaches: []cadvisorapi.Cache{{Id: 0}}}, }, }, {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}}, + {SocketID: 1, Id: 3, Threads: []int{30, 70}, UncoreCaches: []cadvisorapi.Cache{{Id: 0}}}, + {SocketID: 1, Id: 4, Threads: []int{31, 71}, UncoreCaches: []cadvisorapi.Cache{{Id: 0}}}, + {SocketID: 1, Id: 10, Threads: []int{32, 72}, UncoreCaches: []cadvisorapi.Cache{{Id: 0}}}, + {SocketID: 1, Id: 11, Threads: []int{33, 73}, UncoreCaches: []cadvisorapi.Cache{{Id: 0}}}, + {SocketID: 1, Id: 12, Threads: []int{34, 74}, UncoreCaches: []cadvisorapi.Cache{{Id: 0}}}, + {SocketID: 1, Id: 19, Threads: []int{35, 75}, UncoreCaches: []cadvisorapi.Cache{{Id: 0}}}, + {SocketID: 1, Id: 20, Threads: []int{36, 76}, UncoreCaches: []cadvisorapi.Cache{{Id: 0}}}, + {SocketID: 1, Id: 26, Threads: []int{37, 77}, UncoreCaches: []cadvisorapi.Cache{{Id: 0}}}, + {SocketID: 1, Id: 27, Threads: []int{38, 78}, UncoreCaches: []cadvisorapi.Cache{{Id: 0}}}, + {SocketID: 1, Id: 28, Threads: []int{39, 79}, UncoreCaches: []cadvisorapi.Cache{{Id: 0}}}, }, }, }, }, want: &CPUTopology{ - NumCPUs: 80, - NumSockets: 2, - NumCores: 40, - NumNUMANodes: 4, + NumCPUs: 80, + NumSockets: 2, + NumCores: 40, + NumNUMANodes: 4, + NumUncoreCache: 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: 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}, + 0: {CoreID: 0, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 0}, + 1: {CoreID: 1, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 0}, + 2: {CoreID: 2, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 0}, + 3: {CoreID: 3, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 0}, + 4: {CoreID: 4, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 0}, + 5: {CoreID: 5, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 0}, + 6: {CoreID: 6, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 0}, + 7: {CoreID: 7, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 0}, + 8: {CoreID: 8, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 0}, + 9: {CoreID: 9, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 0}, + 10: {CoreID: 10, SocketID: 0, NUMANodeID: 1, UncoreCacheID: 0}, + 11: {CoreID: 11, SocketID: 0, NUMANodeID: 1, UncoreCacheID: 0}, + 12: {CoreID: 12, SocketID: 0, NUMANodeID: 1, UncoreCacheID: 0}, + 13: {CoreID: 13, SocketID: 0, NUMANodeID: 1, UncoreCacheID: 0}, + 14: {CoreID: 14, SocketID: 0, NUMANodeID: 1, UncoreCacheID: 0}, + 15: {CoreID: 15, SocketID: 0, NUMANodeID: 1, UncoreCacheID: 0}, + 16: {CoreID: 16, SocketID: 0, NUMANodeID: 1, UncoreCacheID: 0}, + 17: {CoreID: 17, SocketID: 0, NUMANodeID: 1, UncoreCacheID: 0}, + 18: {CoreID: 18, SocketID: 0, NUMANodeID: 1, UncoreCacheID: 0}, + 19: {CoreID: 19, SocketID: 0, NUMANodeID: 1, UncoreCacheID: 0}, + 20: {CoreID: 20, SocketID: 1, NUMANodeID: 2, UncoreCacheID: 0}, + 21: {CoreID: 21, SocketID: 1, NUMANodeID: 2, UncoreCacheID: 0}, + 22: {CoreID: 22, SocketID: 1, NUMANodeID: 2, UncoreCacheID: 0}, + 23: {CoreID: 23, SocketID: 1, NUMANodeID: 2, UncoreCacheID: 0}, + 24: {CoreID: 24, SocketID: 1, NUMANodeID: 2, UncoreCacheID: 0}, + 25: {CoreID: 25, SocketID: 1, NUMANodeID: 2, UncoreCacheID: 0}, + 26: {CoreID: 26, SocketID: 1, NUMANodeID: 2, UncoreCacheID: 0}, + 27: {CoreID: 27, SocketID: 1, NUMANodeID: 2, UncoreCacheID: 0}, + 28: {CoreID: 28, SocketID: 1, NUMANodeID: 2, UncoreCacheID: 0}, + 29: {CoreID: 29, SocketID: 1, NUMANodeID: 2, UncoreCacheID: 0}, + 30: {CoreID: 30, SocketID: 1, NUMANodeID: 3, UncoreCacheID: 0}, + 31: {CoreID: 31, SocketID: 1, NUMANodeID: 3, UncoreCacheID: 0}, + 32: {CoreID: 32, SocketID: 1, NUMANodeID: 3, UncoreCacheID: 0}, + 33: {CoreID: 33, SocketID: 1, NUMANodeID: 3, UncoreCacheID: 0}, + 34: {CoreID: 34, SocketID: 1, NUMANodeID: 3, UncoreCacheID: 0}, + 35: {CoreID: 35, SocketID: 1, NUMANodeID: 3, UncoreCacheID: 0}, + 36: {CoreID: 36, SocketID: 1, NUMANodeID: 3, UncoreCacheID: 0}, + 37: {CoreID: 37, SocketID: 1, NUMANodeID: 3, UncoreCacheID: 0}, + 38: {CoreID: 38, SocketID: 1, NUMANodeID: 3, UncoreCacheID: 0}, + 39: {CoreID: 39, SocketID: 1, NUMANodeID: 3, UncoreCacheID: 0}, + 40: {CoreID: 0, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 0}, + 41: {CoreID: 1, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 0}, + 42: {CoreID: 2, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 0}, + 43: {CoreID: 3, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 0}, + 44: {CoreID: 4, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 0}, + 45: {CoreID: 5, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 0}, + 46: {CoreID: 6, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 0}, + 47: {CoreID: 7, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 0}, + 48: {CoreID: 8, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 0}, + 49: {CoreID: 9, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 0}, + 50: {CoreID: 10, SocketID: 0, NUMANodeID: 1, UncoreCacheID: 0}, + 51: {CoreID: 11, SocketID: 0, NUMANodeID: 1, UncoreCacheID: 0}, + 52: {CoreID: 12, SocketID: 0, NUMANodeID: 1, UncoreCacheID: 0}, + 53: {CoreID: 13, SocketID: 0, NUMANodeID: 1, UncoreCacheID: 0}, + 54: {CoreID: 14, SocketID: 0, NUMANodeID: 1, UncoreCacheID: 0}, + 55: {CoreID: 15, SocketID: 0, NUMANodeID: 1, UncoreCacheID: 0}, + 56: {CoreID: 16, SocketID: 0, NUMANodeID: 1, UncoreCacheID: 0}, + 57: {CoreID: 17, SocketID: 0, NUMANodeID: 1, UncoreCacheID: 0}, + 58: {CoreID: 18, SocketID: 0, NUMANodeID: 1, UncoreCacheID: 0}, + 59: {CoreID: 19, SocketID: 0, NUMANodeID: 1, UncoreCacheID: 0}, + 60: {CoreID: 20, SocketID: 1, NUMANodeID: 2, UncoreCacheID: 0}, + 61: {CoreID: 21, SocketID: 1, NUMANodeID: 2, UncoreCacheID: 0}, + 62: {CoreID: 22, SocketID: 1, NUMANodeID: 2, UncoreCacheID: 0}, + 63: {CoreID: 23, SocketID: 1, NUMANodeID: 2, UncoreCacheID: 0}, + 64: {CoreID: 24, SocketID: 1, NUMANodeID: 2, UncoreCacheID: 0}, + 65: {CoreID: 25, SocketID: 1, NUMANodeID: 2, UncoreCacheID: 0}, + 66: {CoreID: 26, SocketID: 1, NUMANodeID: 2, UncoreCacheID: 0}, + 67: {CoreID: 27, SocketID: 1, NUMANodeID: 2, UncoreCacheID: 0}, + 68: {CoreID: 28, SocketID: 1, NUMANodeID: 2, UncoreCacheID: 0}, + 69: {CoreID: 29, SocketID: 1, NUMANodeID: 2, UncoreCacheID: 0}, + 70: {CoreID: 30, SocketID: 1, NUMANodeID: 3, UncoreCacheID: 0}, + 71: {CoreID: 31, SocketID: 1, NUMANodeID: 3, UncoreCacheID: 0}, + 72: {CoreID: 32, SocketID: 1, NUMANodeID: 3, UncoreCacheID: 0}, + 73: {CoreID: 33, SocketID: 1, NUMANodeID: 3, UncoreCacheID: 0}, + 74: {CoreID: 34, SocketID: 1, NUMANodeID: 3, UncoreCacheID: 0}, + 75: {CoreID: 35, SocketID: 1, NUMANodeID: 3, UncoreCacheID: 0}, + 76: {CoreID: 36, SocketID: 1, NUMANodeID: 3, UncoreCacheID: 0}, + 77: {CoreID: 37, SocketID: 1, NUMANodeID: 3, UncoreCacheID: 0}, + 78: {CoreID: 38, SocketID: 1, NUMANodeID: 3, UncoreCacheID: 0}, + 79: {CoreID: 39, SocketID: 1, NUMANodeID: 3, UncoreCacheID: 0}, }, }, wantErr: false, @@ -249,140 +286,141 @@ func Test_Discover(t *testing.T) { 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}}, + {SocketID: 0, Id: 0, Threads: []int{0, 40}, UncoreCaches: []cadvisorapi.Cache{{Id: 1}}}, + {SocketID: 0, Id: 1, Threads: []int{1, 41}, UncoreCaches: []cadvisorapi.Cache{{Id: 1}}}, + {SocketID: 0, Id: 2, Threads: []int{2, 42}, UncoreCaches: []cadvisorapi.Cache{{Id: 1}}}, + {SocketID: 0, Id: 8, Threads: []int{3, 43}, UncoreCaches: []cadvisorapi.Cache{{Id: 1}}}, + {SocketID: 0, Id: 9, Threads: []int{4, 44}, UncoreCaches: []cadvisorapi.Cache{{Id: 1}}}, + {SocketID: 0, Id: 16, Threads: []int{5, 45}, UncoreCaches: []cadvisorapi.Cache{{Id: 1}}}, + {SocketID: 0, Id: 17, Threads: []int{6, 46}, UncoreCaches: []cadvisorapi.Cache{{Id: 1}}}, + {SocketID: 0, Id: 18, Threads: []int{7, 47}, UncoreCaches: []cadvisorapi.Cache{{Id: 1}}}, + {SocketID: 0, Id: 24, Threads: []int{8, 48}, UncoreCaches: []cadvisorapi.Cache{{Id: 1}}}, + {SocketID: 0, Id: 25, Threads: []int{9, 49}, UncoreCaches: []cadvisorapi.Cache{{Id: 1}}}, + {SocketID: 1, Id: 3, Threads: []int{10, 50}, UncoreCaches: []cadvisorapi.Cache{{Id: 1}}}, + {SocketID: 1, Id: 4, Threads: []int{11, 51}, UncoreCaches: []cadvisorapi.Cache{{Id: 1}}}, + {SocketID: 1, Id: 10, Threads: []int{12, 52}, UncoreCaches: []cadvisorapi.Cache{{Id: 1}}}, + {SocketID: 1, Id: 11, Threads: []int{13, 53}, UncoreCaches: []cadvisorapi.Cache{{Id: 1}}}, + {SocketID: 1, Id: 12, Threads: []int{14, 54}, UncoreCaches: []cadvisorapi.Cache{{Id: 1}}}, + {SocketID: 1, Id: 19, Threads: []int{15, 55}, UncoreCaches: []cadvisorapi.Cache{{Id: 1}}}, + {SocketID: 1, Id: 20, Threads: []int{16, 56}, UncoreCaches: []cadvisorapi.Cache{{Id: 1}}}, + {SocketID: 1, Id: 26, Threads: []int{17, 57}, UncoreCaches: []cadvisorapi.Cache{{Id: 1}}}, + {SocketID: 1, Id: 27, Threads: []int{18, 58}, UncoreCaches: []cadvisorapi.Cache{{Id: 1}}}, + {SocketID: 1, Id: 28, Threads: []int{19, 59}, UncoreCaches: []cadvisorapi.Cache{{Id: 1}}}, }, }, {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}}, + {SocketID: 2, Id: 0, Threads: []int{20, 60}, UncoreCaches: []cadvisorapi.Cache{{Id: 1}}}, + {SocketID: 2, Id: 1, Threads: []int{21, 61}, UncoreCaches: []cadvisorapi.Cache{{Id: 1}}}, + {SocketID: 2, Id: 2, Threads: []int{22, 62}, UncoreCaches: []cadvisorapi.Cache{{Id: 1}}}, + {SocketID: 2, Id: 8, Threads: []int{23, 63}, UncoreCaches: []cadvisorapi.Cache{{Id: 1}}}, + {SocketID: 2, Id: 9, Threads: []int{24, 64}, UncoreCaches: []cadvisorapi.Cache{{Id: 1}}}, + {SocketID: 2, Id: 16, Threads: []int{25, 65}, UncoreCaches: []cadvisorapi.Cache{{Id: 1}}}, + {SocketID: 2, Id: 17, Threads: []int{26, 66}, UncoreCaches: []cadvisorapi.Cache{{Id: 1}}}, + {SocketID: 2, Id: 18, Threads: []int{27, 67}, UncoreCaches: []cadvisorapi.Cache{{Id: 1}}}, + {SocketID: 2, Id: 24, Threads: []int{28, 68}, UncoreCaches: []cadvisorapi.Cache{{Id: 1}}}, + {SocketID: 2, Id: 25, Threads: []int{29, 69}, UncoreCaches: []cadvisorapi.Cache{{Id: 1}}}, + {SocketID: 3, Id: 3, Threads: []int{30, 70}, UncoreCaches: []cadvisorapi.Cache{{Id: 1}}}, + {SocketID: 3, Id: 4, Threads: []int{31, 71}, UncoreCaches: []cadvisorapi.Cache{{Id: 1}}}, + {SocketID: 3, Id: 10, Threads: []int{32, 72}, UncoreCaches: []cadvisorapi.Cache{{Id: 1}}}, + {SocketID: 3, Id: 11, Threads: []int{33, 73}, UncoreCaches: []cadvisorapi.Cache{{Id: 1}}}, + {SocketID: 3, Id: 12, Threads: []int{34, 74}, UncoreCaches: []cadvisorapi.Cache{{Id: 1}}}, + {SocketID: 3, Id: 19, Threads: []int{35, 75}, UncoreCaches: []cadvisorapi.Cache{{Id: 1}}}, + {SocketID: 3, Id: 20, Threads: []int{36, 76}, UncoreCaches: []cadvisorapi.Cache{{Id: 1}}}, + {SocketID: 3, Id: 26, Threads: []int{37, 77}, UncoreCaches: []cadvisorapi.Cache{{Id: 1}}}, + {SocketID: 3, Id: 27, Threads: []int{38, 78}, UncoreCaches: []cadvisorapi.Cache{{Id: 1}}}, + {SocketID: 3, Id: 28, Threads: []int{39, 79}, UncoreCaches: []cadvisorapi.Cache{{Id: 1}}}, }, }, }, }, want: &CPUTopology{ - NumCPUs: 80, - NumSockets: 4, - NumCores: 40, - NumNUMANodes: 2, + NumCPUs: 80, + NumSockets: 4, + NumCores: 40, + NumNUMANodes: 2, + NumUncoreCache: 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: 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}, + 0: {CoreID: 0, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 1}, + 1: {CoreID: 1, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 1}, + 2: {CoreID: 2, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 1}, + 3: {CoreID: 3, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 1}, + 4: {CoreID: 4, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 1}, + 5: {CoreID: 5, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 1}, + 6: {CoreID: 6, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 1}, + 7: {CoreID: 7, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 1}, + 8: {CoreID: 8, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 1}, + 9: {CoreID: 9, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 1}, + 10: {CoreID: 10, SocketID: 1, NUMANodeID: 0, UncoreCacheID: 1}, + 11: {CoreID: 11, SocketID: 1, NUMANodeID: 0, UncoreCacheID: 1}, + 12: {CoreID: 12, SocketID: 1, NUMANodeID: 0, UncoreCacheID: 1}, + 13: {CoreID: 13, SocketID: 1, NUMANodeID: 0, UncoreCacheID: 1}, + 14: {CoreID: 14, SocketID: 1, NUMANodeID: 0, UncoreCacheID: 1}, + 15: {CoreID: 15, SocketID: 1, NUMANodeID: 0, UncoreCacheID: 1}, + 16: {CoreID: 16, SocketID: 1, NUMANodeID: 0, UncoreCacheID: 1}, + 17: {CoreID: 17, SocketID: 1, NUMANodeID: 0, UncoreCacheID: 1}, + 18: {CoreID: 18, SocketID: 1, NUMANodeID: 0, UncoreCacheID: 1}, + 19: {CoreID: 19, SocketID: 1, NUMANodeID: 0, UncoreCacheID: 1}, + 20: {CoreID: 20, SocketID: 2, NUMANodeID: 1, UncoreCacheID: 1}, + 21: {CoreID: 21, SocketID: 2, NUMANodeID: 1, UncoreCacheID: 1}, + 22: {CoreID: 22, SocketID: 2, NUMANodeID: 1, UncoreCacheID: 1}, + 23: {CoreID: 23, SocketID: 2, NUMANodeID: 1, UncoreCacheID: 1}, + 24: {CoreID: 24, SocketID: 2, NUMANodeID: 1, UncoreCacheID: 1}, + 25: {CoreID: 25, SocketID: 2, NUMANodeID: 1, UncoreCacheID: 1}, + 26: {CoreID: 26, SocketID: 2, NUMANodeID: 1, UncoreCacheID: 1}, + 27: {CoreID: 27, SocketID: 2, NUMANodeID: 1, UncoreCacheID: 1}, + 28: {CoreID: 28, SocketID: 2, NUMANodeID: 1, UncoreCacheID: 1}, + 29: {CoreID: 29, SocketID: 2, NUMANodeID: 1, UncoreCacheID: 1}, + 30: {CoreID: 30, SocketID: 3, NUMANodeID: 1, UncoreCacheID: 1}, + 31: {CoreID: 31, SocketID: 3, NUMANodeID: 1, UncoreCacheID: 1}, + 32: {CoreID: 32, SocketID: 3, NUMANodeID: 1, UncoreCacheID: 1}, + 33: {CoreID: 33, SocketID: 3, NUMANodeID: 1, UncoreCacheID: 1}, + 34: {CoreID: 34, SocketID: 3, NUMANodeID: 1, UncoreCacheID: 1}, + 35: {CoreID: 35, SocketID: 3, NUMANodeID: 1, UncoreCacheID: 1}, + 36: {CoreID: 36, SocketID: 3, NUMANodeID: 1, UncoreCacheID: 1}, + 37: {CoreID: 37, SocketID: 3, NUMANodeID: 1, UncoreCacheID: 1}, + 38: {CoreID: 38, SocketID: 3, NUMANodeID: 1, UncoreCacheID: 1}, + 39: {CoreID: 39, SocketID: 3, NUMANodeID: 1, UncoreCacheID: 1}, + 40: {CoreID: 0, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 1}, + 41: {CoreID: 1, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 1}, + 42: {CoreID: 2, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 1}, + 43: {CoreID: 3, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 1}, + 44: {CoreID: 4, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 1}, + 45: {CoreID: 5, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 1}, + 46: {CoreID: 6, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 1}, + 47: {CoreID: 7, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 1}, + 48: {CoreID: 8, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 1}, + 49: {CoreID: 9, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 1}, + 50: {CoreID: 10, SocketID: 1, NUMANodeID: 0, UncoreCacheID: 1}, + 51: {CoreID: 11, SocketID: 1, NUMANodeID: 0, UncoreCacheID: 1}, + 52: {CoreID: 12, SocketID: 1, NUMANodeID: 0, UncoreCacheID: 1}, + 53: {CoreID: 13, SocketID: 1, NUMANodeID: 0, UncoreCacheID: 1}, + 54: {CoreID: 14, SocketID: 1, NUMANodeID: 0, UncoreCacheID: 1}, + 55: {CoreID: 15, SocketID: 1, NUMANodeID: 0, UncoreCacheID: 1}, + 56: {CoreID: 16, SocketID: 1, NUMANodeID: 0, UncoreCacheID: 1}, + 57: {CoreID: 17, SocketID: 1, NUMANodeID: 0, UncoreCacheID: 1}, + 58: {CoreID: 18, SocketID: 1, NUMANodeID: 0, UncoreCacheID: 1}, + 59: {CoreID: 19, SocketID: 1, NUMANodeID: 0, UncoreCacheID: 1}, + 60: {CoreID: 20, SocketID: 2, NUMANodeID: 1, UncoreCacheID: 1}, + 61: {CoreID: 21, SocketID: 2, NUMANodeID: 1, UncoreCacheID: 1}, + 62: {CoreID: 22, SocketID: 2, NUMANodeID: 1, UncoreCacheID: 1}, + 63: {CoreID: 23, SocketID: 2, NUMANodeID: 1, UncoreCacheID: 1}, + 64: {CoreID: 24, SocketID: 2, NUMANodeID: 1, UncoreCacheID: 1}, + 65: {CoreID: 25, SocketID: 2, NUMANodeID: 1, UncoreCacheID: 1}, + 66: {CoreID: 26, SocketID: 2, NUMANodeID: 1, UncoreCacheID: 1}, + 67: {CoreID: 27, SocketID: 2, NUMANodeID: 1, UncoreCacheID: 1}, + 68: {CoreID: 28, SocketID: 2, NUMANodeID: 1, UncoreCacheID: 1}, + 69: {CoreID: 29, SocketID: 2, NUMANodeID: 1, UncoreCacheID: 1}, + 70: {CoreID: 30, SocketID: 3, NUMANodeID: 1, UncoreCacheID: 1}, + 71: {CoreID: 31, SocketID: 3, NUMANodeID: 1, UncoreCacheID: 1}, + 72: {CoreID: 32, SocketID: 3, NUMANodeID: 1, UncoreCacheID: 1}, + 73: {CoreID: 33, SocketID: 3, NUMANodeID: 1, UncoreCacheID: 1}, + 74: {CoreID: 34, SocketID: 3, NUMANodeID: 1, UncoreCacheID: 1}, + 75: {CoreID: 35, SocketID: 3, NUMANodeID: 1, UncoreCacheID: 1}, + 76: {CoreID: 36, SocketID: 3, NUMANodeID: 1, UncoreCacheID: 1}, + 77: {CoreID: 37, SocketID: 3, NUMANodeID: 1, UncoreCacheID: 1}, + 78: {CoreID: 38, SocketID: 3, NUMANodeID: 1, UncoreCacheID: 1}, + 79: {CoreID: 39, SocketID: 3, NUMANodeID: 1, UncoreCacheID: 1}, }, }, wantErr: false, @@ -395,28 +433,29 @@ func Test_Discover(t *testing.T) { Topology: []cadvisorapi.Node{ {Id: 0, Cores: []cadvisorapi.Core{ - {SocketID: 0, Id: 0, Threads: []int{0}}, - {SocketID: 0, Id: 2, Threads: []int{2}}, + {SocketID: 0, Id: 0, Threads: []int{0}, UncoreCaches: []cadvisorapi.Cache{{Id: 0}}}, + {SocketID: 0, Id: 2, Threads: []int{2}, UncoreCaches: []cadvisorapi.Cache{{Id: 0}}}, }, }, {Id: 1, Cores: []cadvisorapi.Core{ - {SocketID: 1, Id: 1, Threads: []int{1}}, - {SocketID: 1, Id: 3, Threads: []int{3}}, + {SocketID: 1, Id: 1, Threads: []int{1}, UncoreCaches: []cadvisorapi.Cache{{Id: 0}}}, + {SocketID: 1, Id: 3, Threads: []int{3}, UncoreCaches: []cadvisorapi.Cache{{Id: 0}}}, }, }, }, }, want: &CPUTopology{ - NumCPUs: 4, - NumSockets: 2, - NumCores: 4, - NumNUMANodes: 2, + NumCPUs: 4, + NumSockets: 2, + NumCores: 4, + NumNUMANodes: 2, + NumUncoreCache: 1, 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}, + 0: {CoreID: 0, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 0}, + 1: {CoreID: 1, SocketID: 1, NUMANodeID: 1, UncoreCacheID: 0}, + 2: {CoreID: 2, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 0}, + 3: {CoreID: 3, SocketID: 1, NUMANodeID: 1, UncoreCacheID: 0}, }, }, wantErr: false, @@ -429,38 +468,39 @@ func Test_Discover(t *testing.T) { 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}}, + {SocketID: 0, Id: 0, Threads: []int{0, 6}, UncoreCaches: []cadvisorapi.Cache{{Id: 0}}}, + {SocketID: 0, Id: 1, Threads: []int{1, 7}, UncoreCaches: []cadvisorapi.Cache{{Id: 0}}}, + {SocketID: 0, Id: 2, Threads: []int{2, 8}, UncoreCaches: []cadvisorapi.Cache{{Id: 0}}}, }, }, {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}}, + {SocketID: 1, Id: 0, Threads: []int{3, 9}, UncoreCaches: []cadvisorapi.Cache{{Id: 0}}}, + {SocketID: 1, Id: 1, Threads: []int{4, 10}, UncoreCaches: []cadvisorapi.Cache{{Id: 0}}}, + {SocketID: 1, Id: 2, Threads: []int{5, 11}, UncoreCaches: []cadvisorapi.Cache{{Id: 0}}}, }, }, }, }, want: &CPUTopology{ - NumCPUs: 12, - NumSockets: 2, - NumCores: 6, - NumNUMANodes: 2, + NumCPUs: 12, + NumSockets: 2, + NumCores: 6, + NumNUMANodes: 2, + NumUncoreCache: 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: 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}, + 0: {CoreID: 0, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 0}, + 1: {CoreID: 1, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 0}, + 2: {CoreID: 2, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 0}, + 3: {CoreID: 3, SocketID: 1, NUMANodeID: 1, UncoreCacheID: 0}, + 4: {CoreID: 4, SocketID: 1, NUMANodeID: 1, UncoreCacheID: 0}, + 5: {CoreID: 5, SocketID: 1, NUMANodeID: 1, UncoreCacheID: 0}, + 6: {CoreID: 0, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 0}, + 7: {CoreID: 1, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 0}, + 8: {CoreID: 2, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 0}, + 9: {CoreID: 3, SocketID: 1, NUMANodeID: 1, UncoreCacheID: 0}, + 10: {CoreID: 4, SocketID: 1, NUMANodeID: 1, UncoreCacheID: 0}, + 11: {CoreID: 5, SocketID: 1, NUMANodeID: 1, UncoreCacheID: 0}, }, }, wantErr: false, @@ -473,10 +513,10 @@ func Test_Discover(t *testing.T) { 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}}, + {SocketID: 0, Id: 0, Threads: []int{0, 4}, UncoreCaches: []cadvisorapi.Cache{{Id: 1}}}, + {SocketID: 0, Id: 1, Threads: []int{1, 5}, UncoreCaches: []cadvisorapi.Cache{{Id: 1}}}, + {SocketID: 0, Id: 2, Threads: []int{2, 2}, UncoreCaches: []cadvisorapi.Cache{{Id: 1}}}, // Wrong case - should fail here + {SocketID: 0, Id: 3, Threads: []int{3, 7}, UncoreCaches: []cadvisorapi.Cache{{Id: 1}}}, }, }, }, @@ -492,10 +532,10 @@ func Test_Discover(t *testing.T) { 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 + {SocketID: 0, Id: 0, Threads: []int{0, 4}, UncoreCaches: []cadvisorapi.Cache{{Id: 1}}}, + {SocketID: 0, Id: 1, Threads: []int{1, 5}, UncoreCaches: []cadvisorapi.Cache{{Id: 1}}}, + {SocketID: 0, Id: 2, Threads: []int{2, 6}, UncoreCaches: []cadvisorapi.Cache{{Id: 1}}}, + {SocketID: 0, Id: 3, Threads: []int{}, UncoreCaches: []cadvisorapi.Cache{{Id: 1}}}, // Wrong case - should fail here }, }, }, @@ -503,6 +543,280 @@ func Test_Discover(t *testing.T) { want: &CPUTopology{}, wantErr: true, }, + { + // Topology from AMD EPYC 7452 (Rome) 32-Core Processor + // 4 cores per LLC + // Single-socket SMT-disabled + // NPS=1 + name: "UncoreOneSocketNoSMT", + machineInfo: cadvisorapi.MachineInfo{ + NumCores: 32, + NumSockets: 1, + Topology: []cadvisorapi.Node{ + {Id: 0, + Cores: []cadvisorapi.Core{ + {SocketID: 0, Id: 0, Threads: []int{0}, UncoreCaches: []cadvisorapi.Cache{{Id: 0}}}, + {SocketID: 0, Id: 1, Threads: []int{1}, UncoreCaches: []cadvisorapi.Cache{{Id: 0}}}, + {SocketID: 0, Id: 2, Threads: []int{2}, UncoreCaches: []cadvisorapi.Cache{{Id: 0}}}, + {SocketID: 0, Id: 3, Threads: []int{3}, UncoreCaches: []cadvisorapi.Cache{{Id: 0}}}, + {SocketID: 0, Id: 4, Threads: []int{4}, UncoreCaches: []cadvisorapi.Cache{{Id: 1}}}, + {SocketID: 0, Id: 5, Threads: []int{5}, UncoreCaches: []cadvisorapi.Cache{{Id: 1}}}, + {SocketID: 0, Id: 6, Threads: []int{6}, UncoreCaches: []cadvisorapi.Cache{{Id: 1}}}, + {SocketID: 0, Id: 7, Threads: []int{7}, UncoreCaches: []cadvisorapi.Cache{{Id: 1}}}, + {SocketID: 0, Id: 8, Threads: []int{8}, UncoreCaches: []cadvisorapi.Cache{{Id: 2}}}, + {SocketID: 0, Id: 9, Threads: []int{9}, UncoreCaches: []cadvisorapi.Cache{{Id: 2}}}, + {SocketID: 0, Id: 10, Threads: []int{10}, UncoreCaches: []cadvisorapi.Cache{{Id: 2}}}, + {SocketID: 0, Id: 11, Threads: []int{11}, UncoreCaches: []cadvisorapi.Cache{{Id: 2}}}, + {SocketID: 0, Id: 12, Threads: []int{12}, UncoreCaches: []cadvisorapi.Cache{{Id: 3}}}, + {SocketID: 0, Id: 13, Threads: []int{13}, UncoreCaches: []cadvisorapi.Cache{{Id: 3}}}, + {SocketID: 0, Id: 14, Threads: []int{14}, UncoreCaches: []cadvisorapi.Cache{{Id: 3}}}, + {SocketID: 0, Id: 15, Threads: []int{15}, UncoreCaches: []cadvisorapi.Cache{{Id: 3}}}, + {SocketID: 0, Id: 16, Threads: []int{16}, UncoreCaches: []cadvisorapi.Cache{{Id: 4}}}, + {SocketID: 0, Id: 17, Threads: []int{17}, UncoreCaches: []cadvisorapi.Cache{{Id: 4}}}, + {SocketID: 0, Id: 18, Threads: []int{18}, UncoreCaches: []cadvisorapi.Cache{{Id: 4}}}, + {SocketID: 0, Id: 19, Threads: []int{19}, UncoreCaches: []cadvisorapi.Cache{{Id: 4}}}, + {SocketID: 0, Id: 20, Threads: []int{20}, UncoreCaches: []cadvisorapi.Cache{{Id: 5}}}, + {SocketID: 0, Id: 21, Threads: []int{21}, UncoreCaches: []cadvisorapi.Cache{{Id: 5}}}, + {SocketID: 0, Id: 22, Threads: []int{22}, UncoreCaches: []cadvisorapi.Cache{{Id: 5}}}, + {SocketID: 0, Id: 23, Threads: []int{23}, UncoreCaches: []cadvisorapi.Cache{{Id: 5}}}, + {SocketID: 0, Id: 24, Threads: []int{24}, UncoreCaches: []cadvisorapi.Cache{{Id: 6}}}, + {SocketID: 0, Id: 25, Threads: []int{25}, UncoreCaches: []cadvisorapi.Cache{{Id: 6}}}, + {SocketID: 0, Id: 26, Threads: []int{26}, UncoreCaches: []cadvisorapi.Cache{{Id: 6}}}, + {SocketID: 0, Id: 27, Threads: []int{27}, UncoreCaches: []cadvisorapi.Cache{{Id: 6}}}, + {SocketID: 0, Id: 28, Threads: []int{28}, UncoreCaches: []cadvisorapi.Cache{{Id: 7}}}, + {SocketID: 0, Id: 29, Threads: []int{29}, UncoreCaches: []cadvisorapi.Cache{{Id: 7}}}, + {SocketID: 0, Id: 30, Threads: []int{30}, UncoreCaches: []cadvisorapi.Cache{{Id: 7}}}, + {SocketID: 0, Id: 31, Threads: []int{31}, UncoreCaches: []cadvisorapi.Cache{{Id: 7}}}, + }, + }, + }, + }, + want: &CPUTopology{ + NumCPUs: 32, + NumSockets: 1, + NumCores: 32, + NumNUMANodes: 1, + NumUncoreCache: 8, + CPUDetails: map[int]CPUInfo{ + 0: {CoreID: 0, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 0}, + 1: {CoreID: 1, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 0}, + 2: {CoreID: 2, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 0}, + 3: {CoreID: 3, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 0}, + 4: {CoreID: 4, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 1}, + 5: {CoreID: 5, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 1}, + 6: {CoreID: 6, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 1}, + 7: {CoreID: 7, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 1}, + 8: {CoreID: 8, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 2}, + 9: {CoreID: 9, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 2}, + 10: {CoreID: 10, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 2}, + 11: {CoreID: 11, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 2}, + 12: {CoreID: 12, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 3}, + 13: {CoreID: 13, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 3}, + 14: {CoreID: 14, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 3}, + 15: {CoreID: 15, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 3}, + 16: {CoreID: 16, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 4}, + 17: {CoreID: 17, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 4}, + 18: {CoreID: 18, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 4}, + 19: {CoreID: 19, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 4}, + 20: {CoreID: 20, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 5}, + 21: {CoreID: 21, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 5}, + 22: {CoreID: 22, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 5}, + 23: {CoreID: 23, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 5}, + 24: {CoreID: 24, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 6}, + 25: {CoreID: 25, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 6}, + 26: {CoreID: 26, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 6}, + 27: {CoreID: 27, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 6}, + 28: {CoreID: 28, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 7}, + 29: {CoreID: 29, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 7}, + 30: {CoreID: 30, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 7}, + 31: {CoreID: 31, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 7}, + }, + }, + wantErr: false, + }, + { + // Topology from AMD EPYC 24-Core Processor + // 4 cores per LLC + // Dual-socket SMT-enabled + // NPS=2 + name: "UncoreDualSocketSMT", + machineInfo: cadvisorapi.MachineInfo{ + NumCores: 96, + NumSockets: 2, + Topology: []cadvisorapi.Node{ + {Id: 0, + Cores: []cadvisorapi.Core{ + {SocketID: 0, Id: 0, Threads: []int{0, 48}, UncoreCaches: []cadvisorapi.Cache{{Id: 0}}}, + {SocketID: 0, Id: 1, Threads: []int{1, 49}, UncoreCaches: []cadvisorapi.Cache{{Id: 0}}}, + {SocketID: 0, Id: 2, Threads: []int{2, 50}, UncoreCaches: []cadvisorapi.Cache{{Id: 0}}}, + {SocketID: 0, Id: 3, Threads: []int{3, 51}, UncoreCaches: []cadvisorapi.Cache{{Id: 0}}}, + {SocketID: 0, Id: 4, Threads: []int{4, 52}, UncoreCaches: []cadvisorapi.Cache{{Id: 1}}}, + {SocketID: 0, Id: 5, Threads: []int{5, 53}, UncoreCaches: []cadvisorapi.Cache{{Id: 1}}}, + {SocketID: 0, Id: 6, Threads: []int{6, 54}, UncoreCaches: []cadvisorapi.Cache{{Id: 1}}}, + {SocketID: 0, Id: 7, Threads: []int{7, 55}, UncoreCaches: []cadvisorapi.Cache{{Id: 1}}}, + {SocketID: 0, Id: 8, Threads: []int{8, 56}, UncoreCaches: []cadvisorapi.Cache{{Id: 2}}}, + {SocketID: 0, Id: 9, Threads: []int{9, 57}, UncoreCaches: []cadvisorapi.Cache{{Id: 2}}}, + {SocketID: 0, Id: 10, Threads: []int{10, 58}, UncoreCaches: []cadvisorapi.Cache{{Id: 2}}}, + {SocketID: 0, Id: 11, Threads: []int{11, 59}, UncoreCaches: []cadvisorapi.Cache{{Id: 2}}}, + }, + }, + {Id: 1, + Cores: []cadvisorapi.Core{ + {SocketID: 0, Id: 12, Threads: []int{12, 60}, UncoreCaches: []cadvisorapi.Cache{{Id: 3}}}, + {SocketID: 0, Id: 13, Threads: []int{13, 61}, UncoreCaches: []cadvisorapi.Cache{{Id: 3}}}, + {SocketID: 0, Id: 14, Threads: []int{14, 62}, UncoreCaches: []cadvisorapi.Cache{{Id: 3}}}, + {SocketID: 0, Id: 15, Threads: []int{15, 63}, UncoreCaches: []cadvisorapi.Cache{{Id: 3}}}, + {SocketID: 0, Id: 16, Threads: []int{16, 64}, UncoreCaches: []cadvisorapi.Cache{{Id: 4}}}, + {SocketID: 0, Id: 17, Threads: []int{17, 65}, UncoreCaches: []cadvisorapi.Cache{{Id: 4}}}, + {SocketID: 0, Id: 18, Threads: []int{18, 66}, UncoreCaches: []cadvisorapi.Cache{{Id: 4}}}, + {SocketID: 0, Id: 19, Threads: []int{19, 67}, UncoreCaches: []cadvisorapi.Cache{{Id: 4}}}, + {SocketID: 0, Id: 20, Threads: []int{20, 68}, UncoreCaches: []cadvisorapi.Cache{{Id: 5}}}, + {SocketID: 0, Id: 21, Threads: []int{21, 69}, UncoreCaches: []cadvisorapi.Cache{{Id: 5}}}, + {SocketID: 0, Id: 22, Threads: []int{22, 70}, UncoreCaches: []cadvisorapi.Cache{{Id: 5}}}, + {SocketID: 0, Id: 23, Threads: []int{23, 71}, UncoreCaches: []cadvisorapi.Cache{{Id: 5}}}, + }, + }, + {Id: 2, + Cores: []cadvisorapi.Core{ + {SocketID: 1, Id: 24, Threads: []int{24, 72}, UncoreCaches: []cadvisorapi.Cache{{Id: 6}}}, + {SocketID: 1, Id: 25, Threads: []int{25, 73}, UncoreCaches: []cadvisorapi.Cache{{Id: 6}}}, + {SocketID: 1, Id: 26, Threads: []int{26, 74}, UncoreCaches: []cadvisorapi.Cache{{Id: 6}}}, + {SocketID: 1, Id: 27, Threads: []int{27, 75}, UncoreCaches: []cadvisorapi.Cache{{Id: 6}}}, + {SocketID: 1, Id: 28, Threads: []int{28, 76}, UncoreCaches: []cadvisorapi.Cache{{Id: 7}}}, + {SocketID: 1, Id: 29, Threads: []int{29, 77}, UncoreCaches: []cadvisorapi.Cache{{Id: 7}}}, + {SocketID: 1, Id: 30, Threads: []int{30, 78}, UncoreCaches: []cadvisorapi.Cache{{Id: 7}}}, + {SocketID: 1, Id: 31, Threads: []int{31, 79}, UncoreCaches: []cadvisorapi.Cache{{Id: 7}}}, + {SocketID: 1, Id: 32, Threads: []int{32, 80}, UncoreCaches: []cadvisorapi.Cache{{Id: 8}}}, + {SocketID: 1, Id: 33, Threads: []int{33, 81}, UncoreCaches: []cadvisorapi.Cache{{Id: 8}}}, + {SocketID: 1, Id: 34, Threads: []int{34, 82}, UncoreCaches: []cadvisorapi.Cache{{Id: 8}}}, + {SocketID: 1, Id: 35, Threads: []int{35, 83}, UncoreCaches: []cadvisorapi.Cache{{Id: 8}}}, + }, + }, + {Id: 3, + Cores: []cadvisorapi.Core{ + {SocketID: 1, Id: 36, Threads: []int{36, 84}, UncoreCaches: []cadvisorapi.Cache{{Id: 9}}}, + {SocketID: 1, Id: 37, Threads: []int{37, 85}, UncoreCaches: []cadvisorapi.Cache{{Id: 9}}}, + {SocketID: 1, Id: 38, Threads: []int{38, 86}, UncoreCaches: []cadvisorapi.Cache{{Id: 9}}}, + {SocketID: 1, Id: 39, Threads: []int{39, 87}, UncoreCaches: []cadvisorapi.Cache{{Id: 9}}}, + {SocketID: 1, Id: 40, Threads: []int{40, 88}, UncoreCaches: []cadvisorapi.Cache{{Id: 10}}}, + {SocketID: 1, Id: 41, Threads: []int{41, 89}, UncoreCaches: []cadvisorapi.Cache{{Id: 10}}}, + {SocketID: 1, Id: 42, Threads: []int{42, 90}, UncoreCaches: []cadvisorapi.Cache{{Id: 10}}}, + {SocketID: 1, Id: 43, Threads: []int{43, 91}, UncoreCaches: []cadvisorapi.Cache{{Id: 10}}}, + {SocketID: 1, Id: 44, Threads: []int{44, 92}, UncoreCaches: []cadvisorapi.Cache{{Id: 11}}}, + {SocketID: 1, Id: 45, Threads: []int{45, 93}, UncoreCaches: []cadvisorapi.Cache{{Id: 11}}}, + {SocketID: 1, Id: 46, Threads: []int{46, 94}, UncoreCaches: []cadvisorapi.Cache{{Id: 11}}}, + {SocketID: 1, Id: 47, Threads: []int{47, 95}, UncoreCaches: []cadvisorapi.Cache{{Id: 11}}}, + }, + }, + }, + }, + want: &CPUTopology{ + NumCPUs: 96, + NumSockets: 2, + NumCores: 48, + NumNUMANodes: 4, + NumUncoreCache: 12, + CPUDetails: map[int]CPUInfo{ + 0: {CoreID: 0, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 0}, + 1: {CoreID: 1, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 0}, + 2: {CoreID: 2, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 0}, + 3: {CoreID: 3, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 0}, + 4: {CoreID: 4, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 1}, + 5: {CoreID: 5, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 1}, + 6: {CoreID: 6, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 1}, + 7: {CoreID: 7, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 1}, + 8: {CoreID: 8, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 2}, + 9: {CoreID: 9, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 2}, + 10: {CoreID: 10, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 2}, + 11: {CoreID: 11, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 2}, + 12: {CoreID: 12, SocketID: 0, NUMANodeID: 1, UncoreCacheID: 3}, + 13: {CoreID: 13, SocketID: 0, NUMANodeID: 1, UncoreCacheID: 3}, + 14: {CoreID: 14, SocketID: 0, NUMANodeID: 1, UncoreCacheID: 3}, + 15: {CoreID: 15, SocketID: 0, NUMANodeID: 1, UncoreCacheID: 3}, + 16: {CoreID: 16, SocketID: 0, NUMANodeID: 1, UncoreCacheID: 4}, + 17: {CoreID: 17, SocketID: 0, NUMANodeID: 1, UncoreCacheID: 4}, + 18: {CoreID: 18, SocketID: 0, NUMANodeID: 1, UncoreCacheID: 4}, + 19: {CoreID: 19, SocketID: 0, NUMANodeID: 1, UncoreCacheID: 4}, + 20: {CoreID: 20, SocketID: 0, NUMANodeID: 1, UncoreCacheID: 5}, + 21: {CoreID: 21, SocketID: 0, NUMANodeID: 1, UncoreCacheID: 5}, + 22: {CoreID: 22, SocketID: 0, NUMANodeID: 1, UncoreCacheID: 5}, + 23: {CoreID: 23, SocketID: 0, NUMANodeID: 1, UncoreCacheID: 5}, + 24: {CoreID: 24, SocketID: 1, NUMANodeID: 2, UncoreCacheID: 6}, + 25: {CoreID: 25, SocketID: 1, NUMANodeID: 2, UncoreCacheID: 6}, + 26: {CoreID: 26, SocketID: 1, NUMANodeID: 2, UncoreCacheID: 6}, + 27: {CoreID: 27, SocketID: 1, NUMANodeID: 2, UncoreCacheID: 6}, + 28: {CoreID: 28, SocketID: 1, NUMANodeID: 2, UncoreCacheID: 7}, + 29: {CoreID: 29, SocketID: 1, NUMANodeID: 2, UncoreCacheID: 7}, + 30: {CoreID: 30, SocketID: 1, NUMANodeID: 2, UncoreCacheID: 7}, + 31: {CoreID: 31, SocketID: 1, NUMANodeID: 2, UncoreCacheID: 7}, + 32: {CoreID: 32, SocketID: 1, NUMANodeID: 2, UncoreCacheID: 8}, + 33: {CoreID: 33, SocketID: 1, NUMANodeID: 2, UncoreCacheID: 8}, + 34: {CoreID: 34, SocketID: 1, NUMANodeID: 2, UncoreCacheID: 8}, + 35: {CoreID: 35, SocketID: 1, NUMANodeID: 2, UncoreCacheID: 8}, + 36: {CoreID: 36, SocketID: 1, NUMANodeID: 3, UncoreCacheID: 9}, + 37: {CoreID: 37, SocketID: 1, NUMANodeID: 3, UncoreCacheID: 9}, + 38: {CoreID: 38, SocketID: 1, NUMANodeID: 3, UncoreCacheID: 9}, + 39: {CoreID: 39, SocketID: 1, NUMANodeID: 3, UncoreCacheID: 9}, + 40: {CoreID: 40, SocketID: 1, NUMANodeID: 3, UncoreCacheID: 10}, + 41: {CoreID: 41, SocketID: 1, NUMANodeID: 3, UncoreCacheID: 10}, + 42: {CoreID: 42, SocketID: 1, NUMANodeID: 3, UncoreCacheID: 10}, + 43: {CoreID: 43, SocketID: 1, NUMANodeID: 3, UncoreCacheID: 10}, + 44: {CoreID: 44, SocketID: 1, NUMANodeID: 3, UncoreCacheID: 11}, + 45: {CoreID: 45, SocketID: 1, NUMANodeID: 3, UncoreCacheID: 11}, + 46: {CoreID: 46, SocketID: 1, NUMANodeID: 3, UncoreCacheID: 11}, + 47: {CoreID: 47, SocketID: 1, NUMANodeID: 3, UncoreCacheID: 11}, + 48: {CoreID: 0, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 0}, + 49: {CoreID: 1, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 0}, + 50: {CoreID: 2, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 0}, + 51: {CoreID: 3, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 0}, + 52: {CoreID: 4, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 1}, + 53: {CoreID: 5, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 1}, + 54: {CoreID: 6, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 1}, + 55: {CoreID: 7, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 1}, + 56: {CoreID: 8, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 2}, + 57: {CoreID: 9, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 2}, + 58: {CoreID: 10, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 2}, + 59: {CoreID: 11, SocketID: 0, NUMANodeID: 0, UncoreCacheID: 2}, + 60: {CoreID: 12, SocketID: 0, NUMANodeID: 1, UncoreCacheID: 3}, + 61: {CoreID: 13, SocketID: 0, NUMANodeID: 1, UncoreCacheID: 3}, + 62: {CoreID: 14, SocketID: 0, NUMANodeID: 1, UncoreCacheID: 3}, + 63: {CoreID: 15, SocketID: 0, NUMANodeID: 1, UncoreCacheID: 3}, + 64: {CoreID: 16, SocketID: 0, NUMANodeID: 1, UncoreCacheID: 4}, + 65: {CoreID: 17, SocketID: 0, NUMANodeID: 1, UncoreCacheID: 4}, + 66: {CoreID: 18, SocketID: 0, NUMANodeID: 1, UncoreCacheID: 4}, + 67: {CoreID: 19, SocketID: 0, NUMANodeID: 1, UncoreCacheID: 4}, + 68: {CoreID: 20, SocketID: 0, NUMANodeID: 1, UncoreCacheID: 5}, + 69: {CoreID: 21, SocketID: 0, NUMANodeID: 1, UncoreCacheID: 5}, + 70: {CoreID: 22, SocketID: 0, NUMANodeID: 1, UncoreCacheID: 5}, + 71: {CoreID: 23, SocketID: 0, NUMANodeID: 1, UncoreCacheID: 5}, + 72: {CoreID: 24, SocketID: 1, NUMANodeID: 2, UncoreCacheID: 6}, + 73: {CoreID: 25, SocketID: 1, NUMANodeID: 2, UncoreCacheID: 6}, + 74: {CoreID: 26, SocketID: 1, NUMANodeID: 2, UncoreCacheID: 6}, + 75: {CoreID: 27, SocketID: 1, NUMANodeID: 2, UncoreCacheID: 6}, + 76: {CoreID: 28, SocketID: 1, NUMANodeID: 2, UncoreCacheID: 7}, + 77: {CoreID: 29, SocketID: 1, NUMANodeID: 2, UncoreCacheID: 7}, + 78: {CoreID: 30, SocketID: 1, NUMANodeID: 2, UncoreCacheID: 7}, + 79: {CoreID: 31, SocketID: 1, NUMANodeID: 2, UncoreCacheID: 7}, + 80: {CoreID: 32, SocketID: 1, NUMANodeID: 2, UncoreCacheID: 8}, + 81: {CoreID: 33, SocketID: 1, NUMANodeID: 2, UncoreCacheID: 8}, + 82: {CoreID: 34, SocketID: 1, NUMANodeID: 2, UncoreCacheID: 8}, + 83: {CoreID: 35, SocketID: 1, NUMANodeID: 2, UncoreCacheID: 8}, + 84: {CoreID: 36, SocketID: 1, NUMANodeID: 3, UncoreCacheID: 9}, + 85: {CoreID: 37, SocketID: 1, NUMANodeID: 3, UncoreCacheID: 9}, + 86: {CoreID: 38, SocketID: 1, NUMANodeID: 3, UncoreCacheID: 9}, + 87: {CoreID: 39, SocketID: 1, NUMANodeID: 3, UncoreCacheID: 9}, + 88: {CoreID: 40, SocketID: 1, NUMANodeID: 3, UncoreCacheID: 10}, + 89: {CoreID: 41, SocketID: 1, NUMANodeID: 3, UncoreCacheID: 10}, + 90: {CoreID: 42, SocketID: 1, NUMANodeID: 3, UncoreCacheID: 10}, + 91: {CoreID: 43, SocketID: 1, NUMANodeID: 3, UncoreCacheID: 10}, + 92: {CoreID: 44, SocketID: 1, NUMANodeID: 3, UncoreCacheID: 11}, + 93: {CoreID: 45, SocketID: 1, NUMANodeID: 3, UncoreCacheID: 11}, + 94: {CoreID: 46, SocketID: 1, NUMANodeID: 3, UncoreCacheID: 11}, + 95: {CoreID: 47, SocketID: 1, NUMANodeID: 3, UncoreCacheID: 11}, + }, + }, + wantErr: false, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -1100,3 +1414,217 @@ func TestCPUNUMANodeID(t *testing.T) { }) } } + +func TestCPUsInUncoreCaches(t *testing.T) { + tests := []struct { + name string + details CPUDetails + ids []int + want cpuset.CPUSet + }{ + { + name: "Single Uncore Cache", + details: map[int]CPUInfo{ + 0: {UncoreCacheID: 0}, + 1: {UncoreCacheID: 0}, + }, + ids: []int{0}, + want: cpuset.New(0, 1), + }, + { + name: "Multiple Uncore Caches", + details: map[int]CPUInfo{ + 0: {UncoreCacheID: 0}, + 1: {UncoreCacheID: 0}, + 2: {UncoreCacheID: 1}, + }, + ids: []int{0, 1}, + want: cpuset.New(0, 1, 2), + }, + { + name: "Uncore Cache does not exist", + details: map[int]CPUInfo{ + 0: {UncoreCacheID: 0}, + }, + ids: []int{1}, + want: cpuset.New(), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := tt.details.CPUsInUncoreCaches(tt.ids...) + if !reflect.DeepEqual(tt.want, got) { + t.Errorf("CPUsInUncoreCaches() = %v, want %v", got, tt.want) + } + }) + } +} +func TestUncoreInNUMANodes(t *testing.T) { + tests := []struct { + name string + details CPUDetails + ids []int + want cpuset.CPUSet + }{ + { + name: "Single NUMA Node", + details: map[int]CPUInfo{ + 0: {NUMANodeID: 0, UncoreCacheID: 0}, + 1: {NUMANodeID: 0, UncoreCacheID: 1}, + }, + ids: []int{0}, + want: cpuset.New(0, 1), + }, + { + name: "Multiple NUMANode", + details: map[int]CPUInfo{ + 0: {NUMANodeID: 0, UncoreCacheID: 0}, + 1: {NUMANodeID: 0, UncoreCacheID: 0}, + 20: {NUMANodeID: 1, UncoreCacheID: 1}, + 21: {NUMANodeID: 1, UncoreCacheID: 1}, + }, + ids: []int{0, 1}, + want: cpuset.New(0, 1), + }, + { + name: "Non-Existent NUMANode", + details: map[int]CPUInfo{ + 0: {NUMANodeID: 1, UncoreCacheID: 0}, + }, + ids: []int{0}, + want: cpuset.New(), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := tt.details.UncoreInNUMANodes(tt.ids...) + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("UncoreInNUMANodes()= %v, want %v", got, tt.want) + } + }) + + } +} + +func TestUncoreCaches(t *testing.T) { + tests := []struct { + name string + details CPUDetails + want cpuset.CPUSet + }{ + { + name: "Get CPUSet of UncoreCache IDs", + details: map[int]CPUInfo{ + 0: {UncoreCacheID: 0}, + 1: {UncoreCacheID: 1}, + 2: {UncoreCacheID: 2}, + }, + want: cpuset.New(0, 1, 2), + }, + { + name: "Empty CPUDetails", + details: map[int]CPUInfo{}, + want: cpuset.New(), + }, + { + name: "Shared UncoreCache", + details: map[int]CPUInfo{ + 0: {UncoreCacheID: 0}, + 1: {UncoreCacheID: 0}, + 2: {UncoreCacheID: 0}, + }, + want: cpuset.New(0), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := tt.details.UncoreCaches() + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("UncoreCaches() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestCPUsPerUncore(t *testing.T) { + tests := []struct { + name string + topo *CPUTopology + want int + }{ + { + name: "Zero Number of UncoreCache", + topo: &CPUTopology{ + NumCPUs: 8, + NumUncoreCache: 0, + }, + want: 0, + }, + { + name: "Normal case", + topo: &CPUTopology{ + NumCPUs: 16, + NumUncoreCache: 2, + }, + want: 8, + }, + { + name: "Single shared UncoreCache", + topo: &CPUTopology{ + NumCPUs: 8, + NumUncoreCache: 1, + }, + want: 8, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := tt.topo.CPUsPerUncore() + if got != tt.want { + t.Errorf("CPUsPerUncore() = %v, want %v", got, tt.want) + } + }) + } + +} +func Test_getUncoreCacheID(t *testing.T) { + tests := []struct { + name string + args cadvisorapi.Core + want int + }{ + { + name: "Core with uncore cache info", + args: cadvisorapi.Core{ + SocketID: 1, + UncoreCaches: []cadvisorapi.Cache{ + {Id: 5}, + {Id: 6}, + }, + }, + want: 5, + }, + { + name: "Core with empty uncore cache info", + args: cadvisorapi.Core{ + SocketID: 2, + UncoreCaches: []cadvisorapi.Cache{}, + }, + want: 2, + }, + { + name: "Core with nil uncore cache info", + args: cadvisorapi.Core{ + SocketID: 1, + }, + want: 1, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := getUncoreCacheID(tt.args); got != tt.want { + t.Errorf("getUncoreCacheID() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/pkg/kubelet/cm/cpumanager/topology_hints_test.go b/pkg/kubelet/cm/cpumanager/topology_hints_test.go index 53738b613c29e..d38cd9d7cf7ea 100644 --- a/pkg/kubelet/cm/cpumanager/topology_hints_test.go +++ b/pkg/kubelet/cm/cpumanager/topology_hints_test.go @@ -49,16 +49,16 @@ func returnMachineInfo() cadvisorapi.MachineInfo { 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}}, + {SocketID: 0, Id: 0, Threads: []int{0, 6}, UncoreCaches: []cadvisorapi.Cache{{Id: 1}}}, + {SocketID: 0, Id: 1, Threads: []int{1, 7}, UncoreCaches: []cadvisorapi.Cache{{Id: 1}}}, + {SocketID: 0, Id: 2, Threads: []int{2, 8}, UncoreCaches: []cadvisorapi.Cache{{Id: 1}}}, }, }, {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}}, + {SocketID: 1, Id: 0, Threads: []int{3, 9}, UncoreCaches: []cadvisorapi.Cache{{Id: 1}}}, + {SocketID: 1, Id: 1, Threads: []int{4, 10}, UncoreCaches: []cadvisorapi.Cache{{Id: 1}}}, + {SocketID: 1, Id: 2, Threads: []int{5, 11}, UncoreCaches: []cadvisorapi.Cache{{Id: 1}}}, }, }, }, diff --git a/pkg/kubelet/llcalign/llcalign.go b/pkg/kubelet/llcalign/llcalign.go new file mode 100644 index 0000000000000..11dcf0f18bfe6 --- /dev/null +++ b/pkg/kubelet/llcalign/llcalign.go @@ -0,0 +1,46 @@ +/* +Copyright 2024 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 llcalign + +import ( + "os" +) + +var ( + llcAlignmentEnabled bool + llcAlignmentFilename = "/etc/kubernetes/openshift-llc-alignment" +) + +func init() { + readEnablementFile() +} + +func readEnablementFile() { + if _, err := os.Stat(llcAlignmentFilename); err == nil { + llcAlignmentEnabled = true + } +} + +// TestOnlySetEnabled allows changing the state of management partition enablement +// This method MUST NOT be used outside of test code +func TestOnlySetEnabled(enabled bool) { + llcAlignmentEnabled = enabled +} + +func IsEnabled() bool { + return llcAlignmentEnabled +}