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