ThreadPool.cpp 4.5 KB

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