diff --git a/src/core_test/CMakeLists.txt b/src/core_test/CMakeLists.txt index d427993..ee1eac8 100644 --- a/src/core_test/CMakeLists.txt +++ b/src/core_test/CMakeLists.txt @@ -13,6 +13,7 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR}) # ------------------------------------------------------------------------------------ # add_library(test_helper + helper/internal/concurrent.cc helper/internal/parallel.cc helper/internal/hash.cc ) diff --git a/src/core_test/cases/all_cases.cc b/src/core_test/cases/all_cases.cc index ea3003b..1725532 100644 --- a/src/core_test/cases/all_cases.cc +++ b/src/core_test/cases/all_cases.cc @@ -106,11 +106,9 @@ TEST_FF(AllCases, all_cases) { } TEST_FF(AllCases, all_cases_race) { - racer_.Start([] { + racer_.Execute([] { AllCases::instance().build(); }); - EXPECT_FALSE(Available()); - racer_.Join(); EXPECT_TRUE(Available()); Verify(); } @@ -139,13 +137,11 @@ TEST_FF(AllCases, all_cases_async) { TEST_FF(AllCases, all_cases_async_race) { counter_.store(0); - racer_.Start([this] { + racer_.Execute([this] { AllCases::instance().build_async(executor_.Entry(), [this] { counter_.fetch_add(1); }); }); - EXPECT_FALSE(Available()); - racer_.Join(); EXPECT_TRUE(Available()); EXPECT_EQ(counter_.load(), racer_.RaceNum()); Verify(); diff --git a/src/core_test/cases/basic_ranges.cc b/src/core_test/cases/basic_ranges.cc index 98875dd..d76c825 100644 --- a/src/core_test/cases/basic_ranges.cc +++ b/src/core_test/cases/basic_ranges.cc @@ -74,11 +74,9 @@ TEST_FF(BasicRanges, basic_ranges) { } TEST_FF(BasicRanges, basic_ranges_race) { - racer_.Start([] { + racer_.Execute([] { BasicRanges::instance().build(); }); - EXPECT_FALSE(Available()); - racer_.Join(); EXPECT_TRUE(Available()); Verify(); } @@ -107,13 +105,11 @@ TEST_FF(BasicRanges, basic_ranges_async) { TEST_FF(BasicRanges, basic_ranges_async_race) { counter_.store(0); - racer_.Start([this] { + racer_.Execute([this] { BasicRanges::instance().build_async(executor_.Entry(), [this] { counter_.fetch_add(1); }); }); - EXPECT_FALSE(Available()); - racer_.Join(); EXPECT_TRUE(Available()); EXPECT_EQ(counter_.load(), racer_.RaceNum()); Verify(); diff --git a/src/core_test/cases/helper/cases.h b/src/core_test/cases/helper/cases.h index 685873b..ca3ab9e 100644 --- a/src/core_test/cases/helper/cases.h +++ b/src/core_test/cases/helper/cases.h @@ -4,7 +4,7 @@ #include #include "group/group.h" -#include "utility/concurrent.h" +#include "helper/concurrent.h" // ----------------------------------------------------------------------------------------- // @@ -33,13 +33,13 @@ constexpr auto Heads = std::to_array({ class Concurrent { protected: // Execute same task concurrently. - co::Racer racer_ {256}; + helper::Racer racer_ {}; // Execute assigned tasks one by one. - co::Executor serial_ {1}; + helper::Executor serial_ {1}; // Execute assigned tasks on all cores. - co::Executor executor_ {0}; + helper::Executor executor_ {0}; // Atomic helpers for multi-thread testing. std::atomic counter_ {0}; diff --git a/src/core_test/codec/short_code.cc b/src/core_test/codec/short_code.cc index e2369d8..8f8ab16 100644 --- a/src/core_test/codec/short_code.cc +++ b/src/core_test/codec/short_code.cc @@ -5,7 +5,7 @@ #include "helper/expect.h" #include "helper/parallel.h" #include "utility/exposer.h" -#include "utility/concurrent.h" +#include "helper/concurrent.h" #include "all_cases/all_cases.h" #include "short_code/short_code.h" @@ -23,8 +23,6 @@ using klotski::cases::ALL_CASES_NUM; using klotski::cases::ALL_CASES_NUM_; using klotski::codec::SHORT_CODE_LIMIT; -constexpr auto TEST_THREAD_NUM = 256; - /// Forcibly modify private variables to reset state. EXPOSE_VAR(AllCases, bool, available_) EXPOSE_VAR(BasicRanges, bool, available_) @@ -154,7 +152,7 @@ TEST(ShortCode, initialize) { } TEST(ShortCode, speed_up) { - co::Racer racer {TEST_THREAD_NUM}; + helper::Racer racer {}; static auto EXPECT_STAGE_0 = +[]() { EXPECT_FALSE(exposer::ShortCode_fast_()); @@ -182,18 +180,18 @@ TEST(ShortCode, speed_up) { speed_up_reset(); EXPECT_STAGE_0(); - racer.Race([] { ShortCode::speed_up(false); }); + racer.Execute([] { ShortCode::speed_up(false); }); EXPECT_STAGE_1(); - racer.Race([] { ShortCode::speed_up(true); }); + racer.Execute([] { ShortCode::speed_up(true); }); EXPECT_STAGE_2(); - racer.Race([] { ShortCode::speed_up(true); }); + racer.Execute([] { ShortCode::speed_up(true); }); EXPECT_STAGE_2(); - racer.Race([] { ShortCode::speed_up(false); }); + racer.Execute([] { ShortCode::speed_up(false); }); EXPECT_STAGE_2(); speed_up_reset(); EXPECT_STAGE_0(); - racer.Race([] { ShortCode::speed_up(true); }); + racer.Execute([] { ShortCode::speed_up(true); }); EXPECT_STAGE_2(); } diff --git a/src/core_test/helper/concurrent.h b/src/core_test/helper/concurrent.h new file mode 100644 index 0000000..3825d68 --- /dev/null +++ b/src/core_test/helper/concurrent.h @@ -0,0 +1,51 @@ +#pragma once + +/// The concurrency test helper class implements the Executor and Racer based +/// on the BS::thread_pool. The Executor allows you to submit multiple tasks +/// and dispatch them to different threads. The Racer schedules the specified +/// function to a certain number of threads at one time. + +#include +#include + +namespace helper { + +// ----------------------------------------------------------------------------------------- // + +class Executor final { +public: + /// Specify the number of threads, default to the number of CPU cores. + explicit Executor(const int num = 0) : pool_(num) {} + + /// Get the executor entry for submitting tasks. + std::function &&func)> Entry(); + + ~Executor(); + +private: + BS::thread_pool pool_; +}; + +// ----------------------------------------------------------------------------------------- // + +class Racer final { +public: + /// Create race tester with a specified number of concurrency. + explicit Racer(const int num = 256) : race_num_(num), pool_(num) {} + + /// Start the racing test process with specified number. + void Execute(std::function &&item); + + /// Get the number of concurrency in Racer. + int RaceNum() const; + + ~Racer(); + +private: + const int race_num_; + BS::thread_pool pool_; +}; + +// ----------------------------------------------------------------------------------------- // + +} // namespace helper diff --git a/src/core_test/helper/internal/concurrent.cc b/src/core_test/helper/internal/concurrent.cc new file mode 100644 index 0000000..960e4ff --- /dev/null +++ b/src/core_test/helper/internal/concurrent.cc @@ -0,0 +1,36 @@ +#include "helper/concurrent.h" + +using helper::Racer; +using helper::Executor; + +// ----------------------------------------------------------------------------------------- // + +std::function &&)> Executor::Entry() { + return [this](auto &&func) { + pool_.detach_task(func); + }; +} + +Executor::~Executor() { + pool_.wait(); +} + +// ----------------------------------------------------------------------------------------- // + +void Racer::Execute(std::function &&item) { + auto wrapper = [item = std::move(item)](const int) { + item(); // execute racing function + }; + pool_.detach_sequence(0, race_num_, wrapper); + pool_.wait(); +} + +int Racer::RaceNum() const { + return race_num_; // number of racing threads +} + +Racer::~Racer() { + pool_.wait(); +} + +// ----------------------------------------------------------------------------------------- // diff --git a/src/core_test/utility/concurrent.h b/src/core_test/utility/concurrent.h deleted file mode 100644 index 46e4a2d..0000000 --- a/src/core_test/utility/concurrent.h +++ /dev/null @@ -1,65 +0,0 @@ -#pragma once - -/// The concurrency test helper class implements the Executor and Racer based -/// on the BS::thread_pool. The Executor allows you to submit multiple tasks -/// and dispatch them to different threads. The Racer schedules the specified -/// function to a certain number of threads at one time. - -#include - -#include "BS_thread_pool.hpp" - -namespace co { - -class Executor final { -public: - explicit Executor(const int num) : pool_(num) {} - - std::function &&)> Entry() { - return [this](auto &&func) { - pool_.detach_task(func); - }; - } - - ~Executor() { - pool_.wait(); - } - -private: - BS::thread_pool pool_; -}; - -class Racer final { -public: - explicit Racer(const int num) : race_num_(num), pool_(num) {} - - int RaceNum() const { - return race_num_; // number of racing threads - } - - void Race(std::function &&item) { - Start(std::move(item)); - Join(); - } - - void Start(std::function &&item) { - auto wrapper = [item = std::move(item)](const int) { - item(); // execute racing function - }; - pool_.detach_sequence(0, race_num_, wrapper); - } - - void Join() { - pool_.wait(); - } - - ~Racer() { - Join(); - } - -private: - const int race_num_; - BS::thread_pool pool_; -}; - -} // namespace co