Browse Source

test: racing test of BasicRanges

master
Dnomd343 1 month 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) {
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<int> 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();
}

57
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();
}

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::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<int> counter_ {0};
std::atomic_flag condition_ {false};
};
/// 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
/// function to a certain number of threads at one time.
#include <memory>
#include <functional>
#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<void(std::function<void()> &&)> 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<void()> &&item) {
item_ = std::move(item);
pool_.detach_sequence(0, Num, [this](const int) {
item_(); // execute racing function
});
void Start(std::function<void()> &&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<void()> item_;
BS::thread_pool pool_ { Num };
const int race_num_;
BS::thread_pool pool_;
};
} // namespace co

6
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 <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));
}
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));
}

Loading…
Cancel
Save