// 2019/05/15 - modified by Tsung-Wei Huang // - temporarily disable executor test // // 2019/04/11 - modified by Tsung-Wei Huang // - renamed threadpool to executor // // 2019/02/15 - modified by Tsung-Wei Huang // - modified batch tests (reference instead of move) // // 2018/12/04 - modified by Tsung-Wei Huang // - replaced privatized executor with work stealing executor // // 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 executor 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 SpeculativeExecutor // - 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 #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(ExecutorType& 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(ExecutorType& tp) { constexpr size_t num_tasks = 1024; std::atomic counter{0}; for(size_t i=0; i void test_dynamic_tasking(T& executor) { std::atomic sum {0}; std::atomic cnt {0}; std::function insert; std::promise promise; auto future = promise.get_future(); insert = [&executor, &insert, &sum, &promise, &cnt] (int i) { if(i > 0) { ++cnt; executor.emplace([i=i-1, &insert] () { insert(i); }); } else { if(auto s = ++sum; s == executor.num_workers()) { promise.set_value(1); } } }; if(auto W = executor.num_workers(); W > 0) { for(size_t i=0; i void test_external_threads(T& executor) { 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& executor) { 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_executor() { 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: SimpleExecutor // ---------------------------------------------------------------------------- TEST_CASE("SimpleExecutor" * doctest::timeout(300)) { test_executor>>(); } // ---------------------------------------------------------------------------- // Testcase: ProactiveExecutor // ---------------------------------------------------------------------------- TEST_CASE("ProactiveExecutor" * doctest::timeout(300)) { test_executor>>(); } // ---------------------------------------------------------------------------- // Testcase: SpeculativeExecutor // ---------------------------------------------------------------------------- TEST_CASE("SpeculativeExecutor" * doctest::timeout(300)) { test_executor>>(); } // ---------------------------------------------------------------------------- // Testcase: WorkStealingExecutor // ---------------------------------------------------------------------------- TEST_CASE("WorkStealingExecutor" * doctest::timeout(300)) { test_executor>>(); } // ---------------------------------------------------------------------------- // Testcase: EigenWorkStealingExecutor // ---------------------------------------------------------------------------- TEST_CASE("EigenWorkStealingExecutor" * doctest::timeout(300)) { test_executor>>(); } // ---------------------------------------------------------------------------- // Testcase: BinarySemaphore // ---------------------------------------------------------------------------- TEST_CASE("BinarySemaphore" * doctest::timeout(300)) { tf::BinarySemaphore sema; size_t count {0}; std::thread t1([&](){ using namespace std::chrono_literals; for(int i=0; i<100; i++) { std::this_thread::sleep_for(2ms); sema.P(); ++ count; } }); { using namespace std::chrono_literals; for(int i=0; i<100; i++) { sema.V(); std::this_thread::sleep_for(10ms); REQUIRE(count == i+1); } } t1.join(); count = 0; std::thread t2([&](){ using namespace std::chrono_literals; for(int i=0; i<10; i++) { std::this_thread::sleep_for(10ms); sema.V(); count += 1; } }); t2.join(); REQUIRE(count == 10); } */