LLVM  15.0.0git
Threading.inc
Go to the documentation of this file.
1 //===- Unix/Threading.inc - Unix 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 Unix specific implementation of Threading functions.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "Unix.h"
14 #include "llvm/ADT/ScopeExit.h"
15 #include "llvm/ADT/SmallString.h"
16 #include "llvm/ADT/Twine.h"
17 
18 #if defined(__APPLE__)
19 #include <mach/mach_init.h>
20 #include <mach/mach_port.h>
21 #include <pthread/qos.h>
22 #endif
23 
24 #include <pthread.h>
25 
26 #if defined(__FreeBSD__) || defined(__OpenBSD__)
27 #include <pthread_np.h> // For pthread_getthreadid_np() / pthread_set_name_np()
28 #endif
29 
30 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
31 #include <errno.h>
32 #include <sys/cpuset.h>
33 #include <sys/sysctl.h>
34 #include <sys/user.h>
35 #include <unistd.h>
36 #endif
37 
38 #if defined(__NetBSD__)
39 #include <lwp.h> // For _lwp_self()
40 #endif
41 
42 #if defined(__OpenBSD__)
43 #include <unistd.h> // For getthrid()
44 #endif
45 
46 #if defined(__linux__)
47 #include <sched.h> // For sched_getaffinity
48 #include <sys/syscall.h> // For syscall codes
49 #include <unistd.h> // For syscall()
50 #endif
51 
52 namespace llvm {
53 pthread_t
54 llvm_execute_on_thread_impl(void *(*ThreadFunc)(void *), void *Arg,
55  llvm::Optional<unsigned> StackSizeInBytes) {
56  int errnum;
57 
58  // Construct the attributes object.
59  pthread_attr_t Attr;
60  if ((errnum = ::pthread_attr_init(&Attr)) != 0) {
61  ReportErrnumFatal("pthread_attr_init failed", errnum);
62  }
63 
64  auto AttrGuard = llvm::make_scope_exit([&] {
65  if ((errnum = ::pthread_attr_destroy(&Attr)) != 0) {
66  ReportErrnumFatal("pthread_attr_destroy failed", errnum);
67  }
68  });
69 
70  // Set the requested stack size, if given.
71  if (StackSizeInBytes) {
72  if ((errnum = ::pthread_attr_setstacksize(&Attr, *StackSizeInBytes)) != 0) {
73  ReportErrnumFatal("pthread_attr_setstacksize failed", errnum);
74  }
75  }
76 
77  // Construct and execute the thread.
78  pthread_t Thread;
79  if ((errnum = ::pthread_create(&Thread, &Attr, ThreadFunc, Arg)) != 0)
80  ReportErrnumFatal("pthread_create failed", errnum);
81 
82  return Thread;
83 }
84 
85 void llvm_thread_detach_impl(pthread_t Thread) {
86  int errnum;
87 
88  if ((errnum = ::pthread_detach(Thread)) != 0) {
89  ReportErrnumFatal("pthread_detach failed", errnum);
90  }
91 }
92 
93 void llvm_thread_join_impl(pthread_t Thread) {
94  int errnum;
95 
96  if ((errnum = ::pthread_join(Thread, nullptr)) != 0) {
97  ReportErrnumFatal("pthread_join failed", errnum);
98  }
99 }
100 
101 pthread_t llvm_thread_get_id_impl(pthread_t Thread) {
102  return Thread;
103 }
104 
106  return ::pthread_self();
107 }
108 
109 } // namespace llvm
110 
112 #if defined(__APPLE__)
113  // Calling "mach_thread_self()" bumps the reference count on the thread
114  // port, so we need to deallocate it. mach_task_self() doesn't bump the ref
115  // count.
116  thread_port_t Self = mach_thread_self();
117  mach_port_deallocate(mach_task_self(), Self);
118  return Self;
119 #elif defined(__FreeBSD__)
120  return uint64_t(pthread_getthreadid_np());
121 #elif defined(__NetBSD__)
122  return uint64_t(_lwp_self());
123 #elif defined(__OpenBSD__)
124  return uint64_t(getthrid());
125 #elif defined(__ANDROID__)
126  return uint64_t(gettid());
127 #elif defined(__linux__)
128  return uint64_t(syscall(SYS_gettid));
129 #else
130  return uint64_t(pthread_self());
131 #endif
132 }
133 
134 
135 static constexpr uint32_t get_max_thread_name_length_impl() {
136 #if defined(__NetBSD__)
137  return PTHREAD_MAX_NAMELEN_NP;
138 #elif defined(__APPLE__)
139  return 64;
140 #elif defined(__linux__)
141 #if HAVE_PTHREAD_SETNAME_NP
142  return 16;
143 #else
144  return 0;
145 #endif
146 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
147  return 16;
148 #elif defined(__OpenBSD__)
149  return 32;
150 #else
151  return 0;
152 #endif
153 }
154 
156  return get_max_thread_name_length_impl();
157 }
158 
159 void llvm::set_thread_name(const Twine &Name) {
160  // Make sure the input is null terminated.
161  SmallString<64> Storage;
162  StringRef NameStr = Name.toNullTerminatedStringRef(Storage);
163 
164  // Truncate from the beginning, not the end, if the specified name is too
165  // long. For one, this ensures that the resulting string is still null
166  // terminated, but additionally the end of a long thread name will usually
167  // be more unique than the beginning, since a common pattern is for similar
168  // threads to share a common prefix.
169  // Note that the name length includes the null terminator.
170  if (get_max_thread_name_length() > 0)
171  NameStr = NameStr.take_back(get_max_thread_name_length() - 1);
172  (void)NameStr;
173 #if defined(__linux__)
174 #if (defined(__GLIBC__) && defined(_GNU_SOURCE)) || defined(__ANDROID__)
175 #if HAVE_PTHREAD_SETNAME_NP
176  ::pthread_setname_np(::pthread_self(), NameStr.data());
177 #endif
178 #endif
179 #elif defined(__FreeBSD__) || defined(__OpenBSD__)
180  ::pthread_set_name_np(::pthread_self(), NameStr.data());
181 #elif defined(__NetBSD__)
182  ::pthread_setname_np(::pthread_self(), "%s",
183  const_cast<char *>(NameStr.data()));
184 #elif defined(__APPLE__)
185  ::pthread_setname_np(NameStr.data());
186 #endif
187 }
188 
189 void llvm::get_thread_name(SmallVectorImpl<char> &Name) {
190  Name.clear();
191 
192 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
193  int pid = ::getpid();
194  uint64_t tid = get_threadid();
195 
196  struct kinfo_proc *kp = nullptr, *nkp;
197  size_t len = 0;
198  int error;
199  int ctl[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID | KERN_PROC_INC_THREAD,
200  (int)pid };
201 
202  while (1) {
203  error = sysctl(ctl, 4, kp, &len, nullptr, 0);
204  if (kp == nullptr || (error != 0 && errno == ENOMEM)) {
205  // Add extra space in case threads are added before next call.
206  len += sizeof(*kp) + len / 10;
207  nkp = (struct kinfo_proc *)::realloc(kp, len);
208  if (nkp == nullptr) {
209  free(kp);
210  return;
211  }
212  kp = nkp;
213  continue;
214  }
215  if (error != 0)
216  len = 0;
217  break;
218  }
219 
220  for (size_t i = 0; i < len / sizeof(*kp); i++) {
221  if (kp[i].ki_tid == (lwpid_t)tid) {
222  Name.append(kp[i].ki_tdname, kp[i].ki_tdname + strlen(kp[i].ki_tdname));
223  break;
224  }
225  }
226  free(kp);
227  return;
228 #elif defined(__NetBSD__)
229  constexpr uint32_t len = get_max_thread_name_length_impl();
230  char buf[len];
231  ::pthread_getname_np(::pthread_self(), buf, len);
232 
233  Name.append(buf, buf + strlen(buf));
234 #elif defined(__OpenBSD__)
235  constexpr uint32_t len = get_max_thread_name_length_impl();
236  char buf[len];
237  ::pthread_get_name_np(::pthread_self(), buf, len);
238 
239  Name.append(buf, buf + strlen(buf));
240 #elif defined(__linux__)
241 #if HAVE_PTHREAD_GETNAME_NP
242  constexpr uint32_t len = get_max_thread_name_length_impl();
243  char Buffer[len] = {'\0'}; // FIXME: working around MSan false positive.
244  if (0 == ::pthread_getname_np(::pthread_self(), Buffer, len))
245  Name.append(Buffer, Buffer + strlen(Buffer));
246 #endif
247 #endif
248 }
249 
251 #if defined(__linux__) && defined(SCHED_IDLE)
252  // Some *really* old glibcs are missing SCHED_IDLE.
253  // http://man7.org/linux/man-pages/man3/pthread_setschedparam.3.html
254  // http://man7.org/linux/man-pages/man2/sched_setscheduler.2.html
255  sched_param priority;
256  // For each of the above policies, param->sched_priority must be 0.
257  priority.sched_priority = 0;
258  // SCHED_IDLE for running very low priority background jobs.
259  // SCHED_OTHER the standard round-robin time-sharing policy;
260  return !pthread_setschedparam(
261  pthread_self(),
262  // FIXME: consider SCHED_BATCH for Low
263  Priority == ThreadPriority::Default ? SCHED_OTHER : SCHED_IDLE,
264  &priority)
265  ? SetThreadPriorityResult::SUCCESS
266  : SetThreadPriorityResult::FAILURE;
267 #elif defined(__APPLE__)
268  // https://developer.apple.com/documentation/apple-silicon/tuning-your-code-s-performance-for-apple-silicon
269  //
270  // Background - Applies to work that isn’t visible to the user and may take significant
271  // time to complete. Examples include indexing, backing up, or synchronizing data. This
272  // class emphasizes energy efficiency.
273  //
274  // Utility - Applies to work that takes anywhere from a few seconds to a few minutes to
275  // complete. Examples include downloading a document or importing data. This class
276  // offers a balance between responsiveness, performance, and energy efficiency.
277  const auto qosClass = [&](){
278  switch (Priority) {
279  case ThreadPriority::Background: return QOS_CLASS_BACKGROUND;
280  case ThreadPriority::Low: return QOS_CLASS_UTILITY;
281  case ThreadPriority::Default: return QOS_CLASS_DEFAULT;
282  }
283  }();
284  return !pthread_set_qos_class_self_np(qosClass, 0)
285  ? SetThreadPriorityResult::SUCCESS
286  : SetThreadPriorityResult::FAILURE;
287 #endif
288  return SetThreadPriorityResult::FAILURE;
289 }
290 
291 #include <thread>
292 
294 #if defined(__FreeBSD__)
295  cpuset_t mask;
296  CPU_ZERO(&mask);
297  if (cpuset_getaffinity(CPU_LEVEL_WHICH, CPU_WHICH_TID, -1, sizeof(mask),
298  &mask) == 0)
299  return CPU_COUNT(&mask);
300 #elif defined(__linux__)
301  cpu_set_t Set;
302  if (sched_getaffinity(0, sizeof(Set), &Set) == 0)
303  return CPU_COUNT(&Set);
304 #endif
305  // Guard against std::thread::hardware_concurrency() returning 0.
306  if (unsigned Val = std::thread::hardware_concurrency())
307  return Val;
308  return 1;
309 }
310 
312  unsigned ThreadPoolNum) const {}
313 
315  // FIXME: Implement
316  llvm_unreachable("Not implemented!");
317 }
318 
319 unsigned llvm::get_cpus() { return 1; }
i
i
Definition: README.txt:29
llvm::llvm_thread_get_id_impl
thread::id llvm_thread_get_id_impl(thread::native_handle_type Thread)
llvm::hardware_concurrency
ThreadPoolStrategy hardware_concurrency(unsigned ThreadCount=0)
Returns a default thread strategy where all available hardware resources are to be used,...
Definition: Threading.h:185
llvm
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:17
Thread
uint64_t Thread
Definition: Profile.cpp:48
llvm::llvm_thread_get_current_id_impl
thread::id llvm_thread_get_current_id_impl()
llvm::llvm_thread_join_impl
void llvm_thread_join_impl(thread::native_handle_type Thread)
llvm::llvm_thread_detach_impl
void llvm_thread_detach_impl(thread::native_handle_type Thread)
llvm::llvm_execute_on_thread_impl
thread::native_handle_type llvm_execute_on_thread_impl(thread::start_routine_type ThreadFunc, void *Arg, llvm::Optional< unsigned > StackSizeInBytes)
error
#define error(X)
Definition: SymbolRecordMapping.cpp:14
llvm::Optional< unsigned >
Unix.h
Arg
amdgpu Simplify well known AMD library false FunctionCallee Value * Arg
Definition: AMDGPULibCalls.cpp:186
computeHostNumHardwareThreads
int computeHostNumHardwareThreads()
SmallString.h
Twine.h
int
Clang compiles this i1 i64 store i64 i64 store i64 i64 store i64 i64 store i64 align Which gets codegen d xmm0 movaps rbp movaps rbp movaps rbp movaps rbp rbp rbp rbp rbp It would be better to have movq s of instead of the movaps s LLVM produces ret int
Definition: README.txt:536
llvm::get_threadid
uint64_t get_threadid()
Return the current thread id, as used in various OS system calls.
llvm::make_scope_exit
LLVM_NODISCARD detail::scope_exit< typename std::decay< Callable >::type > make_scope_exit(Callable &&F)
Definition: ScopeExit.h:59
llvm::get_max_thread_name_length
uint32_t get_max_thread_name_length()
Get the maximum length of a thread name on this platform.
llvm::get_thread_name
void get_thread_name(SmallVectorImpl< char > &Name)
Get the name of the current thread.
llvm::ThreadPoolStrategy::apply_thread_strategy
void apply_thread_strategy(unsigned ThreadPoolNum) const
Assign the current thread to an ideal hardware CPU or NUMA node.
llvm::BitVector
Definition: BitVector.h:75
uint64_t
llvm::ThreadPriority
ThreadPriority
Definition: Threading.h:235
llvm_unreachable
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
Definition: ErrorHandling.h:143
uint32_t
llvm::GraphProgram::Name
Name
Definition: GraphWriter.h:50
llvm::TargetStackID::Default
@ Default
Definition: TargetFrameLowering.h:28
llvm::set_thread_name
void set_thread_name(const Twine &Name)
Set the name of the current thread.
llvm::get_cpus
unsigned get_cpus()
Returns how many physical CPUs or NUMA groups the system has.
llvm::SetThreadPriorityResult
SetThreadPriorityResult
Definition: Threading.h:250
llvm::get_thread_affinity_mask
llvm::BitVector get_thread_affinity_mask()
Returns a mask that represents on which hardware thread, core, CPU, NUMA group, the calling thread ca...
ReportErrnumFatal
static void ReportErrnumFatal(const char *Msg, int errnum)
Definition: Unix.h:70
ScopeExit.h
llvm::set_thread_priority
SetThreadPriorityResult set_thread_priority(ThreadPriority Priority)