1 //========- unittests/Support/ThreadPools.cpp - ThreadPools.h tests --========// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "llvm/Support/ThreadPool.h" 11 12 #include "llvm/ADT/STLExtras.h" 13 #include "llvm/ADT/SmallVector.h" 14 #include "llvm/ADT/Triple.h" 15 #include "llvm/Support/Host.h" 16 #include "llvm/Support/TargetSelect.h" 17 18 #include "gtest/gtest.h" 19 20 using namespace llvm; 21 22 // Fixture for the unittests, allowing to *temporarily* disable the unittests 23 // on a particular platform 24 class ThreadPoolTest : public testing::Test { 25 Triple Host; 26 SmallVector<Triple::ArchType, 4> UnsupportedArchs; 27 SmallVector<Triple::OSType, 4> UnsupportedOSs; 28 SmallVector<Triple::EnvironmentType, 1> UnsupportedEnvironments; 29 protected: 30 // This is intended for platform as a temporary "XFAIL" 31 bool isUnsupportedOSOrEnvironment() { 32 Triple Host(Triple::normalize(sys::getProcessTriple())); 33 34 if (find(UnsupportedEnvironments, Host.getEnvironment()) != 35 UnsupportedEnvironments.end()) 36 return true; 37 38 if (is_contained(UnsupportedOSs, Host.getOS())) 39 return true; 40 41 if (is_contained(UnsupportedArchs, Host.getArch())) 42 return true; 43 44 return false; 45 } 46 47 ThreadPoolTest() { 48 // Add unsupported configuration here, example: 49 // UnsupportedArchs.push_back(Triple::x86_64); 50 51 // See https://llvm.org/bugs/show_bug.cgi?id=25829 52 UnsupportedArchs.push_back(Triple::ppc64le); 53 UnsupportedArchs.push_back(Triple::ppc64); 54 } 55 56 /// Make sure this thread not progress faster than the main thread. 57 void waitForMainThread() { 58 std::unique_lock<std::mutex> LockGuard(WaitMainThreadMutex); 59 WaitMainThread.wait(LockGuard, [&] { return MainThreadReady; }); 60 } 61 62 /// Set the readiness of the main thread. 63 void setMainThreadReady() { 64 { 65 std::unique_lock<std::mutex> LockGuard(WaitMainThreadMutex); 66 MainThreadReady = true; 67 } 68 WaitMainThread.notify_all(); 69 } 70 71 void SetUp() override { MainThreadReady = false; } 72 73 std::condition_variable WaitMainThread; 74 std::mutex WaitMainThreadMutex; 75 bool MainThreadReady; 76 77 }; 78 79 #define CHECK_UNSUPPORTED() \ 80 do { \ 81 if (isUnsupportedOSOrEnvironment()) \ 82 return; \ 83 } while (0); \ 84 85 TEST_F(ThreadPoolTest, AsyncBarrier) { 86 CHECK_UNSUPPORTED(); 87 // test that async & barrier work together properly. 88 89 std::atomic_int checked_in{0}; 90 91 ThreadPool Pool; 92 for (size_t i = 0; i < 5; ++i) { 93 Pool.async([this, &checked_in, i] { 94 waitForMainThread(); 95 ++checked_in; 96 }); 97 } 98 ASSERT_EQ(0, checked_in); 99 setMainThreadReady(); 100 Pool.wait(); 101 ASSERT_EQ(5, checked_in); 102 } 103 104 static void TestFunc(std::atomic_int &checked_in, int i) { checked_in += i; } 105 106 TEST_F(ThreadPoolTest, AsyncBarrierArgs) { 107 CHECK_UNSUPPORTED(); 108 // Test that async works with a function requiring multiple parameters. 109 std::atomic_int checked_in{0}; 110 111 ThreadPool Pool; 112 for (size_t i = 0; i < 5; ++i) { 113 Pool.async(TestFunc, std::ref(checked_in), i); 114 } 115 Pool.wait(); 116 ASSERT_EQ(10, checked_in); 117 } 118 119 TEST_F(ThreadPoolTest, Async) { 120 CHECK_UNSUPPORTED(); 121 ThreadPool Pool; 122 std::atomic_int i{0}; 123 Pool.async([this, &i] { 124 waitForMainThread(); 125 ++i; 126 }); 127 Pool.async([&i] { ++i; }); 128 ASSERT_NE(2, i.load()); 129 setMainThreadReady(); 130 Pool.wait(); 131 ASSERT_EQ(2, i.load()); 132 } 133 134 TEST_F(ThreadPoolTest, GetFuture) { 135 CHECK_UNSUPPORTED(); 136 ThreadPool Pool{2}; 137 std::atomic_int i{0}; 138 Pool.async([this, &i] { 139 waitForMainThread(); 140 ++i; 141 }); 142 // Force the future using get() 143 Pool.async([&i] { ++i; }).get(); 144 ASSERT_NE(2, i.load()); 145 setMainThreadReady(); 146 Pool.wait(); 147 ASSERT_EQ(2, i.load()); 148 } 149 150 TEST_F(ThreadPoolTest, PoolDestruction) { 151 CHECK_UNSUPPORTED(); 152 // Test that we are waiting on destruction 153 std::atomic_int checked_in{0}; 154 { 155 ThreadPool Pool; 156 for (size_t i = 0; i < 5; ++i) { 157 Pool.async([this, &checked_in, i] { 158 waitForMainThread(); 159 ++checked_in; 160 }); 161 } 162 ASSERT_EQ(0, checked_in); 163 setMainThreadReady(); 164 } 165 ASSERT_EQ(5, checked_in); 166 } 167