From b8d30034bb71f3136168f1c19db4486886f2fb5f Mon Sep 17 00:00:00 2001 From: Dnomd343 Date: Sat, 1 Jun 2024 16:22:33 +0800 Subject: [PATCH] test: racing test of BasicRanges --- src/core_test/cases/all_cases.cc | 12 +++--- src/core_test/cases/basic_ranges.cc | 57 +++++++++++++++++++++++++++-- src/core_test/cases/helper.h | 13 +++++-- src/core_test/utility/concurrent.h | 38 +++++++++++-------- src/core_test/utility/hash.h | 6 +-- 5 files changed, 96 insertions(+), 30 deletions(-) diff --git a/src/core_test/cases/all_cases.cc b/src/core_test/cases/all_cases.cc index 6190346..3a6fab1 100644 --- a/src/core_test/cases/all_cases.cc +++ b/src/core_test/cases/all_cases.cc @@ -79,7 +79,7 @@ TEST_FF(AllCases, all_cases) { } TEST_FF(AllCases, all_cases_race) { - racer_.Begin([] { + racer_.Start([] { AllCases::instance().build(); }); EXPECT_FALSE(Available()); @@ -112,7 +112,7 @@ TEST_FF(AllCases, all_cases_async) { std::atomic_flag flag; flag.clear(); - AllCases::instance().build_parallel_async(executor_.Entry(), [&flag]() { + AllCases::instance().build_async(executor_.Entry(), [&flag]() { flag.test_and_set(); flag.notify_all(); }); @@ -122,7 +122,7 @@ TEST_FF(AllCases, all_cases_async) { Verify(); flag.clear(); - AllCases::instance().build_parallel_async(executor_.Entry(), [&flag]() { + AllCases::instance().build_async(executor_.Entry(), [&flag]() { flag.test_and_set(); flag.notify_all(); }); @@ -135,8 +135,8 @@ TEST_FF(AllCases, all_cases_async) { TEST_FF(AllCases, all_cases_async_race) { std::atomic callback_num(0); - racer_.Begin([this, &callback_num] { - AllCases::instance().build_parallel_async(executor_.Entry(), [&callback_num]() { + racer_.Start([this, &callback_num] { + AllCases::instance().build_async(executor_.Entry(), [&callback_num]() { callback_num.fetch_add(1); }); }); @@ -144,6 +144,6 @@ TEST_FF(AllCases, all_cases_async_race) { racer_.Join(); EXPECT_TRUE(Available()); - EXPECT_EQ(callback_num.load(), co::Racer::Num); + EXPECT_EQ(callback_num.load(), racer_.RaceNum()); Verify(); } diff --git a/src/core_test/cases/basic_ranges.cc b/src/core_test/cases/basic_ranges.cc index e0ced0d..68964c0 100644 --- a/src/core_test/cases/basic_ranges.cc +++ b/src/core_test/cases/basic_ranges.cc @@ -23,13 +23,14 @@ protected: /// Verify that whether basic ranges data is correct. static void Verify() { const auto &basic_ranges = BasicRanges::instance().fetch(); - EXPECT_EQ(basic_ranges.size(), BASIC_RANGES_NUM); // verify basic ranges size + EXPECT_EQ(basic_ranges.size(), BASIC_RANGES_NUM_); // verify basic ranges size EXPECT_EQ(hash::xxh3(basic_ranges), BASIC_RANGES_XXH3); // verify basic ranges checksum } }; TEST_FF(BasicRanges, constant) { - EXPECT_EQ(BASIC_RANGES_NUM, 7311885); + // TODO: check BASIC_RANGES_NUM array + EXPECT_EQ(BASIC_RANGES_NUM_, 7311885); } TEST_FF(BasicRanges, basic_ranges) { @@ -43,7 +44,7 @@ TEST_FF(BasicRanges, basic_ranges) { } TEST_FF(BasicRanges, basic_ranges_race) { - racer_.Begin([] { + racer_.Start([] { BasicRanges::instance().build(); }); EXPECT_FALSE(Available()); @@ -51,3 +52,53 @@ TEST_FF(BasicRanges, basic_ranges_race) { EXPECT_TRUE(Available()); Verify(); } + +TEST_FF(BasicRanges, basic_ranges_async) { + condition_.clear(); + BasicRanges::instance().build_async(executor_.Entry(), [this] { + EXPECT_FALSE(condition_.test_and_set()); + condition_.notify_all(); + }); + EXPECT_FALSE(Available()); + condition_.wait(false); + EXPECT_TRUE(Available()); + Verify(); + + condition_.clear(); + BasicRanges::instance().build_async(executor_.Entry(), [this] { + EXPECT_FALSE(condition_.test_and_set()); + condition_.notify_all(); + }); + EXPECT_TRUE(Available()); + condition_.wait(false); + EXPECT_TRUE(Available()); + Verify(); +} + +TEST_FF(BasicRanges, basic_ranges_async_race) { + counter_.store(0); + racer_.Start([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(); +} + +TEST_FF(BasicRanges, basic_ranges_async_block) { + condition_.clear(); + serial_.Entry()([this] { + BasicRanges::instance().build_async(serial_.Entry(), [this] { + EXPECT_FALSE(condition_.test_and_set()); + condition_.notify_all(); + }); + }); + EXPECT_FALSE(Available()); + condition_.wait(false); + EXPECT_TRUE(Available()); + Verify(); +} diff --git a/src/core_test/cases/helper.h b/src/core_test/cases/helper.h index 29776ab..374e29c 100644 --- a/src/core_test/cases/helper.h +++ b/src/core_test/cases/helper.h @@ -10,13 +10,20 @@ using klotski::cases::BasicRanges; using klotski::cases::ALL_CASES_NUM; using klotski::cases::ALL_CASES_NUM_; + using klotski::cases::BASIC_RANGES_NUM; +using klotski::cases::BASIC_RANGES_NUM_; -/// Test fixture wrapper with Racer and Executor. +/// Test fixture wrapper with concurrency tools. class Concurrent { protected: - co::Racer racer_; - co::Executor executor_; + co::Racer racer_ {256}; + + co::Executor serial_ {1}; + co::Executor executor_ {0}; + + std::atomic counter_ {0}; + std::atomic_flag condition_ {false}; }; /// Forcibly modify private variables to reset state. diff --git a/src/core_test/utility/concurrent.h b/src/core_test/utility/concurrent.h index 2a13418..4086a77 100644 --- a/src/core_test/utility/concurrent.h +++ b/src/core_test/utility/concurrent.h @@ -5,7 +5,6 @@ /// and dispatch them to different threads. The Racer schedules the specified /// function to a certain number of threads at one time. -#include #include #include "BS_thread_pool.hpp" @@ -14,8 +13,7 @@ namespace co { class Executor final { public: - Executor() = default; - ~Executor() { pool_.wait(); } + explicit Executor(const int num) : pool_(num) {} std::function &&)> Entry() { return [this](auto &&func) { @@ -23,30 +21,40 @@ public: }; } + ~Executor() { + pool_.wait(); + } + private: BS::thread_pool pool_; }; class Racer final { public: - Racer() = default; - ~Racer() { Join(); } + explicit Racer(const int num) : race_num_(num), pool_(num) {} - static constexpr int Num = 256; // number of racing threads + int RaceNum() const { + return race_num_; // number of racing threads + } - void Begin(std::function &&item) { - item_ = std::move(item); - pool_.detach_sequence(0, Num, [this](const int) { - item_(); // execute racing function - }); + 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(); } + void Join() { + pool_.wait(); + } + + ~Racer() { + Join(); + } private: - std::function item_; - BS::thread_pool pool_ { Num }; + const int race_num_; + BS::thread_pool pool_; }; - } // namespace co diff --git a/src/core_test/utility/hash.h b/src/core_test/utility/hash.h index a2cfcf0..ca765a1 100644 --- a/src/core_test/utility/hash.h +++ b/src/core_test/utility/hash.h @@ -12,7 +12,7 @@ namespace hash { inline std::string md5(const void *data, const uint64_t size) { - return ::md5::MD5::Hash(data, size); + return md5::MD5::Hash(data, size); } inline uint64_t xxh3(const void *data, const uint64_t size) { @@ -28,12 +28,12 @@ inline uint64_t xxh3(const std::string_view &data) { } template -inline std::string md5(const std::vector &data) { +std::string md5(const std::vector &data) { return md5(data.data(), data.size() * sizeof(T)); } template -inline uint64_t xxh3(const std::vector &data) { +uint64_t xxh3(const std::vector &data) { return xxh3(data.data(), data.size() * sizeof(T)); }