diff --git a/src/core_test/CMakeLists.txt b/src/core_test/CMakeLists.txt index 252f3de..6a4293b 100644 --- a/src/core_test/CMakeLists.txt +++ b/src/core_test/CMakeLists.txt @@ -13,7 +13,7 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR}) # ------------------------------------------------------------------------------------ # add_library(test_helper - helper/internal/impl.cc + helper/internal/parallel.cc ) target_link_libraries(test_helper PRIVATE klotski_core bs::thread_pool) @@ -50,11 +50,10 @@ set(KLSK_TEST_CODEC_SRC codec/raw_code.cc codec/short_code.cc codec/common_code.cc - codec/helper/codec.cc ) add_executable(test_klotski_codec ${KLSK_TEST_CODEC_SRC}) -target_link_libraries(test_klotski_codec PRIVATE ${KLSK_TEST_DEPS}) +target_link_libraries(test_klotski_codec PRIVATE ${KLSK_TEST_DEPS} test_helper) add_test(NAME klotski_codec COMMAND test_klotski_codec) # ------------------------------------------------------------------------------------ # diff --git a/src/core_test/codec/common_code.cc b/src/core_test/codec/common_code.cc index c7032b0..84c02be 100644 --- a/src/core_test/codec/common_code.cc +++ b/src/core_test/codec/common_code.cc @@ -1,9 +1,10 @@ #include #include -#include -#include "helper/codec.h" -#include "helper/sample.h" +#include "test_samples.h" +#include "helper/expect.h" +#include "helper/parallel.h" + #include "raw_code/raw_code.h" #include "all_cases/all_cases.h" #include "short_code/short_code.h" @@ -197,14 +198,14 @@ TEST(CommonCode, code_string) { } TEST(CommonCode, DISABLED_global_verify) { - const auto result = parallel_spawn(0x10'0000'0000ULL, [](uint64_t start, uint64_t end) { - std::vector codes; + const auto result = SCOPE_PARALLEL(0x10'0000'0000ULL, [](uint64_t start, uint64_t end) { + std::vector codes; for (uint64_t common_code = start; common_code < end; ++common_code) { // brute-force search if (CommonCode::check(common_code)) { - codes.emplace_back(common_code); // found valid common code + codes.emplace_back(CommonCode::unsafe_create(common_code)); // found valid common code } } return codes; }); - EXPECT_EQ(result, all_common_codes()); + EXPECT_EQ(result, AllCases::instance().fetch().codes()); } diff --git a/src/core_test/codec/helper/codec.cc b/src/core_test/codec/helper/codec.cc deleted file mode 100644 index 0361923..0000000 --- a/src/core_test/codec/helper/codec.cc +++ /dev/null @@ -1,91 +0,0 @@ -#include - -#include "codec.h" - -using klotski::cases::AllCases; -using klotski::cases::ALL_CASES_NUM_; - -void head_parallel(std::function &&func) { - constexpr auto heads = std::to_array({ - 0, 1, 2, 4, 5, 6, 8, 9, 10, 12, 13, 14 - }); - BS::thread_pool pool; - for (auto head : heads) { - pool.detach_task([head, &func] { - func(head); - }); - } - pool.wait(); -} - -std::vector all_common_codes() { - // TODO: using `std::ranges` - std::vector common_codes; - common_codes.reserve(ALL_CASES_NUM_); - for (uint64_t head = 0; head < 16; ++head) { - for (auto range : AllCases::instance().fetch()[head]) { - common_codes.emplace_back(head << 32 | range); - } - } - return common_codes; -} - -void common_code_parallel(std::function)> &&func) { - - static auto codes = AllCases::instance().fetch().codes(); - - BS::thread_pool pool; - - // TODO: enhance performance - - pool.detach_blocks((uint64_t)0, codes.size(), [func = std::move(func)](auto start, auto end) { - - func(std::span {codes.data() + start, end - start}); - - }, 16); - - pool.wait(); - -} - -static std::vector convert(const std::vector &codes) { - std::vector result; - result.reserve(29334498); - for (auto code : codes) { - result.emplace_back(RawCode::from_common_code(code)); - } - return result; -} - -void raw_code_parallel(std::function)> &&func) { - - static auto codes = convert(AllCases::instance().fetch().codes()); - - BS::thread_pool pool; - pool.detach_blocks((uint64_t)0, codes.size(), [func = std::move(func)](auto start, auto end) { - - func(std::span {codes.data() + start, end - start}); - - }, 16); - - pool.wait(); - -} - -void short_code_parallel(std::function)> &&func) { - static auto codes = []() { - std::vector v (klotski::codec::SHORT_CODE_LIMIT); - std::iota(v.begin(), v.end(), 0); - return v; - }(); - - BS::thread_pool pool; - pool.detach_blocks((uint64_t)0, codes.size(), [func = std::move(func)](auto start, auto end) { - - auto span = std::span {codes.data() + start, end - start}; - func(std::bit_cast>(span)); - - }, 16); - - pool.wait(); -} diff --git a/src/core_test/codec/helper/codec.h b/src/core_test/codec/helper/codec.h deleted file mode 100644 index cbd42d2..0000000 --- a/src/core_test/codec/helper/codec.h +++ /dev/null @@ -1,66 +0,0 @@ -#pragma once - -#include -#include - -#include "raw_code/raw_code.h" -#include "all_cases/all_cases.h" -#include "short_code/short_code.h" -#include "common_code/common_code.h" - -using klotski::codec::RawCode; -using klotski::codec::ShortCode; -using klotski::codec::CommonCode; - -/// Build all valid CommonCodes. -std::vector all_common_codes(); - -// ----------------------------------------------------------------------------------------- // - -/// Capture ostream output as string. -template -std::string ostream_capture(T obj) { - std::ostringstream out; - out << obj; // ostream capture - return out.str(); -} - -#define EXPECT_OSTREAM(obj, expect) EXPECT_EQ(ostream_capture(obj), expect) - -// ----------------------------------------------------------------------------------------- // - -/// Spawn all valid RawCodes in parallel. -void raw_code_parallel(std::function)> &&func); - -/// Spawn all valid ShortCodes in parallel. -void short_code_parallel(std::function)> &&func); - -/// Spawn all valid CommonCodes in parallel. -void common_code_parallel(std::function)> &&func); - -#define CODE_PARALLEL(Type, type, impl) \ - type##_code_parallel([](std::span codes) { \ - for (auto code : codes) {impl} \ - }) - -#define RAW_CODE_PARALLEL(impl) CODE_PARALLEL(Raw, raw, impl) -#define SHORT_CODE_PARALLEL(impl) CODE_PARALLEL(Short, short, impl) -#define COMMON_CODE_PARALLEL(impl) CODE_PARALLEL(Common, common, impl) - -// ----------------------------------------------------------------------------------------- // - -/// Calculate multiple ranges separately and combine the results. -template -requires std::is_integral_v && std::is_invocable_v -auto parallel_spawn(T limit, F &&func) -> std::invoke_result_t { - BS::thread_pool pool; - std::invoke_result_t result; - for (auto &&future : pool.submit_blocks((T)0, limit, func, 0x1000)) { - const auto data = future.get(); - result.insert(result.end(), std::begin(data), std::end(data)); // combine sections - } - pool.wait(); - return result; -} - -// ----------------------------------------------------------------------------------------- // diff --git a/src/core_test/codec/raw_code.cc b/src/core_test/codec/raw_code.cc index 554d90e..de38adc 100644 --- a/src/core_test/codec/raw_code.cc +++ b/src/core_test/codec/raw_code.cc @@ -1,9 +1,10 @@ #include -#include + +#include "test_samples.h" +#include "helper/expect.h" +#include "helper/parallel.h" #include "utils/common.h" -#include "helper/codec.h" -#include "helper/sample.h" #include "raw_code/raw_code.h" #include "all_cases/all_cases.h" #include "common_code/common_code.h" @@ -166,14 +167,14 @@ TEST(RawCode, DISABLED_global_verify) { return raw_code; }; - const auto result = parallel_spawn(0x10'0000'0000ULL, [](uint64_t start, uint64_t end) { - std::vector codes; + const auto result = SCOPE_PARALLEL(0x10'0000'0000ULL, [](uint64_t start, uint64_t end) { + std::vector codes; for (uint64_t common_code = start; common_code < end; ++common_code) { if (RawCode::check(force_convert(common_code))) { - codes.emplace_back(common_code); // store valid code + codes.emplace_back(CommonCode::unsafe_create(common_code)); // store valid code } } return codes; }); - EXPECT_EQ(result, all_common_codes()); + EXPECT_EQ(result, AllCases::instance().fetch().codes()); } diff --git a/src/core_test/codec/short_code.cc b/src/core_test/codec/short_code.cc index 8577034..e2369d8 100644 --- a/src/core_test/codec/short_code.cc +++ b/src/core_test/codec/short_code.cc @@ -1,11 +1,12 @@ #include #include -#include -#include "helper/codec.h" -#include "helper/sample.h" +#include "test_samples.h" +#include "helper/expect.h" +#include "helper/parallel.h" #include "utility/exposer.h" #include "utility/concurrent.h" + #include "all_cases/all_cases.h" #include "short_code/short_code.h" #include "common_code/common_code.h" @@ -221,15 +222,15 @@ TEST(ShortCode, code_string) { TEST(ShortCode, DISABLED_global_verify) { speed_up_reset(); - const auto result = parallel_spawn(SHORT_CODE_LIMIT, [](uint32_t start, uint32_t end) { - std::vector codes; + const auto result = SCOPE_PARALLEL(SHORT_CODE_LIMIT, [](uint32_t start, uint32_t end) { + std::vector codes; codes.reserve(end - start); for (uint32_t short_code = start; short_code < end; ++short_code) { auto common_code = CommonCode::from_short_code(short_code).value(); // ShortCode::tiny_decode EXPECT_EQ(common_code.to_short_code(), short_code); // ShortCode::tiny_encode - codes.emplace_back(common_code.unwrap()); + codes.emplace_back(common_code); } return codes; }); - EXPECT_EQ(result, all_common_codes()); + EXPECT_EQ(result, AllCases::instance().fetch().codes()); } diff --git a/src/core_test/codec/helper/sample.h b/src/core_test/codec/test_samples.h similarity index 100% rename from src/core_test/codec/helper/sample.h rename to src/core_test/codec/test_samples.h diff --git a/src/core_test/helper/expect.h b/src/core_test/helper/expect.h new file mode 100644 index 0000000..59f3f25 --- /dev/null +++ b/src/core_test/helper/expect.h @@ -0,0 +1,18 @@ +#pragma once + +#include +#include + +// ----------------------------------------------------------------------------------------- // + +/// Capture ostream output as string. +template +std::string ostream_capture(T obj) { + std::ostringstream out; + out << obj; // ostream capture + return out.str(); +} + +#define EXPECT_OSTREAM(obj, expect) EXPECT_EQ(ostream_capture(obj), expect) + +// ----------------------------------------------------------------------------------------- // diff --git a/src/core_test/helper/internal/impl.cc b/src/core_test/helper/internal/parallel.cc similarity index 95% rename from src/core_test/helper/internal/impl.cc rename to src/core_test/helper/internal/parallel.cc index cbafd1b..0ab5b74 100644 --- a/src/core_test/helper/internal/impl.cc +++ b/src/core_test/helper/internal/parallel.cc @@ -10,6 +10,10 @@ using klotski::cases::AllCases; using klotski::cases::TYPE_ID_LIMIT; using klotski::cases::ALL_CASES_NUM_; +void helper::group_parallel(std::function &&func) { + // TODO: spawn all Groups +} + void helper::type_id_parallel(std::function &&func) { BS::thread_pool pool; diff --git a/src/core_test/helper/internal/parallel.inl b/src/core_test/helper/internal/parallel.inl new file mode 100644 index 0000000..f845365 --- /dev/null +++ b/src/core_test/helper/internal/parallel.inl @@ -0,0 +1,20 @@ +#pragma once + +#include + +namespace helper { + +template +requires std::is_integral_v && std::is_invocable_v +auto scope_parallel(T limit, F &&func) -> std::invoke_result_t { + BS::thread_pool pool; + std::invoke_result_t result; + for (auto &&future : pool.submit_blocks((T)0, limit, func, 0x1000)) { + const auto data = future.get(); + result.insert(result.end(), std::begin(data), std::end(data)); // combine sections + } + pool.wait(); + return result; +} + +} // namespace helper diff --git a/src/core_test/helper/mirror.h b/src/core_test/helper/mirror.h new file mode 100644 index 0000000..691943b --- /dev/null +++ b/src/core_test/helper/mirror.h @@ -0,0 +1,3 @@ +#pragma once + +// TODO: mirror convert of RawCode diff --git a/src/core_test/helper/parallel.h b/src/core_test/helper/parallel.h index cf241a9..982237d 100644 --- a/src/core_test/helper/parallel.h +++ b/src/core_test/helper/parallel.h @@ -1,30 +1,42 @@ #pragma once #include +#include +#include +#include "group/group.h" #include "raw_code/raw_code.h" #include "short_code/short_code.h" #include "common_code/common_code.h" +using klotski::cases::Group; +using klotski::cases::GroupUnion; + using klotski::codec::RawCode; using klotski::codec::ShortCode; using klotski::codec::CommonCode; -using klotski::cases::GroupUnion; - namespace helper { // ----------------------------------------------------------------------------------------- // +/// Spawn all valid Groups in parallel. +void group_parallel(std::function &&func); + +/// Spawn all valid type_ids in parallel. void type_id_parallel(std::function &&func); +/// Spawn all valid GroupUnions in parallel. void group_union_parallel(std::function &&func); +#define GROUP_PARALLEL(impl) \ + ::helper::group_parallel([](Group group) {impl}) + #define TYPE_ID_PARALLEL(impl) \ - helper::type_id_parallel([](uint32_t type_id) {impl}) + ::helper::type_id_parallel([](uint32_t type_id) {impl}) #define GROUP_UNION_PARALLEL(impl) \ - helper::group_union_parallel([](GroupUnion group_union) {impl}) + ::helper::group_union_parallel([](GroupUnion group_union) {impl}) // ----------------------------------------------------------------------------------------- // @@ -37,9 +49,9 @@ void short_code_parallel(std::function)> &&func); /// Spawn all valid CommonCodes in parallel. void common_code_parallel(std::function)> &&func); -#define CODE_PARALLEL(Type, type, impl) \ - helper::type##_code_parallel([](std::span codes) { \ - for (auto code : codes) {impl} \ +#define CODE_PARALLEL(Type, type, impl) \ + ::helper::type##_code_parallel([](std::span codes) { \ + for (auto code : codes) {impl} \ }) #define RAW_CODE_PARALLEL(impl) CODE_PARALLEL(Raw, raw, impl) @@ -48,4 +60,16 @@ void common_code_parallel(std::function)> &&func); // ----------------------------------------------------------------------------------------- // +/// Calculate multiple scopes separately and combine the results. +template +requires std::is_integral_v && std::is_invocable_v // func(start, end) +auto scope_parallel(T limit, F &&func) -> std::invoke_result_t; + +#define SCOPE_PARALLEL(limit, impl) \ + ::helper::scope_parallel(limit, impl) + +// ----------------------------------------------------------------------------------------- // + } // namespace helper + +#include "internal/parallel.inl"