From 3b66c609ca0064f2c8b2f67d5942505b80bf70f2 Mon Sep 17 00:00:00 2001 From: Dnomd343 Date: Sat, 23 Sep 2023 15:30:28 +0800 Subject: [PATCH] perf: high performance check range demo --- src/core/CMakeLists.txt | 2 +- src/core/all_cases/all_cases.cc | 139 ++++++++++++++++++++++++++++++++ src/core/all_cases/all_cases.h | 2 + src/core/main.cc | 11 ++- 4 files changed, 150 insertions(+), 4 deletions(-) create mode 100644 src/core/all_cases/all_cases.cc diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 72d924d..4013eb9 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -6,4 +6,4 @@ project(klotski-core VERSION 0.1.2 LANGUAGES CXX) add_compile_options(-fno-exceptions) -add_executable(${PROJECT_NAME} main.cc all_cases/basic_ranges.cc) +add_executable(${PROJECT_NAME} main.cc all_cases/basic_ranges.cc all_cases/all_cases.cc) diff --git a/src/core/all_cases/all_cases.cc b/src/core/all_cases/all_cases.cc new file mode 100644 index 0000000..089f0d5 --- /dev/null +++ b/src/core/all_cases/all_cases.cc @@ -0,0 +1,139 @@ +#include + +#include "reverse.h" +#include "all_cases.h" + +//typedef uint32_t Range; + +using klotski::cases::BasicRanges; +using klotski::cases::range_reverse; + +uint32_t check_range(uint32_t head, uint32_t range) noexcept { + /// M_1x1 | M_1x2 | M_2x1 | M_2x2 + /// 1 0 0 0 | 1 1 0 0 | 1 0 0 0 | 1 1 0 0 + /// 0 0 0 0 | 0 0 0 0 | 1 0 0 0 | 1 1 0 0 + /// ... | ... | ... | ... + constexpr uint32_t M_1x1 = 0b1; + constexpr uint32_t M_1x2 = 0b11; + constexpr uint32_t M_2x1 = 0b10001; + constexpr uint32_t M_2x2 = 0b110011; + + uint32_t offset = 1; + uint32_t tmp = M_2x2 << head; // fill 2x2 block + for (int addr = 0; range; range >>= 2, ++offset) { // traverse every 2-bits + while ((tmp >> addr) & 0b1) { + ++addr; // search next unfilled block + } + switch (range & 0b11) { + case 0b00: /// space + case 0b11: /// 1x1 block + tmp |= M_1x1 << addr; // fill space or 1x1 block + break; + case 0b10: /// 2x1 block + if (addr > 15 || tmp >> (addr + 4) & 0b1) { // invalid address + return offset; // broken block number + } + tmp |= M_2x1 << addr; // fill 2x1 block + break; + case 0b01: /// 1x2 block + if ((addr & 0b11) == 0b11 || tmp >> (addr + 1) & 0b1) { // invalid address + return offset; // broken block number + } + tmp |= M_1x2 << addr; // fill 1x2 block + break; + } + } + return 0; // pass check +} + +int check_range_v2(int head, uint32_t range) noexcept { + constexpr uint32_t MASK_1x1 = 0b00000001; + constexpr uint32_t MASK_1x2 = 0b00000011; + constexpr uint32_t MASK_2x1 = 0b00010001; + constexpr uint32_t MASK_2x2 = 0b00110011; + + uint32_t flags = MASK_2x2 << head; + + for (int addr = 0; range; range >>= 2) { + + int nn = __builtin_ctz(~flags); + addr += nn; + flags >>= nn; + + switch (range & 0b11) { + case 0b00: + case 0b11: + flags |= MASK_1x1; + continue; + case 0b10: + if ((flags >> 4) & 0b1 || addr > 15) { // invalid address + return -1; // broken block number + } + flags |= MASK_2x1; + continue; + case 0b01: + if ((flags >> 1) & 0b1 || (addr & 0b11) == 0b11) { // invalid address + return -1; // broken block number + } + flags |= MASK_1x2; + continue; + } + } + + return 0; +} + +void demo() { + +// std::cout << check_range(1, 0x003F78CE) << std::endl; +// std::cout << check_range_v3(1, 0x003F78CE) << std::endl; +// return; + +// uint32_t demo = 0x61; +// std::cout << __builtin_ctz(demo) << std::endl; +// return; + + // 0xA9BF0C00 +// auto ret = check_range_v2(1, range_reverse(0xA9BF0C00)); +// std::cout << ret << std::endl; +// return; +// std::cout << ret << std::endl; + + constexpr std::array heads = { + 0x0, 0x1, 0x2, + 0x4, 0x5, 0x6, + 0x8, 0x9, 0xA, + 0xC, 0xD, 0xE, + }; + + auto num = 0; + for (auto head : heads) { + for (auto x : BasicRanges::Instance().Fetch()) { + if (check_range_v2(head, x) == 0) { + ++num; + } + } + } + + +// auto basic_ranges = BasicRanges::Instance().Fetch(); +// for (auto head : heads) { +// for (uint32_t index = 0; index < basic_ranges.size(); ++index) { +// auto broken_offset = check_range(head, basic_ranges[index]); +// if (broken_offset) { // case invalid +// auto delta = (uint32_t)1 << (32 - broken_offset * 2); // delta to next possible range +// /// !! -> broken +// /// ( xx xx xx ) xx xx xx ... (reversed range) +// /// +1 00 00 00 ... (delta) +// auto at_least = (range_reverse(basic_ranges[index]) & ~(delta - 1)) + delta; +// while (range_reverse(basic_ranges[++index]) < at_least); // located next range +// --index; +// continue; +// } +// volatile auto r = range_reverse(basic_ranges[index]); // release valid cases +// } +// } + +// std::cout << num << std::endl; + +} diff --git a/src/core/all_cases/all_cases.h b/src/core/all_cases/all_cases.h index 795d22b..69700f4 100644 --- a/src/core/all_cases/all_cases.h +++ b/src/core/all_cases/all_cases.h @@ -39,6 +39,8 @@ #include #include +void demo(); + namespace klotski { namespace cases { diff --git a/src/core/main.cc b/src/core/main.cc index c3a5b52..679d69b 100644 --- a/src/core/main.cc +++ b/src/core/main.cc @@ -5,14 +5,19 @@ using klotski::cases::BasicRanges; int main() { + + BasicRanges::Instance().Build(); + auto start = clock(); + demo(); + // std::cout << BasicRanges::Instance().IsAvailable() << std::endl; // BasicRanges::Instance().Build(); // std::cout << BasicRanges::Instance().IsAvailable() << std::endl; - for (auto x : BasicRanges::Instance().Fetch()) { - printf("%08X\n", x); - } +// for (auto x : BasicRanges::Instance().Fetch()) { +// printf("%08X\n", x); +// } std::cerr << ((clock() - start) * 1000 / CLOCKS_PER_SEC) << "ms" << std::endl;