#include <iostream>
#include <sstream>
+#include "cluster.h"
#include "evaluate.h"
#include "misc.h"
#include "movegen.h"
nodes += cnt;
pos.undo_move(m);
}
- if (Root)
+ if (Root && Cluster::is_root())
sync_cout << UCI::move(m, pos.is_chess960()) << ": " << cnt << sync_endl;
}
return nodes;
if (Limits.perft)
{
nodes = perft<true>(rootPos, Limits.perft);
- sync_cout << "\nNodes searched: " << nodes << "\n" << sync_endl;
+ if (Cluster::is_root())
+ sync_cout << "\nNodes searched: " << nodes << "\n" << sync_endl;
+
return;
}
if (rootMoves.empty())
{
rootMoves.emplace_back(MOVE_NONE);
- sync_cout << "info depth 0 score "
- << UCI::value(rootPos.checkers() ? -VALUE_MATE : VALUE_DRAW)
- << sync_endl;
+ if (Cluster::is_root())
+ sync_cout << "info depth 0 score "
+ << UCI::value(rootPos.checkers() ? -VALUE_MATE : VALUE_DRAW)
+ << sync_endl;
}
else
{
// until the GUI sends one of those commands.
while (!Threads.stop && (ponder || Limits.infinite))
- {} // Busy wait for a stop or a ponder reset
+ { Cluster::signals_poll(); } // Busy wait for a stop or a ponder reset
// Stop the threads if not already stopped (also raise the stop if
// "ponderhit" just reset Threads.ponder).
Threads.stop = true;
+ // Signal and synchronize all other ranks
+ Cluster::signals_sync();
+
// Wait until all threads have finished
Threads.wait_for_search_finished();
// When playing in 'nodes as time' mode, subtract the searched nodes from
// the available ones before exiting.
if (Limits.npmsec)
- Time.availableNodes += Limits.inc[us] - Threads.nodes_searched();
+ Time.availableNodes += Limits.inc[us] - Cluster::nodes_searched();
Thread* bestThread = this;
&& rootMoves[0].pv[0] != MOVE_NONE)
bestThread = Threads.get_best_thread();
- bestPreviousScore = bestThread->rootMoves[0].score;
+ // Prepare PVLine and ponder move
+ std::string PVLine = UCI::pv(bestThread->rootPos, bestThread->completedDepth, -VALUE_INFINITE, VALUE_INFINITE);
- // Send again PV info if we have a new best thread
- if (bestThread != this)
- sync_cout << UCI::pv(bestThread->rootPos, bestThread->completedDepth, -VALUE_INFINITE, VALUE_INFINITE) << sync_endl;
+ Move bestMove = bestThread->rootMoves[0].pv[0];
+ Move ponderMove = MOVE_NONE;
+ if (bestThread->rootMoves[0].pv.size() > 1 || bestThread->rootMoves[0].extract_ponder_from_tt(rootPos))
+ ponderMove = bestThread->rootMoves[0].pv[1];
- sync_cout << "bestmove " << UCI::move(bestThread->rootMoves[0].pv[0], rootPos.is_chess960());
+ // Exchange info as needed
+ Cluster::MoveInfo mi{bestMove,
+ ponderMove,
+ bestThread->completedDepth,
+ bestThread->rootMoves[0].score,
+ Cluster::rank()};
+ Cluster::pick_moves(mi, PVLine);
- if (bestThread->rootMoves[0].pv.size() > 1 || bestThread->rootMoves[0].extract_ponder_from_tt(rootPos))
- std::cout << " ponder " << UCI::move(bestThread->rootMoves[0].pv[1], rootPos.is_chess960());
+ bestPreviousScore = static_cast<Value>(mi.score);
+
+ if (Cluster::is_root())
+ {
+ // Send again PV info if we have a new best thread/rank
+ if (bestThread != this || mi.rank != 0)
+ sync_cout << PVLine << sync_endl;
+
+ bestMove = static_cast<Move>(mi.move);
+ ponderMove = static_cast<Move>(mi.ponder);
+
+ if (ponderMove != MOVE_NONE)
+ sync_cout << "bestmove " << UCI::move(bestMove, rootPos.is_chess960())
+ << " ponder " << UCI::move(ponderMove, rootPos.is_chess960()) << sync_endl;
+ else
+ sync_cout << "bestmove " << UCI::move(bestMove, rootPos.is_chess960()) << sync_endl;
+ }
- std::cout << sync_endl;
}
// Iterative deepening loop until requested to stop or the target depth is reached
while ( ++rootDepth < MAX_PLY
&& !Threads.stop
- && !(Limits.depth && mainThread && rootDepth > Limits.depth))
+ && !(Limits.depth && mainThread && Cluster::is_root() && rootDepth > Limits.depth))
{
// Age out PV variability metric
if (mainThread)
totBestMoveChanges /= 2;
+
// Save the last iteration's scores before first PV line is searched and
// all the move scores except the (new) PV are set to -VALUE_INFINITE.
for (RootMove& rm : rootMoves)
// When failing high/low give some update (without cluttering
// the UI) before a re-search.
- if ( mainThread
+ if ( Cluster::is_root()
+ && mainThread
&& multiPV == 1
&& (bestValue <= alpha || bestValue >= beta)
&& Time.elapsed() > 3000)
+ {
sync_cout << UCI::pv(rootPos, rootDepth, alpha, beta) << sync_endl;
+ Cluster::cluster_info(rootDepth);
+ }
// In case of failing low/high increase aspiration window and
// re-search, otherwise exit the loop.
// Sort the PV lines searched so far and update the GUI
std::stable_sort(rootMoves.begin() + pvFirst, rootMoves.begin() + pvIdx + 1);
- if ( mainThread
+ if ( Cluster::is_root() && mainThread
&& (Threads.stop || pvIdx + 1 == multiPV || Time.elapsed() > 3000))
+ {
sync_cout << UCI::pv(rootPos, rootDepth, alpha, beta) << sync_endl;
+ Cluster::cluster_info(rootDepth);
+ }
}
if (!Threads.stop)
if ( b == BOUND_EXACT
|| (b == BOUND_LOWER ? value >= beta : value <= alpha))
{
- tte->save(posKey, value_to_tt(value, ss->ply), ss->ttPv, b,
- std::min(MAX_PLY - 1, depth + 6),
- MOVE_NONE, VALUE_NONE);
+ Cluster::save(thisThread, tte,
+ posKey, value_to_tt(value, ss->ply), ss->ttPv, b,
+ std::min(MAX_PLY - 1, depth + 6),
+ MOVE_NONE, VALUE_NONE);
return value;
}
else
ss->staticEval = eval = -(ss-1)->staticEval + 2 * Tempo;
- tte->save(posKey, VALUE_NONE, ss->ttPv, BOUND_NONE, DEPTH_NONE, MOVE_NONE, eval);
+ Cluster::save(thisThread, tte,
+ posKey, VALUE_NONE, ss->ttPv, BOUND_NONE, DEPTH_NONE, MOVE_NONE,
+ eval);
}
// Step 7. Razoring (~1 Elo)
ss->moveCount = ++moveCount;
- if (rootNode && thisThread == Threads.main() && Time.elapsed() > 3000)
+ if (rootNode && Cluster::is_root() && thisThread == Threads.main() && Time.elapsed() > 3000)
sync_cout << "info depth " << depth
<< " currmove " << UCI::move(move, pos.is_chess960())
<< " currmovenumber " << moveCount + thisThread->pvIdx << sync_endl;
ss->ttPv = ss->ttPv && (ss+1)->ttPv;
if (!excludedMove && !(rootNode && thisThread->pvIdx))
- tte->save(posKey, value_to_tt(bestValue, ss->ply), ss->ttPv,
- bestValue >= beta ? BOUND_LOWER :
- PvNode && bestMove ? BOUND_EXACT : BOUND_UPPER,
- depth, bestMove, ss->staticEval);
+ Cluster::save(thisThread, tte,
+ posKey, value_to_tt(bestValue, ss->ply), ss->ttPv,
+ bestValue >= beta ? BOUND_LOWER :
+ PvNode && bestMove ? BOUND_EXACT : BOUND_UPPER,
+ depth, bestMove, ss->staticEval);
assert(bestValue > -VALUE_INFINITE && bestValue < VALUE_INFINITE);
if (bestValue >= beta)
{
if (!ss->ttHit)
- tte->save(posKey, value_to_tt(bestValue, ss->ply), false, BOUND_LOWER,
- DEPTH_NONE, MOVE_NONE, ss->staticEval);
+ Cluster::save(thisThread, tte,
+ posKey, value_to_tt(bestValue, ss->ply), false, BOUND_LOWER,
+ DEPTH_NONE, MOVE_NONE, ss->staticEval);
return bestValue;
}
if (ss->inCheck && bestValue == -VALUE_INFINITE)
return mated_in(ss->ply); // Plies to mate from the root
- tte->save(posKey, value_to_tt(bestValue, ss->ply), pvHit,
- bestValue >= beta ? BOUND_LOWER :
- PvNode && bestValue > oldAlpha ? BOUND_EXACT : BOUND_UPPER,
- ttDepth, bestMove, ss->staticEval);
+ Cluster::save(thisThread, tte,
+ posKey, value_to_tt(bestValue, ss->ply), pvHit,
+ bestValue >= beta ? BOUND_LOWER :
+ PvNode && bestValue > oldAlpha ? BOUND_EXACT : BOUND_UPPER,
+ ttDepth, bestMove, ss->staticEval);
assert(bestValue > -VALUE_INFINITE && bestValue < VALUE_INFINITE);
dbg_print();
}
+ // poll on MPI signals
+ Cluster::signals_poll();
+
// We should not stop pondering until told so by the GUI
if (ponder)
return;
if ( (Limits.use_time_management() && (elapsed > Time.maximum() - 10 || stopOnPonderhit))
|| (Limits.movetime && elapsed >= Limits.movetime)
- || (Limits.nodes && Threads.nodes_searched() >= (uint64_t)Limits.nodes))
+ || (Limits.nodes && Cluster::nodes_searched() >= (uint64_t)Limits.nodes))
Threads.stop = true;
}
const RootMoves& rootMoves = pos.this_thread()->rootMoves;
size_t pvIdx = pos.this_thread()->pvIdx;
size_t multiPV = std::min((size_t)Options["MultiPV"], rootMoves.size());
- uint64_t nodesSearched = Threads.nodes_searched();
- uint64_t tbHits = Threads.tb_hits() + (TB::RootInTB ? rootMoves.size() : 0);
+ uint64_t nodesSearched = Cluster::nodes_searched();
+ uint64_t tbHits = Cluster::tb_hits() + (TB::RootInTB ? rootMoves.size() : 0);
for (size_t i = 0; i < multiPV; ++i)
{