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 (std::find(UnsupportedEnvironments.begin(), UnsupportedEnvironments.end(), 35 Host.getEnvironment()) != UnsupportedEnvironments.end()) 36 return true; 37 38 if (std::find(UnsupportedOSs.begin(), UnsupportedOSs.end(), Host.getOS()) 39 != UnsupportedOSs.end()) 40 return true; 41 42 if (std::find(UnsupportedArchs.begin(), UnsupportedArchs.end(), Host.getArch()) 43 != UnsupportedArchs.end()) 44 return true; 45 46 return false; 47 } 48 49 ThreadPoolTest() { 50 // Add unsupported configuration here, example: 51 // UnsupportedArchs.push_back(Triple::x86_64); 52 53 // See https://llvm.org/bugs/show_bug.cgi?id=25829 54 UnsupportedArchs.push_back(Triple::ppc64le); 55 UnsupportedArchs.push_back(Triple::ppc64); 56 } 57 58 /// Make sure this thread not progress faster than the main thread. 59 void waitForMainThread() { 60 std::unique_lock<std::mutex> LockGuard(WaitMainThreadMutex); 61 WaitMainThread.wait(LockGuard, [&] { return MainThreadReady; }); 62 } 63 64 /// Set the readiness of the main thread. 65 void setMainThreadReady() { 66 { 67 std::unique_lock<std::mutex> LockGuard(WaitMainThreadMutex); 68 MainThreadReady = true; 69 } 70 WaitMainThread.notify_all(); 71 } 72 73 void SetUp() override { MainThreadReady = false; } 74 75 std::condition_variable WaitMainThread; 76 std::mutex WaitMainThreadMutex; 77 bool MainThreadReady; 78 79 }; 80 81 #define CHECK_UNSUPPORTED() \ 82 do { \ 83 if (isUnsupportedOSOrEnvironment()) \ 84 return; \ 85 } while (0); \ 86 87 TEST_F(ThreadPoolTest, AsyncBarrier) { 88 CHECK_UNSUPPORTED(); 89 // test that async & barrier work together properly. 90 91 std::atomic_int checked_in{0}; 92 93 ThreadPool Pool; 94 for (size_t i = 0; i < 5; ++i) { 95 Pool.async([this, &checked_in, i] { 96 waitForMainThread(); 97 ++checked_in; 98 }); 99 } 100 ASSERT_EQ(0, checked_in); 101 setMainThreadReady(); 102 Pool.wait(); 103 ASSERT_EQ(5, checked_in); 104 } 105 106 static void TestFunc(std::atomic_int &checked_in, int i) { checked_in += i; } 107 108 TEST_F(ThreadPoolTest, AsyncBarrierArgs) { 109 CHECK_UNSUPPORTED(); 110 // Test that async works with a function requiring multiple parameters. 111 std::atomic_int checked_in{0}; 112 113 ThreadPool Pool; 114 for (size_t i = 0; i < 5; ++i) { 115 Pool.async(TestFunc, std::ref(checked_in), i); 116 } 117 Pool.wait(); 118 ASSERT_EQ(10, checked_in); 119 } 120 121 TEST_F(ThreadPoolTest, Async) { 122 CHECK_UNSUPPORTED(); 123 ThreadPool Pool; 124 std::atomic_int i{0}; 125 Pool.async([this, &i] { 126 waitForMainThread(); 127 ++i; 128 }); 129 Pool.async([&i] { ++i; }); 130 ASSERT_NE(2, i.load()); 131 setMainThreadReady(); 132 Pool.wait(); 133 ASSERT_EQ(2, i.load()); 134 } 135 136 TEST_F(ThreadPoolTest, GetFuture) { 137 CHECK_UNSUPPORTED(); 138 ThreadPool Pool; 139 std::atomic_int i{0}; 140 Pool.async([this, &i] { 141 waitForMainThread(); 142 ++i; 143 }); 144 // Force the future using get() 145 Pool.async([&i] { ++i; }).get(); 146 ASSERT_NE(2, i.load()); 147 setMainThreadReady(); 148 Pool.wait(); 149 ASSERT_EQ(2, i.load()); 150 } 151 152 TEST_F(ThreadPoolTest, PoolDestruction) { 153 CHECK_UNSUPPORTED(); 154 // Test that we are waiting on destruction 155 std::atomic_int checked_in{0}; 156 { 157 ThreadPool Pool; 158 for (size_t i = 0; i < 5; ++i) { 159 Pool.async([this, &checked_in, i] { 160 waitForMainThread(); 161 ++checked_in; 162 }); 163 } 164 ASSERT_EQ(0, checked_in); 165 setMainThreadReady(); 166 } 167 ASSERT_EQ(5, checked_in); 168 } 169