Unfortunatly accessing thread local variable
is much slower than object data (see previous
patch log msg), so we have to revert to old code
to avoid speed regression.
No functional change.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
for (size_t i = 0; i < fens.size(); i++)
{
for (size_t i = 0; i < fens.size(); i++)
{
- Position pos(fens[i], false);
+ Position pos(fens[i], false, NULL);
cerr << "\nPosition: " << i + 1 << '/' << fens.size() << endl;
cerr << "\nPosition: " << i + 1 << '/' << fens.size() << endl;
string fen = sides[0] + char('0' + int(8 - code.length()))
+ sides[1] + "/8/8/8/8/8/8/8 w - - 0 10";
string fen = sides[0] + char('0' + int(8 - code.length()))
+ sides[1] + "/8/8/8/8/8/8/8 w - - 0 10";
- return Position(fen, false).material_key();
+ return Position(fen, false, NULL).material_key();
margins[WHITE] = margins[BLACK] = VALUE_ZERO;
// Probe the material hash table
margins[WHITE] = margins[BLACK] = VALUE_ZERO;
// Probe the material hash table
- ei.mi = this_thread->materialTable.probe(pos);
+ ei.mi = pos.this_thread()->materialTable.probe(pos);
score += ei.mi->material_value();
// If we have a specialized evaluation function for the current material
score += ei.mi->material_value();
// If we have a specialized evaluation function for the current material
}
// Probe the pawn hash table
}
// Probe the pawn hash table
- ei.pi = this_thread->pawnTable.probe(pos);
+ ei.pi = pos.this_thread()->pawnTable.probe(pos);
score += ei.pi->pawns_value();
// Initialize attack and king safety bitboards
score += ei.pi->pawns_value();
// Initialize attack and king safety bitboards
-/// Position::operator=() creates a copy of 'pos'. We want the new born Position
+/// Position::copy() creates a copy of 'pos'. We want the new born Position
/// object do not depend on any external data so we detach state pointer from
/// the source one.
/// object do not depend on any external data so we detach state pointer from
/// the source one.
-Position& Position::operator=(const Position& pos) {
+void Position::copy(const Position& pos, Thread* th) {
memcpy(this, &pos, sizeof(Position));
startState = *st;
st = &startState;
memcpy(this, &pos, sizeof(Position));
startState = *st;
st = &startState;
/// string. This function is not very robust - make sure that input FENs are
/// correct (this is assumed to be the responsibility of the GUI).
/// string. This function is not very robust - make sure that input FENs are
/// correct (this is assumed to be the responsibility of the GUI).
-void Position::from_fen(const string& fenStr, bool isChess960) {
+void Position::from_fen(const string& fenStr, bool isChess960, Thread* th) {
/*
A FEN string defines a particular position using only the ASCII character set.
/*
A FEN string defines a particular position using only the ASCII character set.
st->npMaterial[BLACK] = compute_non_pawn_material(BLACK);
st->checkersBB = attackers_to(king_square(sideToMove)) & pieces(~sideToMove);
chess960 = isChess960;
st->npMaterial[BLACK] = compute_non_pawn_material(BLACK);
st->checkersBB = attackers_to(king_square(sideToMove)) & pieces(~sideToMove);
chess960 = isChess960;
+ Position p(*this, thisThread);
cout << "\nMove is: " << (sideToMove == BLACK ? ".." : "") << move_to_san(p, move);
}
cout << "\nMove is: " << (sideToMove == BLACK ? ".." : "") << move_to_san(p, move);
}
}
// Prefetch pawn and material hash tables
}
// Prefetch pawn and material hash tables
- prefetch((char*)this_thread->pawnTable.entries[st->pawnKey]);
- prefetch((char*)this_thread->materialTable.entries[st->materialKey]);
+ prefetch((char*)thisThread->pawnTable.entries[st->pawnKey]);
+ prefetch((char*)thisThread->materialTable.entries[st->materialKey]);
// Update incremental scores
st->psqScore += psq_delta(piece, from, to);
// Update incremental scores
st->psqScore += psq_delta(piece, from, to);
void Position::flip() {
// Make a copy of current position before to start changing
void Position::flip() {
// Make a copy of current position before to start changing
- const Position pos(*this);
+ const Position pos(*this, thisThread);
+ thisThread = pos.this_thread();
// Board
for (Square s = SQ_A1; s <= SQ_H8; s++)
// Board
for (Square s = SQ_A1; s <= SQ_H8; s++)
/// * A counter for detecting 50 move rule draws.
class Position {
/// * A counter for detecting 50 move rule draws.
class Position {
+
+ // No copy c'tor or assignment operator allowed
+ Position(const Position&);
+ Position& operator=(const Position&);
+
- Position(const Position& p) { *this = p; }
- Position(const std::string& f, bool c960) { from_fen(f, c960); }
- Position& operator=(const Position&);
+ Position(const Position& p, Thread* t) { copy(p, t); }
+ Position(const std::string& f, bool c960, Thread* t) { from_fen(f, c960, t); }
- void from_fen(const std::string& fen, bool isChess960);
+ void copy(const Position& pos, Thread* th);
+ void from_fen(const std::string& fen, bool isChess960, Thread* th);
const std::string to_fen() const;
void print(Move m = MOVE_NONE) const;
const std::string to_fen() const;
void print(Move m = MOVE_NONE) const;
Color side_to_move() const;
int startpos_ply_counter() const;
bool is_chess960() const;
Color side_to_move() const;
int startpos_ply_counter() const;
bool is_chess960() const;
+ Thread* this_thread() const;
int64_t nodes_searched() const;
void set_nodes_searched(int64_t n);
template<bool SkipRepetition> bool is_draw() const;
int64_t nodes_searched() const;
void set_nodes_searched(int64_t n);
template<bool SkipRepetition> bool is_draw() const;
int64_t nodes;
int startPosPly;
Color sideToMove;
int64_t nodes;
int startPosPly;
Color sideToMove;
StateInfo* st;
int chess960;
StateInfo* st;
int chess960;
return st->capturedType;
}
return st->capturedType;
}
+inline Thread* Position::this_thread() const {
+ return thisThread;
+}
+
#endif // !defined(POSITION_H_INCLUDED)
#endif // !defined(POSITION_H_INCLUDED)
// but if we are pondering or in infinite search, we shouldn't print the best
// move before we are told to do so.
if (!Signals.stop && (Limits.ponder || Limits.infinite))
// but if we are pondering or in infinite search, we shouldn't print the best
// move before we are told to do so.
if (!Signals.stop && (Limits.ponder || Limits.infinite))
- this_thread->wait_for_stop_or_ponderhit();
+ pos.this_thread()->wait_for_stop_or_ponderhit();
// Best move could be MOVE_NONE when searching on a stalemate position
cout << "bestmove " << move_to_uci(RootMoves[0].pv[0], Chess960)
// Best move could be MOVE_NONE when searching on a stalemate position
cout << "bestmove " << move_to_uci(RootMoves[0].pv[0], Chess960)
bool isPvMove, inCheck, singularExtensionNode, givesCheck;
bool captureOrPromotion, dangerous, doFullDepthSearch;
int moveCount = 0, playedMoveCount = 0;
bool isPvMove, inCheck, singularExtensionNode, givesCheck;
bool captureOrPromotion, dangerous, doFullDepthSearch;
int moveCount = 0, playedMoveCount = 0;
- Thread* thisThread = this_thread;
+ Thread* thisThread = pos.this_thread();
SplitPoint* sp = NULL;
refinedValue = bestValue = value = -VALUE_INFINITE;
SplitPoint* sp = NULL;
refinedValue = bestValue = value = -VALUE_INFINITE;
lock_release(Threads.splitLock);
Stack ss[MAX_PLY_PLUS_2];
lock_release(Threads.splitLock);
Stack ss[MAX_PLY_PLUS_2];
- Position pos(*sp->pos);
+ Position pos(*sp->pos, this);
memcpy(ss, sp->ss - 1, 4 * sizeof(Stack));
(ss+1)->sp = sp;
memcpy(ss, sp->ss - 1, 4 * sizeof(Stack));
(ss+1)->sp = sp;
using namespace Search;
ThreadsManager Threads; // Global object
using namespace Search;
ThreadsManager Threads; // Global object
-THREAD_LOCAL Thread* this_thread; // Thread local variable
namespace { extern "C" {
// start_routine() is the C function which is called when a new thread
// is launched. It is a wrapper to member function pointed by start_fn.
namespace { extern "C" {
// start_routine() is the C function which is called when a new thread
// is launched. It is a wrapper to member function pointed by start_fn.
- long start_routine(Thread* th) {
-
- this_thread = th; // Save pointer into thread local storage
- (th->*(th->start_fn))();
- return 0;
- }
+ long start_routine(Thread* th) { (th->*(th->start_fn))(); return 0; }
// Thread c'tor starts a newly-created thread of execution that will call
// the idle loop function pointed by start_fn going immediately to sleep.
// Thread c'tor starts a newly-created thread of execution that will call
// the idle loop function pointed by start_fn going immediately to sleep.
lock_init(splitLock);
timer = new Thread(&Thread::timer_loop);
threads.push_back(new Thread(&Thread::main_loop));
lock_init(splitLock);
timer = new Thread(&Thread::timer_loop);
threads.push_back(new Thread(&Thread::main_loop));
- this_thread = main_thread(); // Use main thread's resources
assert(beta <= VALUE_INFINITE);
assert(depth > DEPTH_ZERO);
assert(beta <= VALUE_INFINITE);
assert(depth > DEPTH_ZERO);
- Thread* master = this_thread;
+ Thread* master = pos.this_thread();
if (master->splitPointsCnt >= MAX_SPLITPOINTS_PER_THREAD)
return bestValue;
if (master->splitPointsCnt >= MAX_SPLITPOINTS_PER_THREAD)
return bestValue;
Signals.stopOnPonderhit = Signals.firstRootMove = false;
Signals.stop = Signals.failedLowAtRoot = false;
Signals.stopOnPonderhit = Signals.firstRootMove = false;
Signals.stop = Signals.failedLowAtRoot = false;
+ RootPosition.copy(pos, main_thread());
Limits = limits;
RootMoves.clear();
Limits = limits;
RootMoves.clear();
bool use_sleeping_threads() const { return useSleepingThreads; }
int min_split_depth() const { return minimumSplitDepth; }
int size() const { return (int)threads.size(); }
bool use_sleeping_threads() const { return useSleepingThreads; }
int min_split_depth() const { return minimumSplitDepth; }
int size() const { return (int)threads.size(); }
- Thread* main_thread() const { return threads[0]; }
+ Thread* main_thread() { return threads[0]; }
void wake_up() const;
void sleep() const;
void wake_up() const;
void sleep() const;
};
extern ThreadsManager Threads;
};
extern ThreadsManager Threads;
-extern THREAD_LOCAL Thread* this_thread;
#endif // !defined(THREAD_H_INCLUDED)
#endif // !defined(THREAD_H_INCLUDED)
# define FORCE_INLINE inline
#endif
# define FORCE_INLINE inline
#endif
-#if defined(__GNUC__)
-# define THREAD_LOCAL __thread
-#else
-# define THREAD_LOCAL __declspec(thread)
-#endif
-
#if defined(USE_POPCNT)
const bool HasPopCnt = true;
#else
#if defined(USE_POPCNT)
const bool HasPopCnt = true;
#else
void uci_loop(const string& args) {
void uci_loop(const string& args) {
- Position pos(StartFEN, false); // The root position
+ Position pos(StartFEN, false, Threads.main_thread()); // The root position
string cmd, token;
while (token != "quit")
string cmd, token;
while (token != "quit")
- pos.from_fen(fen, Options["UCI_Chess960"]);
+ pos.from_fen(fen, Options["UCI_Chess960"], Threads.main_thread());
// Parse move list (if any)
while (is >> token && (m = move_from_uci(pos, token)) != MOVE_NONE)
// Parse move list (if any)
while (is >> token && (m = move_from_uci(pos, token)) != MOVE_NONE)