-
Notifications
You must be signed in to change notification settings - Fork 28
bins: intial CPU binding support #991
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
base: master
Are you sure you want to change the base?
Conversation
add bindings for `processor_bind()`, the mechanism to make this happen. then, in propolis-standalone, allow a choice of how binding should be done: allow vCPUs to roam with `cpu_binding = "any"` or pin vCPUs to CPUs 1:1 from the last processor downwards with `cpu_binding = "from-last"`. in `propolis-server`, pick between these two strategies automatically based on how the vCPU count compares to the number of available processors. a VM that would use more than half of available processors is bound in the same way as `propolis-standalone` with `cpu_binding = "from-last"`, but otherwise continues to have unbound vCPUs. in the future, Nexus will dictate `propolis-server`'s vCPU bindings, but exactly how is a bit of an open question.
| @@ -0,0 +1,8 @@ | |||
| [package] | |||
| name = "pbind" | |||
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.
hm, since this is a low-level binding to the C headers, should this perhaps be pbind-sys?
|
|
||
| res.try_into().map_err(|_| { | ||
| // sysconf() reports more than 2^31 processors?! | ||
| Error::other(format!("too many processors: {}", res)) |
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.
turbo nit: perhaps res could be inlined here?
| Error::other(format!("too many processors: {}", res)) | |
| Error::other(format!("too many processors: {res}")) |
| // Returns an `i32` to match `processorid_t`, so that `0..online_cpus()` | ||
| // produces a range of processor IDs without additional translation needed. | ||
| pub fn online_cpus() -> Result<i32, 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 worth noting in the comment that this is a wrapper around sysconf(_SC_NPROCESSORS_ONLN)?
| let vcpu_count: i32 = | ||
| machine.vcpus.len().try_into().expect("<2^31 vCPUs"); |
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, considered not that big a deal: this is an error in the user's config file, rather than e.g. a syscall we expect should always work not working. can we make that a little clearer perhaps?
| /// vCPUs are bound to the highest-numbered processors in the system, one | ||
| /// vCPU per CPU, with the last vCPU bound to the last physical processor. | ||
| FromLast, |
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.
...descending?
| let bind_cpus = if vcpu_count > total_cpus / 2 { | ||
| let mut bind_cpus = Vec::new(); | ||
| for i in 0..vcpu_count { | ||
| // Bind to the upper range of CPUs, fairly arbitrary. | ||
| bind_cpus.push(total_cpus - vcpu_count + i); | ||
| } | ||
| Some(bind_cpus) | ||
| } else { | ||
| None | ||
| }; |
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 we ought to log someplace whether we have decided to bind vCPUs or not?
| let mut bind_cpus = Vec::new(); | ||
| for i in 0..vcpu_count { | ||
| // Bind to the upper range of CPUs, fairly arbitrary. | ||
| bind_cpus.push(total_cpus - vcpu_count + i); | ||
| } |
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.
seems like this could be
| let mut bind_cpus = Vec::new(); | |
| for i in 0..vcpu_count { | |
| // Bind to the upper range of CPUs, fairly arbitrary. | |
| bind_cpus.push(total_cpus - vcpu_count + i); | |
| } | |
| ((total_cpus-vcpu_count)..total_cpus).iter().collect() |
or something but maybe that's weirder and worse
this is the interim option I'd described in #984.
add bindings for
processor_bind(), the mechanism to make this happen. then, in propolis-standalone, allow a choice of how binding should be done: allow vCPUs to roam withcpu_binding = "any"or pin vCPUs to CPUs 1:1 from the last processor downwards withcpu_binding = "from-last".in
propolis-server, pick between these two strategies automatically based on how the vCPU count compares to the number of available processors. a VM that would use more than half of available processors is bound in the same way aspropolis-standalonewithcpu_binding = "from-last", but otherwise continues to have unbound vCPUs.in the future, Nexus will dictate
propolis-server's vCPU bindings, but exactly how is a bit of an open question.