Compare commits

...

23 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
13 changed files with 334 additions and 212 deletions

View File

@@ -80,6 +80,7 @@ help:
@echo "Makefile options:"
@echo ""
@echo "make > Default: Compiler = g++"
@echo "make gcc-popcnt > Compiler = g++ + popcnt-support"
@echo "make icc > Compiler = icpc"
@echo "make icc-profile > Compiler = icpc + automatic pgo-build"
@echo "make icc-profile-popcnt > Compiler = icpc + automatic pgo-build + popcnt-support"
@@ -108,6 +109,13 @@ gcc:
CXXFLAGS="$(GCCFLAGS)" \
all
gcc-popcnt:
$(MAKE) \
CXX='g++' \
CXXFLAGS="$(GCCFLAGS) -DUSE_POPCNT" \
all
icc:
$(MAKE) \
CXX='icpc' \

View File

@@ -155,7 +155,7 @@ void benchmark(const string& commandLine) {
cerr << "\nBench position: " << cnt << '/' << positions.size() << endl << endl;
if (limitType == "perft")
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;
totalNodes += nodes_searched();
}

View File

@@ -53,6 +53,30 @@ inline bool cpu_has_popcnt() {
#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
inline bool cpu_has_popcnt() { return false; }

View File

@@ -374,7 +374,6 @@ EndgameFunctions::EndgameFunctions() {
add<ScalingFunction<KBPPKB> >("KBPPKB");
add<ScalingFunction<KBPKN> >("KBPKN");
add<ScalingFunction<KRPPKRP> >("KRPPKRP");
add<ScalingFunction<KRPPKRP> >("KRPPKRP");
}
EndgameFunctions::~EndgameFunctions() {

View File

@@ -50,7 +50,7 @@ using namespace std;
/// Version number. If this is left empty, the current date (in the format
/// YYMMDD) is used as a version number.
static const string EngineVersion = "1.6.2";
static const string EngineVersion = "1.6.3";
static const string AppName = "Stockfish";
static const string AppTag = "";

View File

@@ -143,72 +143,77 @@ void Position::from_fen(const string& fen) {
}
i++;
while(strchr("KQkqabcdefghABCDEFGH-", fen[i])) {
if (fen[i] == '-')
{
while (strchr("KQkqabcdefghABCDEFGH-", fen[i])) {
if (fen[i] == '-')
{
i++;
break;
}
else if (fen[i] == 'K') allow_oo(WHITE);
else if (fen[i] == 'Q') allow_ooo(WHITE);
else if (fen[i] == 'k') allow_oo(BLACK);
else if (fen[i] == 'q') allow_ooo(BLACK);
else if (fen[i] >= 'A' && fen[i] <= 'H') {
File rookFile, kingFile = FILE_NONE;
for (Square square = SQ_B1; square <= SQ_G1; square++)
if (piece_on(square) == WK)
kingFile = square_file(square);
if (kingFile == FILE_NONE) {
std::cout << "Error in FEN at character " << i << std::endl;
return;
}
initialKFile = kingFile;
rookFile = File(fen[i] - 'A') + FILE_A;
if (rookFile < initialKFile) {
allow_ooo(WHITE);
initialQRFile = rookFile;
}
else {
allow_oo(WHITE);
initialKRFile = rookFile;
}
}
else if (fen[i] >= 'a' && fen[i] <= 'h') {
File rookFile, kingFile = FILE_NONE;
for (Square square = SQ_B8; square <= SQ_G8; square++)
if (piece_on(square) == BK)
kingFile = square_file(square);
if (kingFile == FILE_NONE) {
std::cout << "Error in FEN at character " << i << std::endl;
return;
}
initialKFile = kingFile;
rookFile = File(fen[i] - 'a') + FILE_A;
if (rookFile < initialKFile) {
allow_ooo(BLACK);
initialQRFile = rookFile;
}
else {
allow_oo(BLACK);
initialKRFile = rookFile;
}
}
else {
std::cout << "Error in FEN at character " << i << std::endl;
return;
}
i++;
break;
}
else if(fen[i] == 'K') allow_oo(WHITE);
else if(fen[i] == 'Q') allow_ooo(WHITE);
else if(fen[i] == 'k') allow_oo(BLACK);
else if(fen[i] == 'q') allow_ooo(BLACK);
else if(fen[i] >= 'A' && fen[i] <= 'H') {
File rookFile, kingFile = FILE_NONE;
for(Square square = SQ_B1; square <= SQ_G1; square++)
if(piece_on(square) == WK)
kingFile = square_file(square);
if(kingFile == FILE_NONE) {
std::cout << "Error in FEN at character " << i << std::endl;
return;
}
initialKFile = kingFile;
rookFile = File(fen[i] - 'A') + FILE_A;
if(rookFile < initialKFile) {
allow_ooo(WHITE);
initialQRFile = rookFile;
}
else {
allow_oo(WHITE);
initialKRFile = rookFile;
}
}
else if(fen[i] >= 'a' && fen[i] <= 'h') {
File rookFile, kingFile = FILE_NONE;
for(Square square = SQ_B8; square <= SQ_G8; square++)
if(piece_on(square) == BK)
kingFile = square_file(square);
if(kingFile == FILE_NONE) {
std::cout << "Error in FEN at character " << i << std::endl;
return;
}
initialKFile = kingFile;
rookFile = File(fen[i] - 'a') + FILE_A;
if(rookFile < initialKFile) {
allow_ooo(BLACK);
initialQRFile = rookFile;
}
else {
allow_oo(BLACK);
initialKRFile = rookFile;
}
}
else {
std::cout << "Error in FEN at character " << i << std::endl;
return;
}
i++;
}
// Skip blanks
while (fen[i] == ' ')
i++;
// En passant square
// En passant square -- ignore if no capture is possible
if ( i <= fen.length() - 2
&& (fen[i] >= 'a' && fen[i] <= 'h')
&& (fen[i+1] == '3' || fen[i+1] == '6'))
st->epSquare = square_from_string(fen.substr(i, 2));
{
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));
}
// Various initialisation
for (Square sq = SQ_A1; sq <= SQ_H8; sq++)
@@ -266,10 +271,24 @@ const string Position::to_fen() const {
fen += (sideToMove == WHITE ? "w " : "b ");
if (st->castleRights != NO_CASTLES)
{
if (can_castle_kingside(WHITE)) fen += 'K';
if (can_castle_queenside(WHITE)) fen += 'Q';
if (can_castle_kingside(BLACK)) fen += 'k';
if (can_castle_queenside(BLACK)) fen += 'q';
if (initialKFile == FILE_E && initialQRFile == FILE_A && initialKRFile == FILE_H)
{
if (can_castle_kingside(WHITE)) fen += 'K';
if (can_castle_queenside(WHITE)) fen += 'Q';
if (can_castle_kingside(BLACK)) fen += 'k';
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
fen += '-';
@@ -1553,7 +1572,7 @@ Key Position::compute_pawn_key() const {
for (Color c = WHITE; c <= BLACK; c++)
{
b = pieces(PAWN, c);
while(b)
while (b)
{
s = pop_1st_bit(&b);
result ^= zobrist[c][PAWN][s];
@@ -1597,7 +1616,7 @@ Score Position::compute_value() const {
for (PieceType pt = PAWN; pt <= KING; pt++)
{
b = pieces(pt, c);
while(b)
while (b)
{
s = pop_1st_bit(&b);
assert(piece_on(s) == piece_of_color_and_type(c, pt));
@@ -1843,6 +1862,7 @@ bool Position::is_ok(int* failedStep) const {
static const bool debugNonPawnMaterial = false;
static const bool debugPieceCounts = false;
static const bool debugPieceList = false;
static const bool debugCastleSquares = false;
if (failedStep) *failedStep = 1;
@@ -1968,9 +1988,9 @@ bool Position::is_ok(int* failedStep) const {
if (failedStep) (*failedStep)++;
if (debugPieceList)
{
for(Color c = WHITE; c <= BLACK; c++)
for(PieceType pt = PAWN; pt <= KING; pt++)
for(int i = 0; i < pieceCount[c][pt]; i++)
for (Color c = WHITE; c <= BLACK; c++)
for (PieceType pt = PAWN; pt <= KING; pt++)
for (int i = 0; i < pieceCount[c][pt]; i++)
{
if (piece_on(piece_list(c, pt, i)) != piece_of_color_and_type(c, pt))
return false;
@@ -1979,6 +1999,25 @@ bool Position::is_ok(int* failedStep) const {
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;
return true;
}

View File

@@ -227,14 +227,9 @@ namespace {
int MaxNodes, MaxDepth;
int MaxSearchTime, AbsoluteMaxSearchTime, ExtraSearchTime, ExactMaxTime;
int RootMoveNumber;
bool InfiniteSearch;
bool PonderSearch;
bool StopOnPonderhit;
bool AbortSearch; // heavy SMP read access
bool Quit;
bool FailHigh;
bool FailLow;
bool Problem;
bool UseTimeManagement, InfiniteSearch, PonderSearch, StopOnPonderhit;
bool AbortSearch, Quit;
bool FailHigh, FailLow, Problem;
// Show current line?
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 maxNodes, int maxTime, Move searchMoves[]) {
// Look for a book move
if (!infinite && !ponder && get_option_value_bool("OwnBook"))
// Initialize global search variables
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;
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
Idle = false;
SearchStartTime = get_system_time();
for (int i = 0; i < THREAD_MAX; i++)
{
Threads[i].nodes = 0ULL;
@@ -452,6 +457,10 @@ bool think(const Position& pos, bool infinite, bool ponder, int side_to_move,
{
ActiveThreads = newActiveThreads;
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
@@ -463,48 +472,45 @@ bool think(const Position& pos, bool infinite, bool ponder, int side_to_move,
// Set thinking time
int myTime = time[side_to_move];
int myIncrement = increment[side_to_move];
if (!movesToGo) // Sudden death time control
if (UseTimeManagement)
{
if (myIncrement)
if (!movesToGo) // Sudden death time control
{
MaxSearchTime = myTime / 30 + myIncrement;
AbsoluteMaxSearchTime = Max(myTime / 4, myIncrement - 100);
} else { // Blitz game without increment
MaxSearchTime = myTime / 30;
AbsoluteMaxSearchTime = myTime / 8;
if (myIncrement)
{
MaxSearchTime = myTime / 30 + myIncrement;
AbsoluteMaxSearchTime = Max(myTime / 4, myIncrement - 100);
}
else // Blitz game without increment
{
MaxSearchTime = myTime / 30;
AbsoluteMaxSearchTime = myTime / 8;
}
}
}
else // (x moves) / (y minutes)
{
if (movesToGo == 1)
else // (x moves) / (y minutes)
{
MaxSearchTime = myTime / 2;
AbsoluteMaxSearchTime =
(myTime > 3000)? (myTime - 500) : ((myTime * 3) / 4);
} else {
MaxSearchTime = myTime / Min(movesToGo, 20);
AbsoluteMaxSearchTime = Min((4 * myTime) / movesToGo, myTime / 3);
if (movesToGo == 1)
{
MaxSearchTime = myTime / 2;
AbsoluteMaxSearchTime = (myTime > 3000)? (myTime - 500) : ((myTime * 3) / 4);
}
else
{
MaxSearchTime = myTime / Min(movesToGo, 20);
AbsoluteMaxSearchTime = Min((4 * myTime) / movesToGo, myTime / 3);
}
}
if (PonderingEnabled)
{
MaxSearchTime += MaxSearchTime / 4;
MaxSearchTime = Min(MaxSearchTime, AbsoluteMaxSearchTime);
}
}
if (PonderingEnabled)
{
MaxSearchTime += MaxSearchTime / 4;
MaxSearchTime = Min(MaxSearchTime, AbsoluteMaxSearchTime);
}
// Fixed depth or fixed number of nodes?
MaxDepth = maxDepth;
if (MaxDepth)
InfiniteSearch = true; // HACK
MaxNodes = maxNodes;
// Set best NodesBetweenPolls interval
if (MaxNodes)
{
NodesBetweenPolls = Min(MaxNodes, 30000);
InfiniteSearch = true; // HACK
}
else if (myTime && myTime < 1000)
NodesBetweenPolls = 1000;
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() {
volatile int i;
bool ok;
#if !defined(_MSC_VER)
pthread_t pthread[1];
@@ -604,12 +611,18 @@ void init_threads() {
for(i = 1; i < THREAD_MAX; i++)
{
#if !defined(_MSC_VER)
pthread_create(pthread, NULL, init_thread, (void*)(&i));
ok = (pthread_create(pthread, NULL, init_thread, (void*)(&i)) == 0);
#else
DWORD iID[1];
CreateThread(NULL, 0, init_thread, (LPVOID)(&i), 0, iID);
ok = (CreateThread(NULL, 0, init_thread, (LPVOID)(&i), 0, iID) != NULL);
#endif
if (!ok)
{
std::cout << "Failed to create thread number " << i << std::endl;
Application::exit_with_failure();
}
// Wait until the thread has finished launching
while (!Threads[i].running);
}
@@ -782,7 +795,7 @@ namespace {
Problem = false;
if (!InfiniteSearch)
if (UseTimeManagement)
{
// Time to stop?
bool stopSearch = false;
@@ -835,9 +848,9 @@ namespace {
rml.sort();
// If we are pondering, we shouldn't print the best move before we
// are told to do so
if (PonderSearch)
// If we are pondering or in infinite search, we shouldn't print the
// best move before we are told to do so.
if (!AbortSearch && (PonderSearch || InfiniteSearch))
wait_for_stop_or_ponderhit();
else
// Print final search statistics
@@ -2006,7 +2019,14 @@ namespace {
if (sp->ply == 1 && RootMoveNumber == 1)
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;
}
}
@@ -2024,11 +2044,7 @@ namespace {
sp->bestValue = value;
if (value > sp->alpha)
{
sp->alpha = value;
sp_update_pv(sp->parentSstack, ss, sp->ply);
if (value == value_mate_in(sp->ply + 1))
ss[sp->ply].mateKiller = move;
// Ask threads to stop before to modify sp->alpha
if (value >= sp->beta)
{
for (int i = 0; i < ActiveThreads; i++)
@@ -2037,6 +2053,12 @@ namespace {
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
// ply 0, set the 'Problem' variable if the score has dropped a lot
@@ -2642,16 +2664,26 @@ namespace {
if (ShowCurrentLine)
Threads[0].printCurrentLine = true;
}
// Should we stop the search?
if (PonderSearch)
return;
bool overTime = t > AbsoluteMaxSearchTime
|| (RootMoveNumber == 1 && t > MaxSearchTime + ExtraSearchTime && !FailLow) //FIXME: We are not checking any problem flags, BUG?
|| ( !FailHigh && !FailLow && !fail_high_ply_1() && !Problem
&& t > 6*(MaxSearchTime + ExtraSearchTime));
bool stillAtFirstMove = RootMoveNumber == 1
&& !FailLow
&& t > 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)
|| (Iteration >= 3 && MaxNodes && nodes_searched() >= MaxNodes))
AbortSearch = true;
@@ -2666,14 +2698,23 @@ namespace {
int t = current_search_time();
PonderSearch = false;
if (Iteration >= 3 &&
(!InfiniteSearch && (StopOnPonderhit ||
t > AbsoluteMaxSearchTime ||
(RootMoveNumber == 1 &&
t > MaxSearchTime + ExtraSearchTime && !FailLow) ||
(!FailHigh && !FailLow && !fail_high_ply_1() && !Problem &&
t > 6*(MaxSearchTime + ExtraSearchTime)))))
AbortSearch = true;
bool stillAtFirstMove = RootMoveNumber == 1
&& !FailLow
&& t > MaxSearchTime + ExtraSearchTime;
bool noProblemFound = !FailHigh
&& !FailLow
&& !fail_high_ply_1()
&& !Problem
&& t > 6 * (MaxSearchTime + ExtraSearchTime);
bool noMoreTime = t > AbsoluteMaxSearchTime
|| stillAtFirstMove
|| noProblemFound;
if (Iteration >= 3 && UseTimeManagement && (noMoreTime || StopOnPonderhit))
AbortSearch = true;
}
@@ -2767,13 +2808,15 @@ namespace {
}
// If this thread has been assigned work, launch a search
if(Threads[threadID].workIsWaiting) {
Threads[threadID].workIsWaiting = false;
if(Threads[threadID].splitPoint->pvNode)
sp_search_pv(Threads[threadID].splitPoint, threadID);
else
sp_search(Threads[threadID].splitPoint, threadID);
Threads[threadID].idle = true;
if (Threads[threadID].workIsWaiting)
{
Threads[threadID].workIsWaiting = false;
if (Threads[threadID].splitPoint->pvNode)
sp_search_pv(Threads[threadID].splitPoint, threadID);
else
sp_search(Threads[threadID].splitPoint, threadID);
Threads[threadID].idle = true;
}
// If this thread is the master of a split point and all threads have
@@ -2847,17 +2890,22 @@ namespace {
if(!Threads[slave].idle || slave == master)
return false;
if(Threads[slave].activeSplitPoints == 0)
// No active split points means that the thread is available as a slave
// for any other thread.
return true;
// Make a local copy to be sure doesn't change under our feet
int localActiveSplitPoints = Threads[slave].activeSplitPoints;
if (localActiveSplitPoints == 0)
// No active split points means that the thread is available as
// a slave for any other thread.
return true;
if(ActiveThreads == 2)
return true;
// Apply the "helpful master" concept if possible.
if(SplitPointStack[slave][Threads[slave].activeSplitPoints-1].slaves[master])
return true;
// Apply the "helpful master" concept if possible. Use localActiveSplitPoints
// 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 false;
}

View File

@@ -64,7 +64,7 @@ struct SplitPoint {
struct Thread {
SplitPoint *splitPoint;
int activeSplitPoints;
volatile int activeSplitPoints;
uint64_t nodes;
uint64_t betaCutOffs[2];
bool failHighPly1;

View File

@@ -53,11 +53,11 @@ TranspositionTable::~TranspositionTable() {
/// TranspositionTable::set_size sets the size of the transposition table,
/// measured in megabytes.
void TranspositionTable::set_size(unsigned mbSize) {
void TranspositionTable::set_size(size_t mbSize) {
assert(mbSize >= 4 && mbSize <= 2048);
assert(mbSize >= 4 && mbSize <= 8192);
unsigned newSize = 1024;
size_t newSize = 1024;
// We store a cluster of ClusterSize number of TTEntry for each position
// and newSize is the maximum number of storable positions.

View File

@@ -95,7 +95,7 @@ class TranspositionTable {
public:
TranspositionTable();
~TranspositionTable();
void set_size(unsigned mbSize);
void set_size(size_t mbSize);
void clear();
void store(const Key posKey, Value v, ValueType type, Depth d, Move m);
TTEntry* retrieve(const Key posKey) const;
@@ -114,7 +114,7 @@ private:
unsigned writes; // heavy SMP read/write access here
unsigned char pad_after[64];
unsigned size;
size_t size;
TTCluster* entries;
uint8_t generation;
};

View File

@@ -107,7 +107,8 @@ namespace {
UCIInputParser uip(command);
string token;
uip >> token; // operator>>() skips any whitespace
if (!(uip >> token)) // operator>>() skips any whitespace
return true;
if (token == "quit")
return false;
@@ -159,14 +160,8 @@ namespace {
else if (token == "perft")
perft(uip);
else
{
cout << "Unknown command: " << command << endl;
while (!uip.eof())
{
uip >> token;
cout << token << endl;
}
}
return true;
}
@@ -181,33 +176,33 @@ namespace {
string token;
uip >> token; // operator>>() skips any whitespace
if (!(uip >> token)) // operator>>() skips any whitespace
return;
if (token == "startpos")
RootPosition.from_fen(StartPosition);
else if (token == "fen")
{
string fen;
while (token != "moves" && !uip.eof())
while (uip >> token && token != "moves")
{
uip >> token;
fen += token;
fen += ' ';
}
RootPosition.from_fen(fen);
}
if (!uip.eof())
if (uip.good())
{
if (token != "moves")
uip >> token;
if (token == "moves")
{
Move move;
StateInfo st;
while (!uip.eof())
while (uip >> token)
{
uip >> token;
move = move_from_string(RootPosition, token);
RootPosition.do_move(move, st);
if (RootPosition.rule_50_counter() == 0)
@@ -229,27 +224,22 @@ namespace {
void set_option(UCIInputParser& uip) {
string token, name;
string token, name, value;
uip >> token;
if (token == "name")
if (!(uip >> token)) // operator>>() skips any whitespace
return;
if (token == "name" && uip >> name)
{
uip >> name;
while (!uip.eof())
{
uip >> token;
if (token == "value")
break;
while (uip >> token && token != "value")
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
push_button(name);
}
@@ -276,10 +266,8 @@ namespace {
searchMoves[0] = MOVE_NONE;
while (!uip.eof())
while (uip >> token)
{
uip >> token;
if (token == "infinite")
infinite = true;
else if (token == "ponder")
@@ -303,18 +291,13 @@ namespace {
else if (token == "searchmoves")
{
int numOfMoves = 0;
while (!uip.eof())
{
uip >> token;
while (uip >> token)
searchMoves[numOfMoves++] = move_from_string(RootPosition, token);
}
searchMoves[numOfMoves] = MOVE_NONE;
}
}
if (moveTime)
infinite = true; // HACK
assert(RootPosition.is_ok());
return think(RootPosition, infinite, ponder, RootPosition.side_to_move(),
@@ -327,10 +310,9 @@ namespace {
int depth, tm, n;
Position pos = RootPosition;
if (uip.eof())
if (!(uip >> depth))
return;
uip >> depth;
tm = get_system_time();
n = perft(pos, depth * OnePly);

View File

@@ -123,7 +123,7 @@ namespace {
o["Minimum Split Depth"] = Option(4, 4, 7);
o["Maximum Number of Threads per Split Point"] = Option(5, 4, 8);
o["Threads"] = Option(1, 1, THREAD_MAX);
o["Hash"] = Option(32, 4, 2048);
o["Hash"] = Option(32, 4, 8192);
o["Clear Hash"] = Option(false, BUTTON);
o["New Game"] = Option(false, BUTTON);
o["Ponder"] = Option(true);
@@ -196,15 +196,18 @@ void init_uci_options() {
load_defaults(options);
// Limit the default value of "Threads" to 7 even if we have 8 CPU cores.
// According to Ken Dail's tests, Glaurung plays much better with 7 than
// 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.
// Set optimal value for parameter "Minimum Split Depth"
// according to number of available cores.
assert(options.find("Threads") != options.end());
assert(options.find("Minimum Split Depth") != options.end());
options["Threads"].defaultValue = stringify(Min(cpu_count(), 7));
options["Threads"].currentValue = stringify(Min(cpu_count(), 7));
Option& thr = options["Threads"];
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")
v = "0";
if (options.find(name) != options.end())
options[name].currentValue = v;
else
if (options.find(name) == options.end())
{
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;
}

View File

@@ -48,7 +48,8 @@ enum Value {
VALUE_KNOWN_WIN = 15000,
VALUE_MATE = 30000,
VALUE_INFINITE = 30001,
VALUE_NONE = 30002
VALUE_NONE = 30002,
VALUE_ENSURE_SIGNED = -1
};