Compare commits

...

35 Commits

Author SHA1 Message Date
Marco Costalba 48cfdfcc46 Fix threads count setting
Was broken after "Optimal tune for 8 cores" patch.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-01 20:57:33 +01:00
Marco Costalba fa7b244dc9 Optimal tune for 8 cores
After deep tests Louis Zulli found on his OCTAL machine that
best setup for an 8 core CPU is as following

"Threads" = 8
"Minimum Split Depth" = 6 or 7 (mSD)
"Maximum Number of Threads per Split Point" = not important (MNTpSP)

Here are testing results:

mSD7 (8 threads) vs mSD4 (8 threads): 291 - 120 - 589
mSD6 vs mSD7: 168 - 188 - 644
mSD6-MNTpSP5 vs mSD6-MNTpSP6: 172 - 172 - 656
SF-7threads vs SF-8threads: 179 - 204 - 617

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-01 20:57:17 +01:00
Marco Costalba 29ad6a73fc Fix duplicated scaling function
We erroneusly added two times the same scaling function
to endgame's map.

Fix detected by valgrind becasue resulted in a memleak
of the first added scaling function.

Bug introduced by 30e8f0c9ad6a473 of 13/02/2009

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-01 19:40:43 +01:00
Marco Costalba ac48b16708 Update release number
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-01 14:59:55 +01:00
Marco Costalba 38b1c4b6b8 Another TT size limit fix attempt
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-01 14:17:00 +01:00
Marco Costalba 162dbeaee8 Remove a bogus assert
It is not true with old 1.6.xx code

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-01 14:09:23 +01:00
Marco Costalba 85146ca0a9 Check bounds in set_option_value()
Normally it's up to the GUI to check for option's limits,
but we could receive the new value directly from the user
by teminal window. So let's check the bounds anyway.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-01 14:06:59 +01:00
Joona Kiiski 02e12a69a7 Remove InfiniteSearch hack
With current search control system, I can see absolutely no
reason to classify fixed time search as infinite search.

So remove old dated hack

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-01 13:15:28 +01:00
Tord Romstad 6e8116e38f Make sure we make a move at the end of the search when reaching
maximum depth during a "go movetime ..." search. This prevents
Stockfish from hanging forever after finding a mate in two or
three while running a test suite at a level of a few seconds
per move.

No functional change when playing games at normal time controls.
2010-02-01 13:13:58 +01:00
Marco Costalba 29f7fab2a9 Do not wait when AbortSearch is set
It means we have already received "stop" or "quit" commands.

This fixes an hang in tactical test in Fritz GUI. Bug
introduced by previous bug fix :-(

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-01 13:13:20 +01:00
Marco Costalba 2af986bf31 Fix sending of best move during an infinite search
According to UCI standard once engine receives 'go infinite'
command it should search until the "stop" command and do not exit
the search without being told so, even if PLY_MAX has been reached.

Patch is quite invasive because it cleanups some hacks used
by fixed depth and fixed nodes modes, mainly during benchmarks.

Bug found by Pascal Georges.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-01 13:10:21 +01:00
Marco Costalba b67146b100 Add hardware POPCNT support for gcc
With new target 'make gcc-popcnt' it is now
possible to compile with enabled hardware POPCNT
support also with gcc. Until now was possible only
for Intel and MSVC compilers.

When this instruction is supported by CPU, for instance
on Intel i7 or i5 family, produced binary is a bit faster.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-01 12:48:49 +01:00
Joona Kiiski c1b1a94d81 Standardize set_option function
Previously input like "setoption name Use Search Log value true "
(note space at the end of the line) didn't work.

Now parse value same way as option name. This way we implicitly
left- and right-trim value.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-01 12:48:11 +01:00
Joona Kiiski 17212e5fcc Remove last use of uip.eof()
Value of uip.eof() should not be trusted.
input like "go infinite searchmoves " (note space in the end of line)
causes problems.

Check the return value of (uip >> token) instead

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-01 12:46:03 +01:00
Marco Costalba 46921dff27 Fix a couple of MSVC casting warnings
Also removed some trailing whitespaces and aligned
indentation to current standard.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-01 12:45:04 +01:00
Marco Costalba 941016e7a2 Check for thread creation successful completion
It is a good programming practice to verify a system
call has indeed succeed.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-01 12:44:11 +01:00
Tord Romstad 290caf9960 Fixes a Chess960 bug when playing with more than one search thread.
The init_eval() function corrupted the static array castleRightsMask[]
in the Position class, resulting in instant crashes in most Chess960
games. Fixed by repairing the damage directly after the function is
called. Also modified the Position::to_fen() function to display
castle rights correctly for Chess960 positions, and added sanity checks
for uncastled rook files in Position::is_ok().
2010-02-01 12:40:09 +01:00
Marco Costalba 43fa3a4d64 Fix some races in SMP code
When a search fails high then sp->alpha is increased and
slave threads are requested to stop.

So we have to check for a stop request before to start a search
otherwise we could end up with sp->alpha >= sp->beta
leading to an assert in debug run in search_pv().

This patch fixes the assert and get rid of some of possible races.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-01 12:39:53 +01:00
Marco Costalba 64b4836d12 Fix enum Value issue with gcc 4.4
Louis Zulli reports a miscompile with g++-4.4 from MacPorts.

Namely enum Value is compiled as unsigned instead of signed integer
and this yields an issue in score_string() where float(v) is incorrectly
casted when Value v is negative.

This patch ensure that compiler choses a signed variable to store a Value.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-01 12:39:21 +01:00
Marco Costalba 5df7d62eb9 Fix 'position ..... moves ' parsing bug
If after 'moves' there is a space then we crash.

The problem is that operator>>() trims whitespaces so that
after 'moves' has been extract we are still not at eof()
but remaining string contains only spaces. So that the next
extarction operation uip >> token ends up with unchanged token
value that remains 'moves', this garbage value is then feeded
to RootPosition.do_move() through move_from_string() that does
not detect the invalid move value leading to a crash.

This bug is triggered by Shredder 12 interface under Mac that
puts a space after 'moves' without any actual move list.

Bug fixed by Justin Blanchard

After reviewing UCI parsing code I spotted other possible weak
points due to the fact that we don't test if the last extract
operation has been succesful. So I have extended Justing patch
to fix the remaining possible holes in uci.cpp

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-01 12:36:30 +01:00
Marco Costalba 82179c70dc Fix en-passant parsing from fen string
According to standard en-passant is recorded in fen string regardless
of whether there is a pawn in position to make an en passant capture.

Instead internally we set ep square only if the pawn can be captured.
So teach from_fen() to correctly handle this difference.

Bug reported and fixed by Justin Blanchard.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-01 12:36:06 +01:00
Marco Costalba de17652e47 Fix a possible crash in thread_is_available()
When we have more then 2 threads then we do an array
access with index 'Threads[slave].activeSplitPoints - 1'
This should be >= 0 because we tested the variable just
few statements before, but because is a shared variable
it could be that the 'slave' thread set the value to zero
just after we test it, so that when we use the decremented
variable for array access we crash.

Bug spotted by Bruno Causse.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-01 12:34:31 +01:00
Marco Costalba 647b79b556 Extend maximum hash size to 8 GB
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-02-01 12:14:37 +01:00
Marco Costalba e0a8b36436 Stockfish 1.6.2
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-12-30 13:25:20 +01:00
Marco Costalba 8d724220a7 Better fix for gcc optimization issue
According to the standard, compiler is free to choose
the enum type as long as can keep its data.
Also cast to short and right shift are implementation
defined in case of a signed integer.

Normally all the compilers implement this stuff in
the "usual" way, but gcc with -O3 and -O2 pushes
aggressively the language to its limits to squeeze
even the last bit of speed. And this broke our
not 100% standard conforming code.

The fix is to rewrite the Score enum and the 16 bits
word extracting functions in a way that is 100% standard
compliant and with no speed regression on gcc and also on
the other compilers.

Verified it works on all compilers and with equivalent
functionality.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-12-30 13:25:02 +01:00
Marco Costalba 0973cc2ef6 Score enum should be at least 32 bits
The compiler is allowed to chose the size of an enum variable
based on the values it is expected to store. So force the compiler
to use at least a 32 bit integer type for the Score.

MSVC and Intel do not change, while gcc under -O3 is affected
by this change.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-12-27 19:45:19 +01:00
Marco Costalba 3f14f9a478 Revert small pop_1st_bit() optimization
We cannot cast a pointer type to an unrelated pointer type.
This is a violation of the strict aliasing rules.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-12-27 14:07:08 +01:00
Marco Costalba aa86d81f79 Remove a bogus assert
It is not clear why is not true, even in single thread
case, but as a matter of fact it is not!

So remove it.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-12-27 13:54:46 +01:00
Marco Costalba b884351cc7 Use THREAD_MAX instead of hardcoded 8
This will allow to change THREAD_MAX value in the future.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-12-27 13:52:29 +01:00
Marco Costalba 4d9e9ac3d4 Restore development version
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-12-27 08:35:44 +01:00
Marco Costalba 3dc9f95225 Set maximum hash table size to 2GB
We cannot allocate more then 2 GB, so let the limit
reflect this.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-12-27 00:44:08 +01:00
Marco Costalba bc0871acbc Stockfish 1.6.1
Workaround a gcc optimization bug.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-12-26 19:39:22 +01:00
Marco Costalba 2643f1552f Workaround optimization bug in gcc
Unfortunatly we need to slow down to -O1 to be sure
it works always.

Note that sometime it works also with -O2 or even -O3,
but user has to try himself.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-12-26 19:39:13 +01:00
Marco Costalba ba07b95ee0 Fix description of Score enum
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-12-26 19:39:04 +01:00
Marco Costalba ef58551a2d Fix a typo in ReducedStateInfo
It happened to work by accident because Score and
Value are both integer.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2009-12-26 19:38:53 +01:00
15 changed files with 369 additions and 234 deletions
+8
View File
@@ -80,6 +80,7 @@ help:
@echo "Makefile options:" @echo "Makefile options:"
@echo "" @echo ""
@echo "make > Default: Compiler = g++" @echo "make > Default: Compiler = g++"
@echo "make gcc-popcnt > Compiler = g++ + popcnt-support"
@echo "make icc > Compiler = icpc" @echo "make icc > Compiler = icpc"
@echo "make icc-profile > Compiler = icpc + automatic pgo-build" @echo "make icc-profile > Compiler = icpc + automatic pgo-build"
@echo "make icc-profile-popcnt > Compiler = icpc + automatic pgo-build + popcnt-support" @echo "make icc-profile-popcnt > Compiler = icpc + automatic pgo-build + popcnt-support"
@@ -108,6 +109,13 @@ gcc:
CXXFLAGS="$(GCCFLAGS)" \ CXXFLAGS="$(GCCFLAGS)" \
all all
gcc-popcnt:
$(MAKE) \
CXX='g++' \
CXXFLAGS="$(GCCFLAGS) -DUSE_POPCNT" \
all
icc: icc:
$(MAKE) \ $(MAKE) \
CXX='icpc' \ CXX='icpc' \
+1 -1
View File
@@ -155,7 +155,7 @@ void benchmark(const string& commandLine) {
cerr << "\nBench position: " << cnt << '/' << positions.size() << endl << endl; cerr << "\nBench position: " << cnt << '/' << positions.size() << endl << endl;
if (limitType == "perft") if (limitType == "perft")
totalNodes += perft(pos, maxDepth * OnePly); totalNodes += perft(pos, maxDepth * OnePly);
else if (!think(pos, true, false, 0, dummy, dummy, 0, maxDepth, maxNodes, secsPerPos, moves)) else if (!think(pos, false, false, 0, dummy, dummy, 0, maxDepth, maxNodes, secsPerPos, moves))
break; break;
totalNodes += nodes_searched(); totalNodes += nodes_searched();
} }
+9 -7
View File
@@ -348,19 +348,21 @@ union b_union {
Square pop_1st_bit(Bitboard* bb) { Square pop_1st_bit(Bitboard* bb) {
b_union* u; b_union u;
Square ret; Square ret;
u = (b_union*)bb; u.b = *bb;
if (u->dw.l) if (u.dw.l)
{ {
ret = Square(BitTable[((u->dw.l ^ (u->dw.l - 1)) * 0x783a9b23) >> 26]); ret = Square(BitTable[((u.dw.l ^ (u.dw.l - 1)) * 0x783a9b23) >> 26]);
u->dw.l &= (u->dw.l - 1); u.dw.l &= (u.dw.l - 1);
*bb = u.b;
return ret; return ret;
} }
ret = Square(BitTable[((~(u->dw.h ^ (u->dw.h - 1))) * 0x783a9b23) >> 26]); ret = Square(BitTable[((~(u.dw.h ^ (u.dw.h - 1))) * 0x783a9b23) >> 26]);
u->dw.h &= (u->dw.h - 1); u.dw.h &= (u.dw.h - 1);
*bb = u.b;
return ret; return ret;
} }
+24
View File
@@ -53,6 +53,30 @@ inline bool cpu_has_popcnt() {
#define POPCNT_INTRINSIC(x) __popcnt64(x) #define POPCNT_INTRINSIC(x) __popcnt64(x)
#elif defined(__GNUC__) && defined(USE_POPCNT) // Gcc compiler
inline void __cpuid(unsigned int op,
unsigned int *eax, unsigned int *ebx,
unsigned int *ecx, unsigned int *edx)
{
*eax = op;
*ecx = 0;
__asm__("cpuid" : "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx)
: "0" (*eax), "2" (*ecx));
}
inline bool cpu_has_popcnt() {
unsigned int eax, ebx, ecx, edx;
__cpuid(1, &eax, &ebx, &ecx, &edx);
return (ecx >> 23) & 1;
}
#define POPCNT_INTRINSIC(x) ({ \
unsigned long __ret; \
__asm__("popcnt %1, %0" : "=r" (__ret) : "r" (x)); \
__ret; })
#else // Safe fallback for unsupported compilers or when USE_POPCNT is disabled #else // Safe fallback for unsupported compilers or when USE_POPCNT is disabled
inline bool cpu_has_popcnt() { return false; } inline bool cpu_has_popcnt() { return false; }
+4 -3
View File
@@ -251,9 +251,10 @@ namespace {
// in init_safety(). // in init_safety().
Value SafetyTable[100]; Value SafetyTable[100];
// Pawn and material hash tables, indexed by the current thread id // Pawn and material hash tables, indexed by the current thread id.
MaterialInfoTable* MaterialTable[8] = {0, 0, 0, 0, 0, 0, 0, 0}; // Note that they will be initialized at 0 being global variables.
PawnInfoTable* PawnTable[8] = {0, 0, 0, 0, 0, 0, 0, 0}; MaterialInfoTable* MaterialTable[THREAD_MAX];
PawnInfoTable* PawnTable[THREAD_MAX];
// Sizes of pawn and material hash tables // Sizes of pawn and material hash tables
const int PawnTableSize = 16384; const int PawnTableSize = 16384;
-1
View File
@@ -374,7 +374,6 @@ EndgameFunctions::EndgameFunctions() {
add<ScalingFunction<KBPPKB> >("KBPPKB"); add<ScalingFunction<KBPPKB> >("KBPPKB");
add<ScalingFunction<KBPKN> >("KBPKN"); add<ScalingFunction<KBPKN> >("KBPKN");
add<ScalingFunction<KRPPKRP> >("KRPPKRP"); add<ScalingFunction<KRPPKRP> >("KRPPKRP");
add<ScalingFunction<KRPPKRP> >("KRPPKRP");
} }
EndgameFunctions::~EndgameFunctions() { EndgameFunctions::~EndgameFunctions() {
+1 -1
View File
@@ -50,7 +50,7 @@ using namespace std;
/// Version number. If this is left empty, the current date (in the format /// Version number. If this is left empty, the current date (in the format
/// YYMMDD) is used as a version number. /// YYMMDD) is used as a version number.
static const string EngineVersion = "1.6"; static const string EngineVersion = "1.6.3";
static const string AppName = "Stockfish"; static const string AppName = "Stockfish";
static const string AppTag = ""; static const string AppTag = "";
+41 -2
View File
@@ -204,11 +204,16 @@ void Position::from_fen(const string& fen) {
while (fen[i] == ' ') while (fen[i] == ' ')
i++; i++;
// En passant square // En passant square -- ignore if no capture is possible
if ( i <= fen.length() - 2 if ( i <= fen.length() - 2
&& (fen[i] >= 'a' && fen[i] <= 'h') && (fen[i] >= 'a' && fen[i] <= 'h')
&& (fen[i+1] == '3' || fen[i+1] == '6')) && (fen[i+1] == '3' || fen[i+1] == '6'))
{
Square fenEpSquare = square_from_string(fen.substr(i, 2));
Color them = opposite_color(sideToMove);
if (attacks_from<PAWN>(fenEpSquare, them) & this->pieces(PAWN, sideToMove))
st->epSquare = square_from_string(fen.substr(i, 2)); st->epSquare = square_from_string(fen.substr(i, 2));
}
// Various initialisation // Various initialisation
for (Square sq = SQ_A1; sq <= SQ_H8; sq++) for (Square sq = SQ_A1; sq <= SQ_H8; sq++)
@@ -265,11 +270,25 @@ const string Position::to_fen() const {
} }
fen += (sideToMove == WHITE ? "w " : "b "); fen += (sideToMove == WHITE ? "w " : "b ");
if (st->castleRights != NO_CASTLES) if (st->castleRights != NO_CASTLES)
{
if (initialKFile == FILE_E && initialQRFile == FILE_A && initialKRFile == FILE_H)
{ {
if (can_castle_kingside(WHITE)) fen += 'K'; if (can_castle_kingside(WHITE)) fen += 'K';
if (can_castle_queenside(WHITE)) fen += 'Q'; if (can_castle_queenside(WHITE)) fen += 'Q';
if (can_castle_kingside(BLACK)) fen += 'k'; if (can_castle_kingside(BLACK)) fen += 'k';
if (can_castle_queenside(BLACK)) fen += 'q'; if (can_castle_queenside(BLACK)) fen += 'q';
}
else
{
if (can_castle_kingside(WHITE))
fen += char(toupper(file_to_char(initialKRFile)));
if (can_castle_queenside(WHITE))
fen += char(toupper(file_to_char(initialQRFile)));
if (can_castle_kingside(BLACK))
fen += file_to_char(initialKRFile);
if (can_castle_queenside(BLACK))
fen += file_to_char(initialQRFile);
}
} else } else
fen += '-'; fen += '-';
@@ -671,7 +690,7 @@ void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool moveI
Key pawnKey, materialKey; Key pawnKey, materialKey;
int castleRights, rule50, pliesFromNull; int castleRights, rule50, pliesFromNull;
Square epSquare; Square epSquare;
Value value; Score value;
Value npMaterial[2]; Value npMaterial[2];
}; };
@@ -1843,6 +1862,7 @@ bool Position::is_ok(int* failedStep) const {
static const bool debugNonPawnMaterial = false; static const bool debugNonPawnMaterial = false;
static const bool debugPieceCounts = false; static const bool debugPieceCounts = false;
static const bool debugPieceList = false; static const bool debugPieceList = false;
static const bool debugCastleSquares = false;
if (failedStep) *failedStep = 1; if (failedStep) *failedStep = 1;
@@ -1979,6 +1999,25 @@ bool Position::is_ok(int* failedStep) const {
return false; return false;
} }
} }
if (failedStep) (*failedStep)++;
if (debugCastleSquares) {
for (Color c = WHITE; c <= BLACK; c++) {
if (can_castle_kingside(c) && piece_on(initial_kr_square(c)) != piece_of_color_and_type(c, ROOK))
return false;
if (can_castle_queenside(c) && piece_on(initial_qr_square(c)) != piece_of_color_and_type(c, ROOK))
return false;
}
if (castleRightsMask[initial_kr_square(WHITE)] != (ALL_CASTLES ^ WHITE_OO))
return false;
if (castleRightsMask[initial_qr_square(WHITE)] != (ALL_CASTLES ^ WHITE_OOO))
return false;
if (castleRightsMask[initial_kr_square(BLACK)] != (ALL_CASTLES ^ BLACK_OO))
return false;
if (castleRightsMask[initial_qr_square(BLACK)] != (ALL_CASTLES ^ BLACK_OOO))
return false;
}
if (failedStep) *failedStep = 0; if (failedStep) *failedStep = 0;
return true; return true;
} }
+106 -61
View File
@@ -227,14 +227,9 @@ namespace {
int MaxNodes, MaxDepth; int MaxNodes, MaxDepth;
int MaxSearchTime, AbsoluteMaxSearchTime, ExtraSearchTime, ExactMaxTime; int MaxSearchTime, AbsoluteMaxSearchTime, ExtraSearchTime, ExactMaxTime;
int RootMoveNumber; int RootMoveNumber;
bool InfiniteSearch; bool UseTimeManagement, InfiniteSearch, PonderSearch, StopOnPonderhit;
bool PonderSearch; bool AbortSearch, Quit;
bool StopOnPonderhit; bool FailHigh, FailLow, Problem;
bool AbortSearch; // heavy SMP read access
bool Quit;
bool FailHigh;
bool FailLow;
bool Problem;
// Show current line? // Show current line?
bool ShowCurrentLine; bool ShowCurrentLine;
@@ -368,8 +363,20 @@ bool think(const Position& pos, bool infinite, bool ponder, int side_to_move,
int time[], int increment[], int movesToGo, int maxDepth, int time[], int increment[], int movesToGo, int maxDepth,
int maxNodes, int maxTime, Move searchMoves[]) { int maxNodes, int maxTime, Move searchMoves[]) {
// Look for a book move // Initialize global search variables
if (!infinite && !ponder && get_option_value_bool("OwnBook")) Idle = StopOnPonderhit = AbortSearch = Quit = false;
FailHigh = FailLow = Problem = false;
NodesSincePoll = 0;
SearchStartTime = get_system_time();
ExactMaxTime = maxTime;
MaxDepth = maxDepth;
MaxNodes = maxNodes;
InfiniteSearch = infinite;
PonderSearch = ponder;
UseTimeManagement = !ExactMaxTime && !MaxDepth && !MaxNodes && !InfiniteSearch;
// Look for a book move, only during games, not tests
if (UseTimeManagement && !ponder && get_option_value_bool("OwnBook"))
{ {
Move bookMove; Move bookMove;
if (get_option_value_string("Book File") != OpeningBook.file_name()) if (get_option_value_string("Book File") != OpeningBook.file_name())
@@ -384,8 +391,6 @@ bool think(const Position& pos, bool infinite, bool ponder, int side_to_move,
} }
// Initialize global search variables // Initialize global search variables
Idle = false;
SearchStartTime = get_system_time();
for (int i = 0; i < THREAD_MAX; i++) for (int i = 0; i < THREAD_MAX; i++)
{ {
Threads[i].nodes = 0ULL; Threads[i].nodes = 0ULL;
@@ -452,6 +457,10 @@ bool think(const Position& pos, bool infinite, bool ponder, int side_to_move,
{ {
ActiveThreads = newActiveThreads; ActiveThreads = newActiveThreads;
init_eval(ActiveThreads); init_eval(ActiveThreads);
// HACK: init_eval() destroys the static castleRightsMask[] array in the
// Position class. The below line repairs the damage.
Position p(pos.to_fen());
assert(pos.is_ok());
} }
// Wake up sleeping threads // Wake up sleeping threads
@@ -463,14 +472,17 @@ bool think(const Position& pos, bool infinite, bool ponder, int side_to_move,
// Set thinking time // Set thinking time
int myTime = time[side_to_move]; int myTime = time[side_to_move];
int myIncrement = increment[side_to_move]; int myIncrement = increment[side_to_move];
if (UseTimeManagement)
{
if (!movesToGo) // Sudden death time control if (!movesToGo) // Sudden death time control
{ {
if (myIncrement) if (myIncrement)
{ {
MaxSearchTime = myTime / 30 + myIncrement; MaxSearchTime = myTime / 30 + myIncrement;
AbsoluteMaxSearchTime = Max(myTime / 4, myIncrement - 100); AbsoluteMaxSearchTime = Max(myTime / 4, myIncrement - 100);
} else { // Blitz game without increment }
else // Blitz game without increment
{
MaxSearchTime = myTime / 30; MaxSearchTime = myTime / 30;
AbsoluteMaxSearchTime = myTime / 8; AbsoluteMaxSearchTime = myTime / 8;
} }
@@ -480,9 +492,10 @@ bool think(const Position& pos, bool infinite, bool ponder, int side_to_move,
if (movesToGo == 1) if (movesToGo == 1)
{ {
MaxSearchTime = myTime / 2; MaxSearchTime = myTime / 2;
AbsoluteMaxSearchTime = AbsoluteMaxSearchTime = (myTime > 3000)? (myTime - 500) : ((myTime * 3) / 4);
(myTime > 3000)? (myTime - 500) : ((myTime * 3) / 4); }
} else { else
{
MaxSearchTime = myTime / Min(movesToGo, 20); MaxSearchTime = myTime / Min(movesToGo, 20);
AbsoluteMaxSearchTime = Min((4 * myTime) / movesToGo, myTime / 3); AbsoluteMaxSearchTime = Min((4 * myTime) / movesToGo, myTime / 3);
} }
@@ -493,18 +506,11 @@ bool think(const Position& pos, bool infinite, bool ponder, int side_to_move,
MaxSearchTime += MaxSearchTime / 4; MaxSearchTime += MaxSearchTime / 4;
MaxSearchTime = Min(MaxSearchTime, AbsoluteMaxSearchTime); MaxSearchTime = Min(MaxSearchTime, AbsoluteMaxSearchTime);
} }
// Fixed depth or fixed number of nodes?
MaxDepth = maxDepth;
if (MaxDepth)
InfiniteSearch = true; // HACK
MaxNodes = maxNodes;
if (MaxNodes)
{
NodesBetweenPolls = Min(MaxNodes, 30000);
InfiniteSearch = true; // HACK
} }
// Set best NodesBetweenPolls interval
if (MaxNodes)
NodesBetweenPolls = Min(MaxNodes, 30000);
else if (myTime && myTime < 1000) else if (myTime && myTime < 1000)
NodesBetweenPolls = 1000; NodesBetweenPolls = 1000;
else if (myTime && myTime < 5000) else if (myTime && myTime < 5000)
@@ -569,6 +575,7 @@ bool think(const Position& pos, bool infinite, bool ponder, int side_to_move,
void init_threads() { void init_threads() {
volatile int i; volatile int i;
bool ok;
#if !defined(_MSC_VER) #if !defined(_MSC_VER)
pthread_t pthread[1]; pthread_t pthread[1];
@@ -604,12 +611,18 @@ void init_threads() {
for(i = 1; i < THREAD_MAX; i++) for(i = 1; i < THREAD_MAX; i++)
{ {
#if !defined(_MSC_VER) #if !defined(_MSC_VER)
pthread_create(pthread, NULL, init_thread, (void*)(&i)); ok = (pthread_create(pthread, NULL, init_thread, (void*)(&i)) == 0);
#else #else
DWORD iID[1]; DWORD iID[1];
CreateThread(NULL, 0, init_thread, (LPVOID)(&i), 0, iID); ok = (CreateThread(NULL, 0, init_thread, (LPVOID)(&i), 0, iID) != NULL);
#endif #endif
if (!ok)
{
std::cout << "Failed to create thread number " << i << std::endl;
Application::exit_with_failure();
}
// Wait until the thread has finished launching // Wait until the thread has finished launching
while (!Threads[i].running); while (!Threads[i].running);
} }
@@ -782,7 +795,7 @@ namespace {
Problem = false; Problem = false;
if (!InfiniteSearch) if (UseTimeManagement)
{ {
// Time to stop? // Time to stop?
bool stopSearch = false; bool stopSearch = false;
@@ -835,9 +848,9 @@ namespace {
rml.sort(); rml.sort();
// If we are pondering, we shouldn't print the best move before we // If we are pondering or in infinite search, we shouldn't print the
// are told to do so // best move before we are told to do so.
if (PonderSearch) if (!AbortSearch && (PonderSearch || InfiniteSearch))
wait_for_stop_or_ponderhit(); wait_for_stop_or_ponderhit();
else else
// Print final search statistics // Print final search statistics
@@ -1142,9 +1155,6 @@ namespace {
search_pv(pos, ss, alpha, beta, depth-2*OnePly, ply, threadID); search_pv(pos, ss, alpha, beta, depth-2*OnePly, ply, threadID);
ttMove = ss[ply].pv[ply]; ttMove = ss[ply].pv[ply];
tte = TT.retrieve(pos.get_key()); tte = TT.retrieve(pos.get_key());
// If tte->move() != MOVE_NONE then it equals ttMove
assert(!(tte && tte->move()) || tte->move() == ttMove);
} }
// Initialize a MovePicker object for the current position, and prepare // Initialize a MovePicker object for the current position, and prepare
@@ -2009,7 +2019,14 @@ namespace {
if (sp->ply == 1 && RootMoveNumber == 1) if (sp->ply == 1 && RootMoveNumber == 1)
Threads[threadID].failHighPly1 = true; Threads[threadID].failHighPly1 = true;
value = -search_pv(pos, ss, -sp->beta, -sp->alpha, newDepth, sp->ply+1, threadID); // If another thread has failed high then sp->alpha has been increased
// to be higher or equal then beta, if so, avoid to start a PV search.
Value localAlpha = sp->alpha;
if (localAlpha < sp->beta)
value = -search_pv(pos, ss, -sp->beta, -localAlpha, newDepth, sp->ply+1, threadID);
else
assert(thread_should_stop(threadID));
Threads[threadID].failHighPly1 = false; Threads[threadID].failHighPly1 = false;
} }
} }
@@ -2027,11 +2044,7 @@ namespace {
sp->bestValue = value; sp->bestValue = value;
if (value > sp->alpha) if (value > sp->alpha)
{ {
sp->alpha = value; // Ask threads to stop before to modify sp->alpha
sp_update_pv(sp->parentSstack, ss, sp->ply);
if (value == value_mate_in(sp->ply + 1))
ss[sp->ply].mateKiller = move;
if (value >= sp->beta) if (value >= sp->beta)
{ {
for (int i = 0; i < ActiveThreads; i++) for (int i = 0; i < ActiveThreads; i++)
@@ -2040,6 +2053,12 @@ namespace {
sp->finished = true; sp->finished = true;
} }
sp->alpha = value;
sp_update_pv(sp->parentSstack, ss, sp->ply);
if (value == value_mate_in(sp->ply + 1))
ss[sp->ply].mateKiller = move;
} }
// If we are at ply 1, and we are searching the first root move at // If we are at ply 1, and we are searching the first root move at
// ply 0, set the 'Problem' variable if the score has dropped a lot // ply 0, set the 'Problem' variable if the score has dropped a lot
@@ -2645,16 +2664,26 @@ namespace {
if (ShowCurrentLine) if (ShowCurrentLine)
Threads[0].printCurrentLine = true; Threads[0].printCurrentLine = true;
} }
// Should we stop the search? // Should we stop the search?
if (PonderSearch) if (PonderSearch)
return; return;
bool overTime = t > AbsoluteMaxSearchTime bool stillAtFirstMove = RootMoveNumber == 1
|| (RootMoveNumber == 1 && t > MaxSearchTime + ExtraSearchTime && !FailLow) //FIXME: We are not checking any problem flags, BUG? && !FailLow
|| ( !FailHigh && !FailLow && !fail_high_ply_1() && !Problem && t > MaxSearchTime + ExtraSearchTime;
&& t > 6*(MaxSearchTime + ExtraSearchTime));
if ( (Iteration >= 3 && (!InfiniteSearch && overTime)) bool noProblemFound = !FailHigh
&& !FailLow
&& !fail_high_ply_1()
&& !Problem
&& t > 6 * (MaxSearchTime + ExtraSearchTime);
bool noMoreTime = t > AbsoluteMaxSearchTime
|| stillAtFirstMove //FIXME: We are not checking any problem flags, BUG?
|| noProblemFound;
if ( (Iteration >= 3 && UseTimeManagement && noMoreTime)
|| (ExactMaxTime && t >= ExactMaxTime) || (ExactMaxTime && t >= ExactMaxTime)
|| (Iteration >= 3 && MaxNodes && nodes_searched() >= MaxNodes)) || (Iteration >= 3 && MaxNodes && nodes_searched() >= MaxNodes))
AbortSearch = true; AbortSearch = true;
@@ -2669,13 +2698,22 @@ namespace {
int t = current_search_time(); int t = current_search_time();
PonderSearch = false; PonderSearch = false;
if (Iteration >= 3 &&
(!InfiniteSearch && (StopOnPonderhit || bool stillAtFirstMove = RootMoveNumber == 1
t > AbsoluteMaxSearchTime || && !FailLow
(RootMoveNumber == 1 && && t > MaxSearchTime + ExtraSearchTime;
t > MaxSearchTime + ExtraSearchTime && !FailLow) ||
(!FailHigh && !FailLow && !fail_high_ply_1() && !Problem && bool noProblemFound = !FailHigh
t > 6*(MaxSearchTime + ExtraSearchTime))))) && !FailLow
&& !fail_high_ply_1()
&& !Problem
&& t > 6 * (MaxSearchTime + ExtraSearchTime);
bool noMoreTime = t > AbsoluteMaxSearchTime
|| stillAtFirstMove
|| noProblemFound;
if (Iteration >= 3 && UseTimeManagement && (noMoreTime || StopOnPonderhit))
AbortSearch = true; AbortSearch = true;
} }
@@ -2770,12 +2808,14 @@ namespace {
} }
// If this thread has been assigned work, launch a search // If this thread has been assigned work, launch a search
if(Threads[threadID].workIsWaiting) { if (Threads[threadID].workIsWaiting)
{
Threads[threadID].workIsWaiting = false; Threads[threadID].workIsWaiting = false;
if (Threads[threadID].splitPoint->pvNode) if (Threads[threadID].splitPoint->pvNode)
sp_search_pv(Threads[threadID].splitPoint, threadID); sp_search_pv(Threads[threadID].splitPoint, threadID);
else else
sp_search(Threads[threadID].splitPoint, threadID); sp_search(Threads[threadID].splitPoint, threadID);
Threads[threadID].idle = true; Threads[threadID].idle = true;
} }
@@ -2850,16 +2890,21 @@ namespace {
if(!Threads[slave].idle || slave == master) if(!Threads[slave].idle || slave == master)
return false; return false;
if(Threads[slave].activeSplitPoints == 0) // Make a local copy to be sure doesn't change under our feet
// No active split points means that the thread is available as a slave int localActiveSplitPoints = Threads[slave].activeSplitPoints;
// for any other thread.
if (localActiveSplitPoints == 0)
// No active split points means that the thread is available as
// a slave for any other thread.
return true; return true;
if(ActiveThreads == 2) if(ActiveThreads == 2)
return true; return true;
// Apply the "helpful master" concept if possible. // Apply the "helpful master" concept if possible. Use localActiveSplitPoints
if(SplitPointStack[slave][Threads[slave].activeSplitPoints-1].slaves[master]) // that is known to be > 0, instead of Threads[slave].activeSplitPoints that
// could have been set to 0 by another thread leading to an out of bound access.
if (SplitPointStack[slave][localActiveSplitPoints - 1].slaves[master])
return true; return true;
return false; return false;
+1 -1
View File
@@ -64,7 +64,7 @@ struct SplitPoint {
struct Thread { struct Thread {
SplitPoint *splitPoint; SplitPoint *splitPoint;
int activeSplitPoints; volatile int activeSplitPoints;
uint64_t nodes; uint64_t nodes;
uint64_t betaCutOffs[2]; uint64_t betaCutOffs[2];
bool failHighPly1; bool failHighPly1;
+3 -3
View File
@@ -53,11 +53,11 @@ TranspositionTable::~TranspositionTable() {
/// TranspositionTable::set_size sets the size of the transposition table, /// TranspositionTable::set_size sets the size of the transposition table,
/// measured in megabytes. /// measured in megabytes.
void TranspositionTable::set_size(unsigned mbSize) { void TranspositionTable::set_size(size_t mbSize) {
assert(mbSize >= 4 && mbSize <= 4096); assert(mbSize >= 4 && mbSize <= 8192);
unsigned newSize = 1024; size_t newSize = 1024;
// We store a cluster of ClusterSize number of TTEntry for each position // We store a cluster of ClusterSize number of TTEntry for each position
// and newSize is the maximum number of storable positions. // and newSize is the maximum number of storable positions.
+2 -2
View File
@@ -95,7 +95,7 @@ class TranspositionTable {
public: public:
TranspositionTable(); TranspositionTable();
~TranspositionTable(); ~TranspositionTable();
void set_size(unsigned mbSize); void set_size(size_t mbSize);
void clear(); void clear();
void store(const Key posKey, Value v, ValueType type, Depth d, Move m); void store(const Key posKey, Value v, ValueType type, Depth d, Move m);
TTEntry* retrieve(const Key posKey) const; TTEntry* retrieve(const Key posKey) const;
@@ -114,7 +114,7 @@ private:
unsigned writes; // heavy SMP read/write access here unsigned writes; // heavy SMP read/write access here
unsigned char pad_after[64]; unsigned char pad_after[64];
unsigned size; size_t size;
TTCluster* entries; TTCluster* entries;
uint8_t generation; uint8_t generation;
}; };
+25 -43
View File
@@ -107,7 +107,8 @@ namespace {
UCIInputParser uip(command); UCIInputParser uip(command);
string token; string token;
uip >> token; // operator>>() skips any whitespace if (!(uip >> token)) // operator>>() skips any whitespace
return true;
if (token == "quit") if (token == "quit")
return false; return false;
@@ -159,14 +160,8 @@ namespace {
else if (token == "perft") else if (token == "perft")
perft(uip); perft(uip);
else else
{
cout << "Unknown command: " << command << endl; cout << "Unknown command: " << command << endl;
while (!uip.eof())
{
uip >> token;
cout << token << endl;
}
}
return true; return true;
} }
@@ -181,33 +176,33 @@ namespace {
string token; string token;
uip >> token; // operator>>() skips any whitespace if (!(uip >> token)) // operator>>() skips any whitespace
return;
if (token == "startpos") if (token == "startpos")
RootPosition.from_fen(StartPosition); RootPosition.from_fen(StartPosition);
else if (token == "fen") else if (token == "fen")
{ {
string fen; string fen;
while (token != "moves" && !uip.eof()) while (uip >> token && token != "moves")
{ {
uip >> token;
fen += token; fen += token;
fen += ' '; fen += ' ';
} }
RootPosition.from_fen(fen); RootPosition.from_fen(fen);
} }
if (!uip.eof()) if (uip.good())
{ {
if (token != "moves") if (token != "moves")
uip >> token; uip >> token;
if (token == "moves") if (token == "moves")
{ {
Move move; Move move;
StateInfo st; StateInfo st;
while (!uip.eof()) while (uip >> token)
{ {
uip >> token;
move = move_from_string(RootPosition, token); move = move_from_string(RootPosition, token);
RootPosition.do_move(move, st); RootPosition.do_move(move, st);
if (RootPosition.rule_50_counter() == 0) if (RootPosition.rule_50_counter() == 0)
@@ -229,27 +224,22 @@ namespace {
void set_option(UCIInputParser& uip) { void set_option(UCIInputParser& uip) {
string token, name; string token, name, value;
uip >> token; if (!(uip >> token)) // operator>>() skips any whitespace
if (token == "name") return;
{
uip >> name;
while (!uip.eof())
{
uip >> token;
if (token == "value")
break;
if (token == "name" && uip >> name)
{
while (uip >> token && token != "value")
name += (" " + token); name += (" " + token);
}
if (token == "value")
{
// Reads until end of line and left trim white space
getline(uip, token);
token.erase(0, token.find_first_not_of(" \n\r\t"));
set_option_value(name, token); if (token == "value" && uip >> value)
{
while (uip >> token)
value += (" " + token);
set_option_value(name, value);
} else } else
push_button(name); push_button(name);
} }
@@ -276,10 +266,8 @@ namespace {
searchMoves[0] = MOVE_NONE; searchMoves[0] = MOVE_NONE;
while (!uip.eof()) while (uip >> token)
{ {
uip >> token;
if (token == "infinite") if (token == "infinite")
infinite = true; infinite = true;
else if (token == "ponder") else if (token == "ponder")
@@ -303,18 +291,13 @@ namespace {
else if (token == "searchmoves") else if (token == "searchmoves")
{ {
int numOfMoves = 0; int numOfMoves = 0;
while (!uip.eof()) while (uip >> token)
{
uip >> token;
searchMoves[numOfMoves++] = move_from_string(RootPosition, token); searchMoves[numOfMoves++] = move_from_string(RootPosition, token);
}
searchMoves[numOfMoves] = MOVE_NONE; searchMoves[numOfMoves] = MOVE_NONE;
} }
} }
if (moveTime)
infinite = true; // HACK
assert(RootPosition.is_ok()); assert(RootPosition.is_ok());
return think(RootPosition, infinite, ponder, RootPosition.side_to_move(), return think(RootPosition, infinite, ponder, RootPosition.side_to_move(),
@@ -327,10 +310,9 @@ namespace {
int depth, tm, n; int depth, tm, n;
Position pos = RootPosition; Position pos = RootPosition;
if (uip.eof()) if (!(uip >> depth))
return; return;
uip >> depth;
tm = get_system_time(); tm = get_system_time();
n = perft(pos, depth * OnePly); n = perft(pos, depth * OnePly);
+32 -11
View File
@@ -122,8 +122,8 @@ namespace {
o["Randomness"] = Option(0, 0, 10); o["Randomness"] = Option(0, 0, 10);
o["Minimum Split Depth"] = Option(4, 4, 7); o["Minimum Split Depth"] = Option(4, 4, 7);
o["Maximum Number of Threads per Split Point"] = Option(5, 4, 8); o["Maximum Number of Threads per Split Point"] = Option(5, 4, 8);
o["Threads"] = Option(1, 1, 8); o["Threads"] = Option(1, 1, THREAD_MAX);
o["Hash"] = Option(32, 4, 4096); o["Hash"] = Option(32, 4, 8192);
o["Clear Hash"] = Option(false, BUTTON); o["Clear Hash"] = Option(false, BUTTON);
o["New Game"] = Option(false, BUTTON); o["New Game"] = Option(false, BUTTON);
o["Ponder"] = Option(true); o["Ponder"] = Option(true);
@@ -196,15 +196,18 @@ void init_uci_options() {
load_defaults(options); load_defaults(options);
// Limit the default value of "Threads" to 7 even if we have 8 CPU cores. // Set optimal value for parameter "Minimum Split Depth"
// According to Ken Dail's tests, Glaurung plays much better with 7 than // according to number of available cores.
// with 8 threads. This is weird, but it is probably difficult to find out
// why before I have a 8-core computer to experiment with myself.
assert(options.find("Threads") != options.end()); assert(options.find("Threads") != options.end());
assert(options.find("Minimum Split Depth") != options.end()); assert(options.find("Minimum Split Depth") != options.end());
options["Threads"].defaultValue = stringify(Min(cpu_count(), 7)); Option& thr = options["Threads"];
options["Threads"].currentValue = stringify(Min(cpu_count(), 7)); Option& msd = options["Minimum Split Depth"];
thr.defaultValue = thr.currentValue = stringify(cpu_count());
if (cpu_count() >= 8)
msd.defaultValue = msd.currentValue = stringify(7);
} }
@@ -292,10 +295,28 @@ void set_option_value(const string& name, const string& value) {
else if (v == "false") else if (v == "false")
v = "0"; v = "0";
if (options.find(name) != options.end()) if (options.find(name) == options.end())
options[name].currentValue = v; {
else
std::cout << "No such option: " << name << std::endl; std::cout << "No such option: " << name << std::endl;
return;
}
// Normally it's up to the GUI to check for option's limits,
// but we could receive the new value directly from the user
// by teminal window. So let's check the bounds anyway.
Option& opt = options[name];
if (opt.type == CHECK && v != "0" && v != "1")
return;
else if (opt.type == SPIN)
{
int val = atoi(v.c_str());
if (val < opt.minValue || val > opt.maxValue)
return;
}
opt.currentValue = v;
} }
+19 -5
View File
@@ -48,17 +48,31 @@ enum Value {
VALUE_KNOWN_WIN = 15000, VALUE_KNOWN_WIN = 15000,
VALUE_MATE = 30000, VALUE_MATE = 30000,
VALUE_INFINITE = 30001, VALUE_INFINITE = 30001,
VALUE_NONE = 30002 VALUE_NONE = 30002,
VALUE_ENSURE_SIGNED = -1
}; };
/// Score struct keeps a midgame and an endgame value in a single /// Score enum keeps a midgame and an endgame value in a single
/// ScoreValue 64 bit union. /// integer (enum), first LSB 16 bits are used to store endgame
/// value, while upper bits are used for midgame value.
enum Score {}; // Compiler is free to choose the enum type as long as can keep
// its data, so ensure Score to be an integer type.
enum Score { ENSURE_32_BITS_SIZE_P = (1 << 16), ENSURE_32_BITS_SIZE_N = -(1 << 16)};
// Extracting the _signed_ lower and upper 16 bits it not so trivial
// because according to the standard a simple cast to short is
// implementation defined and so is a right shift of a signed integer.
inline Value mg_value(Score s) { return Value(((int(s) + 32768) & ~0xffff) / 0x10000); }
// Unfortunatly on Intel 64 bit we have a small speed regression, so use a faster code in
// this case, although not 100% standard compliant it seems to work for Intel and MSVC.
#if defined(IS_64BIT) && (!defined(__GNUC__) || defined(__INTEL_COMPILER))
inline Value eg_value(Score s) { return Value(int16_t(s & 0xffff)); } inline Value eg_value(Score s) { return Value(int16_t(s & 0xffff)); }
inline Value mg_value(Score s) { return Value((int(s) + 32768) >> 16); } #else
inline Value eg_value(Score s) { return Value((int)(unsigned(s) & 0x7fffu) - (int)(unsigned(s) & 0x8000u)); }
#endif
inline Score make_score(int mg, int eg) { return Score((mg << 16) + eg); } inline Score make_score(int mg, int eg) { return Score((mg << 16) + eg); }