Skip to content

Commit bb87549

Browse files
authored
Remove PONDERLOCK (#199)
ELO | 0.15 +- 3.08 (95%) SPRT | 10.0+0.10s Threads=1 Hash=8MB LLR | 2.95 (-2.94, 2.94) [-5.00, 0.00] GAMES | N: 23680 W: 5769 L: 5759 D: 12152 http://chess.grantnet.us/test/31797/ ELO | 1.38 +- 3.94 (95%) SPRT | 5.0+0.05s Threads=8 Hash=64MB LLR | 2.95 (-2.94, 2.94) [-5.00, 0.00] GAMES | N: 14604 W: 3601 L: 3543 D: 7460 http://chess.grantnet.us/test/31798/ BENCH : 3,349,466
1 parent f71ac47 commit bb87549

File tree

4 files changed

+86
-85
lines changed

4 files changed

+86
-85
lines changed

src/search.c

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,39 @@ void initSearch() {
160160
}
161161
}
162162

163+
void *start_search_threads(void *arguments) {
164+
165+
// Unpack the UCIGoStruct that was cast to void*
166+
Thread *threads = ((UCIGoStruct*) arguments)->threads;
167+
Board *board = ((UCIGoStruct*) arguments)->board;
168+
Limits *limits = &((UCIGoStruct*) arguments)->limits;
169+
170+
int score;
171+
char str[6];
172+
uint16_t best = NONE_MOVE, ponder = NONE_MOVE;
173+
174+
// Execute search, setting best and ponder moves
175+
getBestMove(threads, board, limits, &best, &ponder, &score);
176+
177+
// UCI spec does not want reports until out of pondering
178+
while (IS_PONDERING);
179+
180+
// Report best move ( we should always have one )
181+
moveToString(best, str, board->chess960);
182+
printf("bestmove %s", str);
183+
184+
// Report ponder move ( if we have one )
185+
if (ponder != NONE_MOVE) {
186+
moveToString(ponder, str, board->chess960);
187+
printf(" ponder %s", str);
188+
}
189+
190+
// Make sure this all gets reported
191+
printf("\n"); fflush(stdout);
192+
193+
return NULL;
194+
}
195+
163196
void getBestMove(Thread *threads, Board *board, Limits *limits, uint16_t *best, uint16_t *ponder, int *score) {
164197

165198
pthread_t pthreads[threads->nthreads];

src/search.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ struct PVariation {
2828
};
2929

3030
void initSearch();
31+
void *start_search_threads(void *arguments);
3132
void getBestMove(Thread *threads, Board *board, Limits *limits, uint16_t *best, uint16_t *ponder, int *score);
3233
void* iterativeDeepening(void *vthread);
3334
void aspirationWindow(Thread *thread);

src/uci.c

Lines changed: 48 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@ extern volatile int ABORT_SIGNAL; // Defined by search.c
4848
extern volatile int IS_PONDERING; // Defined by search.c
4949
extern PKNetwork PKNN; // Defined by network.c
5050

51-
pthread_mutex_t PONDERLOCK = PTHREAD_MUTEX_INITIALIZER;
5251
const char *StartPosition = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
5352

5453
int main(int argc, char **argv) {
@@ -123,21 +122,11 @@ int main(int argc, char **argv) {
123122
else if (strStartsWith(str, "position"))
124123
uciPosition(str, &board, chess960);
125124

126-
else if (strStartsWith(str, "go")) {
127-
pthread_mutex_lock(&PONDERLOCK);
128-
uciGoStruct.multiPV = multiPV;
129-
uciGoStruct.board = &board;
130-
uciGoStruct.threads = threads;
131-
strncpy(uciGoStruct.str, str, 512);
132-
pthread_create(&pthreadsgo, NULL, &uciGo, &uciGoStruct);
133-
pthread_detach(pthreadsgo);
134-
}
125+
else if (strStartsWith(str, "go"))
126+
uciGo(&uciGoStruct, &pthreadsgo, threads, &board, multiPV, str);
135127

136-
else if (strEquals(str, "ponderhit")) {
137-
pthread_mutex_lock(&PONDERLOCK);
128+
else if (strEquals(str, "ponderhit"))
138129
IS_PONDERING = 0;
139-
pthread_mutex_unlock(&PONDERLOCK);
140-
}
141130

142131
else if (strEquals(str, "stop"))
143132
ABORT_SIGNAL = 1, IS_PONDERING = 0;
@@ -155,101 +144,78 @@ int main(int argc, char **argv) {
155144
return 0;
156145
}
157146

158-
void *uciGo(void *cargo) {
147+
void uciGo(UCIGoStruct *ucigo, pthread_t *pthread, Thread *threads, Board *board, int multiPV, char *str) {
159148

160-
// Get our starting time as soon as possible
161-
double start = get_real_time();
162-
163-
Limits limits = {0};
164-
uint16_t bestMove, ponderMove;
165-
char moveStr[6];
166-
int score;
149+
/// Parse the entire "go" command in order to fill out a Limits struct, found at ucigo->limits.
150+
/// After we have processed all of this, we can execute a new search thread, held by *pthread,
151+
/// and detach it.
167152

168-
uint64_t nodes = 0;
169-
int depth = 0, infinite = 0;
170-
double wtime = 0, btime = 0, movetime = 0;
153+
double start = get_real_time();
154+
double wtime = 0, btime = 0;
171155
double winc = 0, binc = 0, mtg = -1;
172156

173-
int multiPV = ((UCIGoStruct*)cargo)->multiPV;
174-
char *str = ((UCIGoStruct*)cargo)->str;
175-
Board *board = ((UCIGoStruct*)cargo)->board;
176-
Thread *threads = ((UCIGoStruct*)cargo)->threads;
157+
char moveStr[6];
158+
char *ptr = strtok(str, " ");
177159

178160
uint16_t moves[MAX_MOVES];
179-
int size = genAllLegalMoves(board, moves);
180-
int idx = 0, searchmoves = 0;
161+
int size = genAllLegalMoves(board, moves), idx = 0;
181162

182-
// Reset global signals
183-
IS_PONDERING = 0;
163+
Limits *limits = &ucigo->limits;
164+
memset(limits, 0, sizeof(Limits));
184165

185-
// Init the tokenizer with spaces
186-
char* ptr = strtok(str, " ");
166+
IS_PONDERING = FALSE; // Reset PONDERING every time to be safe
187167

188-
// Parse any time control and search method information that was sent
189168
for (ptr = strtok(NULL, " "); ptr != NULL; ptr = strtok(NULL, " ")) {
190169

170+
// Parse time control conditions
191171
if (strEquals(ptr, "wtime" )) wtime = atoi(strtok(NULL, " "));
192172
if (strEquals(ptr, "btime" )) btime = atoi(strtok(NULL, " "));
193173
if (strEquals(ptr, "winc" )) winc = atoi(strtok(NULL, " "));
194174
if (strEquals(ptr, "binc" )) binc = atoi(strtok(NULL, " "));
195175
if (strEquals(ptr, "movestogo" )) mtg = atoi(strtok(NULL, " "));
196-
if (strEquals(ptr, "depth" )) depth = atoi(strtok(NULL, " "));
197-
if (strEquals(ptr, "movetime" )) movetime = atoi(strtok(NULL, " "));
198-
if (strEquals(ptr, "nodes" )) nodes = atof(strtok(NULL, " "));
199176

200-
if (strEquals(ptr, "infinite" )) infinite = 1;
201-
if (strEquals(ptr, "searchmoves")) searchmoves = 1;
202-
if (strEquals(ptr, "ponder" )) IS_PONDERING = 1;
177+
// Parse special search termination conditions
178+
if (strEquals(ptr, "depth" )) limits->depthLimit = atoi(strtok(NULL, " "));
179+
if (strEquals(ptr, "movetime" )) limits->timeLimit = atoi(strtok(NULL, " "));
180+
if (strEquals(ptr, "nodes" )) limits->nodeLimit = atof(strtok(NULL, " "));
203181

182+
// Parse special search modes
183+
if (strEquals(ptr, "infinite" )) limits->limitedByNone = TRUE;
184+
if (strEquals(ptr, "searchmoves")) limits->limitedByMoves = TRUE;
185+
if (strEquals(ptr, "ponder" )) IS_PONDERING = TRUE;
186+
187+
// Parse any specific moves that we are to search
204188
for (int i = 0; i < size; i++) {
205189
moveToString(moves[i], moveStr, board->chess960);
206-
if (strEquals(ptr, moveStr)) limits.searchMoves[idx++] = moves[i];
190+
if (strEquals(ptr, moveStr)) limits->searchMoves[idx++] = moves[i];
207191
}
208192
}
209193

210-
// Initialize limits for the search
211-
limits.limitedByNone = infinite != 0;
212-
limits.limitedByTime = movetime != 0;
213-
limits.limitedByDepth = depth != 0;
214-
limits.limitedByNodes = nodes != 0;
215-
limits.limitedBySelf = !depth && !movetime && !infinite && !nodes;
216-
limits.limitedByMoves = searchmoves;
217-
limits.timeLimit = movetime;
218-
limits.depthLimit = depth;
219-
limits.nodeLimit = nodes;
194+
// Special exit cases: Time, Depth, and Nodes
195+
limits->limitedByTime = limits->timeLimit != 0;
196+
limits->limitedByDepth = limits->depthLimit != 0;
197+
limits->limitedByNodes = limits->nodeLimit != 0;
198+
199+
// No special case nor infinite, so we set our own time
200+
limits->limitedBySelf = !limits->depthLimit && !limits->timeLimit
201+
&& !limits->limitedByNone && !limits->nodeLimit;
220202

221203
// Pick the time values for the colour we are playing as
222-
limits.start = (board->turn == WHITE) ? start : start;
223-
limits.time = (board->turn == WHITE) ? wtime : btime;
224-
limits.inc = (board->turn == WHITE) ? winc : binc;
225-
limits.mtg = (board->turn == WHITE) ? mtg : mtg;
204+
limits->start = (board->turn == WHITE) ? start : start;
205+
limits->time = (board->turn == WHITE) ? wtime : btime;
206+
limits->inc = (board->turn == WHITE) ? winc : binc;
207+
limits->mtg = (board->turn == WHITE) ? mtg : mtg;
226208

227209
// Cap our MultiPV search based on the suggested or legal moves
228-
limits.multiPV = MIN(multiPV, searchmoves ? idx : size);
210+
limits->multiPV = MIN(multiPV, limits->limitedByMoves ? idx : size);
229211

230-
// Allow the main thread to respond to ponderhit
231-
pthread_mutex_unlock(&PONDERLOCK);
212+
// Prepare the uciGoStruct for the new pthread
213+
ucigo->board = board;
214+
ucigo->threads = threads;
232215

233-
// Execute search, return best and ponder moves
234-
getBestMove(threads, board, &limits, &bestMove, &ponderMove, &score);
235-
236-
// UCI spec does not want reports until out of pondering
237-
while (IS_PONDERING);
238-
239-
// Report best move ( we should always have one )
240-
moveToString(bestMove, moveStr, board->chess960);
241-
printf("bestmove %s ", moveStr);
242-
243-
// Report ponder move ( if we have one )
244-
if (ponderMove != NONE_MOVE) {
245-
moveToString(ponderMove, moveStr, board->chess960);
246-
printf("ponder %s", moveStr);
247-
}
248-
249-
// Make sure this all gets reported
250-
printf("\n"); fflush(stdout);
251-
252-
return NULL;
216+
// Spawn a new thread to handle the search
217+
pthread_create(pthread, NULL, &start_search_threads, ucigo);
218+
pthread_detach(*pthread);
253219
}
254220

255221
void uciSetOption(char *str, Thread **threads, int *multiPV, int *chess960) {
@@ -363,6 +329,7 @@ void uciPosition(char *str, Board *board, int chess960) {
363329
}
364330
}
365331

332+
366333
void uciReport(Thread *threads, PVariation *pv, int alpha, int beta) {
367334

368335
// Gather all of the statistics that the UCI protocol would be
@@ -414,6 +381,7 @@ void uciReportCurrentMove(Board *board, uint16_t move, int currmove, int depth)
414381

415382
}
416383

384+
417385
int strEquals(char *str1, char *str2) {
418386
return strcmp(str1, str2) == 0;
419387
}

src/uci.h

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222

2323
#include "types.h"
2424

25-
#define VERSION_ID "14.07"
25+
#define VERSION_ID "14.08"
2626

2727
#ifndef LICENSE_OWNER
2828
#define LICENSE_OWNER "Unlicensed"
@@ -47,13 +47,12 @@ struct Limits {
4747
};
4848

4949
struct UCIGoStruct {
50-
int multiPV;
51-
char str[512];
52-
Board *board;
5350
Thread *threads;
51+
Board *board;
52+
Limits limits;
5453
};
5554

56-
void *uciGo(void *cargo);
55+
void uciGo(UCIGoStruct *ucigo, pthread_t *pthread, Thread *threads, Board *board, int multiPV, char *str);
5756
void uciSetOption(char *str, Thread **threads, int *multiPV, int *chess960);
5857
void uciPosition(char *str, Board *board, int chess960);
5958

0 commit comments

Comments
 (0)