Skip to content

std: count all processor groups in available_parallelism on Windows#159511

Open
valentynkit wants to merge 1 commit into
rust-lang:mainfrom
valentynkit:fix/available-parallelism-windows-groups
Open

std: count all processor groups in available_parallelism on Windows#159511
valentynkit wants to merge 1 commit into
rust-lang:mainfrom
valentynkit:fix/available-parallelism-windows-groups

Conversation

@valentynkit

@valentynkit valentynkit commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

On Windows 11 and Server 2022 a process spans all processor groups by default, so GetSystemInfo undercounts any machine with more than 64 CPUs: it only sees the primary group. Before Windows 11 the process is confined to that one group, so unconditionally switching to GetActiveProcessorCount(ALL_PROCESSOR_GROUPS) would overcount there instead. That's the Windows 10 problem you raised.

GetProcessGroupAffinity gives the group count without an OS-version check: 1 before Windows 11, more than 1 once the process spans multiple groups. So gate on it, count every group when there's more than one, and fall back to GetSystemInfo otherwise. A one-element buffer is enough: a multi-group process fails with ERROR_INSUFFICIENT_BUFFER and writes the real count, every other case keeps the initial 1, so the BOOL is ignorable.

Same call #114856 (klensy) proposed, now gated so it can't overcount on Windows 10.

Miri doesn't model processor groups, so the two new calls get shims reporting more than one group and num_cpus. That runs the existing -Zmiri-num-cpus=1024 test through the multi-group branch, which has to count rather than read a mask since a mask can't hold 1024 CPUs.

A few cases stay imprecise:

No hermetic test for the real >64-CPU path since it needs the hardware; the Miri test covers the branch. I can't build the Windows target or Miri on macOS, so CI is the real check.

Fixes #152389

r? @workingjubilee

On Windows 11 and Server 2022 a process spans every processor group by
default, so GetSystemInfo undercounts a machine with more than 64 logical
CPUs because it only reports the process's primary group. When the process
is in more than one group, sum the active CPUs across all of them;
otherwise keep using GetSystemInfo. The group count tells the two apart
without an OS-version check.

Add the matching Miri shims for the two new calls.
@rustbot

rustbot commented Jul 18, 2026

Copy link
Copy Markdown
Collaborator

miri is developed in its own repository. If the Miri part of this change can be broken out, consider making this change to rust-lang/miri instead. However, if Miri needs adjusting for rustc changes, just ignore this message.

cc @rust-lang/miri

@rustbot rustbot added O-windows Operating system: Windows S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-libs Relevant to the library team, which will review and decide on the PR/issue. labels Jul 18, 2026
@rustbot

rustbot commented Jul 18, 2026

Copy link
Copy Markdown
Collaborator

workingjubilee is currently at their maximum review capacity.
They may take a while to respond.

@RalfJung RalfJung left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand this processor group stuff, but it sounds like Miri is doing something wrong by putting a number bigger than 64 into dwNumberOfProcessors in GetSystemInfo?

View changes since this review

let group_count = this.deref_pointer_as(group_count, this.machine.layouts.u16)?;
this.write_scalar(Scalar::from_u16(2), &group_count)?;
this.write_scalar(Scalar::from_i32(1), dest)?; // TRUE
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Each shim here should either

  • be correct, in the sense that it checks all arguments for for every possible value either does the right thing or throws an "unsupported error"
  • or be restricted to std like the shims at the bottom of this file (e.g. SetThreadStackGuarantee)

These shims here ignore some of their arguments so they satisfy neither of these criteria.

)?;
// Report more than one group so `available_parallelism` takes the
// `GetActiveProcessorCount(ALL_PROCESSOR_GROUPS)` path; a single-group
// affinity mask cannot hold the up-to-1024 CPUs the num-cpus test uses.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could also just limit the number of CPUs we support on Windows to 64. It's entirely virtual anyway, Miri never really runs stuff in parallel.

@RalfJung

Copy link
Copy Markdown
Member

I can't build the Windows target or Miri on macOS

FWIW, ./x test miri --target x86_64-pc-windows-msvc is supposed to work on macOS, and also builds the standard library for the Windows target. So if that does not work then please ask on Zulip or file an issue.

@RalfJung

Copy link
Copy Markdown
Member

Cc @ChrisDenton

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

O-windows Operating system: Windows S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-libs Relevant to the library team, which will review and decide on the PR/issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

std::thread::available_parallelism() is wrong about Windows 11/Server 2022

4 participants