Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions library/src/calc_tables.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ auto calc_all_boards_n(
int err = RETURN_NO_FAULT;
if (nthreads <= 1)
{
SolverContext ctx;
SolverContext& ctx = dds::internal::worker_solver_context();
for (int bno = 0; bno < n; ++bno)
{
err = calc_single_common_internal(ctx, *bop, *solvedp, bno);
Expand All @@ -140,8 +140,6 @@ auto calc_all_boards_n(
}
else
{
std::vector<SolverContext> contexts(static_cast<unsigned>(nthreads));

// Dispatch hardest boards first to shorten the parallel tail. This only
// helps across distinct deals (batch calc); for a single deal every board
// shares one fanout, so the sort is skipped (it would be a no-op anyway).
Expand All @@ -162,8 +160,11 @@ auto calc_all_boards_n(

err = parallel_all_boards_n(n, nthreads,
[&](const int worker_id, const int bno) -> int {
(void)worker_id;
// Persistent per-thread context: pool worker threads survive across
// batches, so the TT allocated here is reused for the whole run.
return calc_single_common_internal(
contexts[static_cast<unsigned>(worker_id)], *bop, *solvedp, bno);
dds::internal::worker_solver_context(), *bop, *solvedp, bno);
},
order.empty() ? nullptr : &order);
}
Expand Down
13 changes: 9 additions & 4 deletions library/src/solve_board.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <chrono>

#include "solve_board.hpp"
#include <api/solve_board.hpp>
#include <solver_if.hpp>
#include <pbn.hpp>
#include <system/memory.hpp>
Expand Down Expand Up @@ -80,9 +81,12 @@ auto solve_all_boards_n(

FutureTricks fut;
const auto t0 = std::chrono::steady_clock::now();
const int res = SolveBoard(
// Persistent per-thread context: reuses the worker's TT across boards
// and consecutive batch calls instead of allocating one per board.
const int res = solve_board(
dds::internal::worker_solver_context(),
bds.deals[bno], bds.target[bno], bds.solutions[bno],
bds.mode[bno], &fut, 0);
bds.mode[bno], &fut);
auto dur = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::steady_clock::now() - t0).count();
if (dur < 0) dur = 0;
Expand Down Expand Up @@ -272,9 +276,10 @@ auto solve_all_boards_n_seq(
for (int bno = 0; bno < n && error == 0; bno++) {
FutureTricks fut;
const auto t0 = std::chrono::steady_clock::now();
const int res = SolveBoard(
const int res = solve_board(
dds::internal::worker_solver_context(),
bds.deals[bno], bds.target[bno], bds.solutions[bno],
bds.mode[bno], &fut, 0);
bds.mode[bno], &fut);
auto dur = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::steady_clock::now() - t0).count();
if (dur < 0) dur = 0;
Expand Down
33 changes: 33 additions & 0 deletions library/src/solver_context/solver_context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,39 @@ auto SolverContext::reset_best_moves_lite() const -> void
#endif
}

namespace dds::internal
{

namespace
{

std::atomic<std::uint64_t> g_worker_contexts_created{0};

struct CountedWorkerContext
{
CountedWorkerContext()
{
g_worker_contexts_created.fetch_add(1, std::memory_order_relaxed);
}

SolverContext ctx;
};

} // namespace

auto worker_solver_context() -> SolverContext&
{
thread_local CountedWorkerContext holder;
return holder.ctx;
}

auto worker_solver_contexts_created() -> std::uint64_t
{
return g_worker_contexts_created.load(std::memory_order_relaxed);
}

} // namespace dds::internal

auto ThreadMemoryUsed() -> double
{
// Fixed per-thread lookup-table memory (RelRanksType) included in memUsed
Expand Down
18 changes: 18 additions & 0 deletions library/src/solver_context/solver_context.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#pragma once

#include <cstddef>
#include <cstdint>
#include <memory>
#include <string>
#include <vector>
Expand Down Expand Up @@ -451,3 +452,20 @@ class SolverContext
};

auto ThreadMemoryUsed() -> double;

namespace dds::internal
{

// Persistent per-thread SolverContext for batch solve/calc paths. Created
// lazily on first use on whichever thread calls it — pool workers, or the
// calling thread for single-worker / sequential runs — and kept alive for that
// thread's lifetime, so the transposition table survives across boards, chunks
// and consecutive batch calls instead of being reallocated each time. Combined
// with the persistent worker pool this removes per-batch TT churn (the unported
// half of the ddss fork's batching optimization).
auto worker_solver_context() -> SolverContext&;

// Cumulative count of worker contexts ever created (test seam).
auto worker_solver_contexts_created() -> std::uint64_t;

} // namespace dds::internal
Loading
Loading