1 //===- unittests/Threading.cpp - Thread tests -----------------------------===// 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 #include "llvm/Support/Threading.h" 10 #include "llvm/Config/llvm-config.h" // for LLVM_ENABLE_THREADS 11 #include "llvm/Support/thread.h" 12 #include "llvm/TargetParser/Host.h" 13 #include "llvm/TargetParser/Triple.h" 14 #include "gtest/gtest.h" 15 16 #include <atomic> 17 #include <condition_variable> 18 19 using namespace llvm; 20 21 namespace { 22 23 static bool isThreadingSupportedArchAndOS() { 24 #if LLVM_ENABLE_THREADS 25 Triple Host(Triple::normalize(sys::getProcessTriple())); 26 27 // Initially this is only testing detection of the number of 28 // physical cores, which is currently only supported/tested on 29 // some systems. 30 return (Host.isOSWindows() && llvm_is_multithreaded()) || Host.isOSDarwin() || 31 (Host.isX86() && Host.isOSLinux()) || 32 (Host.isOSLinux() && !Host.isAndroid()) || 33 (Host.isSystemZ() && Host.isOSzOS()) || Host.isOSAIX(); 34 #else 35 return false; 36 #endif 37 } 38 39 TEST(Threading, PhysicalConcurrency) { 40 auto Num = heavyweight_hardware_concurrency(); 41 // Since Num is unsigned this will also catch us trying to 42 // return -1. 43 ASSERT_LE(Num.compute_thread_count(), 44 hardware_concurrency().compute_thread_count()); 45 } 46 47 TEST(Threading, NumPhysicalCoresSupported) { 48 if (!isThreadingSupportedArchAndOS()) 49 GTEST_SKIP(); 50 int Num = get_physical_cores(); 51 ASSERT_GT(Num, 0); 52 } 53 54 TEST(Threading, NumPhysicalCoresUnsupported) { 55 if (isThreadingSupportedArchAndOS()) 56 GTEST_SKIP(); 57 int Num = get_physical_cores(); 58 ASSERT_EQ(Num, -1); 59 } 60 61 #if LLVM_ENABLE_THREADS 62 63 class Notification { 64 public: 65 void notify() { 66 { 67 std::lock_guard<std::mutex> Lock(M); 68 Notified = true; 69 // Broadcast with the lock held, so it's safe to destroy the Notification 70 // after wait() returns. 71 CV.notify_all(); 72 } 73 } 74 75 bool wait() { 76 std::unique_lock<std::mutex> Lock(M); 77 using steady_clock = std::chrono::steady_clock; 78 auto Deadline = steady_clock::now() + 79 std::chrono::duration_cast<steady_clock::duration>( 80 std::chrono::duration<double>(5)); 81 return CV.wait_until(Lock, Deadline, [this] { return Notified; }); 82 } 83 84 private: 85 bool Notified = false; 86 mutable std::condition_variable CV; 87 mutable std::mutex M; 88 }; 89 90 TEST(Threading, RunOnThreadSyncAsync) { 91 Notification ThreadStarted, ThreadAdvanced, ThreadFinished; 92 93 auto ThreadFunc = [&] { 94 ThreadStarted.notify(); 95 ASSERT_TRUE(ThreadAdvanced.wait()); 96 ThreadFinished.notify(); 97 }; 98 99 llvm::thread Thread(ThreadFunc); 100 Thread.detach(); 101 ASSERT_TRUE(ThreadStarted.wait()); 102 ThreadAdvanced.notify(); 103 ASSERT_TRUE(ThreadFinished.wait()); 104 } 105 106 TEST(Threading, RunOnThreadSync) { 107 std::atomic_bool Executed(false); 108 llvm::thread Thread( 109 [](void *Arg) { *static_cast<std::atomic_bool *>(Arg) = true; }, 110 &Executed); 111 Thread.join(); 112 ASSERT_EQ(Executed, true); 113 } 114 115 #if defined(__APPLE__) 116 TEST(Threading, AppleStackSize) { 117 llvm::thread Thread([] { 118 volatile unsigned char Var[8 * 1024 * 1024 - 10240]; 119 Var[0] = 0xff; 120 ASSERT_EQ(Var[0], 0xff); 121 }); 122 Thread.join(); 123 } 124 #endif 125 #endif 126 127 } // namespace 128