diff --git a/clang-tools-extra/clangd/test/Inputs/BenchmarkHeader.h b/clang-tools-extra/clangd/test/Inputs/BenchmarkHeader.h index bf760e367ff783..3b7620adafb103 100644 --- a/clang-tools-extra/clangd/test/Inputs/BenchmarkHeader.h +++ b/clang-tools-extra/clangd/test/Inputs/BenchmarkHeader.h @@ -7,7 +7,11 @@ class Dex; } // namespace clang namespace llvm { -int get_physical_cores(); +namespace sys { + +int getHostNumPhysicalCores(); + +} // namespace sys } // namespace llvm namespace { diff --git a/llvm/include/llvm/Support/Host.h b/llvm/include/llvm/Support/Host.h index dcebebdca6cb7d..369d6745db5ae1 100644 --- a/llvm/include/llvm/Support/Host.h +++ b/llvm/include/llvm/Support/Host.h @@ -54,6 +54,11 @@ namespace sys { /// \return - True on success. bool getHostCPUFeatures(StringMap &Features); + /// Get the number of physical cores (as opposed to logical cores returned + /// from thread::hardware_concurrency(), which includes hyperthreads). + /// Returns -1 if unknown for the current host system. + int getHostNumPhysicalCores(); + namespace detail { /// Helper functions to extract HostCPUName from /proc/cpuinfo on linux. StringRef getHostCPUNameForPowerPC(StringRef ProcCpuinfoContent); diff --git a/llvm/include/llvm/Support/Threading.h b/llvm/include/llvm/Support/Threading.h index f3f7c44bd439a2..7f2708ddbb4678 100644 --- a/llvm/include/llvm/Support/Threading.h +++ b/llvm/include/llvm/Support/Threading.h @@ -231,11 +231,6 @@ constexpr bool llvm_is_multithreaded() { return LLVM_ENABLE_THREADS; } /// Returns how many physical CPUs or NUMA groups the system has. unsigned get_cpus(); - /// Returns how many physical cores (as opposed to logical cores returned from - /// thread::hardware_concurrency(), which includes hyperthreads). - /// Returns -1 if unknown for the current host system. - int get_physical_cores(); - enum class ThreadPriority { /// Lower the current thread's priority as much as possible. Can be used /// for long-running tasks that are not time critical; more energy- diff --git a/llvm/lib/Support/Host.cpp b/llvm/lib/Support/Host.cpp index c87d9644d09795..713227c4b088c7 100644 --- a/llvm/lib/Support/Host.cpp +++ b/llvm/lib/Support/Host.cpp @@ -1576,6 +1576,128 @@ VendorSignatures getVendorSignature(unsigned *MaxLeaf) { } // namespace llvm #endif +#if defined(__linux__) && (defined(__i386__) || defined(__x86_64__)) +// On Linux, the number of physical cores can be computed from /proc/cpuinfo, +// using the number of unique physical/core id pairs. The following +// implementation reads the /proc/cpuinfo format on an x86_64 system. +static int computeHostNumPhysicalCores() { + // Enabled represents the number of physical id/core id pairs with at least + // one processor id enabled by the CPU affinity mask. + cpu_set_t Affinity, Enabled; + if (sched_getaffinity(0, sizeof(Affinity), &Affinity) != 0) + return -1; + CPU_ZERO(&Enabled); + + // Read /proc/cpuinfo as a stream (until EOF reached). It cannot be + // mmapped because it appears to have 0 size. + llvm::ErrorOr> Text = + llvm::MemoryBuffer::getFileAsStream("/proc/cpuinfo"); + if (std::error_code EC = Text.getError()) { + llvm::errs() << "Can't read " + << "/proc/cpuinfo: " << EC.message() << "\n"; + return -1; + } + SmallVector strs; + (*Text)->getBuffer().split(strs, "\n", /*MaxSplit=*/-1, + /*KeepEmpty=*/false); + int CurProcessor = -1; + int CurPhysicalId = -1; + int CurSiblings = -1; + int CurCoreId = -1; + for (StringRef Line : strs) { + std::pair Data = Line.split(':'); + auto Name = Data.first.trim(); + auto Val = Data.second.trim(); + // These fields are available if the kernel is configured with CONFIG_SMP. + if (Name == "processor") + Val.getAsInteger(10, CurProcessor); + else if (Name == "physical id") + Val.getAsInteger(10, CurPhysicalId); + else if (Name == "siblings") + Val.getAsInteger(10, CurSiblings); + else if (Name == "core id") { + Val.getAsInteger(10, CurCoreId); + // The processor id corresponds to an index into cpu_set_t. + if (CPU_ISSET(CurProcessor, &Affinity)) + CPU_SET(CurPhysicalId * CurSiblings + CurCoreId, &Enabled); + } + } + return CPU_COUNT(&Enabled); +} +#elif defined(__linux__) && defined(__s390x__) +static int computeHostNumPhysicalCores() { + return sysconf(_SC_NPROCESSORS_ONLN); +} +#elif defined(__linux__) && !defined(__ANDROID__) +static int computeHostNumPhysicalCores() { + cpu_set_t Affinity; + if (sched_getaffinity(0, sizeof(Affinity), &Affinity) == 0) + return CPU_COUNT(&Affinity); + + // The call to sched_getaffinity() may have failed because the Affinity + // mask is too small for the number of CPU's on the system (i.e. the + // system has more than 1024 CPUs). Allocate a mask large enough for + // twice as many CPUs. + cpu_set_t *DynAffinity; + DynAffinity = CPU_ALLOC(2048); + if (sched_getaffinity(0, CPU_ALLOC_SIZE(2048), DynAffinity) == 0) { + int NumCPUs = CPU_COUNT(DynAffinity); + CPU_FREE(DynAffinity); + return NumCPUs; + } + return -1; +} +#elif defined(__APPLE__) +// Gets the number of *physical cores* on the machine. +static int computeHostNumPhysicalCores() { + uint32_t count; + size_t len = sizeof(count); + sysctlbyname("hw.physicalcpu", &count, &len, NULL, 0); + if (count < 1) { + int nm[2]; + nm[0] = CTL_HW; + nm[1] = HW_AVAILCPU; + sysctl(nm, 2, &count, &len, NULL, 0); + if (count < 1) + return -1; + } + return count; +} +#elif defined(__MVS__) +static int computeHostNumPhysicalCores() { + enum { + // Byte offset of the pointer to the Communications Vector Table (CVT) in + // the Prefixed Save Area (PSA). The table entry is a 31-bit pointer and + // will be zero-extended to uintptr_t. + FLCCVT = 16, + // Byte offset of the pointer to the Common System Data Area (CSD) in the + // CVT. The table entry is a 31-bit pointer and will be zero-extended to + // uintptr_t. + CVTCSD = 660, + // Byte offset to the number of live CPs in the LPAR, stored as a signed + // 32-bit value in the table. + CSD_NUMBER_ONLINE_STANDARD_CPS = 264, + }; + char *PSA = 0; + char *CVT = reinterpret_cast( + static_cast(reinterpret_cast(PSA[FLCCVT]))); + char *CSD = reinterpret_cast( + static_cast(reinterpret_cast(CVT[CVTCSD]))); + return reinterpret_cast(CSD[CSD_NUMBER_ONLINE_STANDARD_CPS]); +} +#elif defined(_WIN32) && LLVM_ENABLE_THREADS != 0 +// Defined in llvm/lib/Support/Windows/Threading.inc +int computeHostNumPhysicalCores(); +#else +// On other systems, return -1 to indicate unknown. +static int computeHostNumPhysicalCores() { return -1; } +#endif + +int sys::getHostNumPhysicalCores() { + static int NumCores = computeHostNumPhysicalCores(); + return NumCores; +} + #if defined(__i386__) || defined(_M_IX86) || \ defined(__x86_64__) || defined(_M_X64) bool sys::getHostCPUFeatures(StringMap &Features) { diff --git a/llvm/lib/Support/Threading.cpp b/llvm/lib/Support/Threading.cpp index 6c2ff116b17bd2..bd954fd7c85aaa 100644 --- a/llvm/lib/Support/Threading.cpp +++ b/llvm/lib/Support/Threading.cpp @@ -13,12 +13,8 @@ #include "llvm/Support/Threading.h" #include "llvm/ADT/Optional.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/StringRef.h" #include "llvm/Config/config.h" -#include "llvm/Config/llvm-config.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/Host.h" #include #include @@ -54,8 +50,8 @@ unsigned llvm::ThreadPoolStrategy::compute_thread_count() const { static int computeHostNumHardwareThreads(); unsigned llvm::ThreadPoolStrategy::compute_thread_count() const { - int MaxThreadCount = - UseHyperThreads ? computeHostNumHardwareThreads() : get_physical_cores(); + int MaxThreadCount = UseHyperThreads ? computeHostNumHardwareThreads() + : sys::getHostNumPhysicalCores(); if (MaxThreadCount <= 0) MaxThreadCount = 1; if (ThreadsRequested == 0) @@ -110,125 +106,3 @@ llvm::get_threadpool_strategy(StringRef Num, ThreadPoolStrategy Default) { S.ThreadsRequested = V; return S; } - -#if defined(__linux__) && (defined(__i386__) || defined(__x86_64__)) -// On Linux, the number of physical cores can be computed from /proc/cpuinfo, -// using the number of unique physical/core id pairs. The following -// implementation reads the /proc/cpuinfo format on an x86_64 system. -static int computeHostNumPhysicalCores() { - // Enabled represents the number of physical id/core id pairs with at least - // one processor id enabled by the CPU affinity mask. - cpu_set_t Affinity, Enabled; - if (sched_getaffinity(0, sizeof(Affinity), &Affinity) != 0) - return -1; - CPU_ZERO(&Enabled); - - // Read /proc/cpuinfo as a stream (until EOF reached). It cannot be - // mmapped because it appears to have 0 size. - llvm::ErrorOr> Text = - llvm::MemoryBuffer::getFileAsStream("/proc/cpuinfo"); - if (std::error_code EC = Text.getError()) { - llvm::errs() << "Can't read " - << "/proc/cpuinfo: " << EC.message() << "\n"; - return -1; - } - SmallVector strs; - (*Text)->getBuffer().split(strs, "\n", /*MaxSplit=*/-1, - /*KeepEmpty=*/false); - int CurProcessor = -1; - int CurPhysicalId = -1; - int CurSiblings = -1; - int CurCoreId = -1; - for (StringRef Line : strs) { - std::pair Data = Line.split(':'); - auto Name = Data.first.trim(); - auto Val = Data.second.trim(); - // These fields are available if the kernel is configured with CONFIG_SMP. - if (Name == "processor") - Val.getAsInteger(10, CurProcessor); - else if (Name == "physical id") - Val.getAsInteger(10, CurPhysicalId); - else if (Name == "siblings") - Val.getAsInteger(10, CurSiblings); - else if (Name == "core id") { - Val.getAsInteger(10, CurCoreId); - // The processor id corresponds to an index into cpu_set_t. - if (CPU_ISSET(CurProcessor, &Affinity)) - CPU_SET(CurPhysicalId * CurSiblings + CurCoreId, &Enabled); - } - } - return CPU_COUNT(&Enabled); -} -#elif defined(__linux__) && defined(__s390x__) -static int computeHostNumPhysicalCores() { - return sysconf(_SC_NPROCESSORS_ONLN); -} -#elif defined(__linux__) && !defined(__ANDROID__) -static int computeHostNumPhysicalCores() { - cpu_set_t Affinity; - if (sched_getaffinity(0, sizeof(Affinity), &Affinity) == 0) - return CPU_COUNT(&Affinity); - - // The call to sched_getaffinity() may have failed because the Affinity - // mask is too small for the number of CPU's on the system (i.e. the - // system has more than 1024 CPUs). Allocate a mask large enough for - // twice as many CPUs. - cpu_set_t *DynAffinity; - DynAffinity = CPU_ALLOC(2048); - if (sched_getaffinity(0, CPU_ALLOC_SIZE(2048), DynAffinity) == 0) { - int NumCPUs = CPU_COUNT(DynAffinity); - CPU_FREE(DynAffinity); - return NumCPUs; - } - return -1; -} -#elif defined(__APPLE__) -// Gets the number of *physical cores* on the machine. -static int computeHostNumPhysicalCores() { - uint32_t count; - size_t len = sizeof(count); - sysctlbyname("hw.physicalcpu", &count, &len, NULL, 0); - if (count < 1) { - int nm[2]; - nm[0] = CTL_HW; - nm[1] = HW_AVAILCPU; - sysctl(nm, 2, &count, &len, NULL, 0); - if (count < 1) - return -1; - } - return count; -} -#elif defined(__MVS__) -static int computeHostNumPhysicalCores() { - enum { - // Byte offset of the pointer to the Communications Vector Table (CVT) in - // the Prefixed Save Area (PSA). The table entry is a 31-bit pointer and - // will be zero-extended to uintptr_t. - FLCCVT = 16, - // Byte offset of the pointer to the Common System Data Area (CSD) in the - // CVT. The table entry is a 31-bit pointer and will be zero-extended to - // uintptr_t. - CVTCSD = 660, - // Byte offset to the number of live CPs in the LPAR, stored as a signed - // 32-bit value in the table. - CSD_NUMBER_ONLINE_STANDARD_CPS = 264, - }; - char *PSA = 0; - char *CVT = reinterpret_cast( - static_cast(reinterpret_cast(PSA[FLCCVT]))); - char *CSD = reinterpret_cast( - static_cast(reinterpret_cast(CVT[CVTCSD]))); - return reinterpret_cast(CSD[CSD_NUMBER_ONLINE_STANDARD_CPS]); -} -#elif defined(_WIN32) && LLVM_ENABLE_THREADS != 0 -// Defined in llvm/lib/Support/Windows/Threading.inc -int computeHostNumPhysicalCores(); -#else -// On other systems, return -1 to indicate unknown. -static int computeHostNumPhysicalCores() { return -1; } -#endif - -int llvm::get_physical_cores() { - static int NumCores = computeHostNumPhysicalCores(); - return NumCores; -} diff --git a/llvm/unittests/Support/Host.cpp b/llvm/unittests/Support/Host.cpp index 2c89971f4f4d56..7a999094f1ecf6 100644 --- a/llvm/unittests/Support/Host.cpp +++ b/llvm/unittests/Support/Host.cpp @@ -30,6 +30,37 @@ using namespace llvm; +class HostTest : public testing::Test { + Triple Host; + +protected: + bool isSupportedArchAndOS() { + // Initially this is only testing detection of the number of + // physical cores, which is currently only supported/tested on + // some systems. + return (Host.isOSWindows() && llvm_is_multithreaded()) || + Host.isOSDarwin() || (Host.isX86() && Host.isOSLinux()) || + (Host.isOSLinux() && !Host.isAndroid()) || + (Host.isSystemZ() && Host.isOSzOS()); + } + + HostTest() : Host(Triple::normalize(sys::getProcessTriple())) {} +}; + +TEST_F(HostTest, NumPhysicalCoresSupported) { + if (!isSupportedArchAndOS()) + GTEST_SKIP(); + int Num = sys::getHostNumPhysicalCores(); + ASSERT_GT(Num, 0); +} + +TEST_F(HostTest, NumPhysicalCoresUnsupported) { + if (isSupportedArchAndOS()) + GTEST_SKIP(); + int Num = sys::getHostNumPhysicalCores(); + ASSERT_EQ(Num, -1); +} + TEST(getLinuxHostCPUName, ARM) { StringRef CortexA9ProcCpuinfo = R"( processor : 0 @@ -408,13 +439,13 @@ static bool runAndGetCommandOutput( return Success; } -TEST(HostTest, DummyRunAndGetCommandOutputUse) { +TEST_F(HostTest, DummyRunAndGetCommandOutputUse) { // Suppress defined-but-not-used warnings when the tests using the helper are // disabled. (void)&runAndGetCommandOutput; } -TEST(HostTest, getMacOSHostVersion) { +TEST_F(HostTest, getMacOSHostVersion) { llvm::Triple HostTriple(llvm::sys::getProcessTriple()); if (!HostTriple.isMacOSX()) GTEST_SKIP(); @@ -460,7 +491,7 @@ static void getAIXSystemVersion(VersionTuple &SystemVersion) { .getOSVersion(); } -TEST(HostTest, AIXHostVersionDetect) { +TEST_F(HostTest, AIXHostVersionDetect) { llvm::Triple HostTriple(llvm::sys::getProcessTriple()); if (HostTriple.getOS() != Triple::AIX) GTEST_SKIP(); @@ -486,7 +517,7 @@ TEST(HostTest, AIXHostVersionDetect) { ASSERT_EQ(SysMinor, HostVersion.getMinor()); } -TEST(HostTest, AIXTargetVersionDetect) { +TEST_F(HostTest, AIXTargetVersionDetect) { llvm::Triple TargetTriple(llvm::sys::getDefaultTargetTriple()); if (TargetTriple.getOS() != Triple::AIX) GTEST_SKIP(); @@ -504,7 +535,7 @@ TEST(HostTest, AIXTargetVersionDetect) { ASSERT_EQ(SystemVersion.getMinor(), TargetVersion.getMinor()); } -TEST(HostTest, AIXHostCPUDetect) { +TEST_F(HostTest, AIXHostCPUDetect) { llvm::Triple HostTriple(llvm::sys::getProcessTriple()); if (HostTriple.getOS() != Triple::AIX) GTEST_SKIP(); diff --git a/llvm/unittests/Support/Threading.cpp b/llvm/unittests/Support/Threading.cpp index 4069d89b2d25c6..87008f17feb676 100644 --- a/llvm/unittests/Support/Threading.cpp +++ b/llvm/unittests/Support/Threading.cpp @@ -7,8 +7,6 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/Threading.h" -#include "llvm/ADT/Triple.h" -#include "llvm/Support/Host.h" #include "llvm/Support/thread.h" #include "gtest/gtest.h" @@ -19,18 +17,6 @@ using namespace llvm; namespace { -static bool isThreadingSupportedArchAndOS() { - Triple Host(Triple::normalize(sys::getProcessTriple())); - - // Initially this is only testing detection of the number of - // physical cores, which is currently only supported/tested on - // some systems. - return (Host.isOSWindows() && llvm_is_multithreaded()) || - Host.isOSDarwin() || (Host.isX86() && Host.isOSLinux()) || - (Host.isOSLinux() && !Host.isAndroid()) || - (Host.isSystemZ() && Host.isOSzOS()); -} - TEST(Threading, PhysicalConcurrency) { auto Num = heavyweight_hardware_concurrency(); // Since Num is unsigned this will also catch us trying to @@ -39,20 +25,6 @@ TEST(Threading, PhysicalConcurrency) { hardware_concurrency().compute_thread_count()); } -TEST(Threading, NumPhysicalCoresSupported) { - if (!isThreadingSupportedArchAndOS()) - GTEST_SKIP(); - int Num = get_physical_cores(); - ASSERT_GT(Num, 0); -} - -TEST(Threading, NumPhysicalCoresUnsupported) { - if (isThreadingSupportedArchAndOS()) - GTEST_SKIP(); - int Num = get_physical_cores(); - ASSERT_EQ(Num, -1); -} - #if LLVM_ENABLE_THREADS class Notification {