Browse Source

test: racing test of BasicRanges

legacy
Dnomd343 7 months ago
parent
commit
b8d30034bb
  1. 12
      src/core_test/cases/all_cases.cc
  2. 57
      src/core_test/cases/basic_ranges.cc
  3. 13
      src/core_test/cases/helper.h
  4. 38
      src/core_test/utility/concurrent.h
  5. 6
      src/core_test/utility/hash.h

12
src/core_test/cases/all_cases.cc

@ -79,7 +79,7 @@ TEST_FF(AllCases, all_cases) {
} }
TEST_FF(AllCases, all_cases_race) { TEST_FF(AllCases, all_cases_race) {
racer_.Begin([] { racer_.Start([] {
AllCases::instance().build(); AllCases::instance().build();
}); });
EXPECT_FALSE(Available()); EXPECT_FALSE(Available());
@ -112,7 +112,7 @@ TEST_FF(AllCases, all_cases_async) {
std::atomic_flag flag; std::atomic_flag flag;
flag.clear(); flag.clear();
AllCases::instance().build_parallel_async(executor_.Entry(), [&flag]() { AllCases::instance().build_async(executor_.Entry(), [&flag]() {
flag.test_and_set(); flag.test_and_set();
flag.notify_all(); flag.notify_all();
}); });
@ -122,7 +122,7 @@ TEST_FF(AllCases, all_cases_async) {
Verify(); Verify();
flag.clear(); flag.clear();
AllCases::instance().build_parallel_async(executor_.Entry(), [&flag]() { AllCases::instance().build_async(executor_.Entry(), [&flag]() {
flag.test_and_set(); flag.test_and_set();
flag.notify_all(); flag.notify_all();
}); });
@ -135,8 +135,8 @@ TEST_FF(AllCases, all_cases_async) {
TEST_FF(AllCases, all_cases_async_race) { TEST_FF(AllCases, all_cases_async_race) {
std::atomic<int> callback_num(0); std::atomic<int> callback_num(0);
racer_.Begin([this, &callback_num] { racer_.Start([this, &callback_num] {
AllCases::instance().build_parallel_async(executor_.Entry(), [&callback_num]() { AllCases::instance().build_async(executor_.Entry(), [&callback_num]() {
callback_num.fetch_add(1); callback_num.fetch_add(1);
}); });
}); });
@ -144,6 +144,6 @@ TEST_FF(AllCases, all_cases_async_race) {
racer_.Join(); racer_.Join();
EXPECT_TRUE(Available()); EXPECT_TRUE(Available());
EXPECT_EQ(callback_num.load(), co::Racer::Num); EXPECT_EQ(callback_num.load(), racer_.RaceNum());
Verify(); Verify();
} }

57
src/core_test/cases/basic_ranges.cc

@ -23,13 +23,14 @@ protected:
/// Verify that whether basic ranges data is correct. /// Verify that whether basic ranges data is correct.
static void Verify() { static void Verify() {
const auto &basic_ranges = BasicRanges::instance().fetch(); 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 EXPECT_EQ(hash::xxh3(basic_ranges), BASIC_RANGES_XXH3); // verify basic ranges checksum
} }
}; };
TEST_FF(BasicRanges, constant) { 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) { TEST_FF(BasicRanges, basic_ranges) {
@ -43,7 +44,7 @@ TEST_FF(BasicRanges, basic_ranges) {
} }
TEST_FF(BasicRanges, basic_ranges_race) { TEST_FF(BasicRanges, basic_ranges_race) {
racer_.Begin([] { racer_.Start([] {
BasicRanges::instance().build(); BasicRanges::instance().build();
}); });
EXPECT_FALSE(Available()); EXPECT_FALSE(Available());
@ -51,3 +52,53 @@ TEST_FF(BasicRanges, basic_ranges_race) {
EXPECT_TRUE(Available()); EXPECT_TRUE(Available());
Verify(); 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();
}

13
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::ALL_CASES_NUM_; using klotski::cases::ALL_CASES_NUM_;
using klotski::cases::BASIC_RANGES_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 { class Concurrent {
protected: protected:
co::Racer racer_; co::Racer racer_ {256};
co::Executor executor_;
co::Executor serial_ {1};
co::Executor executor_ {0};
std::atomic<int> counter_ {0};
std::atomic_flag condition_ {false};
}; };
/// Forcibly modify private variables to reset state. /// Forcibly modify private variables to reset state.

38
src/core_test/utility/concurrent.h

@ -5,7 +5,6 @@
/// and dispatch them to different threads. The Racer schedules the specified /// and dispatch them to different threads. The Racer schedules the specified
/// function to a certain number of threads at one time. /// function to a certain number of threads at one time.
#include <memory>
#include <functional> #include <functional>
#include "BS_thread_pool.hpp" #include "BS_thread_pool.hpp"
@ -14,8 +13,7 @@ namespace co {
class Executor final { class Executor final {
public: public:
Executor() = default; explicit Executor(const int num) : pool_(num) {}
~Executor() { pool_.wait(); }
std::function<void(std::function<void()> &&)> Entry() { std::function<void(std::function<void()> &&)> Entry() {
return [this](auto &&func) { return [this](auto &&func) {
@ -23,30 +21,40 @@ public:
}; };
} }
~Executor() {
pool_.wait();
}
private: private:
BS::thread_pool pool_; BS::thread_pool pool_;
}; };
class Racer final { class Racer final {
public: public:
Racer() = default; explicit Racer(const int num) : race_num_(num), pool_(num) {}
~Racer() { Join(); }
static constexpr int Num = 256; // number of racing threads int RaceNum() const {
return race_num_; // number of racing threads
}
void Begin(std::function<void()> &&item) { void Start(std::function<void()> &&item) {
item_ = std::move(item); auto wrapper = [item = std::move(item)](const int) {
pool_.detach_sequence(0, Num, [this](const int) { item(); // execute racing function
item_(); // execute racing function };
}); pool_.detach_sequence(0, race_num_, wrapper);
} }
void Join() { pool_.wait(); } void Join() {
pool_.wait();
}
~Racer() {
Join();
}
private: private:
std::function<void()> item_; const int race_num_;
BS::thread_pool pool_ { Num }; BS::thread_pool pool_;
}; };
} // namespace co } // namespace co

6
src/core_test/utility/hash.h

@ -12,7 +12,7 @@
namespace hash { namespace hash {
inline std::string md5(const void *data, const uint64_t size) { 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) { 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 <typename T> template <typename T>
inline std::string md5(const std::vector<T> &data) { std::string md5(const std::vector<T> &data) {
return md5(data.data(), data.size() * sizeof(T)); return md5(data.data(), data.size() * sizeof(T));
} }
template <typename T> template <typename T>
inline uint64_t xxh3(const std::vector<T> &data) { uint64_t xxh3(const std::vector<T> &data) {
return xxh3(data.data(), data.size() * sizeof(T)); return xxh3(data.data(), data.size() * sizeof(T));
} }

Loading…
Cancel
Save