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