New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
KEP-3327: Add CPUManager policy option to align CPUs by Socket instead of by NUMA node #111278
Conversation
@arpitsardhana: You must be a member of the kubernetes/milestone-maintainers GitHub team to set the milestone. If you believe you should be able to issue the /milestone command, please contact your Milestone Maintainers Team and have them propose you as an additional delegate for this responsibility. In response to this:
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. |
Welcome @arpitsardhana! |
Hi @arpitsardhana. Thanks for your PR. I'm waiting for a kubernetes member to verify that this patch is reasonable to test. If it is, they should reply with Once the patch is verified, the new status will be reflected by the I understand the commands that are listed here. Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. |
/ok-to-test |
@arpitsardhana Looks like this has a little bit of work to do to get basic tests/builds working before it's ready for review, but looks like a good start, thanks! |
Thanks @endocrimes I did run quick-release on my system(mac) and verified the unit test are working ok. |
/cc |
/assign @klueska |
@@ -115,11 +115,11 @@ func NewStaticPolicyOptions(policyOptions map[string]string) (StaticPolicyOption | |||
|
|||
func ValidateStaticPolicyOptions(opts StaticPolicyOptions, topology *topology.CPUTopology, topologyManager topologymanager.Store) error { | |||
if opts.AlignBySocket == true { | |||
//1. not compatible with topology manager single numa policy option | |||
//1. Not compatible with topology manager single-numa-node policy option. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please remove the numbers from these comments
if opts.AlignBySocket == true { | ||
//1. Not compatible with topology manager single-numa-node policy option. | ||
if topologyManager.GetPolicy().Name() == topologymanager.PolicySingleNumaNode { | ||
return fmt.Errorf("Topolgy manager Single numa policy is incompatible with CPUManager Align by socket policy option") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typos in the string, please also use a %s
to pull in the actual name of the policy as stored in topologymanager.PolicySingleNumaNode
instead of writing it out yourself.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed in latest commit
@@ -99,3 +112,17 @@ func NewStaticPolicyOptions(policyOptions map[string]string) (StaticPolicyOption | |||
} | |||
return opts, nil | |||
} | |||
|
|||
func ValidateStaticPolicyOptions(opts StaticPolicyOptions, topology *topology.CPUTopology, topologyManager topologymanager.Store) error { | |||
if opts.AlignBySocket == true { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove == true
@@ -115,6 +115,10 @@ func NewStaticPolicy(topology *topology.CPUTopology, numReservedCPUs int, reserv | |||
if err != nil { | |||
return nil, err | |||
} | |||
err = ValidateStaticPolicyOptions(opts, topology, affinity) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think part of the problem here is that this new flag probably belongs on the topologymanager as a "topology-manager-policy-option", not the CPUManager (for which we don't have any infrastructure yet). Let's leave it as is for the time being until we have time to evaluate if it makes sense moving this flag to the topologymanager in a future release (which may just have the opposite problem for the 2nd check going on which is CPUManager specific).
// socket aligned hint. It will ensure that first socket aligned available CPUs are | ||
// allocated before we try to find CPUs across socket to satify allocation request. | ||
if p.options.AlignBySocket { | ||
socketBits := p.topology.CPUDetails.SocketsInNUMANodes(numaBits[:]...).ToSliceNoSort() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are you making a copy of the numaBits
slice before passing it? Is it necessary for some reason?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Initially, i had some difficulty in calling SocketInNumaNodes since it is variadic function. Intent was to convert numBits into slice and then pass.
However, fixed in latest commit.
} else { | ||
for _, numaNodeID := range numaBits { | ||
alignedCPUs = alignedCPUs.Union(allocatableCPUs.Intersection(p.topology.CPUDetails.CPUsInNUMANodes(numaNodeID))) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree it's nice to avoid else
statements when possible, but I think this is fine for now. We can revisit this as a follow-up.
//isHintSocketAligned function return true if numa nodes in hint are within one socket. | ||
func (p *staticPolicy) isHintSocketAligned(hint bitmask.BitMask) bool { | ||
numaNodes := hint.GetBits() | ||
if p.topology.CPUDetails.SocketsInNUMANodes(numaNodes[:]...).Size() == 1 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it really necessary to make a copy of the numaNodes
slice before passing it in here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed it in latest commit
if hints[i].NUMANodeAffinity.Count() == minAffinitySize { | ||
hints[i].Preferred = true | ||
} | ||
} | ||
|
||
return hints | ||
} | ||
|
||
//isHintSocketAligned function return true if numa nodes in hint are within one socket. | ||
func (p *staticPolicy) isHintSocketAligned(hint bitmask.BitMask) bool { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given the name it seems this should take a hint as a paramater, not a bitmask.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed function input parameter
@@ -95,6 +95,7 @@ type HintProvider interface { | |||
//Store interface is to allow Hint Providers to retrieve pod affinity | |||
type Store interface { | |||
GetAffinity(podUID string, containerName string) TopologyHint | |||
GetPolicy() Policy |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems like a strange addition to an interface called Store
. I never actually liked the name Store
to begin with but it was part of the original design before I got involved. I feel fairly strongly that this new function needs to live elsewhere.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the interface which is passed to CPUManager from where i can deduce anything about Topology manager allowing me to fetch topology manager policy and perform validation checks in policy options for compatibility.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK. I took a closer look at this.
I think the issue is that we should not have an interface called Store
in the topologymanager, and instead should call this interface something more generic (I don't have a good suggestion off the top of my head though). Let's leave it in here for now as you have done, and do a follow-up PR to rename this interface to something more appropriate.
f0ebad9
to
0512e3a
Compare
Tried my best to address all comments. Things to track on Beta: |
I'll have another pass today/ASAPish, but I agree with Kevin's comments and we seem to be in agreement about the general direction. |
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))) | ||
} | ||
} else { | ||
for _, numaNodeID := range numaBits { | ||
alignedCPUs = alignedCPUs.Union(allocatableCPUs.Intersection(p.topology.CPUDetails.CPUsInNUMANodes(numaNodeID))) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The way to avoid an if/else and make this a little cleaner here would be to introduce a new function as
func (p *staticPolicy) getAlignedCPUs(numaAffinity bitmask.BitMask) {
alignedCPUs := cpuset.NewCPUSet()
if p.options.AlignBySocket {
socketBits := p.topology.CPUDetails.SocketsInNUMANodes(numaAffinity.GetBits()...).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
}
And then at the callsite here, just do:
alignedCPUs := p.getAlignedCPUs(numaAffinity)
@@ -514,10 +558,18 @@ func TestStaticPolicyAdd(t *testing.T) { | |||
for _, testCase := range smtalignOptionTestCases { | |||
runStaticPolicyTestCase(t, testCase) | |||
} | |||
for _, testCase := range alignBySocketOptionTestCases { | |||
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, pkgfeatures.CPUManagerPolicyAlphaOptions, true)() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's odd to put the defer in the middle of a for loop like this. Defers are function scoped and will only be run once this entire function exits. You are essentially adding a new function to run at function exit each time around the loop. Is this your intention here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You will likely need to add a wrapping function around runStaticPolicyTestCase()
called something like runStaticPolicyTestCaseWithFeatureGates()
that sets up the necessary feature gates around the test.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed in latest commit
} | ||
|
||
func runStaticPolicyTestCase(t *testing.T, testCase staticPolicyTest) { | ||
policy, _ := NewStaticPolicy(testCase.topo, testCase.numReservedCPUs, cpuset.NewCPUSet(), topologymanager.NewFakeManager(), testCase.options) | ||
topoManager := topologymanager.NewFakeManager() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
just call the variable tm
if you don't want to spell it out completely. topoManager
is awkward.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed in latest commit
// NewFakeManagerWithPolicy returns an instance of fake topology manager with specified policy | ||
func NewFakeManagerWithPolicy(policy Policy) Manager { | ||
klog.InfoS("NewFakeManagerWithPolicy") | ||
return &fakeManager{ | ||
policy: policy, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not a huge fan of introducing yet another NewFakeManager()
function. What if we want a FakeManager
with a hint and a policy set? We need to come up with something more generic.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ideally there should be a generic FakeManager(). I added since we already have one withAffinity, however underlying structure is same. I can track it for beta to improve FakeManager()
func (m *mockAffinityStore) GetPolicy() topologymanager.Policy { | ||
return m.policy | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this ever get exercised anyhwere? It looks like you just always set the policy to nil
in all test cases.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in latest commit
}, | ||
{ | ||
NUMANodeAffinity: m0011, | ||
Preferred: true, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, this is correct. When setting this flag, think of a socket as a super-NUMA-node
for the purpose of alignment. So long as the set of bits in the NUMA mask all point to the same socket, then alignment should be preferred.
} | ||
activePods = append(activePods, &pod) | ||
} | ||
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, pkgfeatures.CPUManagerPolicyAlphaOptions, true)() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again -- it's weird to have this here in the middle of the function like this. If you want it set during this test, jut put it at the top of the function, not in the middle.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in latest commit
}) | ||
} | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At some point it would be good to add unit tests in pkg/kubelet/cm
that can test across all of the hint-providers (with their various options) instead of just testing each of them in isolation like this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will track this item for beta.
I think testcases under pkg/kubelet/cm are definitely required and should be tracked via separate issue
{ | ||
option: AlignBySocketOption, | ||
featureGate: pkgfeatures.CPUManagerPolicyAlphaOptions, | ||
featureGateEnable: true, | ||
expectedAvailable: true, | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add one more test case that ensures this is not available if CPUManagerPolicyBetaOptions is set.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed!
// isHintSocketAligned function return true if numa nodes in hint are within one socket. | ||
func (p *staticPolicy) isHintSocketAligned(hint topologymanager.TopologyHint) bool { | ||
numaNodesBitMask := hint.NUMANodeAffinity.GetBits() | ||
return p.topology.CPUDetails.SocketsInNUMANodes(numaNodesBitMask...).Size() == 1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it sufficient to just check Size() == 1
? What if minAffinitySize
is greater than the number of numa nodes on a socket?
Should this really be something like:
minSockets := (minAffinitySize + numaNodesPerSocket - 1) / numaNodesPerSocket
return p.topology.CPUDetails.SocketsInNUMANodes(numaNodesBitMask...).Size() == minSockets
We should also add a test case for this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you give an example topology where above will apply?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is independent of the topology. It depends on the request size. Imagine a 2 socket machine with 4 NUMA nodes per socket and 20 CPUs per NUMA node. If a request comes in for 81 CPUs, this requires at least 5 NUMA nodes (meaning minAffinity will be 5) and (by definition) at least 2 sockets.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The thought process i had is:
If allocation need to spread across two sockets, CPUs by definition are not socket aligned. Assumption is by socket alignment, we mean CPUs from one socket are preferred for allocation over cross-socket allocation.
In 2 socket architecture, With above logic, if allocation spreads two sockets then all hints become preferred and the whole point of finding optimized hint may become moot.
In my view, considering minSockets may be relevant for architecture where there are more than 2 sockets(viz 4 socket or 6 sockets etc) where we want the CPUs to be localized to let say 2 sockets.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Intent is to have simplicity, in sense that CPU's will be considered aligned if they can come from one-socket. In my opinion, Making align-by-socket to consider CPUs as aligned within minAffinitySockets(2 or more ) may bring complexity whose performance returns may not be much. Since anyway allocation is anyway spreading across sockets
I could be wrong and open to suggestions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If allocation need to spread across two sockets, CPUs by definition are not socket aligned.
This is true, but I don't see how that is relevant here. The point of the align-by-socket
flag is not to try and force alignment to a single socket, but rather to generate hints at the socket boundary rather than the NUMA boundary.
If an allocation request has so many CPUs that it must always pull from more than one socket to satisfy its allocation (meaning, the topology dictates this, not the current allocation to other pods), then we need to generate a preferred hint that is representative of this.
Not doing so would make this flag inconsistent with its purpose -- i.e. to generate hints as if we were working at socket boundaries instead of NUMA boundaries.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's the reason we need to do this loop on the other side (instead of just assuming things always come from one socket):
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
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in latest commit
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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: line break here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in latest commit
if err != nil { | ||
panic(err) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would just remove the panic here and ignore the error. If an erorr is returned here as part of test declaration we have bigger issues.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in latest commit
|
||
for _, testCase := range testCases { | ||
t.Run(testCase.description, func(t *testing.T) { | ||
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, pkgfeatures.CPUManagerPolicyAlphaOptions, true)() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: line break after this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in latest commit
@@ -32,13 +32,18 @@ import ( | |||
) | |||
|
|||
type mockAffinityStore struct { | |||
hint topologymanager.TopologyHint | |||
hint topologymanager.TopologyHint | |||
policy topologymanager.Policy |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove policy from here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in latest commit
…d of by NUMA node
Also addressed MR comments as part of same commit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One final comment, but it is not a blocker for merging.
Thanks for being patient with the comments / addressing them so quickly.
/lgtm
/approve
numaNodesPerSocket := p.topology.NumNUMANodes / p.topology.NumSockets | ||
if numaNodesPerSocket == 0 { | ||
return false | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Technically this can never happen because we gate calling this function by p.options.AlignBySocket
which will error out at startup if p.topology.NumNUMANodes > p.topology.NumSockets
.
I thin it's fine to leave it here for completeness though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah! Prefer to leave it there, In future other functions might leverage isHintSocketAligned and we may run into div by 0 issues
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: arpitsardhana, klueska The full list of commands accepted by this bot can be found here. The pull request process is described here
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
/retest |
@arpitsardhana: The following test failed, say
Full PR test history. Your PR dashboard. Please help us cut down on flakes by linking to an open issue when you hit one in your PR. Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. I understand the commands that are listed here. |
/test pull-kubernetes-e2e-kind-ipv6 |
@@ -571,10 +572,50 @@ func (p *staticPolicy) generateCPUTopologyHints(availableCPUs cpuset.CPUSet, reu | |||
// to the minAffinitySize. Only those with an equal number of bits set (and | |||
// with a minimal set of numa nodes) will be considered preferred. | |||
for i := range hints { | |||
if p.options.AlignBySocket && p.isHintSocketAligned(hints[i], minAffinitySize) { | |||
hints[i].Preferred = true | |||
continue |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this mean that if the AlignBySocket option is enabled, the number of NUMA nodes in the final CPU allocation may not be minimal (although there may be CPU allocations with fewer NUMA nodes, and within a socket)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. It may not be minimal.
This option makes it so that allocation decisions are made at the socket boundary, rather than the NUMA node boundary. All CPUs will come from the same socket, but not necessarily the same NUMA node.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it be better to also consider the number of NUMA nodes if the AlignBySocket option is enabled? First the CPUs should be in a socket, then the minimum number of NUMA nodes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That is not guarantees by the API (because if you are using this setting, you should not be caring about NUMA alignment, but only socket alignment), but under the hood, CPUs will in fact be handed out on one NUMA node first before moving onto the next.
This ensures all CPUs in the same socket are considered aligned:
socketBits := p.topology.CPUDetails.SocketsInNUMANodes(numaBits...).ToSliceNoSort() |
And this (depending on the setting of DistributeCPUsAcrossNUMA
) will make sure to pull those CPUs from a minimal set of NUMA nodes:
func (p *staticPolicy) takeByTopology(availableCPUs cpuset.CPUSet, numCPUs int) (cpuset.CPUSet, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe I got it. Does this mean that the final allocated CPUs in the Allocate() method may be different from the TopologyHint returned by the GetTopologyHints() method and merged by the Topology Manager?
Assume NUMA node 0 and NUMA node 1 are on the same socket and they both have 2 CPUs. AlignBySocket is enabled while DistributeCPUsAcrossNUMA is not enabled. An incoming container requests 2 CPUs.
- In the GetTopologyHints() method, the returned TopologyHints are {{01, true}, {10, true}, {11, true}}
- In Topology Manager, the merged result is {11, true}
- In the Allocate() method, the final allocated CPUs to the container are both taken from NUMA node 0.
Is my understanding correct?
What type of PR is this?
/kind feature
/sig node
What this PR does / why we need it:
This PR implements logic of KEP-3327
Which issue(s) this PR fixes:
Enhancement KEP-3327
Special notes for your reviewer:
Does this PR introduce a user-facing change?
Additional documentation e.g., KEPs (Kubernetes Enhancement Proposals), usage docs, etc.: