static storage duration are automatically set to zero before enter main()
*/
public:
+ Thread& operator[](int threadID) { return threads[threadID]; }
void init_threads();
void exit_threads();
bool available_thread_exists(int master) const;
bool thread_is_available(int slave, int master) const;
bool cutoff_at_splitpoint(int threadID) const;
- void wake_sleeping_thread(int threadID);
void idle_loop(int threadID, SplitPoint* sp);
template <bool Fake>
- void split(Position& pos, SearchStack* ss, int ply, Value* alpha, const Value beta, Value* bestValue,
+ void split(Position& pos, SearchStack* ss, Value* alpha, const Value beta, Value* bestValue,
Depth depth, Move threatMove, int moveCount, MovePicker* mp, bool pvNode);
-
private:
+ Lock mpLock;
Depth minimumSplitDepth;
int maxThreadsPerSplitPoint;
bool useSleepingThreads;
int activeThreads;
volatile bool allThreadsShouldExit;
Thread threads[MAX_THREADS];
- Lock mpLock, sleepLock[MAX_THREADS];
- WaitCondition sleepCond[MAX_THREADS];
};
void extract_pv_from_tt(Position& pos);
void insert_pv_in_tt(Position& pos);
- std::string pv_info_to_uci(Position& pos, int depth, Value alpha, Value beta, int pvIdx);
+ std::string pv_info_to_uci(Position& pos, int depth, int selDepth, Value alpha, Value beta, int pvIdx);
int64_t nodes;
Value pv_score;
int8_t ReductionMatrix[2][64][64]; // [pv][depth][moveNumber]
template <NodeType PV>
- inline Depth reduction(Depth d, int mn) { return (Depth) ReductionMatrix[PV][Min(d / 2, 63)][Min(mn, 63)]; }
+ inline Depth reduction(Depth d, int mn) { return (Depth) ReductionMatrix[PV][Min(d / ONE_PLY, 63)][Min(mn, 63)]; }
// Easy move margin. An easy move candidate must be at least this much
// better than the second best move.
int MultiPV, UCIMultiPV;
// Time management variables
- int SearchStartTime, MaxNodes, MaxDepth, ExactMaxTime;
+ int MaxNodes, MaxDepth, ExactMaxTime;
bool UseTimeManagement, InfiniteSearch, Pondering, StopOnPonderhit;
bool FirstRootMove, StopRequest, QuitRequest, AspirationFailLow;
TimeManager TimeMgr;
Move id_loop(Position& pos, Move searchMoves[], Move* ponderMove);
template <NodeType PvNode, bool SpNode, bool Root>
- Value search(Position& pos, SearchStack* ss, Value alpha, Value beta, Depth depth, int ply);
+ Value search(Position& pos, SearchStack* ss, Value alpha, Value beta, Depth depth);
template <NodeType PvNode>
- Value qsearch(Position& pos, SearchStack* ss, Value alpha, Value beta, Depth depth, int ply);
+ Value qsearch(Position& pos, SearchStack* ss, Value alpha, Value beta, Depth depth);
template <NodeType PvNode>
- inline Value search(Position& pos, SearchStack* ss, Value alpha, Value beta, Depth depth, int ply) {
+ inline Value search(Position& pos, SearchStack* ss, Value alpha, Value beta, Depth depth) {
- return depth < ONE_PLY ? qsearch<PvNode>(pos, ss, alpha, beta, DEPTH_ZERO, ply)
- : search<PvNode, false, false>(pos, ss, alpha, beta, depth, ply);
+ return depth < ONE_PLY ? qsearch<PvNode>(pos, ss, alpha, beta, DEPTH_ZERO)
+ : search<PvNode, false, false>(pos, ss, alpha, beta, depth);
}
template <NodeType PvNode>
void update_gains(const Position& pos, Move move, Value before, Value after);
void do_skill_level(Move* best, Move* ponder);
- int current_search_time();
+ int current_search_time(int set = 0);
std::string value_to_uci(Value v);
std::string speed_to_uci(int64_t nodes);
void poll(const Position& pos);
// Initialize global search-related variables
StopOnPonderhit = StopRequest = QuitRequest = AspirationFailLow = SendSearchedNodes = false;
NodesSincePoll = 0;
- SearchStartTime = get_system_time();
+ current_search_time(get_system_time());
ExactMaxTime = maxTime;
MaxDepth = maxDepth;
MaxNodes = maxNodes;
ThreadsMgr.read_uci_options();
init_eval(ThreadsMgr.active_threads());
- // Wake up needed threads. Main thread, with threadID == 0, is always active
- for (int i = 1; i < ThreadsMgr.active_threads(); i++)
- ThreadsMgr.wake_sleeping_thread(i);
+ // Wake up needed threads and reset maxPly counter
+ for (int i = 0; i < ThreadsMgr.active_threads(); i++)
+ {
+ ThreadsMgr[i].wake_up();
+ ThreadsMgr[i].maxPly = 0;
+ }
// Set thinking time
int myTime = time[pos.side_to_move()];
SearchStack ss[PLY_MAX_PLUS_2];
Value bestValues[PLY_MAX_PLUS_2];
int bestMoveChanges[PLY_MAX_PLUS_2];
- int depth, aspirationDelta, skillSamplingDepth;
+ int depth, selDepth, aspirationDelta;
Value value, alpha, beta;
Move bestMove, easyMove, skillBest, skillPonder;
TT.new_search();
H.clear();
*ponderMove = bestMove = easyMove = skillBest = skillPonder = MOVE_NONE;
- depth = aspirationDelta = skillSamplingDepth = 0;
+ depth = aspirationDelta = 0;
alpha = -VALUE_INFINITE, beta = VALUE_INFINITE;
ss->currentMove = MOVE_NULL; // Hack to skip update_gains()
return MOVE_NONE;
}
- // Choose a random sampling depth according to SkillLevel so that at low
- // skills there is an higher risk to pick up a blunder.
- if (SkillLevelEnabled)
- skillSamplingDepth = 4 + SkillLevel + (RK.rand<unsigned>() % 4);
-
// Iterative deepening loop
while (++depth <= PLY_MAX && (!MaxDepth || depth <= MaxDepth) && !StopRequest)
{
// research with bigger window until not failing high/low anymore.
do {
// Search starting from ss+1 to allow calling update_gains()
- value = search<PV, false, true>(pos, ss+1, alpha, beta, depth * ONE_PLY, 0);
+ value = search<PV, false, true>(pos, ss+1, alpha, beta, depth * ONE_PLY);
// Write PV back to transposition table in case the relevant entries
// have been overwritten during the search.
bestMoveChanges[depth] = Rml.bestMoveChanges;
// Do we need to pick now the best and the ponder moves ?
- if (SkillLevelEnabled && depth == skillSamplingDepth)
+ if (SkillLevelEnabled && depth == 1 + SkillLevel)
do_skill_level(&skillBest, &skillPonder);
+ // Retrieve max searched depth among threads
+ selDepth = 0;
+ for (int i = 0; i < ThreadsMgr.active_threads(); i++)
+ if (ThreadsMgr[i].maxPly > selDepth)
+ selDepth = ThreadsMgr[i].maxPly;
+
// Send PV line to GUI and to log file
for (int i = 0; i < Min(UCIMultiPV, (int)Rml.size()); i++)
- cout << Rml[i].pv_info_to_uci(pos, depth, alpha, beta, i) << endl;
+ cout << Rml[i].pv_info_to_uci(pos, depth, selDepth, alpha, beta, i) << endl;
if (UseLogFile)
LogFile << pretty_pv(pos, depth, value, current_search_time(), Rml[0].pv) << endl;
// here: This is taken care of after we return from the split point.
template <NodeType PvNode, bool SpNode, bool Root>
- Value search(Position& pos, SearchStack* ss, Value alpha, Value beta, Depth depth, int ply) {
+ Value search(Position& pos, SearchStack* ss, Value alpha, Value beta, Depth depth) {
assert(alpha >= -VALUE_INFINITE && alpha <= VALUE_INFINITE);
assert(beta > alpha && beta <= VALUE_INFINITE);
assert(PvNode || alpha == beta - 1);
- assert((Root || ply > 0) && ply < PLY_MAX);
assert(pos.thread() >= 0 && pos.thread() < ThreadsMgr.active_threads());
Move movesSearched[MOVES_MAX];
refinedValue = bestValue = value = -VALUE_INFINITE;
oldAlpha = alpha;
isCheck = pos.is_check();
+ ss->ply = (ss-1)->ply + 1;
+
+ // Used to send selDepth info to GUI
+ if (PvNode && ThreadsMgr[threadID].maxPly < ss->ply)
+ ThreadsMgr[threadID].maxPly = ss->ply;
if (SpNode)
{
if (( StopRequest
|| ThreadsMgr.cutoff_at_splitpoint(threadID)
|| pos.is_draw()
- || ply >= PLY_MAX - 1) && !Root)
+ || ss->ply > PLY_MAX) && !Root)
return VALUE_DRAW;
// Step 3. Mate distance pruning
- alpha = Max(value_mated_in(ply), alpha);
- beta = Min(value_mate_in(ply+1), beta);
+ alpha = Max(value_mated_in(ss->ply), alpha);
+ beta = Min(value_mate_in(ss->ply+1), beta);
if (alpha >= beta)
return alpha;
if ( !Root
&& tte
&& (PvNode ? tte->depth() >= depth && tte->type() == VALUE_TYPE_EXACT
- : ok_to_use_TT(tte, depth, beta, ply)))
+ : ok_to_use_TT(tte, depth, beta, ss->ply)))
{
TT.refresh(tte);
ss->bestMove = ttMove; // Can be MOVE_NONE
- return value_from_tt(tte->value(), ply);
+ return value_from_tt(tte->value(), ss->ply);
}
// Step 5. Evaluate the position statically and update parent's gain statistics
ss->eval = tte->static_value();
ss->evalMargin = tte->static_value_margin();
- refinedValue = refine_eval(tte, ss->eval, ply);
+ refinedValue = refine_eval(tte, ss->eval, ss->ply);
}
else
{
&& !pos.has_pawn_on_7th(pos.side_to_move()))
{
Value rbeta = beta - razor_margin(depth);
- Value v = qsearch<NonPV>(pos, ss, rbeta-1, rbeta, DEPTH_ZERO, ply);
+ Value v = qsearch<NonPV>(pos, ss, rbeta-1, rbeta, DEPTH_ZERO);
if (v < rbeta)
// Logically we should return (v + razor_margin(depth)), but
// surprisingly this did slightly weaker in tests.
pos.do_null_move(st);
(ss+1)->skipNullMove = true;
- nullValue = -search<NonPV>(pos, ss+1, -beta, -alpha, depth-R*ONE_PLY, ply+1);
+ nullValue = -search<NonPV>(pos, ss+1, -beta, -alpha, depth-R*ONE_PLY);
(ss+1)->skipNullMove = false;
pos.undo_null_move();
// Do verification search at high depths
ss->skipNullMove = true;
- Value v = search<NonPV>(pos, ss, alpha, beta, depth-R*ONE_PLY, ply);
+ Value v = search<NonPV>(pos, ss, alpha, beta, depth-R*ONE_PLY);
ss->skipNullMove = false;
if (v >= beta)
Depth d = (PvNode ? depth - 2 * ONE_PLY : depth / 2);
ss->skipNullMove = true;
- search<PvNode>(pos, ss, alpha, beta, d, ply);
+ search<PvNode>(pos, ss, alpha, beta, d);
ss->skipNullMove = false;
ttMove = ss->bestMove;
&& move == tte->move()
&& ext < ONE_PLY)
{
- Value ttValue = value_from_tt(tte->value(), ply);
+ Value ttValue = value_from_tt(tte->value(), ss->ply);
if (abs(ttValue) < VALUE_KNOWN_WIN)
{
Value rBeta = ttValue - int(depth);
ss->excludedMove = move;
ss->skipNullMove = true;
- Value v = search<NonPV>(pos, ss, rBeta - 1, rBeta, depth / 2, ply);
+ Value v = search<NonPV>(pos, ss, rBeta - 1, rBeta, depth / 2);
ss->skipNullMove = false;
ss->excludedMove = MOVE_NONE;
ss->bestMove = MOVE_NONE;
if (Root && MultiPV > 1)
alpha = -VALUE_INFINITE;
- value = -search<PV>(pos, ss+1, -beta, -alpha, newDepth, ply+1);
+ value = -search<PV>(pos, ss+1, -beta, -alpha, newDepth);
}
else
{
{
alpha = SpNode ? sp->alpha : alpha;
Depth d = newDepth - ss->reduction;
- value = -search<NonPV>(pos, ss+1, -(alpha+1), -alpha, d, ply+1);
+ value = -search<NonPV>(pos, ss+1, -(alpha+1), -alpha, d);
doFullDepthSearch = (value > alpha);
}
ss->reduction = 3 * ONE_PLY;
Value rAlpha = alpha - 300;
Depth d = newDepth - ss->reduction;
- value = -search<NonPV>(pos, ss+1, -(rAlpha+1), -rAlpha, d, ply+1);
+ value = -search<NonPV>(pos, ss+1, -(rAlpha+1), -rAlpha, d);
doFullDepthSearch = (value > rAlpha);
ss->reduction = DEPTH_ZERO; // Restore original reduction
}
if (doFullDepthSearch)
{
alpha = SpNode ? sp->alpha : alpha;
- value = -search<NonPV>(pos, ss+1, -(alpha+1), -alpha, newDepth, ply+1);
+ value = -search<NonPV>(pos, ss+1, -(alpha+1), -alpha, newDepth);
// Step extra. pv search (only in PV nodes)
// Search only for possible new PV nodes, if instead value >= beta then
// parent node fails low with value <= alpha and tries another move.
if (PvNode && value > alpha && (Root || value < beta))
- value = -search<PV>(pos, ss+1, -beta, -alpha, newDepth, ply+1);
+ value = -search<PV>(pos, ss+1, -beta, -alpha, newDepth);
}
}
else if (SpNode)
sp->betaCutoff = true;
- if (value == value_mate_in(ply + 1))
+ if (value == value_mate_in(ss->ply + 1))
ss->mateKiller = move;
ss->bestMove = move;
&& ThreadsMgr.available_thread_exists(threadID)
&& !StopRequest
&& !ThreadsMgr.cutoff_at_splitpoint(threadID))
- ThreadsMgr.split<FakeSplit>(pos, ss, ply, &alpha, beta, &bestValue, depth,
+ ThreadsMgr.split<FakeSplit>(pos, ss, &alpha, beta, &bestValue, depth,
threatMove, moveCount, &mp, PvNode);
}
// no legal moves, it must be mate or stalemate.
// If one move was excluded return fail low score.
if (!SpNode && !moveCount)
- return excludedMove ? oldAlpha : isCheck ? value_mated_in(ply) : VALUE_DRAW;
+ return excludedMove ? oldAlpha : isCheck ? value_mated_in(ss->ply) : VALUE_DRAW;
// Step 20. Update tables
// If the search is not aborted, update the transposition table,
vt = bestValue <= oldAlpha ? VALUE_TYPE_UPPER
: bestValue >= beta ? VALUE_TYPE_LOWER : VALUE_TYPE_EXACT;
- TT.store(posKey, value_to_tt(bestValue, ply), vt, depth, move, ss->eval, ss->evalMargin);
+ TT.store(posKey, value_to_tt(bestValue, ss->ply), vt, depth, move, ss->eval, ss->evalMargin);
// Update killers and history only for non capture moves that fails high
if ( bestValue >= beta
// less than ONE_PLY).
template <NodeType PvNode>
- Value qsearch(Position& pos, SearchStack* ss, Value alpha, Value beta, Depth depth, int ply) {
+ Value qsearch(Position& pos, SearchStack* ss, Value alpha, Value beta, Depth depth) {
assert(alpha >= -VALUE_INFINITE && alpha <= VALUE_INFINITE);
assert(beta >= -VALUE_INFINITE && beta <= VALUE_INFINITE);
assert(PvNode || alpha == beta - 1);
assert(depth <= 0);
- assert(ply > 0 && ply < PLY_MAX);
assert(pos.thread() >= 0 && pos.thread() < ThreadsMgr.active_threads());
StateInfo st;
Value oldAlpha = alpha;
ss->bestMove = ss->currentMove = MOVE_NONE;
+ ss->ply = (ss-1)->ply + 1;
// Check for an instant draw or maximum ply reached
- if (pos.is_draw() || ply >= PLY_MAX - 1)
+ if (ss->ply > PLY_MAX || pos.is_draw())
return VALUE_DRAW;
// Decide whether or not to include checks, this fixes also the type of
tte = TT.retrieve(pos.get_key());
ttMove = (tte ? tte->move() : MOVE_NONE);
- if (!PvNode && tte && ok_to_use_TT(tte, ttDepth, beta, ply))
+ if (!PvNode && tte && ok_to_use_TT(tte, ttDepth, beta, ss->ply))
{
ss->bestMove = ttMove; // Can be MOVE_NONE
- return value_from_tt(tte->value(), ply);
+ return value_from_tt(tte->value(), ss->ply);
}
// Evaluate the position statically
if (bestValue >= beta)
{
if (!tte)
- TT.store(pos.get_key(), value_to_tt(bestValue, ply), VALUE_TYPE_LOWER, DEPTH_NONE, MOVE_NONE, ss->eval, evalMargin);
+ TT.store(pos.get_key(), value_to_tt(bestValue, ss->ply), VALUE_TYPE_LOWER, DEPTH_NONE, MOVE_NONE, ss->eval, evalMargin);
return bestValue;
}
// Make and search the move
pos.do_move(move, st, ci, moveIsCheck);
- value = -qsearch<PvNode>(pos, ss+1, -beta, -alpha, depth-ONE_PLY, ply+1);
+ value = -qsearch<PvNode>(pos, ss+1, -beta, -alpha, depth-ONE_PLY);
pos.undo_move(move);
assert(value > -VALUE_INFINITE && value < VALUE_INFINITE);
// All legal moves have been searched. A special case: If we're in check
// and no legal moves were found, it is checkmate.
if (isCheck && bestValue == -VALUE_INFINITE)
- return value_mated_in(ply);
+ return value_mated_in(ss->ply);
// Update transposition table
ValueType vt = (bestValue <= oldAlpha ? VALUE_TYPE_UPPER : bestValue >= beta ? VALUE_TYPE_LOWER : VALUE_TYPE_EXACT);
- TT.store(pos.get_key(), value_to_tt(bestValue, ply), vt, ttDepth, ss->bestMove, ss->eval, evalMargin);
+ TT.store(pos.get_key(), value_to_tt(bestValue, ss->ply), vt, ttDepth, ss->bestMove, ss->eval, evalMargin);
assert(bestValue > -VALUE_INFINITE && bestValue < VALUE_INFINITE);
&& pos.type_of_piece_on(move_to(m)) != PAWN
&& ( pos.non_pawn_material(WHITE) + pos.non_pawn_material(BLACK)
- pos.midgame_value_of_piece_on(move_to(m)) == VALUE_ZERO)
- && !move_is_promotion(m)
- && !move_is_ep(m))
+ && !move_is_special(m))
{
result += PawnEndgameExtension[PvNode];
*dangerous = true;
// current_search_time() returns the number of milliseconds which have passed
// since the beginning of the current search.
- int current_search_time() {
+ int current_search_time(int set) {
+
+ static int searchStartTime;
- return get_system_time() - SearchStartTime;
+ if (set)
+ searchStartTime = set;
+
+ return get_system_time() - searchStartTime;
}
std::stringstream s;
if (abs(v) < VALUE_MATE - PLY_MAX * ONE_PLY)
- s << "cp " << int(v) * 100 / int(PawnValueMidgame); // Scale to centipawns
+ s << "cp " << int(v) * 100 / int(PawnValueMidgame); // Scale to centipawns
else
- s << "mate " << (v > 0 ? VALUE_MATE - v + 1 : -VALUE_MATE - v) / 2;
+ s << "mate " << (v > 0 ? VALUE_MATE - v + 1 : -VALUE_MATE - v) / 2;
return s.str();
}
assert(threadID >= 0 && threadID < MAX_THREADS);
int i;
- bool allFinished = false;
+ bool allFinished;
while (true)
{
// If we are not thinking, wait for a condition to be signaled
// instead of wasting CPU time polling for work.
- while ( threadID >= activeThreads || threads[threadID].state == THREAD_INITIALIZING
+ while ( threadID >= activeThreads
+ || threads[threadID].state == THREAD_INITIALIZING
|| (useSleepingThreads && threads[threadID].state == THREAD_AVAILABLE))
{
assert(!sp || useSleepingThreads);
if (threads[threadID].state == THREAD_INITIALIZING)
threads[threadID].state = THREAD_AVAILABLE;
- // Grab the lock to avoid races with wake_sleeping_thread()
- lock_grab(&sleepLock[threadID]);
+ // Grab the lock to avoid races with Thread::wake_up()
+ lock_grab(&threads[threadID].sleepLock);
// If we are master and all slaves have finished do not go to sleep
for (i = 0; sp && i < activeThreads && !sp->slaves[i]; i++) {}
if (allFinished || allThreadsShouldExit)
{
- lock_release(&sleepLock[threadID]);
+ lock_release(&threads[threadID].sleepLock);
break;
}
// Do sleep here after retesting sleep conditions
if (threadID >= activeThreads || threads[threadID].state == THREAD_AVAILABLE)
- cond_wait(&sleepCond[threadID], &sleepLock[threadID]);
+ cond_wait(&threads[threadID].sleepCond, &threads[threadID].sleepLock);
- lock_release(&sleepLock[threadID]);
+ lock_release(&threads[threadID].sleepLock);
}
// If this thread has been assigned work, launch a search
threads[threadID].state = THREAD_SEARCHING;
- // Copy SplitPoint position and search stack and call search()
+ // Copy split point position and search stack and call search()
// with SplitPoint template parameter set to true.
SearchStack ss[PLY_MAX_PLUS_2];
SplitPoint* tsp = threads[threadID].splitPoint;
(ss+1)->sp = tsp;
if (tsp->pvNode)
- search<PV, true, false>(pos, ss+1, tsp->alpha, tsp->beta, tsp->depth, tsp->ply);
+ search<PV, true, false>(pos, ss+1, tsp->alpha, tsp->beta, tsp->depth);
else
- search<NonPV, true, false>(pos, ss+1, tsp->alpha, tsp->beta, tsp->depth, tsp->ply);
+ search<NonPV, true, false>(pos, ss+1, tsp->alpha, tsp->beta, tsp->depth);
assert(threads[threadID].state == THREAD_SEARCHING);
// Wake up master thread so to allow it to return from the idle loop in
// case we are the last slave of the split point.
- if (useSleepingThreads && threadID != tsp->master && threads[tsp->master].state == THREAD_AVAILABLE)
- wake_sleeping_thread(tsp->master);
+ if ( useSleepingThreads
+ && threadID != tsp->master
+ && threads[tsp->master].state == THREAD_AVAILABLE)
+ threads[tsp->master].wake_up();
}
// If this thread is the master of a split point and all slaves have
}
- // init_threads() is called during startup. It launches all helper threads,
- // and initializes the split point stack and the global locks and condition
- // objects.
+ // init_threads() is called during startup. Initializes locks and condition
+ // variables and launches all threads sending them immediately to sleep.
void ThreadsManager::init_threads() {
int i, arg[MAX_THREADS];
bool ok;
- // Initialize global locks
+ // This flag is needed to properly end the threads when program exits
+ allThreadsShouldExit = false;
+
+ // Threads will sent to sleep as soon as created, only main thread is kept alive
+ activeThreads = 1;
+
lock_init(&mpLock);
for (i = 0; i < MAX_THREADS; i++)
{
- lock_init(&sleepLock[i]);
- cond_init(&sleepCond[i]);
- }
+ // Initialize thread and split point locks
+ lock_init(&threads[i].sleepLock);
+ cond_init(&threads[i].sleepCond);
- // Initialize splitPoints[] locks
- for (i = 0; i < MAX_THREADS; i++)
for (int j = 0; j < MAX_ACTIVE_SPLIT_POINTS; j++)
lock_init(&(threads[i].splitPoints[j].lock));
- // Will be set just before program exits to properly end the threads
- allThreadsShouldExit = false;
-
- // Threads will be put all threads to sleep as soon as created
- activeThreads = 1;
-
- // All threads except the main thread should be initialized to THREAD_INITIALIZING
- threads[0].state = THREAD_SEARCHING;
- for (i = 1; i < MAX_THREADS; i++)
- threads[i].state = THREAD_INITIALIZING;
+ // All threads but first should be set to THREAD_INITIALIZING
+ threads[i].state = (i == 0 ? THREAD_SEARCHING : THREAD_INITIALIZING);
+ }
- // Launch the helper threads
+ // Create and startup the threads
for (i = 1; i < MAX_THREADS; i++)
{
arg[i] = i;
void ThreadsManager::exit_threads() {
- allThreadsShouldExit = true; // Let the woken up threads to exit idle_loop()
+ // Force the woken up threads to exit idle_loop() and hence terminate
+ allThreadsShouldExit = true;
- // Wake up all the threads and waits for termination
- for (int i = 1; i < MAX_THREADS; i++)
+ for (int i = 0; i < MAX_THREADS; i++)
{
- wake_sleeping_thread(i);
- while (threads[i].state != THREAD_TERMINATED) {}
- }
+ // Wake up all the threads and waits for termination
+ if (i != 0)
+ {
+ threads[i].wake_up();
+ while (threads[i].state != THREAD_TERMINATED) {}
+ }
+
+ // Now we can safely destroy the locks and wait conditions
+ lock_destroy(&threads[i].sleepLock);
+ cond_destroy(&threads[i].sleepCond);
- // Now we can safely destroy the locks
- for (int i = 0; i < MAX_THREADS; i++)
for (int j = 0; j < MAX_ACTIVE_SPLIT_POINTS; j++)
lock_destroy(&(threads[i].splitPoints[j].lock));
+ }
lock_destroy(&mpLock);
-
- // Now we can safely destroy the wait conditions
- for (int i = 0; i < MAX_THREADS; i++)
- {
- lock_destroy(&sleepLock[i]);
- cond_destroy(&sleepCond[i]);
- }
}
// call search().When all threads have returned from search() then split() returns.
template <bool Fake>
- void ThreadsManager::split(Position& pos, SearchStack* ss, int ply, Value* alpha,
- const Value beta, Value* bestValue, Depth depth, Move threatMove,
+ void ThreadsManager::split(Position& pos, SearchStack* ss, Value* alpha, const Value beta,
+ Value* bestValue, Depth depth, Move threatMove,
int moveCount, MovePicker* mp, bool pvNode) {
assert(pos.is_ok());
- assert(ply > 0 && ply < PLY_MAX);
assert(*bestValue >= -VALUE_INFINITE);
assert(*bestValue <= *alpha);
assert(*alpha < beta);
splitPoint.parent = masterThread.splitPoint;
splitPoint.master = master;
splitPoint.betaCutoff = false;
- splitPoint.ply = ply;
splitPoint.depth = depth;
splitPoint.threatMove = threatMove;
splitPoint.alpha = *alpha;
threads[i].state = THREAD_WORKISWAITING; // This makes the slave to exit from idle_loop()
if (useSleepingThreads && i != master)
- wake_sleeping_thread(i);
+ threads[i].wake_up();
}
// Everything is set up. The master thread enters the idle loop, from
}
- // wake_sleeping_thread() wakes up the thread with the given threadID
- // when it is time to start a new search.
-
- void ThreadsManager::wake_sleeping_thread(int threadID) {
-
- lock_grab(&sleepLock[threadID]);
- cond_signal(&sleepCond[threadID]);
- lock_release(&sleepLock[threadID]);
- }
-
-
/// RootMove and RootMoveList method's definitions
RootMove::RootMove() {
// pv_info_to_uci() returns a string with information on the current PV line
// formatted according to UCI specification.
- std::string RootMove::pv_info_to_uci(Position& pos, int depth, Value alpha,
+ std::string RootMove::pv_info_to_uci(Position& pos, int depth, int selDepth, Value alpha,
Value beta, int pvIdx) {
- std::stringstream s, l;
- Move* m = pv;
-
- while (*m != MOVE_NONE)
- l << *m++ << " ";
+ std::stringstream s;
s << "info depth " << depth
- << " seldepth " << int(m - pv)
+ << " seldepth " << selDepth
<< " multipv " << pvIdx + 1
<< " score " << value_to_uci(pv_score)
<< (pv_score >= beta ? " lowerbound" : pv_score <= alpha ? " upperbound" : "")
<< speed_to_uci(pos.nodes_searched())
- << " pv " << l.str();
+ << " pv ";
+
+ for (Move* m = pv; *m != MOVE_NONE; m++)
+ s << *m << " ";
return s.str();
}