Merge branch 'master' into cluster

This commit is contained in:
Steinar H. Gunderson
2026-01-01 17:33:27 +01:00
67 changed files with 833 additions and 471 deletions
+42 -6
View File
@@ -1,6 +1,6 @@
/*
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
Copyright (C) 2004-2025 The Stockfish developers (see AUTHORS file)
Copyright (C) 2004-2026 The Stockfish developers (see AUTHORS file)
Stockfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -21,14 +21,17 @@
#include <algorithm>
#include <cassert>
#include <deque>
#include <map>
#include <memory>
#include <string>
#include <unordered_map>
#include <utility>
#include "bitboard.h"
#include "cluster.h"
#include "misc.h"
#include "history.h"
#include "memory.h"
#include "misc.h"
#include "movegen.h"
#include "search.h"
#include "syzygy/tbprobe.h"
@@ -44,8 +47,12 @@ namespace Stockfish {
Thread::Thread(Search::SharedState& sharedState,
std::unique_ptr<Search::ISearchManager> sm,
size_t n,
size_t numaN,
size_t totalNumaCount,
OptionalThreadToNumaNodeBinder binder) :
idx(n),
idxInNuma(numaN),
totalNuma(totalNumaCount),
nthreads(sharedState.options["Threads"]),
stdThread(&Thread::idle_loop, this) {
@@ -56,8 +63,8 @@ Thread::Thread(Search::SharedState& sharedState,
// the Worker allocation. Ideally we would also allocate the SearchManager
// here, but that's minor.
this->numaAccessToken = binder();
this->worker = make_unique_large_page<Search::Worker>(sharedState, std::move(sm), n,
this->numaAccessToken);
this->worker = make_unique_large_page<Search::Worker>(
sharedState, std::move(sm), n, idxInNuma, totalNuma, this->numaAccessToken);
});
wait_for_search_finished();
@@ -137,6 +144,8 @@ uint64_t ThreadPool::nodes_searched() const { return accumulate(&Search::Worker:
uint64_t ThreadPool::tb_hits() const { return accumulate(&Search::Worker::tbHits); }
uint64_t ThreadPool::TT_saves() const { return accumulate(&Search::Worker::TTsaves); }
static size_t next_power_of_two(uint64_t count) { return count > 1 ? (2ULL << msb(count - 1)) : 1; }
// Creates/destroys threads to match the requested number.
// Created and launched threads will immediately go to sleep in idle_loop.
// Upon resizing, threads are recreated to allow for binding if necessary.
@@ -175,10 +184,36 @@ void ThreadPool::set(const NumaConfig& numaConfig,
return true;
}();
std::map<NumaIndex, size_t> counts;
boundThreadToNumaNode = doBindThreads
? numaConfig.distribute_threads_among_numa_nodes(requested)
: std::vector<NumaIndex>{};
if (boundThreadToNumaNode.empty())
counts[0] = requested; // Pretend all threads are part of numa node 0
else
{
for (size_t i = 0; i < boundThreadToNumaNode.size(); ++i)
counts[boundThreadToNumaNode[i]]++;
}
sharedState.sharedHistories.clear();
for (auto pair : counts)
{
NumaIndex numaIndex = pair.first;
uint64_t count = pair.second;
auto f = [&]() {
sharedState.sharedHistories.try_emplace(numaIndex, next_power_of_two(count));
};
if (doBindThreads)
numaConfig.execute_on_numa_node(numaIndex, f);
else
f();
}
auto threadsPerNode = counts;
counts.clear();
while (threads.size() < requested)
{
const size_t threadId = threads.size();
@@ -194,8 +229,9 @@ void ThreadPool::set(const NumaConfig& numaConfig,
auto binder = doBindThreads ? OptionalThreadToNumaNodeBinder(numaConfig, numaId)
: OptionalThreadToNumaNodeBinder(numaId);
threads.emplace_back(
std::make_unique<Thread>(sharedState, std::move(manager), threadId, binder));
threads.emplace_back(std::make_unique<Thread>(sharedState, std::move(manager), threadId,
counts[numaId]++, threadsPerNode[numaId],
binder));
}
clear();