diff --git a/src/klotski_core/benchmark/benchmark.h b/src/klotski_core/benchmark/benchmark.h index 973c3e0..b7036aa 100644 --- a/src/klotski_core/benchmark/benchmark.h +++ b/src/klotski_core/benchmark/benchmark.h @@ -8,15 +8,16 @@ /// returned according to the specified time format (seconds, milliseconds, /// microseconds, nanoseconds). -/// The test items are all multi-thread safe(except `data_prepare`), but you -/// should not run multiple test items at the same time, which will lead to -/// unstable tests in many ways, such as changes in CPU turbo frequency. +/// The test items are all multi-thread safe, but you should not run multiple +/// test items at the same time, which will lead to unstable tests in many ways, +/// such as changes in CPU turbo frequency. /// Pay attention to the two test items `basic_ranges` and `all_cases`, they can /// only be run once (the reason for the construction of static data), and cannot /// be run after other global related items. #include +#include #include #include #include @@ -64,12 +65,14 @@ namespace klotski { private: static bool data_ready; + static std::mutex data_building; static std::vector all_raw_codes; static std::vector all_short_codes; static std::vector all_common_codes; static std::vector all_short_codes_str; static std::vector all_common_codes_str; + static void build_data() noexcept; 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; diff --git a/src/klotski_core/benchmark/chore.cc b/src/klotski_core/benchmark/chore.cc index 1452070..2226d7a 100644 --- a/src/klotski_core/benchmark/chore.cc +++ b/src/klotski_core/benchmark/chore.cc @@ -8,6 +8,7 @@ using klotski::CommonCode; using klotski::Benchmark; bool Benchmark::data_ready = false; +std::mutex Benchmark::data_building; std::vector Benchmark::all_raw_codes; std::vector Benchmark::all_short_codes; std::vector Benchmark::all_common_codes; @@ -74,10 +75,18 @@ std::vector Benchmark::generate_u64_rand(uint32_t count) noexcept { } void Benchmark::data_preparation() noexcept { - if (Benchmark::data_ready) { - return; + if (!Benchmark::data_ready) { + if (Benchmark::data_building.try_lock()) { // mutex lock success + build_data(); // start build process + Benchmark::data_ready = true; // set available flag + } else { + Benchmark::data_building.lock(); // blocking waiting + } + Benchmark::data_building.unlock(); // release mutex } +} +void Benchmark::build_data() noexcept { /// short code data preparation std::vector tmp(klotski::SHORT_CODE_LIMIT); std::iota(tmp.begin(), tmp.end(), 0); @@ -114,6 +123,4 @@ void Benchmark::data_preparation() noexcept { for (auto &&common_code : all_common_codes) { all_raw_codes.emplace_back(common_code.to_raw_code()); } - - Benchmark::data_ready = true; } diff --git a/src/rust_ffi/src/benchmark/ffi.rs b/src/rust_ffi/src/benchmark/ffi.rs index 181c13b..4429ee2 100644 --- a/src/rust_ffi/src/benchmark/ffi.rs +++ b/src/rust_ffi/src/benchmark/ffi.rs @@ -87,3 +87,197 @@ pub(crate) fn common_code_check_random() -> Duration { Duration::from_ns(Core::benchmark_common_code_check_random_ns()) } } + +pub(crate) fn short_code_to_string() -> Result { + unsafe { + let time = Core::benchmark_short_code_to_string_ns(); + match time.total_cmp(&(0 as f64)) { + Ordering::Greater => Ok(Duration::from_ns(time)), + _ => Err("data not ready"), + } + } +} + +pub(crate) fn short_code_from_string() -> Result { + unsafe { + let time = Core::benchmark_short_code_from_string_ns(); + match time.total_cmp(&(0 as f64)) { + Ordering::Greater => Ok(Duration::from_ns(time)), + _ => Err("data not ready"), + } + } +} + +pub(crate) fn common_code_to_string() -> Result { + unsafe { + let time = Core::benchmark_common_code_to_string_ns(); + match time.total_cmp(&(0 as f64)) { + Ordering::Greater => Ok(Duration::from_ns(time)), + _ => Err("data not ready"), + } + } +} + +pub(crate) fn common_code_from_string() -> Result { + unsafe { + let time = Core::benchmark_common_code_from_string_ns(); + match time.total_cmp(&(0 as f64)) { + Ordering::Greater => Ok(Duration::from_ns(time)), + _ => Err("data not ready"), + } + } +} + +pub(crate) fn common_code_to_raw_code() -> Result { + unsafe { + let time = Core::benchmark_common_code_to_raw_code_ns(); + match time.total_cmp(&(0 as f64)) { + Ordering::Greater => Ok(Duration::from_ns(time)), + _ => Err("data not ready"), + } + } +} + +pub(crate) fn raw_code_to_common_code() -> Result { + unsafe { + let time = Core::benchmark_raw_code_to_common_code_ns(); + match time.total_cmp(&(0 as f64)) { + Ordering::Greater => Ok(Duration::from_ns(time)), + _ => Err("data not ready"), + } + } +} + +pub(crate) fn common_code_to_short_code() -> Result { + unsafe { + let time = Core::benchmark_common_code_to_short_code_us(); + match time.total_cmp(&(0 as f64)) { + Ordering::Greater => Ok(Duration::from_us(time)), + _ => Err("data not ready"), + } + } +} + +pub(crate) fn short_code_to_common_code() -> Result { + unsafe { + let time = Core::benchmark_short_code_to_common_code_us(); + match time.total_cmp(&(0 as f64)) { + Ordering::Greater => Ok(Duration::from_us(time)), + _ => Err("data not ready"), + } + } +} + +pub(crate) fn common_code_to_short_code_fast() -> Result { + unsafe { + let time = Core::benchmark_common_code_to_short_code_fast_ns(); + match time.total_cmp(&(0 as f64)) { + Ordering::Greater => Ok(Duration::from_ns(time)), + _ => Err("data not ready"), + } + } +} + +pub(crate) fn short_code_to_common_code_fast() -> Result { + unsafe { + let time = Core::benchmark_short_code_to_common_code_fast_ns(); + match time.total_cmp(&(0 as f64)) { + Ordering::Greater => Ok(Duration::from_ns(time)), + _ => Err("data not ready"), + } + } +} + +pub(crate) fn vertical_mirror_check() -> Result { + unsafe { + let time = Core::benchmark_vertical_mirror_check_ns(); + match time.total_cmp(&(0 as f64)) { + Ordering::Greater => Ok(Duration::from_ns(time)), + _ => Err("data not ready"), + } + } +} + +pub(crate) fn horizontal_mirror_check() -> Result { + unsafe { + let time = Core::benchmark_horizontal_mirror_check_ns(); + match time.total_cmp(&(0 as f64)) { + Ordering::Greater => Ok(Duration::from_ns(time)), + _ => Err("data not ready"), + } + } +} + +pub(crate) fn vertical_mirror_convert() -> Result { + unsafe { + let time = Core::benchmark_vertical_mirror_convert_ns(); + match time.total_cmp(&(0 as f64)) { + Ordering::Greater => Ok(Duration::from_ns(time)), + _ => Err("data not ready"), + } + } +} + +pub(crate) fn horizontal_mirror_convert() -> Result { + unsafe { + let time = Core::benchmark_horizontal_mirror_convert_ns(); + match time.total_cmp(&(0 as f64)) { + Ordering::Greater => Ok(Duration::from_ns(time)), + _ => Err("data not ready"), + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn basic() { + range_flip(); + preparation(); + warm_up(0x1_000_000); + assert!(basic_ranges().is_err()); + assert!(all_cases().is_err()); + } + + #[test] + fn checker() { + preparation(); + raw_code_check_random(); + short_code_check_random(); + common_code_check_random(); + assert!(raw_code_check().is_ok()); + assert!(short_code_check().is_ok()); + assert!(common_code_check().is_ok()); + } + + #[test] + fn string() { + preparation(); + assert!(short_code_to_string().is_ok()); + assert!(short_code_from_string().is_ok()); + assert!(common_code_to_string().is_ok()); + assert!(common_code_from_string().is_ok()); + } + + #[test] + fn convert() { + preparation(); + assert!(common_code_to_raw_code().is_ok()); + assert!(raw_code_to_common_code().is_ok()); + assert!(common_code_to_short_code().is_ok()); + assert!(short_code_to_common_code().is_ok()); + assert!(common_code_to_short_code_fast().is_ok()); + assert!(short_code_to_common_code_fast().is_ok()); + } + + #[test] + fn mirror() { + preparation(); + assert!(vertical_mirror_check().is_ok()); + assert!(horizontal_mirror_check().is_ok()); + assert!(vertical_mirror_convert().is_ok()); + assert!(horizontal_mirror_convert().is_ok()); + } +} diff --git a/src/rust_ffi/src/benchmark/mod.rs b/src/rust_ffi/src/benchmark/mod.rs index 988c7d1..d1261d5 100644 --- a/src/rust_ffi/src/benchmark/mod.rs +++ b/src/rust_ffi/src/benchmark/mod.rs @@ -7,12 +7,7 @@ pub fn demo() { use ffi::*; - // println!("demo: {}", Duration::from_ps(233 as f64).to_string()); - // println!("demo: {}", Duration::from_ns(233 as f64).to_string()); - // println!("demo: {}", Duration::from_us(233 as f64).to_string()); - // println!("demo: {}", Duration::from_ms(233 as f64).to_string()); - // println!("demo: {}", Duration::from_ms(233000 as f64).to_string()); - + println!("start benchmark\n"); println!("warm up: {}", warm_up(0x100_0000)); println!("range flip: {}", range_flip()); @@ -30,6 +25,23 @@ pub fn demo() { println!("short code check random: {}", short_code_check_random()); println!("common code check random: {}", common_code_check_random()); - println!("benchmark complete"); + println!("short code to string: {}", short_code_to_string().unwrap()); + println!("short code from string: {}", short_code_from_string().unwrap()); + println!("common code to string: {}", common_code_to_string().unwrap()); + println!("common code from string: {}", common_code_from_string().unwrap()); + + println!("common code to raw code: {}", common_code_to_raw_code().unwrap()); + println!("raw code to common code: {}", raw_code_to_common_code().unwrap()); + println!("common code to short code: {}", common_code_to_short_code().unwrap()); + println!("short code to common code: {}", short_code_to_common_code().unwrap()); + println!("common code to short code fast: {}", common_code_to_short_code_fast().unwrap()); + println!("short code to common code fast: {}", short_code_to_common_code_fast().unwrap()); + + println!("vertical mirror check: {}", vertical_mirror_check().unwrap()); + println!("horizontal mirror check: {}", horizontal_mirror_check().unwrap()); + println!("vertical mirror convert: {}", vertical_mirror_convert().unwrap()); + println!("horizontal mirror convert: {}", horizontal_mirror_convert().unwrap()); + + println!("\nbenchmark complete"); }