From f0a8d401f3257508529b9ce9b44836358973440b Mon Sep 17 00:00:00 2001 From: Dnomd343 Date: Thu, 2 Mar 2023 19:05:27 +0800 Subject: [PATCH] update: enhance benchmark module --- src/klotski_core/benchmark/benchmark.cc | 91 ++++++++++++++++++++++++- src/klotski_core/benchmark/benchmark.h | 21 +++--- src/klotski_core/benchmark/chore.cc | 36 +++++++++- src/klotski_core/ffi/tmain.cc | 63 ++++++++++++----- 4 files changed, 182 insertions(+), 29 deletions(-) diff --git a/src/klotski_core/benchmark/benchmark.cc b/src/klotski_core/benchmark/benchmark.cc index 2b7ad16..520aa60 100644 --- a/src/klotski_core/benchmark/benchmark.cc +++ b/src/klotski_core/benchmark/benchmark.cc @@ -1,8 +1,23 @@ +#include "common.h" #include "benchmark.h" #include "all_cases.h" using klotski::Benchmark; +/// ----------------------------- Benchmark Utils ----------------------------- + +double Benchmark::range_flip(TIME format) noexcept { + uint32_t num = 0; + auto start = clock(); + for (uint32_t i = 0; i < 0x1'0000'0000 - 0xF; i += 0xE) { + Common::range_reverse(i); + ++num; + } + return time_format(start, format) / (double)num; +} + +/// --------------------------- Benchmark AllCases ---------------------------- + double Benchmark::basic_ranges(TIME format) noexcept { if (BasicRanges::status() != BasicRanges::NO_INIT) { return -1; // data already built -> skip @@ -22,12 +37,82 @@ double Benchmark::all_cases(TIME format) noexcept { return time_format(start, format); } +/// -------------------------- Benchmark Code Check --------------------------- + +double Benchmark::raw_code_check(TIME format) noexcept { + if (!data_ready) { + return -1; // data no ready -> skip + } + auto start = clock(); + for (auto &&raw_code : all_raw_codes) { + raw_code.valid(); + } + return time_format(start, format) / (double)all_raw_codes.size(); +} + +double Benchmark::short_code_check(TIME format) noexcept { + if (!data_ready) { + return -1; // data no ready -> skip + } + auto start = clock(); + for (auto &&short_code : all_short_codes) { + short_code.valid(); + } + return time_format(start, format) / (double)all_short_codes.size(); +} + +double Benchmark::common_code_check(TIME format) noexcept { + if (!data_ready) { + return -1; // data no ready -> skip + } + auto start = clock(); + for (auto &&common_code : all_common_codes) { + common_code.valid(); + } + return time_format(start, format) / (double)all_common_codes.size(); +} + +double Benchmark::raw_code_check_random(TIME format) noexcept { + auto random_data = generate_u64_rand(klotski::ALL_CASES_SIZE_SUM); + for (auto &&val : random_data) { + val &= ~((uint64_t)0b1111 << 60); // clear high 4-bits + } + auto start = clock(); + for (auto &&raw_code : random_data) { + RawCode::check(raw_code); + } + return time_format(start, format) / (double)random_data.size(); +} + +double Benchmark::short_code_check_random(TIME format) noexcept { + auto random_data = generate_u32_rand(klotski::ALL_CASES_SIZE_SUM); + auto start = clock(); + for (auto &&short_code : random_data) { + ShortCode::check(short_code); + } + return time_format(start, format) / (double)random_data.size(); +} + +double Benchmark::common_code_check_random(TIME format) noexcept { + auto random_data = generate_u64_rand(klotski::ALL_CASES_SIZE_SUM); + for (auto &&val : random_data) { + val &= ~((uint64_t)0xFFFFFFF << 36); // clear high 28-bits + } + auto start = clock(); + for (auto &&common_code : random_data) { + CommonCode::check(common_code); + } + return time_format(start, format) / (double)random_data.size(); +} + +/// -------------------------- Benchmark Code String -------------------------- + double Benchmark::short_code_to_string(TIME format) noexcept { if (!data_ready) { return -1; // data no ready -> skip } auto start = clock(); - for (const auto &short_code : all_short_codes) { + for (auto &&short_code : all_short_codes) { short_code.to_string(); } return time_format(start, format) / (double)all_short_codes.size(); @@ -49,7 +134,7 @@ double Benchmark::common_code_to_string(TIME format) noexcept { return -1; // data no ready -> skip } auto start = clock(); - for (const auto &common_code : all_common_codes) { + for (auto &&common_code : all_common_codes) { common_code.to_string(); } return time_format(start, format) / (double)all_common_codes.size(); @@ -66,6 +151,8 @@ double Benchmark::common_code_from_string(TIME format) noexcept { return time_format(start, format) / (double)all_common_codes_str.size(); } +/// ------------------------- Benchmark Code Convert -------------------------- + double Benchmark::common_code_to_raw_code(TIME format) noexcept { if (!data_ready) { return -1; // data no ready -> skip diff --git a/src/klotski_core/benchmark/benchmark.h b/src/klotski_core/benchmark/benchmark.h index 5304993..0e1bc98 100644 --- a/src/klotski_core/benchmark/benchmark.h +++ b/src/klotski_core/benchmark/benchmark.h @@ -34,9 +34,19 @@ namespace klotski { static void data_preparation() noexcept; static double warm_up(uint64_t count) noexcept; + static double range_flip(TIME format = NS) noexcept; + static double all_cases(TIME format = MS) noexcept; static double basic_ranges(TIME format = MS) noexcept; + static double raw_code_check(TIME format = NS) noexcept; + static double short_code_check(TIME format = NS) noexcept; + static double common_code_check(TIME format = NS) noexcept; + + static double raw_code_check_random(TIME format = NS) noexcept; + static double short_code_check_random(TIME format = NS) noexcept; + static double common_code_check_random(TIME format = NS) noexcept; + static double short_code_to_string(TIME format = NS) noexcept; static double short_code_from_string(TIME format = NS) noexcept; @@ -52,14 +62,6 @@ namespace klotski { static double common_code_to_short_code_fast(TIME format = NS) noexcept; static double short_code_to_common_code_fast(TIME format = NS) noexcept; - -// static float codec_common_to_raw(TIME format = US); -// static float codec_raw_to_common(TIME format = US); -// static float codec_common_to_short(); -// static float codec_short_to_common(); -// static float codec_common_to_short_fast(); -// static float codec_short_to_common_fast(); - private: static bool data_ready; static std::vector all_raw_codes; @@ -68,6 +70,9 @@ namespace klotski { static std::vector all_short_codes_str; static std::vector all_common_codes_str; + static uint32_t random_seed() noexcept; static double time_format(clock_t start, TIME format) noexcept; + static std::vector generate_u32_rand(uint32_t count) noexcept; + static std::vector generate_u64_rand(uint32_t count) noexcept; }; } diff --git a/src/klotski_core/benchmark/chore.cc b/src/klotski_core/benchmark/chore.cc index c900ff2..1452070 100644 --- a/src/klotski_core/benchmark/chore.cc +++ b/src/klotski_core/benchmark/chore.cc @@ -1,4 +1,5 @@ -#include +#include +#include #include "benchmark.h" using klotski::RawCode; @@ -13,6 +14,12 @@ std::vector Benchmark::all_common_codes; std::vector Benchmark::all_short_codes_str; std::vector Benchmark::all_common_codes_str; +uint32_t Benchmark::random_seed() noexcept { + using namespace std::chrono; + auto tmp = system_clock::now().time_since_epoch(); + return duration_cast(tmp).count(); +} + double Benchmark::warm_up(uint64_t count) noexcept { auto start = clock(); volatile uint64_t tmp = 0; @@ -39,6 +46,33 @@ double Benchmark::time_format(clock_t start, TIME format) noexcept { return time / CLOCKS_PER_SEC; } +std::vector Benchmark::generate_u32_rand(uint32_t count) noexcept { + std::vector result; + result.reserve(count); + + auto seed = random_seed(); + auto high_bit = (uint32_t)seed << 31; + + std::srand(seed); + for (uint32_t i = 0; i < count; ++i) { + auto tmp = high_bit | static_cast(std::rand()); + result.emplace_back(tmp); + high_bit = tmp << 31; + } + return result; +} + +std::vector Benchmark::generate_u64_rand(uint32_t count) noexcept { + std::vector result; + result.reserve(count); + + auto tmp = generate_u32_rand(count * 2); + for (uint32_t i = 0; i < count; ++i) { + result.emplace_back((uint64_t)tmp[i * 2] << 32 | tmp[i * 2 + 1]); + } + return result; +} + void Benchmark::data_preparation() noexcept { if (Benchmark::data_ready) { return; diff --git a/src/klotski_core/ffi/tmain.cc b/src/klotski_core/ffi/tmain.cc index 8b33cc4..803c873 100644 --- a/src/klotski_core/ffi/tmain.cc +++ b/src/klotski_core/ffi/tmain.cc @@ -18,27 +18,54 @@ void tmain() { // std::cout << "warm up: " << Benchmark::warm_up(1000000) << "us" << std::endl; -// std::cout << "basic ranges: " << Benchmark::basic_ranges() << "ms" << std::endl; -// std::cout << "all cases: " << Benchmark::all_cases() << "ms" << std::endl; + std::cout << "range flip: " << + Benchmark::range_flip() << "ns" << std::endl; - Benchmark::data_preparation(); - - std::cout << "start benchmark" << std::endl; + std::cout << "basic ranges: " << + Benchmark::basic_ranges() << "ms" << std::endl; + std::cout << "all cases: " << + Benchmark::all_cases() << "ms" << std::endl; -// std::cout << Benchmark::short_code_to_string() << "ns" << std::endl; -// std::cout << Benchmark::short_code_from_string() << "ns" << std::endl; -// -// std::cout << Benchmark::common_code_to_string() << "ns" << std::endl; -// std::cout << Benchmark::common_code_from_string() << "ns" << std::endl; -// -// std::cout << Benchmark::common_code_to_raw_code() << "ns" << std::endl; -// std::cout << Benchmark::raw_code_to_common_code() << "ns" << std::endl; - - std::cout << Benchmark::common_code_to_short_code() << "ns" << std::endl; - std::cout << Benchmark::short_code_to_common_code() << "ns" << std::endl; + Benchmark::data_preparation(); - std::cout << Benchmark::common_code_to_short_code_fast() << "ns" << std::endl; - std::cout << Benchmark::short_code_to_common_code_fast() << "ns" << std::endl; + std::cout << "raw code check: " << + Benchmark::raw_code_check() << "ns" << std::endl; + std::cout << "short code check: " << + Benchmark::short_code_check() << "ns" << std::endl; + std::cout << "common code check: " << + Benchmark::common_code_check() << "ns" << std::endl; + + std::cout << "raw code check random: " << + Benchmark::raw_code_check_random() << "ns" << std::endl; + std::cout << "short code check random: " << + Benchmark::short_code_check_random() << "ns" << std::endl; + std::cout << "common code check random: " << + Benchmark::common_code_check_random() << "ns" << std::endl; + + std::cout << "short code to string: " << + Benchmark::short_code_to_string() << "ns" << std::endl; + std::cout << "short code from string: " << + Benchmark::short_code_from_string() << "ns" << std::endl; + + std::cout << "common code to string: " << + Benchmark::common_code_to_string() << "ns" << std::endl; + std::cout << "common code from string: " << + Benchmark::common_code_from_string() << "ns" << std::endl; + + std::cout << "common code to raw code: " << + Benchmark::common_code_to_raw_code() << "ns" << std::endl; + std::cout << "raw code to common code: " << + Benchmark::raw_code_to_common_code() << "ns" << std::endl; + + std::cout << "common code to short code: " << + Benchmark::common_code_to_short_code() << "ns" << std::endl; + std::cout << "short code to common code: " << + Benchmark::short_code_to_common_code() << "ns" << std::endl; + + std::cout << "common code to short code fast: " << + Benchmark::common_code_to_short_code_fast() << "ns" << std::endl; + std::cout << "short code to common code fast: " << + Benchmark::short_code_to_common_code_fast() << "ns" << std::endl; return;