diff --git a/library/src/ab_search.cpp b/library/src/ab_search.cpp index a055f4bba..27b950dca 100644 --- a/library/src/ab_search.cpp +++ b/library/src/ab_search.cpp @@ -56,6 +56,13 @@ auto apply_ab_tt_lookup( limit, lowerFlag); TIMER_END(TIMER_NO_LOOKUP, depth); + // Instrumentation: per-thread TT lookup/hit counters + if (thrp) { + ++thrp->tt_lookup_count; + if (cardsP) + ++thrp->tt_hit_count; + } + if (!cardsP) return false; diff --git a/library/src/solver_if.cpp b/library/src/solver_if.cpp index f935f004e..c9702f191 100644 --- a/library/src/solver_if.cpp +++ b/library/src/solver_if.cpp @@ -7,6 +7,8 @@ See LICENSE and README. */ +#include +#include #include #include #include @@ -284,6 +286,9 @@ auto solve_board_internal( thrp->ABStats.Reset(); thrp->ABStats.ResetCum(); #endif + thrp->tt_lookup_count = 0; + thrp->tt_hit_count = 0; + if (auto* tt = ctx.trans_table()) tt->reset_op_stats(); #ifdef DDS_TOP_LEVEL { @@ -670,6 +675,29 @@ auto solve_board_internal( futp->nodes = ctx.search().trick_nodes(); } + // Print TT stats if requested + if (auto* env = std::getenv("DDS_PRINT_TT_STATS"); env && std::string(env) == "1") { + ThreadData* thrp_ptr = ctx.thread_ptr(); + if (thrp_ptr && thrp_ptr->tt_lookup_count > 0) { + double hit_rate = 100.0 * (double)thrp_ptr->tt_hit_count / + (double)thrp_ptr->tt_lookup_count; + std::fprintf(stderr, + "DDS_TT_STATS: lookups=%llu hits=%llu hit_rate=%.2f%%\n", + (unsigned long long)thrp_ptr->tt_lookup_count, + (unsigned long long)thrp_ptr->tt_hit_count, + hit_rate); + if (auto* tt = ctx.trans_table()) { + int adds, overwrites, harvests; + tt->get_op_stats(adds, overwrites, harvests); + double ow_rate = adds > 0 ? + 100.0 * (double)overwrites / (double)adds : 0.0; + std::fprintf(stderr, + "DDS_TT_STATS: adds=%d overwrites=%d overwrite_rate=%.2f%% harvests=%d\n", + adds, overwrites, ow_rate, harvests); + } + } + } + #ifdef DDS_MEMORY_LEAKS_WIN32 _CrtDumpMemoryLeaks(); #endif @@ -721,6 +749,9 @@ auto solve_same_board( thrp->ABStats.Reset(); thrp->ABStats.ResetCum(); #endif + thrp->tt_lookup_count = 0; + thrp->tt_hit_count = 0; + if (auto* tt = ctx.trans_table()) tt->reset_op_stats(); #ifdef DDS_TOP_LEVEL { @@ -811,6 +842,29 @@ auto solve_same_board( futp->nodes = ctx.search().trick_nodes(); } + // Print TT stats if requested + if (auto* env = std::getenv("DDS_PRINT_TT_STATS"); env && std::string(env) == "1") { + ThreadData* thrp_ptr = ctx.thread_ptr(); + if (thrp_ptr && thrp_ptr->tt_lookup_count > 0) { + double hit_rate = 100.0 * (double)thrp_ptr->tt_hit_count / + (double)thrp_ptr->tt_lookup_count; + std::fprintf(stderr, + "DDS_TT_STATS: lookups=%llu hits=%llu hit_rate=%.2f%%\n", + (unsigned long long)thrp_ptr->tt_lookup_count, + (unsigned long long)thrp_ptr->tt_hit_count, + hit_rate); + if (auto* tt = ctx.trans_table()) { + int adds, overwrites, harvests; + tt->get_op_stats(adds, overwrites, harvests); + double ow_rate = adds > 0 ? + 100.0 * (double)overwrites / (double)adds : 0.0; + std::fprintf(stderr, + "DDS_TT_STATS: adds=%d overwrites=%d overwrite_rate=%.2f%% harvests=%d\n", + adds, overwrites, ow_rate, harvests); + } + } + } + #ifdef DDS_MEMORY_LEAKS_WIN32 _CrtDumpMemoryLeaks(); #endif @@ -905,6 +959,9 @@ auto analyse_later_board( thrp->ABStats.Reset(); thrp->ABStats.ResetCum(); #endif + thrp->tt_lookup_count = 0; + thrp->tt_hit_count = 0; + if (auto* tt = ctx.trans_table()) tt->reset_op_stats(); #ifdef DDS_TOP_LEVEL { diff --git a/library/src/system/thread_data.hpp b/library/src/system/thread_data.hpp index a9b1035d0..909b1b4da 100644 --- a/library/src/system/thread_data.hpp +++ b/library/src/system/thread_data.hpp @@ -6,6 +6,7 @@ #include #include #include +#include #ifdef DDS_AB_STATS #include "ab_stats.hpp" @@ -61,6 +62,9 @@ struct ThreadData double memUsed; int nodes; int trickNodes; + // TT instrumentation (per-context, single-threaded) + uint64_t tt_lookup_count = 0; + uint64_t tt_hit_count = 0; // Constant for a given hand. // 960 KB diff --git a/library/src/trans_table/trans_table.hpp b/library/src/trans_table/trans_table.hpp index 88e64c119..c57be3b4f 100644 --- a/library/src/trans_table/trans_table.hpp +++ b/library/src/trans_table/trans_table.hpp @@ -225,6 +225,12 @@ class TransTable virtual auto print_all_suit_stats(std::ofstream& fout) const -> void = 0; /// \brief Print summary suit statistics. + /// \brief Get add/overwrite/harvest counters for instrumentation. + virtual auto get_op_stats(int& adds, int& overwrites, int& harvests) const -> void = 0; + + /// \brief Reset add/overwrite/harvest counters for per-solve stats. + virtual auto reset_op_stats() -> void = 0; + virtual auto print_summary_suit_stats(std::ofstream& fout) const -> void = 0; /// \brief Print entries distribution for a specific hand. diff --git a/library/src/trans_table/trans_table_l.cpp b/library/src/trans_table/trans_table_l.cpp index e8dea203c..5e8adf3d9 100644 --- a/library/src/trans_table/trans_table_l.cpp +++ b/library/src/trans_table/trans_table_l.cpp @@ -209,7 +209,7 @@ TransTableL::TransTableL() pages_maximum_ = 0; harvest_trick_ = 0; harvest_hand_ = 0; - page_stats_ = PageStats{0,0,0,0,0}; + page_stats_ = PageStats{0,0,0,0,0,0,0}; timestamp_ = 0; pool_ = nullptr; next_block_ = nullptr; @@ -470,6 +470,8 @@ auto TransTableL::return_all_memory() -> void page_stats_.num_frees_ = 0; page_stats_.num_harvests_ = 0; page_stats_.last_current_ = 0; + page_stats_.num_adds_ = 0; + page_stats_.num_overwrites_ = 0; TransTableL::release_tt(); @@ -931,7 +933,10 @@ auto TransTableL::create_or_update( return; } + // Instrumentation: count new insertions and overwrites + page_stats_.num_adds_++; if (n == BlocksPerEntry) { + page_stats_.num_overwrites_++; if (bp->next_write_no_ >= BlocksPerEntry) bp->next_write_no_ = 0; } diff --git a/library/src/trans_table/trans_table_l.hpp b/library/src/trans_table/trans_table_l.hpp index 34c7a2b8f..ad6e981b3 100644 --- a/library/src/trans_table/trans_table_l.hpp +++ b/library/src/trans_table/trans_table_l.hpp @@ -142,6 +142,8 @@ class TransTableL: public TransTable int num_frees_; ///< Total deallocations int num_harvests_; ///< Total harvest operations int last_current_; ///< Last current page number + int num_adds_; ///< Total new entries inserted + int num_overwrites_; ///< Insertions that overwrote existing entries }; /// \brief Harvested blocks saved for potential reuse (16 bytes). @@ -463,6 +465,18 @@ class TransTableL: public TransTable /// \brief Print summary suit statistics. /// /// \param fout Output stream + auto reset_op_stats() -> void override + { + page_stats_.num_adds_ = 0; + page_stats_.num_overwrites_ = 0; + page_stats_.num_harvests_ = 0; + } + auto get_op_stats(int& adds, int& overwrites, int& harvests) const -> void override + { + adds = page_stats_.num_adds_; + overwrites = page_stats_.num_overwrites_; + harvests = page_stats_.num_harvests_; + } auto print_summary_suit_stats(std::ofstream& fout) const -> void override; /// \brief Print entries for a specific hand distribution. diff --git a/library/src/trans_table/trans_table_s.hpp b/library/src/trans_table/trans_table_s.hpp index f044018b2..6560c225f 100644 --- a/library/src/trans_table/trans_table_s.hpp +++ b/library/src/trans_table/trans_table_s.hpp @@ -299,6 +299,15 @@ class TransTableS: public TransTable auto print_all_suit_stats(std::ofstream& /*fout*/) const -> void override { } + auto reset_op_stats() -> void override + { + } + auto get_op_stats(int& adds, int& overwrites, int& harvests) const -> void override + { + adds = 0; + overwrites = 0; + harvests = 0; // TransTableS not instrumented + } auto print_summary_suit_stats(std::ofstream& /*fout*/) const -> void override { } diff --git a/library/tests/trans_table/trans_table_base_test.cpp b/library/tests/trans_table/trans_table_base_test.cpp index 8834a91cf..420a4e258 100644 --- a/library/tests/trans_table/trans_table_base_test.cpp +++ b/library/tests/trans_table/trans_table_base_test.cpp @@ -37,6 +37,15 @@ class TransTableBaseTest : public ::testing::Test MockTransTable() : TransTable() {} ~MockTransTable() override = default; + auto get_op_stats(int& adds, int& overwrites, int& harvests) const -> void override + { + adds = 0; + overwrites = 0; + harvests = 0; + } + auto reset_op_stats() -> void override + { + } void init(const int handLookup[][15]) override {