ThreadPool.cpp 4.2 KB

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