summaryrefslogtreecommitdiff
path: root/src/engine/thread.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/engine/thread.c')
-rw-r--r--src/engine/thread.c51
1 files changed, 39 insertions, 12 deletions
diff --git a/src/engine/thread.c b/src/engine/thread.c
index 5891558..1bb9a83 100644
--- a/src/engine/thread.c
+++ b/src/engine/thread.c
@@ -40,7 +40,7 @@ void threads_go(struct threads *handler) {
void *child_thread(void *_args) {
struct child_thread_args *args = (struct child_thread_args*)_args;
- args->stop = 0;
+ atomic_store(&args->stop, 0);
atomic_bool stop = false;
u64 nodes = 0;
@@ -71,7 +71,7 @@ void *child_thread(void *_args) {
// iteration's block or the search is stopped
if (sp == NULL) {
static _Thread_local int spins = 0;
- if (++spins == 5000000) fprintf(stderr, "CHILD %d STUCK stop=%d\n", args->id, atomic_load(&args->stop));
+ if (++spins == 5000000) fprintf(stderr, "CHILD %d STUCK stop=%d (ptr=%p)\n", args->id, atomic_load(&args->stop), (void*)&args->stop);
sched_yield();
continue;
}
@@ -89,8 +89,14 @@ void *child_thread(void *_args) {
position_t child = sp->position_snapshot;
position_make_move(&child, move);
+ u64 prev_nodes = nodes;
search_result_t res = search(child, sp->depth - 1, alpha, beta, &ctx);
+ // §2.1 thrashing guard: track how many nodes were searched at this
+ // split point so that split_point_worth_sharing() can refuse HELP
+ // on very shallow / barely-searched blocks.
+ atomic_fetch_add(&sp->nodes_searched, (int)(nodes - prev_nodes));
+
// Share (§2.8): negamax — our value flips sign for the parent side
split_point_share(sp, -res.score, move);
if (-res.score > best_score) {
@@ -125,7 +131,7 @@ void *child_thread(void *_args) {
// tree
void *root_thread(void *_args) {
struct root_thread_args *args = (struct root_thread_args*)_args;
- args->stop = 0;
+ atomic_store(&args->stop, 0);
atomic_bool stop = false;
u64 nodes = 0;
@@ -149,6 +155,12 @@ void *root_thread(void *_args) {
// iterative deepening: search at increasing depths, publishing an info
// message per completed depth so the UCI thread can emit `info ... pv`.
for (int depth = 1; depth <= max_depth; depth++) {
+ // propagate external stop signal into the search context so that
+ // search_should_stop() picks it up at the next node.
+ if (atomic_load(&args->stop)) {
+ atomic_store(&stop, true);
+ break;
+ }
if (atomic_load(&stop)) break;
// root move list (DTS §3.4: splitting at the root is always safe/PV)
@@ -156,7 +168,8 @@ void *root_thread(void *_args) {
moves_init(&moves);
get_legal_moves(&moves, *args->position);
- bool can_split = moves.length > 1 && args->split_points != NULL;
+ bool can_split = moves.length > 1 && args->split_points != NULL
+ && depth >= 3; // §2.1 thrashing guard: don't split at depth < 3
split_point_t *sp = can_split
? __pool_alloc(args->split_points, args->sp_pool_capacity)
: NULL;
@@ -221,6 +234,7 @@ void *root_thread(void *_args) {
result.score = atomic_load(&sp->best_score);
result.best_move = sp->best_move;
+ moves_deinit(sp->moves);
// the move list now belongs to the pool block (released on its next
// reuse), so there is nothing to free here
} else {
@@ -230,17 +244,28 @@ void *root_thread(void *_args) {
}
if (atomic_load(&stop)) break;
+ if (atomic_load(&args->stop)) {
+ atomic_store(&stop, true);
+ break;
+ }
message->depth = depth;
message->nodes = nodes > INT_MAX ? INT_MAX : (int)nodes;
message->score_cp = result.score;
message->mate = __score_to_mate(result.score);
- // pv is already initialized by engine_message_init / handler_push.
message->pv.count = 0;
- add_ipc_move(&message->pv, (ipc_move_t) {
- result.best_move.from,
- result.best_move.to,
- });
+ move_t pv_buf[32];
+ int pv_len = reconstruct_pv(*args->position, *args->ttable, pv_buf, 32);
+ if (pv_len > 0) {
+ for (int i = 0; i < pv_len; i++) {
+ add_ipc_move(&message->pv, (ipc_move_t) { pv_buf[i].from, pv_buf[i].to });
+ }
+ } else {
+ add_ipc_move(&message->pv, (ipc_move_t) {
+ result.best_move.from,
+ result.best_move.to,
+ });
+ }
if (!should_continue(message, args->go_args)) {
break;
@@ -257,8 +282,8 @@ void *root_thread(void *_args) {
engine_message_mark_ready(message);
// signal workers to stop their loops, then mark this thread as finished.
- for (int i = 0; i < args->workers_count; i++) {
- atomic_store(&args->workers_stop[i], 1);
+ for (int i = 1; i <= args->workers_count; i++) {
+ atomic_store(&args->handler->args[i].child_thread_args.stop, 1);
}
atomic_store(&args->stop, 1);
atomic_store(&args->finished, 1);
@@ -291,6 +316,7 @@ static bool __root_thread_run(
ttable_t tt;
ttable_init(&tt, ttable_log);
+ args->ttable = &tt;
root_thread(args);
@@ -350,7 +376,7 @@ bool test_root_thread_emits_info_and_bestmove() {
// every published message must have a valid depth and on-board pv move.
for (engine_message_t *m = messages; m != NULL; m = m->next) {
ok &= m->depth >= 1 && m->depth <= 3;
- ok &= m->pv.count == 1;
+ ok &= m->pv.count >= 1;
ok &= m->pv.data[0].from >= 0 && m->pv.data[0].from < 64;
ok &= m->pv.data[0].to >= 0 && m->pv.data[0].to < 64;
}
@@ -694,6 +720,7 @@ static void __root_split_env_deinit(
engine_message_handler_deinit(&env->message_handlers[i]);
}
ttable_deinit(env->handler.ttable);
+ threads_cleanup(&env->handler);
threads_deinit(&env->handler);
}