Subversion Repositories Games.Chess Giants

Rev

Rev 154 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 154 Rev 169
Line 4... Line 4...
4
  Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
4
  Copyright (C) 2008-2015 Marco Costalba, Joona Kiiski, Tord Romstad
5
  Copyright (C) 2015-2016 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
5
  Copyright (C) 2015-2018 Marco Costalba, Joona Kiiski, Gary Linscott, Tord Romstad
6
 
6
 
7
  Stockfish is free software: you can redistribute it and/or modify
7
  Stockfish is free software: you can redistribute it and/or modify
8
  it under the terms of the GNU General Public License as published by
8
  it under the terms of the GNU General Public License as published by
9
  the Free Software Foundation, either version 3 of the License, or
9
  the Free Software Foundation, either version 3 of the License, or
10
  (at your option) any later version.
10
  (at your option) any later version.
Line 27... Line 27...
27
#include "uci.h"
27
#include "uci.h"
28
#include "syzygy/tbprobe.h"
28
#include "syzygy/tbprobe.h"
29
 
29
 
30
ThreadPool Threads; // Global object
30
ThreadPool Threads; // Global object
31
 
31
 
32
/// Thread constructor launches the thread and then waits until it goes to sleep
-
 
33
/// in idle_loop().
-
 
34
 
32
 
35
Thread::Thread() {
33
/// Thread constructor launches the thread and waits until it goes to sleep
-
 
34
/// in idle_loop(). Note that 'searching' and 'exit' should be alredy set.
36
 
35
 
37
  resetCalls = exit = false;
-
 
38
  maxPly = callsCnt = 0;
-
 
39
  tbHits = 0;
-
 
40
  history.clear();
-
 
41
  counterMoves.clear();
-
 
42
  idx = Threads.size(); // Start from 0
36
Thread::Thread(size_t n) : idx(n), stdThread(&Thread::idle_loop, this) {
43
 
37
 
44
  std::unique_lock<Mutex> lk(mutex);
-
 
45
  searching = true;
38
  wait_for_search_finished();
46
  nativeThread = std::thread(&Thread::idle_loop, this);
-
 
47
  sleepCondition.wait(lk, [&]{ return !searching; });
-
 
48
}
39
}
49
 
40
 
50
 
41
 
51
/// Thread destructor waits for thread termination before returning
42
/// Thread destructor wakes up the thread in idle_loop() and waits
-
 
43
/// for its termination. Thread should be already waiting.
52
 
44
 
53
Thread::~Thread() {
45
Thread::~Thread() {
54
 
46
 
55
  mutex.lock();
47
  assert(!searching);
-
 
48
 
56
  exit = true;
49
  exit = true;
57
  sleepCondition.notify_one();
-
 
58
  mutex.unlock();
50
  start_searching();
59
  nativeThread.join();
51
  stdThread.join();
60
}
52
}
61
 
53
 
62
 
54
 
63
/// Thread::wait_for_search_finished() waits on sleep condition
55
/// Thread::clear() reset histories, usually before a new game
64
/// until not searching
-
 
65
 
56
 
66
void Thread::wait_for_search_finished() {
57
void Thread::clear() {
67
 
58
 
68
  std::unique_lock<Mutex> lk(mutex);
59
  counterMoves.fill(MOVE_NONE);
-
 
60
  mainHistory.fill(0);
69
  sleepCondition.wait(lk, [&]{ return !searching; });
61
  captureHistory.fill(0);
70
}
-
 
71
 
62
 
-
 
63
  for (auto& to : contHistory)
-
 
64
      for (auto& h : to)
-
 
65
          h.fill(0);
72
 
66
 
73
/// Thread::wait() waits on sleep condition until condition is true
67
  contHistory[NO_PIECE][0].fill(Search::CounterMovePruneThreshold - 1);
-
 
68
}
74
 
69
 
75
void Thread::wait(std::atomic_bool& condition) {
70
/// Thread::start_searching() wakes up the thread that will start the search
76
 
71
 
-
 
72
void Thread::start_searching() {
-
 
73
 
77
  std::unique_lock<Mutex> lk(mutex);
74
  std::lock_guard<Mutex> lk(mutex);
-
 
75
  searching = true;
78
  sleepCondition.wait(lk, [&]{ return bool(condition); });
76
  cv.notify_one(); // Wake up the thread in idle_loop()
79
}
77
}
80
 
78
 
81
 
79
 
82
/// Thread::start_searching() wakes up the thread that will start the search
80
/// Thread::wait_for_search_finished() blocks on the condition variable
-
 
81
/// until the thread has finished searching.
83
 
82
 
84
void Thread::start_searching(bool resume) {
83
void Thread::wait_for_search_finished() {
85
 
84
 
86
  std::unique_lock<Mutex> lk(mutex);
85
  std::unique_lock<Mutex> lk(mutex);
87
 
-
 
88
  if (!resume)
-
 
89
      searching = true;
86
  cv.wait(lk, [&]{ return !searching; });
90
 
-
 
91
  sleepCondition.notify_one();
-
 
92
}
87
}
93
 
88
 
94
 
89
 
95
/// Thread::idle_loop() is where the thread is parked when it has no work to do
90
/// Thread::idle_loop() is where the thread is parked, blocked on the
-
 
91
/// condition variable, when it has no work to do.
96
 
92
 
97
void Thread::idle_loop() {
93
void Thread::idle_loop() {
98
 
94
 
-
 
95
  // If OS already scheduled us on a different group than 0 then don't overwrite
-
 
96
  // the choice, eventually we are one of many one-threaded processes running on
-
 
97
  // some Windows NUMA hardware, for instance in fishtest. To make it simple,
-
 
98
  // just check if running threads are below a threshold, in this case all this
-
 
99
  // NUMA machinery is not needed.
-
 
100
  if (Options["Threads"] >= 8)
-
 
101
      WinProcGroup::bindThisThread(idx);
-
 
102
 
99
  while (!exit)
103
  while (true)
100
  {
104
  {
101
      std::unique_lock<Mutex> lk(mutex);
105
      std::unique_lock<Mutex> lk(mutex);
102
 
-
 
103
      searching = false;
106
      searching = false;
-
 
107
      cv.notify_one(); // Wake up anyone waiting for search finished
-
 
108
      cv.wait(lk, [&]{ return searching; });
104
 
109
 
105
      while (!searching && !exit)
-
 
106
      {
110
      if (exit)
107
          sleepCondition.notify_one(); // Wake up any waiting thread
-
 
108
          sleepCondition.wait(lk);
111
          return;
109
      }
-
 
110
 
112
 
111
      lk.unlock();
113
      lk.unlock();
112
 
114
 
113
      if (!exit)
-
 
114
          search();
115
      search();
115
  }
116
  }
116
}
117
}
117
 
118
 
-
 
119
/// ThreadPool::set() creates/destroys threads to match the requested number.
-
 
120
/// Created and launced threads wil go immediately to sleep in idle_loop.
-
 
121
/// Upon resizing, threads are recreated to allow for binding if necessary.
118
 
122
 
119
/// ThreadPool::init() creates and launches requested threads that will go
123
void ThreadPool::set(size_t requested) {
120
/// immediately to sleep. We cannot use a constructor because Threads is a
-
 
121
/// static object and we need a fully initialized engine at this point due to
-
 
122
/// allocation of Endgames in the Thread constructor.
-
 
123
 
124
 
-
 
125
  if (size() > 0) { // destroy any existing thread(s)
124
void ThreadPool::init() {
126
      main()->wait_for_search_finished();
125
 
127
 
126
  push_back(new MainThread);
128
      while (size() > 0)
127
  read_uci_options();
129
          delete back(), pop_back();
128
}
130
  }
129
 
131
 
-
 
132
  if (requested > 0) { // create new thread(s)
-
 
133
      push_back(new MainThread(0));
130
 
134
 
131
/// ThreadPool::exit() terminates threads before the program exits. Cannot be
-
 
132
/// done in destructor because threads must be terminated before deleting any
135
      while (size() < requested)
133
/// static objects while still in main().
136
          push_back(new Thread(size()));
134
 
-
 
135
void ThreadPool::exit() {
137
      clear();
136
 
138
  }
137
  while (size())
-
 
138
      delete back(), pop_back();
-
 
139
}
139
}
140
 
140
 
-
 
141
/// ThreadPool::clear() sets threadPool data to initial values.
141
 
142
 
142
/// ThreadPool::read_uci_options() updates internal threads parameters from the
-
 
143
/// corresponding UCI options and creates/destroys threads to match requested
-
 
144
/// number. Thread objects are dynamically allocated.
143
void ThreadPool::clear() {
145
 
144
 
146
void ThreadPool::read_uci_options() {
-
 
147
 
-
 
148
  size_t requested = Options["Threads"];
-
 
149
 
-
 
150
  assert(requested > 0);
-
 
151
 
-
 
152
  while (size() < requested)
-
 
153
      push_back(new Thread);
-
 
154
 
-
 
155
  while (size() > requested)
-
 
156
      delete back(), pop_back();
-
 
157
}
-
 
158
 
-
 
159
 
-
 
160
/// ThreadPool::nodes_searched() returns the number of nodes searched
-
 
161
 
-
 
162
uint64_t ThreadPool::nodes_searched() const {
-
 
163
 
-
 
164
  uint64_t nodes = 0;
-
 
165
  for (Thread* th : *this)
145
  for (Thread* th : *this)
166
      nodes += th->rootPos.nodes_searched();
-
 
167
  return nodes;
146
      th->clear();
168
}
-
 
169
 
147
 
170
 
-
 
171
/// ThreadPool::tb_hits() returns the number of TB hits
-
 
172
 
-
 
173
uint64_t ThreadPool::tb_hits() const {
-
 
174
 
-
 
175
  uint64_t hits = 0;
148
  main()->callsCnt = 0;
176
  for (Thread* th : *this)
149
  main()->previousScore = VALUE_INFINITE;
177
      hits += th->tbHits;
150
  main()->previousTimeReduction = 1;
178
  return hits;
-
 
179
}
151
}
180
 
152
 
181
 
-
 
182
/// ThreadPool::start_thinking() wakes up the main thread sleeping in idle_loop()
153
/// ThreadPool::start_thinking() wakes up main thread waiting in idle_loop() and
183
/// and starts a new search, then returns immediately.
154
/// returns immediately. Main thread will wake up other threads and start the search.
184
 
155
 
185
void ThreadPool::start_thinking(Position& pos, StateListPtr& states,
156
void ThreadPool::start_thinking(Position& pos, StateListPtr& states,
186
                                const Search::LimitsType& limits) {
157
                                const Search::LimitsType& limits, bool ponderMode) {
187
 
158
 
188
  main()->wait_for_search_finished();
159
  main()->wait_for_search_finished();
189
 
160
 
190
  Search::Signals.stopOnPonderhit = Search::Signals.stop = false;
161
  stopOnPonderhit = stop = false;
-
 
162
  ponder = ponderMode;
191
  Search::Limits = limits;
163
  Search::Limits = limits;
192
  Search::RootMoves rootMoves;
164
  Search::RootMoves rootMoves;
193
 
165
 
194
  for (const auto& m : MoveList<LEGAL>(pos))
166
  for (const auto& m : MoveList<LEGAL>(pos))
195
      if (   limits.searchmoves.empty()
167
      if (   limits.searchmoves.empty()
196
          || std::count(limits.searchmoves.begin(), limits.searchmoves.end(), m))
168
          || std::count(limits.searchmoves.begin(), limits.searchmoves.end(), m))
197
          rootMoves.push_back(Search::RootMove(m));
169
          rootMoves.emplace_back(m);
198
 
170
 
199
  if (!rootMoves.empty())
171
  if (!rootMoves.empty())
200
      Tablebases::filter_root_moves(pos, rootMoves);
172
      Tablebases::filter_root_moves(pos, rootMoves);
201
 
173
 
202
  // After ownership transfer 'states' becomes empty, so if we stop the search
174
  // After ownership transfer 'states' becomes empty, so if we stop the search
Line 204... Line 176...
204
  assert(states.get() || setupStates.get());
176
  assert(states.get() || setupStates.get());
205
 
177
 
206
  if (states.get())
178
  if (states.get())
207
      setupStates = std::move(states); // Ownership transfer, states is now empty
179
      setupStates = std::move(states); // Ownership transfer, states is now empty
208
 
180
 
-
 
181
  // We use Position::set() to set root position across threads. But there are
-
 
182
  // some StateInfo fields (previous, pliesFromNull, capturedPiece) that cannot
-
 
183
  // be deduced from a fen string, so set() clears them and to not lose the info
-
 
184
  // we need to backup and later restore setupStates->back(). Note that setupStates
-
 
185
  // is shared by threads but is accessed in read-only mode.
209
  StateInfo tmp = setupStates->back();
186
  StateInfo tmp = setupStates->back();
210
 
187
 
211
  for (Thread* th : Threads)
188
  for (Thread* th : *this)
212
  {
189
  {
213
      th->maxPly = 0;
-
 
214
      th->tbHits = 0;
190
      th->nodes = th->tbHits = th->nmp_ply = th->nmp_odd = 0;
215
      th->rootDepth = DEPTH_ZERO;
191
      th->rootDepth = th->completedDepth = DEPTH_ZERO;
216
      th->rootMoves = rootMoves;
192
      th->rootMoves = rootMoves;
217
      th->rootPos.set(pos.fen(), pos.is_chess960(), &setupStates->back(), th);
193
      th->rootPos.set(pos.fen(), pos.is_chess960(), &setupStates->back(), th);
218
  }
194
  }
219
 
195
 
220
  setupStates->back() = tmp; // Restore st->previous, cleared by Position::set()
196
  setupStates->back() = tmp;
221
 
197
 
222
  main()->start_searching();
198
  main()->start_searching();
223
}
199
}