mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-23 19:56:01 +00:00
KEP-3327: Add CPUManager policy option to align CPUs by Socket instead of by NUMA node
This commit is contained in:
parent
51ea7b2169
commit
35849bf7fb
@ -28,11 +28,13 @@ import (
|
|||||||
const (
|
const (
|
||||||
FullPCPUsOnlyOption string = "full-pcpus-only"
|
FullPCPUsOnlyOption string = "full-pcpus-only"
|
||||||
DistributeCPUsAcrossNUMAOption string = "distribute-cpus-across-numa"
|
DistributeCPUsAcrossNUMAOption string = "distribute-cpus-across-numa"
|
||||||
|
AlignBySocketOption string = "align-by-socket"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
alphaOptions = sets.NewString(
|
alphaOptions = sets.NewString(
|
||||||
DistributeCPUsAcrossNUMAOption,
|
DistributeCPUsAcrossNUMAOption,
|
||||||
|
AlignBySocketOption,
|
||||||
)
|
)
|
||||||
betaOptions = sets.NewString(
|
betaOptions = sets.NewString(
|
||||||
FullPCPUsOnlyOption,
|
FullPCPUsOnlyOption,
|
||||||
@ -69,6 +71,9 @@ type StaticPolicyOptions struct {
|
|||||||
// Flag to evenly distribute CPUs across NUMA nodes in cases where more
|
// Flag to evenly distribute CPUs across NUMA nodes in cases where more
|
||||||
// than one NUMA node is required to satisfy the allocation.
|
// than one NUMA node is required to satisfy the allocation.
|
||||||
DistributeCPUsAcrossNUMA bool
|
DistributeCPUsAcrossNUMA bool
|
||||||
|
// Flag to ensure CPU's are considered aligned at socket boundary rather than
|
||||||
|
// NUMA boundary
|
||||||
|
AlignBySocket bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewStaticPolicyOptions(policyOptions map[string]string) (StaticPolicyOptions, error) {
|
func NewStaticPolicyOptions(policyOptions map[string]string) (StaticPolicyOptions, error) {
|
||||||
@ -91,6 +96,12 @@ func NewStaticPolicyOptions(policyOptions map[string]string) (StaticPolicyOption
|
|||||||
return opts, fmt.Errorf("bad value for option %q: %w", name, err)
|
return opts, fmt.Errorf("bad value for option %q: %w", name, err)
|
||||||
}
|
}
|
||||||
opts.DistributeCPUsAcrossNUMA = optValue
|
opts.DistributeCPUsAcrossNUMA = optValue
|
||||||
|
case AlignBySocketOption:
|
||||||
|
optValue, err := strconv.ParseBool(value)
|
||||||
|
if err != nil {
|
||||||
|
return opts, fmt.Errorf("bad value for option %q: %w", name, err)
|
||||||
|
}
|
||||||
|
opts.AlignBySocket = optValue
|
||||||
default:
|
default:
|
||||||
// this should never be reached, we already detect unknown options,
|
// this should never be reached, we already detect unknown options,
|
||||||
// but we keep it as further safety.
|
// but we keep it as further safety.
|
||||||
|
@ -325,10 +325,7 @@ func (p *staticPolicy) allocateCPUs(s state.State, numCPUs int, numaAffinity bit
|
|||||||
// If there are aligned CPUs in numaAffinity, attempt to take those first.
|
// If there are aligned CPUs in numaAffinity, attempt to take those first.
|
||||||
result := cpuset.NewCPUSet()
|
result := cpuset.NewCPUSet()
|
||||||
if numaAffinity != nil {
|
if numaAffinity != nil {
|
||||||
alignedCPUs := cpuset.NewCPUSet()
|
alignedCPUs := p.getAlignedCPUs(numaAffinity, allocatableCPUs)
|
||||||
for _, numaNodeID := range numaAffinity.GetBits() {
|
|
||||||
alignedCPUs = alignedCPUs.Union(allocatableCPUs.Intersection(p.topology.CPUDetails.CPUsInNUMANodes(numaNodeID)))
|
|
||||||
}
|
|
||||||
|
|
||||||
numAlignedToAlloc := alignedCPUs.Size()
|
numAlignedToAlloc := alignedCPUs.Size()
|
||||||
if numCPUs < numAlignedToAlloc {
|
if numCPUs < numAlignedToAlloc {
|
||||||
@ -571,6 +568,10 @@ func (p *staticPolicy) generateCPUTopologyHints(availableCPUs cpuset.CPUSet, reu
|
|||||||
// to the minAffinitySize. Only those with an equal number of bits set (and
|
// to the minAffinitySize. Only those with an equal number of bits set (and
|
||||||
// with a minimal set of numa nodes) will be considered preferred.
|
// with a minimal set of numa nodes) will be considered preferred.
|
||||||
for i := range hints {
|
for i := range hints {
|
||||||
|
if p.options.AlignBySocket && p.isHintSocketAligned(hints[i].NUMANodeAffinity) {
|
||||||
|
hints[i].Preferred = true
|
||||||
|
continue
|
||||||
|
}
|
||||||
if hints[i].NUMANodeAffinity.Count() == minAffinitySize {
|
if hints[i].NUMANodeAffinity.Count() == minAffinitySize {
|
||||||
hints[i].Preferred = true
|
hints[i].Preferred = true
|
||||||
}
|
}
|
||||||
@ -578,3 +579,33 @@ func (p *staticPolicy) generateCPUTopologyHints(availableCPUs cpuset.CPUSet, reu
|
|||||||
|
|
||||||
return hints
|
return hints
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *staticPolicy) isHintSocketAligned(hint bitmask.BitMask) bool {
|
||||||
|
numaNodes := hint.GetBits()
|
||||||
|
if p.topology.CPUDetails.SocketsInNUMANodes(numaNodes[:]...).Size() == 1 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// getAlignedCPUs return set of aligned CPUs based on numa affinity mask and configured policy options.
|
||||||
|
func (p *staticPolicy) getAlignedCPUs(numaAffinity bitmask.BitMask, allocatableCPUs cpuset.CPUSet) cpuset.CPUSet {
|
||||||
|
alignedCPUs := cpuset.NewCPUSet()
|
||||||
|
numaBits := numaAffinity.GetBits()
|
||||||
|
// If align-by-socket policy option is enabled, NUMA based hint is expanded to
|
||||||
|
// socket aligned hint. It will ensure that first socket aligned available CPUs are
|
||||||
|
// allocated before we try to find CPUs across socket to satisfy allocation request.
|
||||||
|
if p.options.AlignBySocket {
|
||||||
|
socketBits := p.topology.CPUDetails.SocketsInNUMANodes(numaBits...).ToSliceNoSort()
|
||||||
|
for _, socketID := range socketBits {
|
||||||
|
alignedCPUs = alignedCPUs.Union(allocatableCPUs.Intersection(p.topology.CPUDetails.CPUsInSockets(socketID)))
|
||||||
|
}
|
||||||
|
return alignedCPUs
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, numaNodeID := range numaBits {
|
||||||
|
alignedCPUs = alignedCPUs.Union(allocatableCPUs.Intersection(p.topology.CPUDetails.CPUsInNUMANodes(numaNodeID)))
|
||||||
|
}
|
||||||
|
|
||||||
|
return alignedCPUs
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user