10b57cec5SDimitry Andric//===- Unix/Threading.inc - Unix Threading Implementation ----- -*- C++ -*-===//
20b57cec5SDimitry Andric//
30b57cec5SDimitry Andric// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric// See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric//
70b57cec5SDimitry Andric//===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric//
90b57cec5SDimitry Andric// This file provides the Unix specific implementation of Threading functions.
100b57cec5SDimitry Andric//
110b57cec5SDimitry Andric//===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric
13480093f4SDimitry Andric#include "Unix.h"
14480093f4SDimitry Andric#include "llvm/ADT/ScopeExit.h"
150b57cec5SDimitry Andric#include "llvm/ADT/SmallString.h"
16bdd1243dSDimitry Andric#include "llvm/ADT/SmallVector.h"
17bdd1243dSDimitry Andric#include "llvm/ADT/StringRef.h"
180b57cec5SDimitry Andric#include "llvm/ADT/Twine.h"
19bdd1243dSDimitry Andric#include "llvm/Support/MemoryBuffer.h"
20bdd1243dSDimitry Andric#include "llvm/Support/raw_ostream.h"
210b57cec5SDimitry Andric
220b57cec5SDimitry Andric#if defined(__APPLE__)
230b57cec5SDimitry Andric#include <mach/mach_init.h>
240b57cec5SDimitry Andric#include <mach/mach_port.h>
2581ad6265SDimitry Andric#include <pthread/qos.h>
26bdd1243dSDimitry Andric#include <sys/sysctl.h>
27bdd1243dSDimitry Andric#include <sys/types.h>
280b57cec5SDimitry Andric#endif
290b57cec5SDimitry Andric
300b57cec5SDimitry Andric#include <pthread.h>
310b57cec5SDimitry Andric
320b57cec5SDimitry Andric#if defined(__FreeBSD__) || defined(__OpenBSD__)
330b57cec5SDimitry Andric#include <pthread_np.h> // For pthread_getthreadid_np() / pthread_set_name_np()
340b57cec5SDimitry Andric#endif
350b57cec5SDimitry Andric
360b57cec5SDimitry Andric#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
370b57cec5SDimitry Andric#include <errno.h>
38c3f7be36SDimitry Andric#include <sys/cpuset.h>
390b57cec5SDimitry Andric#include <sys/sysctl.h>
400b57cec5SDimitry Andric#include <sys/user.h>
410b57cec5SDimitry Andric#include <unistd.h>
420b57cec5SDimitry Andric#endif
430b57cec5SDimitry Andric
440b57cec5SDimitry Andric#if defined(__NetBSD__)
450b57cec5SDimitry Andric#include <lwp.h> // For _lwp_self()
460b57cec5SDimitry Andric#endif
470b57cec5SDimitry Andric
485ffd83dbSDimitry Andric#if defined(__OpenBSD__)
495ffd83dbSDimitry Andric#include <unistd.h> // For getthrid()
505ffd83dbSDimitry Andric#endif
515ffd83dbSDimitry Andric
520b57cec5SDimitry Andric#if defined(__linux__)
535ffd83dbSDimitry Andric#include <sched.h>       // For sched_getaffinity
540b57cec5SDimitry Andric#include <sys/syscall.h> // For syscall codes
550b57cec5SDimitry Andric#include <unistd.h>      // For syscall()
560b57cec5SDimitry Andric#endif
570b57cec5SDimitry Andric
58fe6060f1SDimitry Andricnamespace llvm {
59fe6060f1SDimitry Andricpthread_t
60480093f4SDimitry Andricllvm_execute_on_thread_impl(void *(*ThreadFunc)(void *), void *Arg,
61bdd1243dSDimitry Andric                            std::optional<unsigned> StackSizeInBytes) {
62480093f4SDimitry Andric  int errnum;
630b57cec5SDimitry Andric
640b57cec5SDimitry Andric  // Construct the attributes object.
65480093f4SDimitry Andric  pthread_attr_t Attr;
66480093f4SDimitry Andric  if ((errnum = ::pthread_attr_init(&Attr)) != 0) {
67480093f4SDimitry Andric    ReportErrnumFatal("pthread_attr_init failed", errnum);
68480093f4SDimitry Andric  }
69480093f4SDimitry Andric
70480093f4SDimitry Andric  auto AttrGuard = llvm::make_scope_exit([&] {
71480093f4SDimitry Andric    if ((errnum = ::pthread_attr_destroy(&Attr)) != 0) {
72480093f4SDimitry Andric      ReportErrnumFatal("pthread_attr_destroy failed", errnum);
73480093f4SDimitry Andric    }
74480093f4SDimitry Andric  });
750b57cec5SDimitry Andric
760b57cec5SDimitry Andric  // Set the requested stack size, if given.
77480093f4SDimitry Andric  if (StackSizeInBytes) {
78480093f4SDimitry Andric    if ((errnum = ::pthread_attr_setstacksize(&Attr, *StackSizeInBytes)) != 0) {
79480093f4SDimitry Andric      ReportErrnumFatal("pthread_attr_setstacksize failed", errnum);
80480093f4SDimitry Andric    }
810b57cec5SDimitry Andric  }
820b57cec5SDimitry Andric
830b57cec5SDimitry Andric  // Construct and execute the thread.
84480093f4SDimitry Andric  pthread_t Thread;
85480093f4SDimitry Andric  if ((errnum = ::pthread_create(&Thread, &Attr, ThreadFunc, Arg)) != 0)
86480093f4SDimitry Andric    ReportErrnumFatal("pthread_create failed", errnum);
870b57cec5SDimitry Andric
88fe6060f1SDimitry Andric  return Thread;
890b57cec5SDimitry Andric}
90fe6060f1SDimitry Andric
91fe6060f1SDimitry Andricvoid llvm_thread_detach_impl(pthread_t Thread) {
92fe6060f1SDimitry Andric  int errnum;
93fe6060f1SDimitry Andric
945ffd83dbSDimitry Andric  if ((errnum = ::pthread_detach(Thread)) != 0) {
955ffd83dbSDimitry Andric    ReportErrnumFatal("pthread_detach failed", errnum);
965ffd83dbSDimitry Andric  }
97480093f4SDimitry Andric}
98fe6060f1SDimitry Andric
99fe6060f1SDimitry Andricvoid llvm_thread_join_impl(pthread_t Thread) {
100fe6060f1SDimitry Andric  int errnum;
101fe6060f1SDimitry Andric
102fe6060f1SDimitry Andric  if ((errnum = ::pthread_join(Thread, nullptr)) != 0) {
103fe6060f1SDimitry Andric    ReportErrnumFatal("pthread_join failed", errnum);
104480093f4SDimitry Andric  }
105fe6060f1SDimitry Andric}
106fe6060f1SDimitry Andric
107bdd1243dSDimitry Andricpthread_t llvm_thread_get_id_impl(pthread_t Thread) { return Thread; }
108fe6060f1SDimitry Andric
109bdd1243dSDimitry Andricpthread_t llvm_thread_get_current_id_impl() { return ::pthread_self(); }
110fe6060f1SDimitry Andric
111fe6060f1SDimitry Andric} // namespace llvm
1120b57cec5SDimitry Andric
1130b57cec5SDimitry Andricuint64_t llvm::get_threadid() {
1140b57cec5SDimitry Andric#if defined(__APPLE__)
1150b57cec5SDimitry Andric  // Calling "mach_thread_self()" bumps the reference count on the thread
1160b57cec5SDimitry Andric  // port, so we need to deallocate it. mach_task_self() doesn't bump the ref
1170b57cec5SDimitry Andric  // count.
1180b57cec5SDimitry Andric  thread_port_t Self = mach_thread_self();
1190b57cec5SDimitry Andric  mach_port_deallocate(mach_task_self(), Self);
1200b57cec5SDimitry Andric  return Self;
1210b57cec5SDimitry Andric#elif defined(__FreeBSD__)
1220b57cec5SDimitry Andric  return uint64_t(pthread_getthreadid_np());
1230b57cec5SDimitry Andric#elif defined(__NetBSD__)
1240b57cec5SDimitry Andric  return uint64_t(_lwp_self());
1255ffd83dbSDimitry Andric#elif defined(__OpenBSD__)
1265ffd83dbSDimitry Andric  return uint64_t(getthrid());
1270b57cec5SDimitry Andric#elif defined(__ANDROID__)
1280b57cec5SDimitry Andric  return uint64_t(gettid());
1290b57cec5SDimitry Andric#elif defined(__linux__)
1300b57cec5SDimitry Andric  return uint64_t(syscall(SYS_gettid));
1310b57cec5SDimitry Andric#else
1320b57cec5SDimitry Andric  return uint64_t(pthread_self());
1330b57cec5SDimitry Andric#endif
1340b57cec5SDimitry Andric}
1350b57cec5SDimitry Andric
1360b57cec5SDimitry Andricstatic constexpr uint32_t get_max_thread_name_length_impl() {
1370b57cec5SDimitry Andric#if defined(__NetBSD__)
1380b57cec5SDimitry Andric  return PTHREAD_MAX_NAMELEN_NP;
1390b57cec5SDimitry Andric#elif defined(__APPLE__)
1400b57cec5SDimitry Andric  return 64;
1410b57cec5SDimitry Andric#elif defined(__linux__)
1420b57cec5SDimitry Andric#if HAVE_PTHREAD_SETNAME_NP
1430b57cec5SDimitry Andric  return 16;
1440b57cec5SDimitry Andric#else
1450b57cec5SDimitry Andric  return 0;
1460b57cec5SDimitry Andric#endif
1470b57cec5SDimitry Andric#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
1480b57cec5SDimitry Andric  return 16;
1490b57cec5SDimitry Andric#elif defined(__OpenBSD__)
1500b57cec5SDimitry Andric  return 32;
1510b57cec5SDimitry Andric#else
1520b57cec5SDimitry Andric  return 0;
1530b57cec5SDimitry Andric#endif
1540b57cec5SDimitry Andric}
1550b57cec5SDimitry Andric
1560b57cec5SDimitry Andricuint32_t llvm::get_max_thread_name_length() {
1570b57cec5SDimitry Andric  return get_max_thread_name_length_impl();
1580b57cec5SDimitry Andric}
1590b57cec5SDimitry Andric
1600b57cec5SDimitry Andricvoid llvm::set_thread_name(const Twine &Name) {
1610b57cec5SDimitry Andric  // Make sure the input is null terminated.
1620b57cec5SDimitry Andric  SmallString<64> Storage;
1630b57cec5SDimitry Andric  StringRef NameStr = Name.toNullTerminatedStringRef(Storage);
1640b57cec5SDimitry Andric
1650b57cec5SDimitry Andric  // Truncate from the beginning, not the end, if the specified name is too
1660b57cec5SDimitry Andric  // long.  For one, this ensures that the resulting string is still null
1670b57cec5SDimitry Andric  // terminated, but additionally the end of a long thread name will usually
1680b57cec5SDimitry Andric  // be more unique than the beginning, since a common pattern is for similar
1690b57cec5SDimitry Andric  // threads to share a common prefix.
1700b57cec5SDimitry Andric  // Note that the name length includes the null terminator.
1710b57cec5SDimitry Andric  if (get_max_thread_name_length() > 0)
1720b57cec5SDimitry Andric    NameStr = NameStr.take_back(get_max_thread_name_length() - 1);
1730b57cec5SDimitry Andric  (void)NameStr;
1740b57cec5SDimitry Andric#if defined(__linux__)
1750b57cec5SDimitry Andric#if (defined(__GLIBC__) && defined(_GNU_SOURCE)) || defined(__ANDROID__)
1760b57cec5SDimitry Andric#if HAVE_PTHREAD_SETNAME_NP
1770b57cec5SDimitry Andric  ::pthread_setname_np(::pthread_self(), NameStr.data());
1780b57cec5SDimitry Andric#endif
1790b57cec5SDimitry Andric#endif
1800b57cec5SDimitry Andric#elif defined(__FreeBSD__) || defined(__OpenBSD__)
1810b57cec5SDimitry Andric  ::pthread_set_name_np(::pthread_self(), NameStr.data());
1820b57cec5SDimitry Andric#elif defined(__NetBSD__)
1830b57cec5SDimitry Andric  ::pthread_setname_np(::pthread_self(), "%s",
1840b57cec5SDimitry Andric                       const_cast<char *>(NameStr.data()));
1850b57cec5SDimitry Andric#elif defined(__APPLE__)
1860b57cec5SDimitry Andric  ::pthread_setname_np(NameStr.data());
1870b57cec5SDimitry Andric#endif
1880b57cec5SDimitry Andric}
1890b57cec5SDimitry Andric
1900b57cec5SDimitry Andricvoid llvm::get_thread_name(SmallVectorImpl<char> &Name) {
1910b57cec5SDimitry Andric  Name.clear();
1920b57cec5SDimitry Andric
1930b57cec5SDimitry Andric#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
1940b57cec5SDimitry Andric  int pid = ::getpid();
1950b57cec5SDimitry Andric  uint64_t tid = get_threadid();
1960b57cec5SDimitry Andric
1970b57cec5SDimitry Andric  struct kinfo_proc *kp = nullptr, *nkp;
1980b57cec5SDimitry Andric  size_t len = 0;
1990b57cec5SDimitry Andric  int error;
2000b57cec5SDimitry Andric  int ctl[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID | KERN_PROC_INC_THREAD,
2010b57cec5SDimitry Andric                (int)pid};
2020b57cec5SDimitry Andric
2030b57cec5SDimitry Andric  while (1) {
2040b57cec5SDimitry Andric    error = sysctl(ctl, 4, kp, &len, nullptr, 0);
2050b57cec5SDimitry Andric    if (kp == nullptr || (error != 0 && errno == ENOMEM)) {
2060b57cec5SDimitry Andric      // Add extra space in case threads are added before next call.
2070b57cec5SDimitry Andric      len += sizeof(*kp) + len / 10;
2080b57cec5SDimitry Andric      nkp = (struct kinfo_proc *)::realloc(kp, len);
2090b57cec5SDimitry Andric      if (nkp == nullptr) {
2100b57cec5SDimitry Andric        free(kp);
2110b57cec5SDimitry Andric        return;
2120b57cec5SDimitry Andric      }
2130b57cec5SDimitry Andric      kp = nkp;
2140b57cec5SDimitry Andric      continue;
2150b57cec5SDimitry Andric    }
2160b57cec5SDimitry Andric    if (error != 0)
2170b57cec5SDimitry Andric      len = 0;
2180b57cec5SDimitry Andric    break;
2190b57cec5SDimitry Andric  }
2200b57cec5SDimitry Andric
2210b57cec5SDimitry Andric  for (size_t i = 0; i < len / sizeof(*kp); i++) {
2220b57cec5SDimitry Andric    if (kp[i].ki_tid == (lwpid_t)tid) {
2230b57cec5SDimitry Andric      Name.append(kp[i].ki_tdname, kp[i].ki_tdname + strlen(kp[i].ki_tdname));
2240b57cec5SDimitry Andric      break;
2250b57cec5SDimitry Andric    }
2260b57cec5SDimitry Andric  }
2270b57cec5SDimitry Andric  free(kp);
2280b57cec5SDimitry Andric  return;
2290b57cec5SDimitry Andric#elif defined(__NetBSD__)
2300b57cec5SDimitry Andric  constexpr uint32_t len = get_max_thread_name_length_impl();
2310b57cec5SDimitry Andric  char buf[len];
2320b57cec5SDimitry Andric  ::pthread_getname_np(::pthread_self(), buf, len);
2330b57cec5SDimitry Andric
2340b57cec5SDimitry Andric  Name.append(buf, buf + strlen(buf));
2350b57cec5SDimitry Andric#elif defined(__OpenBSD__)
2360b57cec5SDimitry Andric  constexpr uint32_t len = get_max_thread_name_length_impl();
2370b57cec5SDimitry Andric  char buf[len];
2380b57cec5SDimitry Andric  ::pthread_get_name_np(::pthread_self(), buf, len);
2390b57cec5SDimitry Andric
2400b57cec5SDimitry Andric  Name.append(buf, buf + strlen(buf));
2410b57cec5SDimitry Andric#elif defined(__linux__)
2420b57cec5SDimitry Andric#if HAVE_PTHREAD_GETNAME_NP
2430b57cec5SDimitry Andric  constexpr uint32_t len = get_max_thread_name_length_impl();
2440b57cec5SDimitry Andric  char Buffer[len] = {'\0'}; // FIXME: working around MSan false positive.
2450b57cec5SDimitry Andric  if (0 == ::pthread_getname_np(::pthread_self(), Buffer, len))
2460b57cec5SDimitry Andric    Name.append(Buffer, Buffer + strlen(Buffer));
2470b57cec5SDimitry Andric#endif
2480b57cec5SDimitry Andric#endif
2490b57cec5SDimitry Andric}
2500b57cec5SDimitry Andric
2510b57cec5SDimitry AndricSetThreadPriorityResult llvm::set_thread_priority(ThreadPriority Priority) {
2520b57cec5SDimitry Andric#if defined(__linux__) && defined(SCHED_IDLE)
2530b57cec5SDimitry Andric  // Some *really* old glibcs are missing SCHED_IDLE.
2540b57cec5SDimitry Andric  // http://man7.org/linux/man-pages/man3/pthread_setschedparam.3.html
2550b57cec5SDimitry Andric  // http://man7.org/linux/man-pages/man2/sched_setscheduler.2.html
2560b57cec5SDimitry Andric  sched_param priority;
2570b57cec5SDimitry Andric  // For each of the above policies, param->sched_priority must be 0.
2580b57cec5SDimitry Andric  priority.sched_priority = 0;
2590b57cec5SDimitry Andric  // SCHED_IDLE    for running very low priority background jobs.
2600b57cec5SDimitry Andric  // SCHED_OTHER   the standard round-robin time-sharing policy;
2610b57cec5SDimitry Andric  return !pthread_setschedparam(
2620b57cec5SDimitry Andric             pthread_self(),
26381ad6265SDimitry Andric             // FIXME: consider SCHED_BATCH for Low
26481ad6265SDimitry Andric             Priority == ThreadPriority::Default ? SCHED_OTHER : SCHED_IDLE,
2650b57cec5SDimitry Andric             &priority)
2660b57cec5SDimitry Andric             ? SetThreadPriorityResult::SUCCESS
2670b57cec5SDimitry Andric             : SetThreadPriorityResult::FAILURE;
2680b57cec5SDimitry Andric#elif defined(__APPLE__)
26981ad6265SDimitry Andric  // https://developer.apple.com/documentation/apple-silicon/tuning-your-code-s-performance-for-apple-silicon
27081ad6265SDimitry Andric  //
271bdd1243dSDimitry Andric  // Background - Applies to work that isn’t visible to the user and may take
272bdd1243dSDimitry Andric  // significant time to complete. Examples include indexing, backing up, or
273bdd1243dSDimitry Andric  // synchronizing data. This class emphasizes energy efficiency.
27481ad6265SDimitry Andric  //
275bdd1243dSDimitry Andric  // Utility - Applies to work that takes anywhere from a few seconds to a few
276bdd1243dSDimitry Andric  // minutes to complete. Examples include downloading a document or importing
277bdd1243dSDimitry Andric  // data. This class offers a balance between responsiveness, performance, and
278bdd1243dSDimitry Andric  // energy efficiency.
27981ad6265SDimitry Andric  const auto qosClass = [&]() {
28081ad6265SDimitry Andric    switch (Priority) {
281bdd1243dSDimitry Andric    case ThreadPriority::Background:
282bdd1243dSDimitry Andric      return QOS_CLASS_BACKGROUND;
283bdd1243dSDimitry Andric    case ThreadPriority::Low:
284bdd1243dSDimitry Andric      return QOS_CLASS_UTILITY;
285bdd1243dSDimitry Andric    case ThreadPriority::Default:
286bdd1243dSDimitry Andric      return QOS_CLASS_DEFAULT;
28781ad6265SDimitry Andric    }
28881ad6265SDimitry Andric  }();
28981ad6265SDimitry Andric  return !pthread_set_qos_class_self_np(qosClass, 0)
2900b57cec5SDimitry Andric             ? SetThreadPriorityResult::SUCCESS
2910b57cec5SDimitry Andric             : SetThreadPriorityResult::FAILURE;
2920b57cec5SDimitry Andric#endif
2930b57cec5SDimitry Andric  return SetThreadPriorityResult::FAILURE;
2940b57cec5SDimitry Andric}
2955ffd83dbSDimitry Andric
2965ffd83dbSDimitry Andric#include <thread>
2975ffd83dbSDimitry Andric
298bdd1243dSDimitry Andricstatic int computeHostNumHardwareThreads() {
299c3f7be36SDimitry Andric#if defined(__FreeBSD__)
300c3f7be36SDimitry Andric  cpuset_t mask;
301c3f7be36SDimitry Andric  CPU_ZERO(&mask);
302c3f7be36SDimitry Andric  if (cpuset_getaffinity(CPU_LEVEL_WHICH, CPU_WHICH_TID, -1, sizeof(mask),
303c3f7be36SDimitry Andric                         &mask) == 0)
304c3f7be36SDimitry Andric    return CPU_COUNT(&mask);
305c3f7be36SDimitry Andric#elif defined(__linux__)
3065ffd83dbSDimitry Andric  cpu_set_t Set;
3075ffd83dbSDimitry Andric  if (sched_getaffinity(0, sizeof(Set), &Set) == 0)
3085ffd83dbSDimitry Andric    return CPU_COUNT(&Set);
3095ffd83dbSDimitry Andric#endif
3105ffd83dbSDimitry Andric  // Guard against std::thread::hardware_concurrency() returning 0.
3115ffd83dbSDimitry Andric  if (unsigned Val = std::thread::hardware_concurrency())
3125ffd83dbSDimitry Andric    return Val;
3135ffd83dbSDimitry Andric  return 1;
3145ffd83dbSDimitry Andric}
3155ffd83dbSDimitry Andric
3165ffd83dbSDimitry Andricvoid llvm::ThreadPoolStrategy::apply_thread_strategy(
3175ffd83dbSDimitry Andric    unsigned ThreadPoolNum) const {}
3185ffd83dbSDimitry Andric
3195ffd83dbSDimitry Andricllvm::BitVector llvm::get_thread_affinity_mask() {
3205ffd83dbSDimitry Andric  // FIXME: Implement
3215ffd83dbSDimitry Andric  llvm_unreachable("Not implemented!");
3225ffd83dbSDimitry Andric}
3235ffd83dbSDimitry Andric
3245ffd83dbSDimitry Andricunsigned llvm::get_cpus() { return 1; }
325bdd1243dSDimitry Andric
326bdd1243dSDimitry Andric#if defined(__linux__) && (defined(__i386__) || defined(__x86_64__))
327bdd1243dSDimitry Andric// On Linux, the number of physical cores can be computed from /proc/cpuinfo,
328bdd1243dSDimitry Andric// using the number of unique physical/core id pairs. The following
329bdd1243dSDimitry Andric// implementation reads the /proc/cpuinfo format on an x86_64 system.
330bdd1243dSDimitry Andricstatic int computeHostNumPhysicalCores() {
331bdd1243dSDimitry Andric  // Enabled represents the number of physical id/core id pairs with at least
332bdd1243dSDimitry Andric  // one processor id enabled by the CPU affinity mask.
333bdd1243dSDimitry Andric  cpu_set_t Affinity, Enabled;
334bdd1243dSDimitry Andric  if (sched_getaffinity(0, sizeof(Affinity), &Affinity) != 0)
335bdd1243dSDimitry Andric    return -1;
336bdd1243dSDimitry Andric  CPU_ZERO(&Enabled);
337bdd1243dSDimitry Andric
338bdd1243dSDimitry Andric  // Read /proc/cpuinfo as a stream (until EOF reached). It cannot be
339bdd1243dSDimitry Andric  // mmapped because it appears to have 0 size.
340bdd1243dSDimitry Andric  llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Text =
341bdd1243dSDimitry Andric      llvm::MemoryBuffer::getFileAsStream("/proc/cpuinfo");
342bdd1243dSDimitry Andric  if (std::error_code EC = Text.getError()) {
343bdd1243dSDimitry Andric    llvm::errs() << "Can't read "
344bdd1243dSDimitry Andric                 << "/proc/cpuinfo: " << EC.message() << "\n";
345bdd1243dSDimitry Andric    return -1;
346bdd1243dSDimitry Andric  }
347bdd1243dSDimitry Andric  SmallVector<StringRef, 8> strs;
348bdd1243dSDimitry Andric  (*Text)->getBuffer().split(strs, "\n", /*MaxSplit=*/-1,
349bdd1243dSDimitry Andric                             /*KeepEmpty=*/false);
350bdd1243dSDimitry Andric  int CurProcessor = -1;
351bdd1243dSDimitry Andric  int CurPhysicalId = -1;
352bdd1243dSDimitry Andric  int CurSiblings = -1;
353bdd1243dSDimitry Andric  int CurCoreId = -1;
354bdd1243dSDimitry Andric  for (StringRef Line : strs) {
355bdd1243dSDimitry Andric    std::pair<StringRef, StringRef> Data = Line.split(':');
356bdd1243dSDimitry Andric    auto Name = Data.first.trim();
357bdd1243dSDimitry Andric    auto Val = Data.second.trim();
358bdd1243dSDimitry Andric    // These fields are available if the kernel is configured with CONFIG_SMP.
359bdd1243dSDimitry Andric    if (Name == "processor")
360bdd1243dSDimitry Andric      Val.getAsInteger(10, CurProcessor);
361bdd1243dSDimitry Andric    else if (Name == "physical id")
362bdd1243dSDimitry Andric      Val.getAsInteger(10, CurPhysicalId);
363bdd1243dSDimitry Andric    else if (Name == "siblings")
364bdd1243dSDimitry Andric      Val.getAsInteger(10, CurSiblings);
365bdd1243dSDimitry Andric    else if (Name == "core id") {
366bdd1243dSDimitry Andric      Val.getAsInteger(10, CurCoreId);
367bdd1243dSDimitry Andric      // The processor id corresponds to an index into cpu_set_t.
368bdd1243dSDimitry Andric      if (CPU_ISSET(CurProcessor, &Affinity))
369bdd1243dSDimitry Andric        CPU_SET(CurPhysicalId * CurSiblings + CurCoreId, &Enabled);
370bdd1243dSDimitry Andric    }
371bdd1243dSDimitry Andric  }
372bdd1243dSDimitry Andric  return CPU_COUNT(&Enabled);
373bdd1243dSDimitry Andric}
3745f757f3fSDimitry Andric#elif (defined(__linux__) && defined(__s390x__)) || defined(_AIX)
375bdd1243dSDimitry Andricstatic int computeHostNumPhysicalCores() {
376bdd1243dSDimitry Andric  return sysconf(_SC_NPROCESSORS_ONLN);
377bdd1243dSDimitry Andric}
378bdd1243dSDimitry Andric#elif defined(__linux__) && !defined(__ANDROID__)
379bdd1243dSDimitry Andricstatic int computeHostNumPhysicalCores() {
380bdd1243dSDimitry Andric  cpu_set_t Affinity;
381bdd1243dSDimitry Andric  if (sched_getaffinity(0, sizeof(Affinity), &Affinity) == 0)
382bdd1243dSDimitry Andric    return CPU_COUNT(&Affinity);
383bdd1243dSDimitry Andric
384bdd1243dSDimitry Andric  // The call to sched_getaffinity() may have failed because the Affinity
385bdd1243dSDimitry Andric  // mask is too small for the number of CPU's on the system (i.e. the
386bdd1243dSDimitry Andric  // system has more than 1024 CPUs). Allocate a mask large enough for
387bdd1243dSDimitry Andric  // twice as many CPUs.
388bdd1243dSDimitry Andric  cpu_set_t *DynAffinity;
389bdd1243dSDimitry Andric  DynAffinity = CPU_ALLOC(2048);
390bdd1243dSDimitry Andric  if (sched_getaffinity(0, CPU_ALLOC_SIZE(2048), DynAffinity) == 0) {
391bdd1243dSDimitry Andric    int NumCPUs = CPU_COUNT(DynAffinity);
392bdd1243dSDimitry Andric    CPU_FREE(DynAffinity);
393bdd1243dSDimitry Andric    return NumCPUs;
394bdd1243dSDimitry Andric  }
395bdd1243dSDimitry Andric  return -1;
396bdd1243dSDimitry Andric}
397bdd1243dSDimitry Andric#elif defined(__APPLE__)
398bdd1243dSDimitry Andric// Gets the number of *physical cores* on the machine.
399bdd1243dSDimitry Andricstatic int computeHostNumPhysicalCores() {
400bdd1243dSDimitry Andric  uint32_t count;
401bdd1243dSDimitry Andric  size_t len = sizeof(count);
402bdd1243dSDimitry Andric  sysctlbyname("hw.physicalcpu", &count, &len, NULL, 0);
403bdd1243dSDimitry Andric  if (count < 1) {
404bdd1243dSDimitry Andric    int nm[2];
405bdd1243dSDimitry Andric    nm[0] = CTL_HW;
406bdd1243dSDimitry Andric    nm[1] = HW_AVAILCPU;
407bdd1243dSDimitry Andric    sysctl(nm, 2, &count, &len, NULL, 0);
408bdd1243dSDimitry Andric    if (count < 1)
409bdd1243dSDimitry Andric      return -1;
410bdd1243dSDimitry Andric  }
411bdd1243dSDimitry Andric  return count;
412bdd1243dSDimitry Andric}
413bdd1243dSDimitry Andric#elif defined(__MVS__)
414bdd1243dSDimitry Andricstatic int computeHostNumPhysicalCores() {
415bdd1243dSDimitry Andric  enum {
416bdd1243dSDimitry Andric    // Byte offset of the pointer to the Communications Vector Table (CVT) in
417bdd1243dSDimitry Andric    // the Prefixed Save Area (PSA). The table entry is a 31-bit pointer and
418bdd1243dSDimitry Andric    // will be zero-extended to uintptr_t.
419bdd1243dSDimitry Andric    FLCCVT = 16,
420bdd1243dSDimitry Andric    // Byte offset of the pointer to the Common System Data Area (CSD) in the
421bdd1243dSDimitry Andric    // CVT. The table entry is a 31-bit pointer and will be zero-extended to
422bdd1243dSDimitry Andric    // uintptr_t.
423bdd1243dSDimitry Andric    CVTCSD = 660,
424bdd1243dSDimitry Andric    // Byte offset to the number of live CPs in the LPAR, stored as a signed
425bdd1243dSDimitry Andric    // 32-bit value in the table.
426bdd1243dSDimitry Andric    CSD_NUMBER_ONLINE_STANDARD_CPS = 264,
427bdd1243dSDimitry Andric  };
428bdd1243dSDimitry Andric  char *PSA = 0;
429bdd1243dSDimitry Andric  char *CVT = reinterpret_cast<char *>(
430bdd1243dSDimitry Andric      static_cast<uintptr_t>(reinterpret_cast<unsigned int &>(PSA[FLCCVT])));
431bdd1243dSDimitry Andric  char *CSD = reinterpret_cast<char *>(
432bdd1243dSDimitry Andric      static_cast<uintptr_t>(reinterpret_cast<unsigned int &>(CVT[CVTCSD])));
433bdd1243dSDimitry Andric  return reinterpret_cast<int &>(CSD[CSD_NUMBER_ONLINE_STANDARD_CPS]);
434bdd1243dSDimitry Andric}
435bdd1243dSDimitry Andric#else
436bdd1243dSDimitry Andric// On other systems, return -1 to indicate unknown.
437bdd1243dSDimitry Andricstatic int computeHostNumPhysicalCores() { return -1; }
438bdd1243dSDimitry Andric#endif
439bdd1243dSDimitry Andric
440bdd1243dSDimitry Andricint llvm::get_physical_cores() {
441bdd1243dSDimitry Andric  static int NumCores = computeHostNumPhysicalCores();
442bdd1243dSDimitry Andric  return NumCores;
443bdd1243dSDimitry Andric}
444