LLVM 24.0.0git
Threading.inc
Go to the documentation of this file.
1//===- Windows/Threading.inc - Win32 Threading Implementation - -*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file provides the Win32 specific implementation of Threading functions.
10//
11//===----------------------------------------------------------------------===//
12
14#include "llvm/ADT/Twine.h"
15#include "llvm/Support/thread.h"
16
18#include <process.h>
19
20#include <bitset>
21
22// Windows will at times define MemoryFence.
23#ifdef MemoryFence
24#undef MemoryFence
25#endif
26
27namespace llvm {
28HANDLE
29llvm_execute_on_thread_impl(unsigned(__stdcall *ThreadFunc)(void *), void *Arg,
30 std::optional<unsigned> StackSizeInBytes) {
31 HANDLE hThread = (HANDLE)::_beginthreadex(NULL, StackSizeInBytes.value_or(0),
32 ThreadFunc, Arg, 0, NULL);
33
34 if (!hThread)
35 ReportLastErrorFatal("_beginthreadex failed");
36
37 return hThread;
38}
39
40void llvm_thread_join_impl(HANDLE hThread) {
41 if (::WaitForSingleObject(hThread, INFINITE) == WAIT_FAILED)
42 ReportLastErrorFatal("WaitForSingleObject failed");
43 if (::CloseHandle(hThread) == FALSE)
44 ReportLastErrorFatal("CloseHandle failed");
45}
46
47void llvm_thread_detach_impl(HANDLE hThread) {
48 if (::CloseHandle(hThread) == FALSE)
49 ReportLastErrorFatal("CloseHandle failed");
50}
51
52DWORD llvm_thread_get_id_impl(HANDLE hThread) {
53 // AppVerifier (runtime verification tool from Windows SDK) reports an error
54 // when GetThreadId(NULL) is called. Suppress this by manually checking for
55 // NULL. Return 0 as this is what's returned (by documentation) if
56 // GetThreadId() fails.
57 if (!hThread)
58 return 0;
59 return ::GetThreadId(hThread);
60}
61
62DWORD llvm_thread_get_current_id_impl() { return ::GetCurrentThreadId(); }
63
64} // namespace llvm
65
66uint64_t llvm::get_threadid() { return uint64_t(::GetCurrentThreadId()); }
67
69
70#if defined(_MSC_VER)
71static void SetThreadName(DWORD Id, LPCSTR Name) {
72 constexpr DWORD MS_VC_EXCEPTION = 0x406D1388;
73
74#pragma pack(push, 8)
75 struct THREADNAME_INFO {
76 DWORD dwType; // Must be 0x1000.
77 LPCSTR szName; // Pointer to thread name
78 DWORD dwThreadId; // Thread ID (-1 == current thread)
79 DWORD dwFlags; // Reserved. Do not use.
80 };
81#pragma pack(pop)
82
83 THREADNAME_INFO info;
84 info.dwType = 0x1000;
85 info.szName = Name;
86 info.dwThreadId = Id;
87 info.dwFlags = 0;
88
89 __try {
90 ::RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR),
91 (ULONG_PTR *)&info);
92 } __except (EXCEPTION_EXECUTE_HANDLER) {
93 }
94}
95#endif
96
97void llvm::set_thread_name(const Twine &Name) {
98#if defined(_MSC_VER)
99 // Make sure the input is null terminated.
100 SmallString<64> Storage;
101 StringRef NameStr = Name.toNullTerminatedStringRef(Storage);
102 SetThreadName(::GetCurrentThreadId(), NameStr.data());
103#endif
104}
105
106void llvm::get_thread_name(SmallVectorImpl<char> &Name) {
107 // "Name" is not an inherent property of a thread on Windows. In fact, when
108 // you "set" the name, you are only firing a one-time message to a debugger
109 // which it interprets as a program setting its threads' name. We may be
110 // able to get fancy by creating a TLS entry when someone calls
111 // set_thread_name so that subsequent calls to get_thread_name return this
112 // value.
113 Name.clear();
114}
115
117llvm::set_thread_priority(ThreadPriority Priority) {
118#ifdef THREAD_POWER_THROTTLING_CURRENT_VERSION
119 HMODULE kernelM = llvm::sys::windows::loadSystemModuleSecure(L"kernel32.dll");
120 if (kernelM) {
121 // SetThreadInformation is only available on Windows 8 and later. Since we
122 // still support compilation on Windows 7, we load the function dynamically.
123 typedef BOOL(WINAPI * SetThreadInformation_t)(
124 HANDLE hThread, THREAD_INFORMATION_CLASS ThreadInformationClass,
125 _In_reads_bytes_(ThreadInformationSize) PVOID ThreadInformation,
126 ULONG ThreadInformationSize);
127 static const auto pfnSetThreadInformation =
128 (SetThreadInformation_t)(void *)::GetProcAddress(
129 kernelM, "SetThreadInformation");
130 if (pfnSetThreadInformation) {
131 auto setThreadInformation = [](ULONG ControlMaskAndStateMask) {
132 THREAD_POWER_THROTTLING_STATE state{};
133 state.Version = THREAD_POWER_THROTTLING_CURRENT_VERSION;
134 state.ControlMask = ControlMaskAndStateMask;
135 state.StateMask = ControlMaskAndStateMask;
136 return pfnSetThreadInformation(
137 ::GetCurrentThread(), ThreadPowerThrottling, &state, sizeof(state));
138 };
139
140 // Use EcoQoS for ThreadPriority::Background available (running on most
141 // efficent cores at the most efficient cpu frequency):
142 // https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-setthreadinformation
143 // https://learn.microsoft.com/en-us/windows/win32/procthread/quality-of-service
144 setThreadInformation(Priority == ThreadPriority::Background
145 ? THREAD_POWER_THROTTLING_EXECUTION_SPEED
146 : 0);
147 }
148 }
149#endif
150
151 // https://docs.microsoft.com/en-us/windows/desktop/api/processthreadsapi/nf-processthreadsapi-setthreadpriority
152 // Begin background processing mode. The system lowers the resource scheduling
153 // priorities of the thread so that it can perform background work without
154 // significantly affecting activity in the foreground.
155 // End background processing mode. The system restores the resource scheduling
156 // priorities of the thread as they were before the thread entered background
157 // processing mode.
158 //
159 // FIXME: consider THREAD_PRIORITY_BELOW_NORMAL for Low
160 return SetThreadPriority(GetCurrentThread(),
161 Priority != ThreadPriority::Default
162 ? THREAD_MODE_BACKGROUND_BEGIN
163 : THREAD_MODE_BACKGROUND_END)
164 ? SetThreadPriorityResult::SUCCESS
165 : SetThreadPriorityResult::FAILURE;
166}
167
168struct ProcessorGroup {
169 unsigned ID;
170 unsigned AllThreads;
171 unsigned UsableThreads;
172 unsigned ThreadsPerCore;
173 uint64_t Affinity;
174
175 unsigned useableCores() const {
176 return std::max(1U, UsableThreads / ThreadsPerCore);
177 }
178};
179
180template <typename F>
181static bool IterateProcInfo(LOGICAL_PROCESSOR_RELATIONSHIP Relationship, F Fn) {
182 DWORD Len = 0;
183 BOOL R = ::GetLogicalProcessorInformationEx(Relationship, NULL, &Len);
184 if (R || GetLastError() != ERROR_INSUFFICIENT_BUFFER)
185 return false;
186
187 auto *Info = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)calloc(1, Len);
188 R = ::GetLogicalProcessorInformationEx(Relationship, Info, &Len);
189 if (R) {
190 auto *End =
191 (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)((uint8_t *)Info + Len);
192 for (auto *Curr = Info; Curr < End;
193 Curr = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)((uint8_t *)Curr +
194 Curr->Size)) {
195 if (Curr->Relationship != Relationship)
196 continue;
197 Fn(Curr);
198 }
199 }
200 free(Info);
201 return true;
202}
203
204static std::optional<std::vector<USHORT>> getActiveGroups() {
205 USHORT Count = 0;
206 if (::GetProcessGroupAffinity(GetCurrentProcess(), &Count, nullptr))
207 return std::nullopt;
208
209 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
210 return std::nullopt;
211
212 std::vector<USHORT> Groups;
213 Groups.resize(Count);
214 if (!::GetProcessGroupAffinity(GetCurrentProcess(), &Count, Groups.data()))
215 return std::nullopt;
216
217 return Groups;
218}
219
220static llvm::ArrayRef<ProcessorGroup> getProcessorGroups() {
221 auto computeGroups = []() {
223
224 auto HandleGroup = [&](SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *ProcInfo) {
225 GROUP_RELATIONSHIP &El = ProcInfo->Group;
226 for (unsigned J = 0; J < El.ActiveGroupCount; ++J) {
227 ProcessorGroup G;
228 G.ID = Groups.size();
229 G.AllThreads = El.GroupInfo[J].MaximumProcessorCount;
230 G.UsableThreads = El.GroupInfo[J].ActiveProcessorCount;
231 assert(G.UsableThreads <= 64);
232 G.Affinity = El.GroupInfo[J].ActiveProcessorMask;
233 Groups.push_back(G);
234 }
235 };
236
237 if (!IterateProcInfo(RelationGroup, HandleGroup))
238 return std::vector<ProcessorGroup>();
239
240 auto HandleProc = [&](SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *ProcInfo) {
241 PROCESSOR_RELATIONSHIP &El = ProcInfo->Processor;
242 assert(El.GroupCount == 1);
243 unsigned NumHyperThreads = 1;
244 // If the flag is set, each core supports more than one hyper-thread.
245 if (El.Flags & LTP_PC_SMT)
246 NumHyperThreads = std::bitset<64>(El.GroupMask[0].Mask).count();
247 unsigned I = El.GroupMask[0].Group;
248 Groups[I].ThreadsPerCore = NumHyperThreads;
249 };
250
251 if (!IterateProcInfo(RelationProcessorCore, HandleProc))
252 return std::vector<ProcessorGroup>();
253
254 auto ActiveGroups = getActiveGroups();
255 if (!ActiveGroups)
256 return std::vector<ProcessorGroup>();
257
258 // If there's an affinity mask set, assume the user wants to constrain the
259 // current process to only a single CPU group. On Windows, it is not
260 // possible for affinity masks to cross CPU group boundaries.
261 DWORD_PTR ProcessAffinityMask = 0, SystemAffinityMask = 0;
262 if (::GetProcessAffinityMask(GetCurrentProcess(), &ProcessAffinityMask,
263 &SystemAffinityMask)) {
264
265 if (ProcessAffinityMask != SystemAffinityMask) {
266 if (llvm::RunningWindows11OrGreater() && ActiveGroups->size() > 1) {
267 // The process affinity mask is spurious, due to an OS bug, ignore it.
268 return std::vector<ProcessorGroup>(Groups.begin(), Groups.end());
269 }
270
271 assert(ActiveGroups->size() == 1 &&
272 "When an affinity mask is set, the process is expected to be "
273 "assigned to a single processor group!");
274
275 unsigned CurrentGroupID = (*ActiveGroups)[0];
276 ProcessorGroup NewG{Groups[CurrentGroupID]};
277 NewG.Affinity = ProcessAffinityMask;
278 NewG.UsableThreads = llvm::popcount(ProcessAffinityMask);
279 Groups.clear();
280 Groups.push_back(NewG);
281 }
282 }
283 return std::vector<ProcessorGroup>(Groups.begin(), Groups.end());
284 };
285 static auto Groups = computeGroups();
287}
288
289template <typename R, typename UnaryPredicate>
290static unsigned aggregate(R &&Range, UnaryPredicate P) {
291 unsigned I{};
292 for (const auto &It : Range)
293 I += P(It);
294 return I;
295}
296
298 static unsigned Cores =
299 aggregate(getProcessorGroups(), [](const ProcessorGroup &G) {
300 return G.UsableThreads / G.ThreadsPerCore;
301 });
302 return Cores;
303}
304
305static int computeHostNumHardwareThreads() {
306 static unsigned Threads =
307 aggregate(getProcessorGroups(),
308 [](const ProcessorGroup &G) { return G.UsableThreads; });
309 return Threads;
310}
311
312// Finds the proper CPU socket where a thread number should go. Returns
313// 'std::nullopt' if the thread shall remain on the actual CPU socket.
314std::optional<unsigned>
315llvm::ThreadPoolStrategy::compute_cpu_socket(unsigned ThreadPoolNum) const {
316 ArrayRef<ProcessorGroup> Groups = getProcessorGroups();
317 // Only one CPU socket in the system or process affinity was set, no need to
318 // move the thread(s) to another CPU socket.
319 if (Groups.size() <= 1)
320 return std::nullopt;
321
322 // We ask for less threads than there are hardware threads per CPU socket, no
323 // need to dispatch threads to other CPU sockets.
324 unsigned MaxThreadsPerSocket =
325 UseHyperThreads ? Groups[0].UsableThreads : Groups[0].useableCores();
326 if (compute_thread_count() <= MaxThreadsPerSocket)
327 return std::nullopt;
328
329 assert(ThreadPoolNum < compute_thread_count() &&
330 "The thread index is not within thread strategy's range!");
331
332 // Assumes the same number of hardware threads per CPU socket.
333 return (ThreadPoolNum * Groups.size()) / compute_thread_count();
334}
335
336// Assign the current thread to a more appropriate CPU socket or CPU group
338 unsigned ThreadPoolNum) const {
339
340 // After Windows 11 and Windows Server 2022, let the OS do the scheduling,
341 // since a process automatically gains access to all processor groups.
343 return;
344
345 std::optional<unsigned> Socket = compute_cpu_socket(ThreadPoolNum);
346 if (!Socket)
347 return;
348 ArrayRef<ProcessorGroup> Groups = getProcessorGroups();
349 GROUP_AFFINITY Affinity{};
350 Affinity.Group = Groups[*Socket].ID;
351 Affinity.Mask = Groups[*Socket].Affinity;
352 SetThreadGroupAffinity(GetCurrentThread(), &Affinity, nullptr);
353}
354
356 GROUP_AFFINITY Affinity{};
357 GetThreadGroupAffinity(GetCurrentThread(), &Affinity);
358
359 static unsigned All =
360 aggregate(getProcessorGroups(),
361 [](const ProcessorGroup &G) { return G.AllThreads; });
362
363 unsigned StartOffset =
364 aggregate(getProcessorGroups(), [&](const ProcessorGroup &G) {
365 return G.ID < Affinity.Group ? G.AllThreads : 0;
366 });
367
369 V.resize(All);
370 for (unsigned I = 0; I < sizeof(KAFFINITY) * 8; ++I) {
371 if ((Affinity.Mask >> I) & 1)
372 V.set(StartOffset + I);
373 }
374 return V;
375}
376
377unsigned llvm::get_cpus() { return getProcessorGroups().size(); }
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
unsigned uint64_t
lazy value info
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
#define G(x, y, z)
Definition MD5.cpp:55
ConstantRange Range(APInt(BitWidth, Low), APInt(BitWidth, High))
#define P(N)
This file defines the SmallString class.
static const X86InstrFMA3Group Groups[]
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
LLVM_ABI void apply_thread_strategy(unsigned ThreadPoolNum) const
Assign the current thread to an ideal hardware CPU or NUMA node.
LLVM_ABI std::optional< unsigned > compute_cpu_socket(unsigned ThreadPoolNum) const
Finds the CPU socket where a thread should go.
LLVM_ABI unsigned compute_thread_count() const
Retrieves the max available threads for the current strategy.
Definition Threading.cpp:43
LLVM_ABI HMODULE loadSystemModuleSecure(LPCWSTR lpModuleName)
Retrieves the handle to a in-memory system module such as ntdll.dll, while ensuring we're not retriev...
This is an optimization pass for GlobalISel generic memory operations.
void ReportLastErrorFatal(const char *Msg)
LLVM_ABI llvm::BitVector get_thread_affinity_mask()
Returns a mask that represents on which hardware thread, core, CPU, NUMA group, the calling thread ca...
Definition Threading.cpp:41
LLVM_ABI uint32_t get_max_thread_name_length()
Get the maximum length of a thread name on this platform.
Definition Threading.cpp:35
constexpr int popcount(T Value) noexcept
Count the number of set bits in a value.
Definition bit.h:156
LLVM_ABI SetThreadPriorityResult set_thread_priority(ThreadPriority Priority)
LLVM_ABI unsigned get_cpus()
Returns how many physical CPUs or NUMA groups the system has.
LLVM_ABI bool RunningWindows11OrGreater()
Determines if the program is running on Windows 11 or Windows Server 2022.
LLVM_ABI void set_thread_name(const Twine &Name)
Set the name of the current thread.
Definition Threading.cpp:37
SetThreadPriorityResult
Definition Threading.h:285
LLVM_ABI void get_thread_name(SmallVectorImpl< char > &Name)
Get the name of the current thread.
Definition Threading.cpp:39
LLVM_ABI int get_physical_cores()
Returns how many physical cores (as opposed to logical cores returned from thread::hardware_concurren...
Definition Threading.cpp:49
LLVM_ABI uint64_t get_threadid()
Return the current thread id, as used in various OS system calls.
Definition Threading.cpp:33
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Count
Definition InstrProf.h:145
ArrayRef(const T &OneElt) -> ArrayRef< T >