Skip to content

Conversation

@YexuanXiao
Copy link
Contributor

@YexuanXiao YexuanXiao commented Nov 15, 2025

Starting with Windows 11, processes can utilize more than 64 processors by default, but GetSystemInfo can only report a maximum of 64. Starting with Windows Vista, GetActiveProcessorCount accurately retrieves the total number of processors on the current system. I’ve implemented similar improvements to Microsoft STL. The following links contain additional background information: microsoft/STL#5453, microsoft/STL#5459 (note: Reason STL uses the more complex GetLogicalProcessorInformationEx: microsoft/STL#5459 (comment).).

@YexuanXiao YexuanXiao requested a review from a team as a code owner November 15, 2025 19:37
@llvmbot llvmbot added the libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi. label Nov 15, 2025
@llvmbot
Copy link
Member

llvmbot commented Nov 15, 2025

@llvm/pr-subscribers-libcxx

Author: Yexuan Xiao (YexuanXiao)

Changes

… than 64 processors

Starting with Windows 11, processes can utilize more than 64 processors by default, but GetSystemInfo can only report a maximum of 64. Starting with Windows Vista, GetActiveProcessorCount accurately retrieves the total number of processors on the current system. I’ve implemented similar improvements to Microsoft STL. The following links contain additional background information: microsoft/STL#5453, microsoft/STL#5459 (note: Reason STL uses the more complex GetLogicalProcessorInformationEx: microsoft/STL#5459 (comment).).


Full diff: https://github.com/llvm/llvm-project/pull/168229.diff

1 Files Affected:

  • (modified) libcxx/src/thread.cpp (+1-3)
diff --git a/libcxx/src/thread.cpp b/libcxx/src/thread.cpp
index 028d36e3bfb37..e494574ec21dd 100644
--- a/libcxx/src/thread.cpp
+++ b/libcxx/src/thread.cpp
@@ -74,9 +74,7 @@ unsigned thread::hardware_concurrency() noexcept {
     return 0;
   return static_cast<unsigned>(result);
 #elif defined(_LIBCPP_WIN32API)
-  SYSTEM_INFO info;
-  GetSystemInfo(&info);
-  return info.dwNumberOfProcessors;
+  return static_cast<unsigned>(GetActiveProcessorCount(ALL_PROCESSOR_GROUPS));
 #else // defined(CTL_HW) && defined(HW_NCPU)
   // TODO: grovel through /proc or check cpuid on x86 and similar
   // instructions on other architectures.

@philnik777 philnik777 requested a review from mstorsjo November 16, 2025 10:53
@mstorsjo
Copy link
Member

Starting with Windows 11, processes can utilize more than 64 processors by default, but GetSystemInfo can only report a maximum of 64. Starting with Windows Vista, GetActiveProcessorCount accurately retrieves the total number of processors on the current system. I’ve implemented similar improvements to Microsoft STL. The following links contain additional background information: microsoft/STL#5453, microsoft/STL#5459 (note: Reason STL uses the more complex GetLogicalProcessorInformationEx: microsoft/STL#5459 (comment).).

Thanks for these links for context, that's appreciated!

For libc++, I'm not sure how many care about being able to target UWP. For llvm-mingw, I do want to support that to some extent - but there, we primarily use the strategy of linking in a static library of stubs for functions that we aren't allowed to call - https://github.com/mingw-w64/mingw-w64/tree/master/mingw-w64-libraries/winstorecompat/src. I think it should be straightforward to add emulation of GetActiveProcessorCount there, that just uses the old codepath with GetSystemInfo.

Therefore, I think it should be fine to just go with this simple straightforward implementation here.

@mstorsjo
Copy link
Member

Starting with Windows 11, processes can utilize more than 64 processors by default, but GetSystemInfo can only report a maximum of 64. Starting with Windows Vista, GetActiveProcessorCount accurately retrieves the total number of processors on the current system. I’ve implemented similar improvements to Microsoft STL. The following links contain additional background information: microsoft/STL#5453, microsoft/STL#5459 (note: Reason STL uses the more complex GetLogicalProcessorInformationEx: microsoft/STL#5459 (comment).).

Thanks for these links for context, that's appreciated!

For libc++, I'm not sure how many care about being able to target UWP. For llvm-mingw, I do want to support that to some extent - but there, we primarily use the strategy of linking in a static library of stubs for functions that we aren't allowed to call - https://github.com/mingw-w64/mingw-w64/tree/master/mingw-w64-libraries/winstorecompat/src. I think it should be straightforward to add emulation of GetActiveProcessorCount there, that just uses the old codepath with GetSystemInfo.

Therefore, I think it should be fine to just go with this simple straightforward implementation here.

Such an implementation done in https://sourceforge.net/p/mingw-w64/mailman/message/59262278/. So unless anyone else has a desire to target UWP with libc++, this should be fine with me.

Copy link
Member

@mstorsjo mstorsjo left a comment

Choose a reason for hiding this comment

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

LGTM

@frederick-vs-ja frederick-vs-ja changed the title [libc++][Windows] Enable thread::hardware_concurrency to support more… [libc++][Windows] Enable thread::hardware_concurrency to support more than 64 processors Nov 21, 2025
Copy link
Contributor

@frederick-vs-ja frederick-vs-ja left a comment

Choose a reason for hiding this comment

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

Thanks. I modified the PR title and description, which are generally used as squashed commit message, to a more conventional form.

@frederick-vs-ja frederick-vs-ja merged commit 5a3c257 into llvm:main Nov 21, 2025
82 checks passed
aadeshps-mcw pushed a commit to aadeshps-mcw/llvm-project that referenced this pull request Nov 26, 2025
… than 64 processors (llvm#168229)

Starting with Windows 11, processes can utilize more than 64 processors
by default, but GetSystemInfo can only report a maximum of 64. Starting
with Windows Vista, GetActiveProcessorCount accurately retrieves the
total number of processors on the current system. I’ve implemented
similar improvements to Microsoft STL. The following links contain
additional background information:
microsoft/STL#5453,
microsoft/STL#5459 (note: Reason STL uses the
more complex GetLogicalProcessorInformationEx:
microsoft/STL#5459 (comment).).
Priyanshu3820 pushed a commit to Priyanshu3820/llvm-project that referenced this pull request Nov 26, 2025
… than 64 processors (llvm#168229)

Starting with Windows 11, processes can utilize more than 64 processors
by default, but GetSystemInfo can only report a maximum of 64. Starting
with Windows Vista, GetActiveProcessorCount accurately retrieves the
total number of processors on the current system. I’ve implemented
similar improvements to Microsoft STL. The following links contain
additional background information:
microsoft/STL#5453,
microsoft/STL#5459 (note: Reason STL uses the
more complex GetLogicalProcessorInformationEx:
microsoft/STL#5459 (comment).).
@Sharjeel-Khan
Copy link
Contributor

Where is ALL_PROCESSOR_GROUPS coming from? We are getting this error in Android:

[1883/1896] Building CXX object libcxx/src/CMakeFiles/cxx_static.dir/thread.cpp.obj
FAILED: libcxx/src/CMakeFiles/cxx_static.dir/thread.cpp.obj 
/b/f/w/src/git/out/stage2-install/bin/clang++ --sysroot=/b/f/w/src/git/out/sysroots/x86_64-w64-mingw32 -DLIBCXX_BUILDING_LIBCXXABI -DLIBC_NAMESPACE=__llvm_libc_common_utils -D_FILE_OFFSET_BITS=64 -D_LIBCPP_BUILDING_LIBRARY -D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS="" -D_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER -D_LIBCPP_REMOVE_TRANSITIVE_INCLUDES -D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -I/b/f/w/src/git/out/llvm-project/libcxx/src -I/b/f/w/src/git/out/lib/win-libcxx-windows/include/x86_64-w64-windows-gnu/c++/v1 -I/b/f/w/src/git/out/lib/win-libcxx-windows/include/c++/v1 -I/b/f/w/src/git/out/llvm-project/libcxxabi/include -I/b/f/w/src/git/out/llvm-project/cmake/Modules/../../libc -ffile-prefix-map=/b/f/w/src/git/= -B/b/f/w/src/git/prebuilts/gcc/linux-x86/host/x86_64-w64-mingw32-4.8/x86_64-w64-mingw32/bin --target=x86_64-pc-windows-gnu -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_WIN32_WINNT=0x0600 -DWINVER=0x0600 -D__MSVCRT_VERSION__=0x1400 -D_LIBCPP_AVAILABILITY_HAS_NO_VERBOSE_ABORT=1 --sysroot=/b/f/w/src/git/out/sysroots/x86_64-w64-mingw32 -stdlib=libc++ -fvisibility-inlines-hidden -Werror=date-time -Werror=unguarded-availability-new -Wall -Wextra -Wno-unused-parameter -Wwrite-strings -Wcast-qual -Wmissing-field-initializers -Wimplicit-fallthrough -Wcovered-switch-default -Wno-noexcept-type -Wnon-virtual-dtor -Wdelete-non-virtual-dtor -Wsuggest-override -Wno-comment -Wstring-conversion -Wno-pass-failed -ffunction-sections -fdata-sections -O3 -DNDEBUG -faligned-allocation -nostdinc++ -fvisibility-inlines-hidden -fvisibility=hidden -fsized-deallocation -Wall -Wextra -Wnewline-eof -Wshadow -Wwrite-strings -Wno-unused-parameter -Wno-long-long -Werror=return-type -Wextra-semi -Wundef -Wunused-template -Wformat-nonliteral -Wzero-length-array -Wdeprecated-redundant-constexpr-static-def -Wno-nullability-completeness -Wno-user-defined-literals -Wno-covered-switch-default -Wno-suggest-override -Wno-error -fvisibility-global-new-delete=force-hidden -fdebug-prefix-map=/b/f/w/src/git/out/lib/win-libcxx-windows/include/c++/v1=/b/f/w/src/git/out/llvm-project/libcxx/include -std=c++2b -MD -MT libcxx/src/CMakeFiles/cxx_static.dir/thread.cpp.obj -MF libcxx/src/CMakeFiles/cxx_static.dir/thread.cpp.obj.d -o libcxx/src/CMakeFiles/cxx_static.dir/thread.cpp.obj -c /b/f/w/src/git/out/llvm-project/libcxx/src/thread.cpp
/[b/f/w/src/git/out/llvm-project/libcxx/src/thread.cpp:77](https://cs.corp.google.com/piper///depot/google3/b/f/w/src/git/out/llvm-project/libcxx/src/thread.cpp?l=77):56: error: use of undeclared identifier 'ALL_PROCESSOR_GROUPS'
   77 |   return static_cast<unsigned>(GetActiveProcessorCount(ALL_PROCESSOR_GROUPS));
      |                                                        ^~~~~~~~~~~~~~~~~~~~
1 error generated.

@mstorsjo
Copy link
Member

Where is ALL_PROCESSOR_GROUPS coming from? We are getting this error in Android:

[1883/1896] Building CXX object libcxx/src/CMakeFiles/cxx_static.dir/thread.cpp.obj
FAILED: libcxx/src/CMakeFiles/cxx_static.dir/thread.cpp.obj 
/b/f/w/src/git/out/stage2-install/bin/clang++ --sysroot=/b/f/w/src/git/out/sysroots/x86_64-w64-mingw32 -DLIBCXX_BUILDING_LIBCXXABI -DLIBC_NAMESPACE=__llvm_libc_common_utils -D_FILE_OFFSET_BITS=64 -D_LIBCPP_BUILDING_LIBRARY -D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS="" -D_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER -D_LIBCPP_REMOVE_TRANSITIVE_INCLUDES -D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -I/b/f/w/src/git/out/llvm-project/libcxx/src -I/b/f/w/src/git/out/lib/win-libcxx-windows/include/x86_64-w64-windows-gnu/c++/v1 -I/b/f/w/src/git/out/lib/win-libcxx-windows/include/c++/v1 -I/b/f/w/src/git/out/llvm-project/libcxxabi/include -I/b/f/w/src/git/out/llvm-project/cmake/Modules/../../libc -ffile-prefix-map=/b/f/w/src/git/= -B/b/f/w/src/git/prebuilts/gcc/linux-x86/host/x86_64-w64-mingw32-4.8/x86_64-w64-mingw32/bin --target=x86_64-pc-windows-gnu -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_WIN32_WINNT=0x0600 -DWINVER=0x0600 -D__MSVCRT_VERSION__=0x1400 -D_LIBCPP_AVAILABILITY_HAS_NO_VERBOSE_ABORT=1 --sysroot=/b/f/w/src/git/out/sysroots/x86_64-w64-mingw32 -stdlib=libc++ -fvisibility-inlines-hidden -Werror=date-time -Werror=unguarded-availability-new -Wall -Wextra -Wno-unused-parameter -Wwrite-strings -Wcast-qual -Wmissing-field-initializers -Wimplicit-fallthrough -Wcovered-switch-default -Wno-noexcept-type -Wnon-virtual-dtor -Wdelete-non-virtual-dtor -Wsuggest-override -Wno-comment -Wstring-conversion -Wno-pass-failed -ffunction-sections -fdata-sections -O3 -DNDEBUG -faligned-allocation -nostdinc++ -fvisibility-inlines-hidden -fvisibility=hidden -fsized-deallocation -Wall -Wextra -Wnewline-eof -Wshadow -Wwrite-strings -Wno-unused-parameter -Wno-long-long -Werror=return-type -Wextra-semi -Wundef -Wunused-template -Wformat-nonliteral -Wzero-length-array -Wdeprecated-redundant-constexpr-static-def -Wno-nullability-completeness -Wno-user-defined-literals -Wno-covered-switch-default -Wno-suggest-override -Wno-error -fvisibility-global-new-delete=force-hidden -fdebug-prefix-map=/b/f/w/src/git/out/lib/win-libcxx-windows/include/c++/v1=/b/f/w/src/git/out/llvm-project/libcxx/include -std=c++2b -MD -MT libcxx/src/CMakeFiles/cxx_static.dir/thread.cpp.obj -MF libcxx/src/CMakeFiles/cxx_static.dir/thread.cpp.obj.d -o libcxx/src/CMakeFiles/cxx_static.dir/thread.cpp.obj -c /b/f/w/src/git/out/llvm-project/libcxx/src/thread.cpp
/[b/f/w/src/git/out/llvm-project/libcxx/src/thread.cpp:77](https://cs.corp.google.com/piper///depot/google3/b/f/w/src/git/out/llvm-project/libcxx/src/thread.cpp?l=77):56: error: use of undeclared identifier 'ALL_PROCESSOR_GROUPS'
   77 |   return static_cast<unsigned>(GetActiveProcessorCount(ALL_PROCESSOR_GROUPS));
      |                                                        ^~~~~~~~~~~~~~~~~~~~
1 error generated.

It should be defined in winnt.h. In the case of mingw-w64, it's been available in the headers since 2013: mingw-w64/mingw-w64@d38dbec

@Sharjeel-Khan
Copy link
Contributor

It seems it is guarded by _WIN32_WINNT >= 0x601 and Android have _WIN32_WINNT defined as 0x600. Is it possible have a check if it is defined to use it else stick to GetSystemInfo?

@mstorsjo
Copy link
Member

It seems it is guarded by _WIN32_WINNT >= 0x601 and Android have _WIN32_WINNT defined as 0x600. Is it possible have a check if it is defined to use it else stick to GetSystemInfo?

I see. Well _WIN32_WINNT 0x601 is Windows 7 while 0x600 is Vista - our documented required minimum version is Windows 7 (see 80ae168).

In support/win32/thread_win32.cpp we unconditionally use TryAcquireSRWLockExclusive, which is available only since Windows 7 (https://learn.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-tryacquiresrwlockexclusive) - contrary to most of the other SRW functions that are available since Vista. However I do see that it is incorrectly guarded in https://github.com/mingw-w64/mingw-w64/blob/v13.0.0/mingw-w64-headers/include/synchapi.h#L60-L71 while only requiring _WIN32_WINNT >= 0x600.

I would suggest bumping your _WIN32_WINNT up to 0x601, as your build hasn't been working on Vista anyway (unless you've been using winpthreads instead of the native win32 threading)?

@Sharjeel-Khan
Copy link
Contributor

Sharjeel-Khan commented Nov 26, 2025

I asked someone and it does seem we use winpthreads: https://android.googlesource.com/toolchain/llvm_android/+/mirror-goog-main-llvm-toolchain-source/do_build.py#284. People are out but I will discuss bumping up to 0x601 when they are back

augusto2112 pushed a commit to augusto2112/llvm-project that referenced this pull request Dec 3, 2025
… than 64 processors (llvm#168229)

Starting with Windows 11, processes can utilize more than 64 processors
by default, but GetSystemInfo can only report a maximum of 64. Starting
with Windows Vista, GetActiveProcessorCount accurately retrieves the
total number of processors on the current system. I’ve implemented
similar improvements to Microsoft STL. The following links contain
additional background information:
microsoft/STL#5453,
microsoft/STL#5459 (note: Reason STL uses the
more complex GetLogicalProcessorInformationEx:
microsoft/STL#5459 (comment).).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants