Skip to content

Commit

Permalink
Addition of "Introduce coordination between searching threads".
Browse files Browse the repository at this point in the history
This patch had been skipped earlier:
official-stockfish/Stockfish@217840a
The implementation in Cfish is a bit different but should be functionally
more or less equivalent (SMP noise will make it impossible to see a
difference in search efficiency, unless a bug crept in).
  • Loading branch information
syzygy1 committed Jun 28, 2020
1 parent f461978 commit b73fed9
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 3 deletions.
34 changes: 32 additions & 2 deletions src/ntsearch.c
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,26 @@ Value search_NonPV(Pos *pos, Stack *ss, Value alpha, Depth depth, int cutNode)
singularLMR = moveCountPruning = false;
ttCapture = ttMove && is_capture_or_promotion(pos, ttMove);

// Check for a breadcrumb and leave one if none found
_Atomic uint64_t *crumb = NULL;
bool marked = false;
if (ss->ply < 8) {
crumb = &breadcrumbs[posKey & 1023];
// The next line assumes there are at most 65535 search threads
uint64_t v = (posKey & ~0xffffULL) | (pos->threadIdx + 1), expected = 0ULL;
// If no crumb is in place yet, leave ours
if (!atomic_compare_exchange_strong_explicit(crumb, &expected, v,
memory_order_relaxed, memory_order_relaxed))
{
// Some crumb was in place already. Its value is now in expected.
crumb = NULL;
// Was the crumb is for the same position and was left by another thread?
v ^= expected;
if (v != 0 && (v & ~0xffffULL) == 0)
marked = true;
}
}

// Step 12. Loop through moves
// Loop through all pseudo-legal moves until no moves remain or a beta
// cutoff occurs
Expand Down Expand Up @@ -507,8 +527,10 @@ Value search_NonPV(Pos *pos, Stack *ss, Value alpha, Depth depth, int cutNode)
// assume that this expected cut-node is not singular, i.e. multiple
// moves fail high. We therefore prune the whole subtree by returning
// a soft bound.
else if (singularBeta >= beta)
else if (singularBeta >= beta) {
if (crumb) store_rlx(*crumb, 0);
return singularBeta;
}

// The call to search_NonPV with the same value of ss messed up our
// move picker data. So we fix it.
Expand Down Expand Up @@ -575,6 +597,10 @@ Value search_NonPV(Pos *pos, Stack *ss, Value alpha, Depth depth, int cutNode)
if (pos->ttHitAverage > 500 * ttHitAverageResolution * ttHitAverageWindow / 1024)
r--;

// Reduction if other threads are searching this position.
if (marked)
r++;

// Decrease reduction if position is or has been on the PV
if (ttPv)
r -= 2;
Expand Down Expand Up @@ -680,8 +706,10 @@ Value search_NonPV(Pos *pos, Stack *ss, Value alpha, Depth depth, int cutNode)
// Finished searching the move. If a stop occurred, the return value of
// the search cannot be trusted, and we return immediately without
// updating best move, PV and TT.
if (load_rlx(Signals.stop))
if (load_rlx(Signals.stop)) {
if (crumb) store_rlx(*crumb, 0);
return 0;
}

if (rootNode) {
RootMove *rm = NULL;
Expand Down Expand Up @@ -739,6 +767,8 @@ Value search_NonPV(Pos *pos, Stack *ss, Value alpha, Depth depth, int cutNode)
capturesSearched[captureCount++] = move;
}

if (crumb) store_rlx(*crumb, 0);

// The following condition would detect a stop only after move loop has
// been completed. But in this case bestValue is valid because we have
// fully searched our subtree, and we can anyhow save the result in TT.
Expand Down
6 changes: 5 additions & 1 deletion src/search.c
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,8 @@ struct Skill {
// Move best = 0;
};

//static CounterMoveHistoryStat CounterMoveHistory;
// Breadcrumbs are used to mark nodes as being search by a given thread
static _Atomic uint64_t breadcrumbs[1024];

static Value search_PV(Pos *pos, Stack *ss, Value alpha, Value beta, Depth depth);
static Value search_NonPV(Pos *pos, Stack *ss, Value alpha, Depth depth, int cutNode);
Expand Down Expand Up @@ -980,6 +981,9 @@ void start_thinking(Pos *root)
Signals.stopOnPonderhit = Signals.stop = 0;
Threads.increaseDepth = true;

for (int i = 0; i < 1024; i++)
store_rlx(breadcrumbs[i], 0);

// Generate all legal moves.
ExtMove list[MAX_MOVES];
ExtMove *end = generate_legal(root, list);
Expand Down

0 comments on commit b73fed9

Please sign in to comment.