Home | History | Annotate | Download | only in Support
      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