+// SearchManager manages the search from the main thread. It is responsible for
+// keeping track of the time, and storing data strictly related to the main thread.
+class SearchManager: public ISearchManager {
+ public:
+ using UpdateShort = std::function<void(const InfoShort&)>;
+ using UpdateFull = std::function<void(const InfoFull&)>;
+ using UpdateIter = std::function<void(const InfoIteration&)>;
+ using UpdateBestmove = std::function<void(std::string_view, std::string_view)>;
+
+ struct UpdateContext {
+ UpdateShort onUpdateNoMoves;
+ UpdateFull onUpdateFull;
+ UpdateIter onIter;
+ UpdateBestmove onBestmove;
+ };
+
+
+ SearchManager(const UpdateContext& updateContext) :
+ updates(updateContext) {}
+
+ void check_time(Search::Worker& worker) override;
+
+ void pv(Search::Worker& worker,
+ const ThreadPool& threads,
+ const TranspositionTable& tt,
+ Depth depth);
+
+ Stockfish::TimeManagement tm;
+ double originalTimeAdjust;
+ int callsCnt;
+ std::atomic_bool ponder;
+
+ std::array<Value, 4> iterValue;
+ double previousTimeReduction;
+ Value bestPreviousScore;
+ Value bestPreviousAverageScore;
+ bool stopOnPonderhit;
+
+ size_t id;
+
+ const UpdateContext& updates;
+};
+
+class NullSearchManager: public ISearchManager {
+ public:
+ void check_time(Search::Worker&) override {}
+};
+
+
+// Search::Worker is the class that does the actual search.
+// It is instantiated once per thread, and it is responsible for keeping track
+// of the search history, and storing data required for the search.
+class Worker {
+ public:
+ Worker(SharedState&, std::unique_ptr<ISearchManager>, size_t, NumaReplicatedAccessToken);
+
+ // Called at instantiation to initialize reductions tables.
+ // Reset histories, usually before a new game.
+ void clear();
+
+ // Called when the program receives the UCI 'go' command.
+ // It searches from the root position and outputs the "bestmove".
+ void start_searching();
+
+ bool is_mainthread() const { return threadIdx == 0; }
+
+ void ensure_network_replicated();
+
+ // Public because they need to be updatable by the stats
+ ButterflyHistory mainHistory;
+ CapturePieceToHistory captureHistory;
+ ContinuationHistory continuationHistory[2][2];
+ PawnHistory pawnHistory;
+ PawnCorrectionHistory pawnCorrectionHistory;
+ MaterialCorrectionHistory materialCorrectionHistory;
+
+ private:
+ void iterative_deepening();
+
+ // This is the main search function, for both PV and non-PV nodes
+ template<NodeType nodeType>
+ Value search(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth, bool cutNode);
+
+ // Quiescence search function, which is called by the main search
+ template<NodeType nodeType>
+ Value qsearch(Position& pos, Stack* ss, Value alpha, Value beta);
+
+ Depth reduction(bool i, Depth d, int mn, int delta) const;
+
+ // Pointer to the search manager, only allowed to be called by the main thread
+ SearchManager* main_manager() const {
+ assert(threadIdx == 0);
+ return static_cast<SearchManager*>(manager.get());
+ }
+
+ TimePoint elapsed() const;
+ TimePoint elapsed_time() const;
+
+ LimitsType limits;
+
+ size_t pvIdx, pvLast;
+ std::atomic<uint64_t> nodes, tbHits, bestMoveChanges;
+ int selDepth, nmpMinPly;
+
+ Value optimism[COLOR_NB];
+
+ Position rootPos;
+ StateInfo rootState;
+ RootMoves rootMoves;
+ Depth rootDepth, completedDepth;
+ Value rootDelta;
+
+ size_t threadIdx;
+ NumaReplicatedAccessToken numaAccessToken;
+
+ // Reductions lookup table initialized at startup
+ std::array<int, MAX_MOVES> reductions; // [depth or moveNumber]
+
+ // The main thread has a SearchManager, the others have a NullSearchManager
+ std::unique_ptr<ISearchManager> manager;
+
+ Tablebases::Config tbConfig;
+
+ const OptionsMap& options;
+ ThreadPool& threads;
+ TranspositionTable& tt;
+ const LazyNumaReplicated<Eval::NNUE::Networks>& networks;
+
+ // Used by NNUE
+ Eval::NNUE::AccumulatorCaches refreshTable;
+
+ friend class Stockfish::ThreadPool;
+ friend class SearchManager;
+};