// 2018/12/04 - modified by Tsung-Wei Huang // - replaced privatized threadpool with work stealing threadpool // // 2018/12/03 - modified by Tsung-Wei Huang // - added work stealing queue tests // // 2018/11/29 - modified by Chun-Xun Lin // - added batch tests // // 2018/10/04 - modified by Tsung-Wei Huang // - removed binary tree tests // - removed spawn/shutdown tests // - removed siltne_async and async tests // - added emplace test // - adopted the new thread pool implementation // // 2018/09/29 - modified by Tsung-Wei Huang // - added binary tree tests // - added worker queue tests // - added external thread tests // - refactored threadpool tests // // 2018/09/13 - modified by Tsung-Wei Huang & Chun-Xun // - added tests for ownership // - modified spawn-shutdown tests // // 2018/09/10 - modified by Tsung-Wei Huang // - added tests for SpeculativeThreadpool // - added dynamic tasking tests // - added spawn and shutdown tests // // 2018/09/02 - created by Guannan // - test_silent_async // - test_async // - test_wait_for_all #define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN #include #include // ============================================================================ // WorkStealingQueue tests // ============================================================================ // Procedure: wsq_test_owner void wsq_test_owner() { int64_t cap = 2; tf::WorkStealingQueue queue(cap); std::deque gold; REQUIRE(queue.capacity() == 2); REQUIRE(queue.empty()); for(int i=2; i<=(1<<20); i <<= 1) { REQUIRE(queue.empty()); for(int j=0; j queue(cap); REQUIRE(queue.capacity() == 2); REQUIRE(queue.empty()); for(int i=2; i<=(1<<20); i <<= 1) { REQUIRE(queue.empty()); int p = 0; std::vector> cdeqs(N); std::vector consumers; std::deque pdeq; auto num_stolen = [&] () { int total = 0; for(const auto& cdeq : cdeqs) { total += cdeq.size(); } return total; }; for(int n=0; n set; for(const auto& cdeq : cdeqs) { for(auto k : cdeq) { set.insert(k); } } for(auto k : pdeq) { set.insert(k); } for(int j=0; j void test_ownership(ThreadpoolType& tp) { REQUIRE(tp.is_owner()); tp.emplace([&](){ if(tp.num_workers() == 0) { REQUIRE(tp.is_owner()); } else { REQUIRE(!tp.is_owner()); } }); std::vector threads; for(int i=0; i<10; ++i) { threads.emplace_back([&] () { REQUIRE(!tp.is_owner()); }); } for(auto& t : threads) { t.join(); } } // Procedure: test_emplace template void test_emplace(ThreadpoolType& tp) { constexpr size_t num_tasks = 1024; std::atomic counter{0}; for(size_t i=0; i void test_dynamic_tasking(T& threadpool) { std::atomic sum {0}; std::atomic cnt {0}; std::function insert; std::promise promise; auto future = promise.get_future(); insert = [&threadpool, &insert, &sum, &promise, &cnt] (int i) { if(i > 0) { ++cnt; threadpool.emplace([i=i-1, &insert] () { insert(i); }); } else { if(auto s = ++sum; s == threadpool.num_workers()) { promise.set_value(1); } } }; if(auto W = threadpool.num_workers(); W > 0) { for(size_t i=0; i void test_external_threads(T& threadpool) { constexpr int num_tasks = 65536; std::vector threads; std::atomic sum {0}; for(int i=0; i<10; ++i) { threads.emplace_back([&] () { std::this_thread::sleep_for(std::chrono::microseconds(100)); for(int j=0; j void test_batch_insertion(T& threadpool) { constexpr int num_iterations = 50; size_t total {0}; std::atomic count {0}; for(size_t i=1; i> funs; for(size_t j=0; j void test_threadpool() { SUBCASE("Ownership") { for(unsigned i=0; i<=4; ++i) { T tp(i); test_ownership(tp); } } SUBCASE("Emplace") { for(unsigned i=0; i<=4; ++i) { T tp(i); test_emplace(tp); } } SUBCASE("DynamicTasking") { for(unsigned i=0; i<=4; ++i) { T tp(i); test_dynamic_tasking(tp); } } SUBCASE("ExternalThreads") { for(unsigned i=0; i<=4; ++i) { T tp(i); test_external_threads(tp); } } SUBCASE("Batch") { for(unsigned i=0; i<=4; ++i) { T tp(i); test_batch_insertion(tp); } } } // ---------------------------------------------------------------------------- // Testcase: SimpleThreadpool // ---------------------------------------------------------------------------- TEST_CASE("SimpleThreadpool" * doctest::timeout(300)) { test_threadpool>>(); } // ---------------------------------------------------------------------------- // Testcase: ProactiveThreadpool // ---------------------------------------------------------------------------- TEST_CASE("ProactiveThreadpool" * doctest::timeout(300)) { test_threadpool>>(); } // ---------------------------------------------------------------------------- // Testcase: SpeculativeThreadpool // ---------------------------------------------------------------------------- TEST_CASE("SpeculativeThreadpool" * doctest::timeout(300)) { test_threadpool>>(); } // ---------------------------------------------------------------------------- // Testcase: WorkStealingThreadpool // ---------------------------------------------------------------------------- TEST_CASE("WorkStealingThreadpool" * doctest::timeout(300)) { test_threadpool>>(); }