diff options
| author | Sebastiano Tronto <sebastiano@tronto.net> | 2025-05-23 16:48:58 +0200 |
|---|---|---|
| committer | Sebastiano Tronto <sebastiano@tronto.net> | 2025-05-23 16:54:59 +0200 |
| commit | c6a77f30f64be73a5e55e06336975f2ecfbb2324 (patch) | |
| tree | 3c243fbee268b824f18c5dc4d5bff9a9413b9407 /src | |
| parent | 62d87e063318cc4c842b1b2d8c184f48aeaf6659 (diff) | |
| download | nissy-core-c6a77f30f64be73a5e55e06336975f2ecfbb2324.tar.gz nissy-core-c6a77f30f64be73a5e55e06336975f2ecfbb2324.zip | |
Do all loggin in main thread
Before this committ, the solver (via the generic solution-appender
routines in src/solve/solutions.h) and the H48 data generator did some
logging in the worker threads, without using any locks. This was not nice,
but in practice it did not cause any problem, because the log messages
were rare.
However, this turned out to be a problem when building to WASM, because
web workers do not have access to the main JS memory, and therefore
they cannot call functions from the main JS. This includes not only the
callback functions for logging, but also those for polling the status
of the solver (run / pause / stop).
This commit fixes this at the cost or being somewhat inelegant: the
solutions are not logged as they are found, but only every 500ms.
Diffstat (limited to '')
| -rw-r--r-- | src/solvers/coord/solve.h | 5 | ||||
| -rw-r--r-- | src/solvers/distribution.h | 5 | ||||
| -rw-r--r-- | src/solvers/h48/gendata_h48.h | 42 | ||||
| -rw-r--r-- | src/solvers/h48/gendata_types_macros.h | 2 | ||||
| -rw-r--r-- | src/solvers/h48/solve.h | 136 | ||||
| -rw-r--r-- | src/solvers/solutions.h | 24 | ||||
| -rw-r--r-- | src/utils/sleep.h | 2 |
7 files changed, 124 insertions, 92 deletions
diff --git a/src/solvers/coord/solve.h b/src/solvers/coord/solve.h index 659040c..018aa90 100644 --- a/src/solvers/coord/solve.h +++ b/src/solvers/coord/solve.h | |||
| @@ -123,8 +123,7 @@ solve_coord_dfs(dfsarg_solve_coord_t arg[static 1]) | |||
| 123 | if (!coord_solution_admissible(arg)) | 123 | if (!coord_solution_admissible(arg)) |
| 124 | return 0; | 124 | return 0; |
| 125 | return appendsolution(arg->solution_moves, | 125 | return appendsolution(arg->solution_moves, |
| 126 | arg->solution_settings, arg->solution_list, true, | 126 | arg->solution_settings, arg->solution_list); |
| 127 | arg->coord->name); | ||
| 128 | } | 127 | } |
| 129 | 128 | ||
| 130 | if (solve_coord_dfs_stop(arg)) | 129 | if (solve_coord_dfs_stop(arg)) |
| @@ -326,7 +325,7 @@ solve_coord( | |||
| 326 | 325 | ||
| 327 | if (coord->coord(c, coord_data) == 0) { | 326 | if (coord->coord(c, coord_data) == 0) { |
| 328 | if (minmoves == 0 && !appendsolution(&solution_moves, | 327 | if (minmoves == 0 && !appendsolution(&solution_moves, |
| 329 | &solution_settings, &solution_list, true, coord->name)) | 328 | &solution_settings, &solution_list)) |
| 330 | goto solve_coord_error_buffer; | 329 | goto solve_coord_error_buffer; |
| 331 | goto solve_coord_done; | 330 | goto solve_coord_done; |
| 332 | } | 331 | } |
diff --git a/src/solvers/distribution.h b/src/solvers/distribution.h index 3c006a7..27b72d7 100644 --- a/src/solvers/distribution.h +++ b/src/solvers/distribution.h | |||
| @@ -94,10 +94,13 @@ distribution_equal( | |||
| 94 | LOG("[checkdata] Value for depth %" PRIu8 | 94 | LOG("[checkdata] Value for depth %" PRIu8 |
| 95 | ": expected %" PRIu64 ", found %" PRIu64 "\n", | 95 | ": expected %" PRIu64 ", found %" PRIu64 "\n", |
| 96 | i, expected[i], actual[i]); | 96 | i, expected[i], actual[i]); |
| 97 | } else { | 97 | } |
| 98 | /* | ||
| 99 | else { | ||
| 98 | LOG("[checkdata] Value for depth %" PRIu8 | 100 | LOG("[checkdata] Value for depth %" PRIu8 |
| 99 | " is correct (%" PRIu64 ")\n", i, actual[i]); | 101 | " is correct (%" PRIu64 ")\n", i, actual[i]); |
| 100 | } | 102 | } |
| 103 | */ | ||
| 101 | } | 104 | } |
| 102 | 105 | ||
| 103 | return wrong == 0; | 106 | return wrong == 0; |
diff --git a/src/solvers/h48/gendata_h48.h b/src/solvers/h48/gendata_h48.h index d1ab3bd..4e5daee 100644 --- a/src/solvers/h48/gendata_h48.h +++ b/src/solvers/h48/gendata_h48.h | |||
| @@ -105,7 +105,7 @@ gendata_h48(gendata_h48_arg_t arg[static 1]) | |||
| 105 | return size; /* Dry-run */ | 105 | return size; /* Dry-run */ |
| 106 | 106 | ||
| 107 | if (arg->buf_size < size) { | 107 | if (arg->buf_size < size) { |
| 108 | LOG("[H48 gendata] Error data: buffer is too small " | 108 | LOG("[H48 gendata] Error: buffer is too small " |
| 109 | "(needed %" PRId64 " bytes but received %" PRId64 ")\n", | 109 | "(needed %" PRId64 " bytes but received %" PRId64 ")\n", |
| 110 | size, arg->buf_size); | 110 | size, arg->buf_size); |
| 111 | return NISSY_ERROR_BUFFER_SIZE; | 111 | return NISSY_ERROR_BUFFER_SIZE; |
| @@ -392,9 +392,11 @@ gendata_h48k2(gendata_h48_arg_t arg[static 1]) | |||
| 392 | }; | 392 | }; |
| 393 | 393 | ||
| 394 | uint8_t t; | 394 | uint8_t t; |
| 395 | int sleeptime; | ||
| 395 | unsigned char *table; | 396 | unsigned char *table; |
| 396 | int64_t j; | 397 | int64_t j; |
| 397 | uint64_t i, ii, inext, count, bufsize; | 398 | _Atomic uint64_t count; |
| 399 | uint64_t i, ii, inext, bufsize, done, nshort, velocity; | ||
| 398 | h48map_t shortcubes; | 400 | h48map_t shortcubes; |
| 399 | gendata_h48short_arg_t shortarg; | 401 | gendata_h48short_arg_t shortarg; |
| 400 | h48k2_dfs_arg_t dfsarg[THREADS]; | 402 | h48k2_dfs_arg_t dfsarg[THREADS]; |
| @@ -414,7 +416,8 @@ gendata_h48k2(gendata_h48_arg_t arg[static 1]) | |||
| 414 | .map = &shortcubes | 416 | .map = &shortcubes |
| 415 | }; | 417 | }; |
| 416 | gendata_h48short(&shortarg); | 418 | gendata_h48short(&shortarg); |
| 417 | LOG("[H48 gendata] Computed %" PRIu64 " positions\n", shortarg.map->n); | 419 | nshort = shortarg.map->n; |
| 420 | LOG("[H48 gendata] Computed %" PRIu64 " positions\n", nshort); | ||
| 418 | 421 | ||
| 419 | if (arg->base >= 20) | 422 | if (arg->base >= 20) |
| 420 | arg->base = base[arg->h]; | 423 | arg->base = base[arg->h]; |
| @@ -446,6 +449,31 @@ gendata_h48k2(gendata_h48_arg_t arg[static 1]) | |||
| 446 | &thread[i], NULL, gendata_h48k2_runthread, &dfsarg[i]); | 449 | &thread[i], NULL, gendata_h48k2_runthread, &dfsarg[i]); |
| 447 | } | 450 | } |
| 448 | 451 | ||
| 452 | if (NISSY_CANSLEEP) { | ||
| 453 | /* Log the progress periodically */ | ||
| 454 | LOG("Processing 'short cubes'. This will take a while.\n"); | ||
| 455 | |||
| 456 | /* Estimate velocity by checking how much is done after 1s */ | ||
| 457 | msleep(1000); | ||
| 458 | velocity = count; | ||
| 459 | |||
| 460 | /* We plan to log 10 times */ | ||
| 461 | sleeptime = (100*(nshort-velocity)) / velocity; | ||
| 462 | |||
| 463 | done = count; | ||
| 464 | while (nshort - done > (velocity * sleeptime) / 1000) { | ||
| 465 | msleep(sleeptime); | ||
| 466 | pthread_mutex_lock(&shortcubes_mutex); | ||
| 467 | done = count; | ||
| 468 | pthread_mutex_unlock(&shortcubes_mutex); | ||
| 469 | LOG("Processed %" PRIu64 " / %" PRIu64 " cubes\n", | ||
| 470 | (done / 1000) * 1000, nshort); | ||
| 471 | } | ||
| 472 | } else { | ||
| 473 | LOG("Status updates won't be available because the sleep() " | ||
| 474 | "functionality is not available on this platform.\n"); | ||
| 475 | } | ||
| 476 | |||
| 449 | for (i = 0; i < THREADS; i++) | 477 | for (i = 0; i < THREADS; i++) |
| 450 | pthread_join(thread[i], NULL); | 478 | pthread_join(thread[i], NULL); |
| 451 | 479 | ||
| @@ -463,7 +491,7 @@ gendata_h48k2(gendata_h48_arg_t arg[static 1]) | |||
| 463 | STATIC void * | 491 | STATIC void * |
| 464 | gendata_h48k2_runthread(void *arg) | 492 | gendata_h48k2_runthread(void *arg) |
| 465 | { | 493 | { |
| 466 | uint64_t count, coord, mutex; | 494 | uint64_t coord, mutex; |
| 467 | kvpair_t kv; | 495 | kvpair_t kv; |
| 468 | h48k2_dfs_arg_t *dfsarg; | 496 | h48k2_dfs_arg_t *dfsarg; |
| 469 | 497 | ||
| @@ -477,13 +505,9 @@ gendata_h48k2_runthread(void *arg) | |||
| 477 | pthread_mutex_unlock(dfsarg->shortcubes_mutex); | 505 | pthread_mutex_unlock(dfsarg->shortcubes_mutex); |
| 478 | break; | 506 | break; |
| 479 | } | 507 | } |
| 480 | count = ++(*dfsarg->count); | 508 | (*dfsarg->count)++; |
| 481 | pthread_mutex_unlock(dfsarg->shortcubes_mutex); | 509 | pthread_mutex_unlock(dfsarg->shortcubes_mutex); |
| 482 | 510 | ||
| 483 | if (count % UINT64_C(1000000) == 0) | ||
| 484 | LOG("[H48 gendata] Processing %" PRIu64 | ||
| 485 | "th short cube\n", count); | ||
| 486 | |||
| 487 | if (kv.val < dfsarg->shortdepth) { | 511 | if (kv.val < dfsarg->shortdepth) { |
| 488 | coord = kv.key >> (int64_t)(11 - dfsarg->h); | 512 | coord = kv.key >> (int64_t)(11 - dfsarg->h); |
| 489 | mutex = H48_INDEX(coord, dfsarg->k) % CHUNKS; | 513 | mutex = H48_INDEX(coord, dfsarg->k) % CHUNKS; |
diff --git a/src/solvers/h48/gendata_types_macros.h b/src/solvers/h48/gendata_types_macros.h index b0592c2..21f0134 100644 --- a/src/solvers/h48/gendata_types_macros.h +++ b/src/solvers/h48/gendata_types_macros.h | |||
| @@ -107,7 +107,7 @@ typedef struct { | |||
| 107 | pthread_mutex_t *shortcubes_mutex; | 107 | pthread_mutex_t *shortcubes_mutex; |
| 108 | pthread_mutex_t *table_mutex[CHUNKS]; | 108 | pthread_mutex_t *table_mutex[CHUNKS]; |
| 109 | uint64_t *next; | 109 | uint64_t *next; |
| 110 | uint64_t *count; | 110 | _Atomic uint64_t *count; |
| 111 | } h48k2_dfs_arg_t; | 111 | } h48k2_dfs_arg_t; |
| 112 | 112 | ||
| 113 | typedef struct { | 113 | typedef struct { |
diff --git a/src/solvers/h48/solve.h b/src/solvers/h48/solve.h index 2818c09..4d3c451 100644 --- a/src/solvers/h48/solve.h +++ b/src/solvers/h48/solve.h | |||
| @@ -35,10 +35,8 @@ typedef struct { | |||
| 35 | solve_h48_task_t *tasks; | 35 | solve_h48_task_t *tasks; |
| 36 | int thread_id; | 36 | int thread_id; |
| 37 | pthread_mutex_t *solutions_mutex; | 37 | pthread_mutex_t *solutions_mutex; |
| 38 | int (*poll_status)(void *); | 38 | _Atomic int *status; |
| 39 | void *poll_status_data; | 39 | _Atomic bool thread_done; |
| 40 | _Atomic bool cancelled; | ||
| 41 | _Atomic bool cantsleep; | ||
| 42 | } dfsarg_solve_h48_t; | 40 | } dfsarg_solve_h48_t; |
| 43 | 41 | ||
| 44 | typedef struct { | 42 | typedef struct { |
| @@ -58,9 +56,9 @@ STATIC_INLINE bool solve_h48_stop(dfsarg_solve_h48_t [static 1]); | |||
| 58 | STATIC int64_t solve_h48_maketasks( | 56 | STATIC int64_t solve_h48_maketasks( |
| 59 | dfsarg_solve_h48_t [static 1], dfsarg_solve_h48_maketasks_t [static 1], | 57 | dfsarg_solve_h48_t [static 1], dfsarg_solve_h48_maketasks_t [static 1], |
| 60 | solve_h48_task_t [static STARTING_CUBES], int [static 1]); | 58 | solve_h48_task_t [static STARTING_CUBES], int [static 1]); |
| 61 | STATIC bool solve_h48_runthread_continue(dfsarg_solve_h48_t *); | ||
| 62 | STATIC void *solve_h48_runthread(void *); | 59 | STATIC void *solve_h48_runthread(void *); |
| 63 | STATIC int64_t solve_h48_dfs(dfsarg_solve_h48_t [static 1]); | 60 | STATIC int64_t solve_h48_dfs(dfsarg_solve_h48_t [static 1]); |
| 61 | STATIC void solve_h48_log_solutions(solution_list_t [static 1], size_t); | ||
| 64 | STATIC int64_t solve_h48(oriented_cube_t, uint8_t, uint8_t, uint8_t, uint8_t, | 62 | STATIC int64_t solve_h48(oriented_cube_t, uint8_t, uint8_t, uint8_t, uint8_t, |
| 65 | uint8_t, uint64_t, const unsigned char *, size_t n, char [n], | 63 | uint8_t, uint64_t, const unsigned char *, size_t n, char [n], |
| 66 | long long [static NISSY_SIZE_SOLVE_STATS], int (*)(void *), void *); | 64 | long long [static NISSY_SIZE_SOLVE_STATS], int (*)(void *), void *); |
| @@ -201,7 +199,7 @@ solve_h48_dfs(dfsarg_solve_h48_t arg[static 1]) | |||
| 201 | return 0; | 199 | return 0; |
| 202 | pthread_mutex_lock(arg->solutions_mutex); | 200 | pthread_mutex_lock(arg->solutions_mutex); |
| 203 | ret = appendsolution(arg->solution_moves, | 201 | ret = appendsolution(arg->solution_moves, |
| 204 | arg->solution_settings, arg->solution_list, true, "H48"); | 202 | arg->solution_settings, arg->solution_list); |
| 205 | pthread_mutex_unlock(arg->solutions_mutex); | 203 | pthread_mutex_unlock(arg->solutions_mutex); |
| 206 | return ret; | 204 | return ret; |
| 207 | } | 205 | } |
| @@ -271,41 +269,20 @@ solve_h48_dfs(dfsarg_solve_h48_t arg[static 1]) | |||
| 271 | return ret; | 269 | return ret; |
| 272 | } | 270 | } |
| 273 | 271 | ||
| 274 | STATIC bool | ||
| 275 | solve_h48_runthread_continue(dfsarg_solve_h48_t *arg) | ||
| 276 | { | ||
| 277 | int status; | ||
| 278 | |||
| 279 | for (status = NISSY_STATUS_PAUSE; status == NISSY_STATUS_PAUSE; ) { | ||
| 280 | status = arg->poll_status == NULL ? NISSY_STATUS_RUN : | ||
| 281 | arg->poll_status(arg->poll_status_data); | ||
| 282 | msleep(500); | ||
| 283 | } | ||
| 284 | |||
| 285 | return status == NISSY_STATUS_RUN; | ||
| 286 | } | ||
| 287 | |||
| 288 | STATIC void * | 272 | STATIC void * |
| 289 | solve_h48_runthread(void *arg) | 273 | solve_h48_runthread(void *arg) |
| 290 | { | 274 | { |
| 291 | int i, j, status; | 275 | int i, j; |
| 292 | solve_h48_task_t task; | 276 | solve_h48_task_t task; |
| 293 | dfsarg_solve_h48_t *dfsarg; | 277 | dfsarg_solve_h48_t *dfsarg; |
| 294 | 278 | ||
| 295 | dfsarg = (dfsarg_solve_h48_t *)arg; | 279 | dfsarg = (dfsarg_solve_h48_t *)arg; |
| 296 | 280 | ||
| 297 | for (i = dfsarg->thread_id; i < dfsarg->ntasks; i += dfsarg->threads) { | 281 | for (i = dfsarg->thread_id; i < dfsarg->ntasks; i += dfsarg->threads) { |
| 298 | status = dfsarg->poll_status == NULL ? NISSY_STATUS_RUN : | 282 | if (*dfsarg->status == NISSY_STATUS_STOP) |
| 299 | dfsarg->poll_status(dfsarg->poll_status_data); | 283 | goto solve_h48_runthread_end; |
| 300 | switch (status) { | 284 | while (*dfsarg->status == NISSY_STATUS_PAUSE) |
| 301 | case NISSY_STATUS_STOP: | 285 | msleep(BASE_SLEEP_TIME); |
| 302 | goto solve_h48_runthread_cancel; | ||
| 303 | case NISSY_STATUS_PAUSE: | ||
| 304 | if (!NISSY_CANSLEEP) | ||
| 305 | goto solve_h48_runthread_cantsleep; | ||
| 306 | if (!solve_h48_runthread_continue(dfsarg)) | ||
| 307 | goto solve_h48_runthread_cancel; | ||
| 308 | } | ||
| 309 | 286 | ||
| 310 | task = dfsarg->tasks[i]; | 287 | task = dfsarg->tasks[i]; |
| 311 | 288 | ||
| @@ -329,12 +306,8 @@ solve_h48_runthread(void *arg) | |||
| 329 | solve_h48_dfs(dfsarg); | 306 | solve_h48_dfs(dfsarg); |
| 330 | } | 307 | } |
| 331 | 308 | ||
| 332 | return NULL; | 309 | solve_h48_runthread_end: |
| 333 | 310 | dfsarg->thread_done = true; | |
| 334 | solve_h48_runthread_cantsleep: | ||
| 335 | dfsarg->cantsleep = true; | ||
| 336 | solve_h48_runthread_cancel: | ||
| 337 | dfsarg->cancelled = true; | ||
| 338 | return NULL; | 311 | return NULL; |
| 339 | } | 312 | } |
| 340 | 313 | ||
| @@ -366,7 +339,7 @@ solve_h48_maketasks( | |||
| 366 | maketasks_arg->moves, maketasks_arg->nmoves); | 339 | maketasks_arg->moves, maketasks_arg->nmoves); |
| 367 | 340 | ||
| 368 | appret = appendsolution(&moves, solve_arg->solution_settings, | 341 | appret = appendsolution(&moves, solve_arg->solution_settings, |
| 369 | solve_arg->solution_list, true, "H48"); | 342 | solve_arg->solution_list); |
| 370 | return appret < 0 ? appret : NISSY_OK; | 343 | return appret < 0 ? appret : NISSY_OK; |
| 371 | } | 344 | } |
| 372 | 345 | ||
| @@ -410,6 +383,22 @@ solve_h48_maketasks( | |||
| 410 | return NISSY_OK; | 383 | return NISSY_OK; |
| 411 | } | 384 | } |
| 412 | 385 | ||
| 386 | STATIC void | ||
| 387 | solve_h48_log_solutions(solution_list_t s[static 1], size_t e) | ||
| 388 | { | ||
| 389 | size_t i; | ||
| 390 | char b; | ||
| 391 | while (e != s->used) { | ||
| 392 | LOG("[h48 solve] Found solution: "); | ||
| 393 | for (i = e; s->buf[i] != '\n' && s->buf[i] != '\0'; i++) ; | ||
| 394 | b = s->buf[i]; | ||
| 395 | s->buf[i] = '\0'; | ||
| 396 | LOG("%s\n", s->buf + e); | ||
| 397 | s->buf[i] = b; | ||
| 398 | e = i + 1; | ||
| 399 | } | ||
| 400 | } | ||
| 401 | |||
| 413 | STATIC int64_t | 402 | STATIC int64_t |
| 414 | solve_h48( | 403 | solve_h48( |
| 415 | oriented_cube_t oc, | 404 | oriented_cube_t oc, |
| @@ -427,8 +416,10 @@ solve_h48( | |||
| 427 | void *poll_status_data | 416 | void *poll_status_data |
| 428 | ) | 417 | ) |
| 429 | { | 418 | { |
| 430 | bool anycancelled, anycantsleep; | ||
| 431 | int i, ntasks, eoesep_table_index; | 419 | int i, ntasks, eoesep_table_index; |
| 420 | bool td, fp; | ||
| 421 | _Atomic int status; | ||
| 422 | size_t lastused; | ||
| 432 | int8_t d; | 423 | int8_t d; |
| 433 | dfsarg_solve_h48_t arg[THREADS]; | 424 | dfsarg_solve_h48_t arg[THREADS]; |
| 434 | solve_h48_task_t tasks[STARTING_CUBES]; | 425 | solve_h48_task_t tasks[STARTING_CUBES]; |
| @@ -508,10 +499,7 @@ solve_h48( | |||
| 508 | .threads = threads, | 499 | .threads = threads, |
| 509 | .thread_id = i, | 500 | .thread_id = i, |
| 510 | .solutions_mutex = &solutions_mutex, | 501 | .solutions_mutex = &solutions_mutex, |
| 511 | .poll_status = poll_status, | 502 | .status = &status, |
| 512 | .poll_status_data = poll_status_data, | ||
| 513 | .cancelled = false, | ||
| 514 | .cantsleep = false, | ||
| 515 | }; | 503 | }; |
| 516 | 504 | ||
| 517 | } | 505 | } |
| @@ -538,35 +526,69 @@ solve_h48( | |||
| 538 | 526 | ||
| 539 | LOG("[H48 solve] Prepared %d tasks\n", ntasks); | 527 | LOG("[H48 solve] Prepared %d tasks\n", ntasks); |
| 540 | 528 | ||
| 541 | anycancelled = anycantsleep = false; | 529 | solve_h48_log_solutions(&sollist, 0); |
| 530 | lastused = sollist.used; | ||
| 531 | status = poll_status == NULL ? NISSY_STATUS_RUN : | ||
| 532 | poll_status(poll_status_data); | ||
| 533 | if (!NISSY_CANSLEEP) { | ||
| 534 | LOG("[solve h48] Pause / Stop / Resume functionality won't " | ||
| 535 | "be available on this system (can't sleep()).\n"); | ||
| 536 | } | ||
| 542 | for ( | 537 | for ( |
| 543 | d = MAX(minmoves, STARTING_MOVES + 1); | 538 | d = MAX(minmoves, STARTING_MOVES + 1); |
| 544 | !(solutions_done(&sollist, &settings, d) || anycancelled); | 539 | !(solutions_done(&sollist, &settings, d)) && |
| 540 | status != NISSY_STATUS_STOP; | ||
| 545 | d++ | 541 | d++ |
| 546 | ) { | 542 | ) { |
| 547 | if (d >= 15) | 543 | if (d >= 15) { |
| 548 | LOG("[H48 solve] Found %" PRId64 " solutions, " | 544 | LOG("[H48 solve] Found %" PRId64 " solutions, " |
| 549 | "searching at depth %" PRId8 "\n", | 545 | "searching at depth %" PRId8 "\n", |
| 550 | sollist.nsols, d); | 546 | sollist.nsols, d); |
| 547 | } | ||
| 548 | |||
| 551 | for (i = 0; i < threads; i++) { | 549 | for (i = 0; i < threads; i++) { |
| 552 | arg[i].target_depth = d; | 550 | arg[i].target_depth = d; |
| 551 | arg[i].thread_done = false; | ||
| 553 | pthread_create( | 552 | pthread_create( |
| 554 | &thread[i], NULL, solve_h48_runthread, &arg[i]); | 553 | &thread[i], NULL, solve_h48_runthread, &arg[i]); |
| 555 | } | 554 | } |
| 556 | for (i = 0; i < threads; i++) { | 555 | |
| 557 | pthread_join(thread[i], NULL); | 556 | /* Log solutions and handle pause / stop / resume */ |
| 558 | anycancelled = anycancelled || arg[i].cancelled; | 557 | if (d >= 15 && NISSY_CANSLEEP) { |
| 559 | anycantsleep = anycantsleep || arg[i].cantsleep; | 558 | td = false; |
| 559 | fp = true; | ||
| 560 | while (!td && status != NISSY_STATUS_STOP) { | ||
| 561 | msleep(BASE_SLEEP_TIME); | ||
| 562 | |||
| 563 | pthread_mutex_lock(&solutions_mutex); | ||
| 564 | solve_h48_log_solutions(&sollist, lastused); | ||
| 565 | lastused = sollist.used; | ||
| 566 | pthread_mutex_unlock(&solutions_mutex); | ||
| 567 | |||
| 568 | if (poll_status == NULL) | ||
| 569 | continue; | ||
| 570 | |||
| 571 | status = poll_status(poll_status_data); | ||
| 572 | if (status == NISSY_STATUS_PAUSE && fp) { | ||
| 573 | LOG("[H48 solve] Paused\n"); | ||
| 574 | fp = false; | ||
| 575 | } | ||
| 576 | if (status == NISSY_STATUS_RUN) | ||
| 577 | fp = true; | ||
| 578 | |||
| 579 | for (td = true, i = 0; i < threads; i++) | ||
| 580 | td = td && arg[i].thread_done; | ||
| 581 | } | ||
| 560 | } | 582 | } |
| 561 | } | ||
| 562 | 583 | ||
| 563 | if (anycantsleep) { | 584 | for (i = 0; i < threads; i++) |
| 564 | LOG("[H48 solve] Received pause request, but this feature is " | 585 | pthread_join(thread[i], NULL); |
| 565 | "not available on this system. " | 586 | |
| 566 | "Taking it as a stop request.\n"); | 587 | solve_h48_log_solutions(&sollist, lastused); |
| 588 | lastused = sollist.used; | ||
| 567 | } | 589 | } |
| 568 | 590 | ||
| 569 | if (anycancelled) { | 591 | if (status == NISSY_STATUS_STOP) { |
| 570 | LOG("[H48 solve] Received stop request, ending solution " | 592 | LOG("[H48 solve] Received stop request, ending solution " |
| 571 | "search early.\n"); | 593 | "search early.\n"); |
| 572 | } | 594 | } |
diff --git a/src/solvers/solutions.h b/src/solvers/solutions.h index 75d0804..182ae18 100644 --- a/src/solvers/solutions.h +++ b/src/solvers/solutions.h | |||
| @@ -12,8 +12,7 @@ STATIC bool appendnormal( | |||
| 12 | STATIC bool appendinverse( | 12 | STATIC bool appendinverse( |
| 13 | const solution_moves_t [static 1], solution_list_t [static 1]); | 13 | const solution_moves_t [static 1], solution_list_t [static 1]); |
| 14 | STATIC int64_t appendsolution(const solution_moves_t [static 1], | 14 | STATIC int64_t appendsolution(const solution_moves_t [static 1], |
| 15 | const solution_settings_t [static 1], solution_list_t [static 1], bool, | 15 | const solution_settings_t [static 1], solution_list_t [static 1]); |
| 16 | const char *); | ||
| 17 | STATIC bool solutions_done(const solution_list_t [static 1], | 16 | STATIC bool solutions_done(const solution_list_t [static 1], |
| 18 | const solution_settings_t [static 1], int8_t depth); | 17 | const solution_settings_t [static 1], int8_t depth); |
| 19 | 18 | ||
| @@ -53,10 +52,8 @@ solution_moves_reorient(solution_moves_t moves[static 1], uint8_t or) | |||
| 53 | STATIC bool | 52 | STATIC bool |
| 54 | solution_list_init(solution_list_t sols[static 1], size_t n, char buf[n]) | 53 | solution_list_init(solution_list_t sols[static 1], size_t n, char buf[n]) |
| 55 | { | 54 | { |
| 56 | if (n == 0) { | 55 | if (n == 0) |
| 57 | LOG("Error: cannot use solution buffer with size 0\n"); | ||
| 58 | return false; | 56 | return false; |
| 59 | } | ||
| 60 | 57 | ||
| 61 | sols->nsols = 0; | 58 | sols->nsols = 0; |
| 62 | sols->shortest_sol = MAXLEN + 1; | 59 | sols->shortest_sol = MAXLEN + 1; |
| @@ -158,16 +155,13 @@ STATIC int64_t | |||
| 158 | appendsolution( | 155 | appendsolution( |
| 159 | const solution_moves_t moves[static 1], | 156 | const solution_moves_t moves[static 1], |
| 160 | const solution_settings_t settings[static 1], | 157 | const solution_settings_t settings[static 1], |
| 161 | solution_list_t list[static 1], | 158 | solution_list_t list[static 1] |
| 162 | bool log, | ||
| 163 | const char *solver_name | ||
| 164 | ) | 159 | ) |
| 165 | { | 160 | { |
| 166 | int64_t r; | 161 | int64_t r; |
| 167 | int i; | 162 | int i; |
| 168 | uint8_t t; | 163 | uint8_t t; |
| 169 | solution_moves_t tsol[NTRANS]; | 164 | solution_moves_t tsol[NTRANS]; |
| 170 | char *last_start; | ||
| 171 | 165 | ||
| 172 | if (moves->nmoves + moves->npremoves > MAXLEN) | 166 | if (moves->nmoves + moves->npremoves > MAXLEN) |
| 173 | goto appendsolution_error_solution_length; | 167 | goto appendsolution_error_solution_length; |
| @@ -210,8 +204,6 @@ appendsolution( | |||
| 210 | if (solution_moves_is_duplicate(r, tsol)) | 204 | if (solution_moves_is_duplicate(r, tsol)) |
| 211 | continue; | 205 | continue; |
| 212 | 206 | ||
| 213 | last_start = list->buf + list->used; | ||
| 214 | |||
| 215 | /* Append first the moves on the side that has more */ | 207 | /* Append first the moves on the side that has more */ |
| 216 | /* E.g. write (U L F) B instead of B (U L F) */ | 208 | /* E.g. write (U L F) B instead of B (U L F) */ |
| 217 | if (tsol[r].nmoves >= tsol[r].npremoves) { | 209 | if (tsol[r].nmoves >= tsol[r].npremoves) { |
| @@ -244,26 +236,16 @@ appendsolution( | |||
| 244 | list->shortest_sol, tsol[r].nmoves + tsol[r].npremoves); | 236 | list->shortest_sol, tsol[r].nmoves + tsol[r].npremoves); |
| 245 | r++; | 237 | r++; |
| 246 | 238 | ||
| 247 | if (log) { | ||
| 248 | list->buf[list->used-1] = '\0'; | ||
| 249 | LOG("[%s solve] Found solution #%" PRIu64 ": %s\n", | ||
| 250 | solver_name, list->nsols, last_start); | ||
| 251 | list->buf[list->used-1] = '\n'; | ||
| 252 | } | ||
| 253 | } | 239 | } |
| 254 | 240 | ||
| 255 | list->buf[list->used] = '\0'; | 241 | list->buf[list->used] = '\0'; |
| 256 | return r; | 242 | return r; |
| 257 | 243 | ||
| 258 | appendsolution_error_buffer: | 244 | appendsolution_error_buffer: |
| 259 | LOG("[%s solve] Error: buffer too small\n", solver_name); | ||
| 260 | list->buf[0] = '\0'; | 245 | list->buf[0] = '\0'; |
| 261 | return NISSY_ERROR_BUFFER_SIZE; | 246 | return NISSY_ERROR_BUFFER_SIZE; |
| 262 | 247 | ||
| 263 | appendsolution_error_solution_length: | 248 | appendsolution_error_solution_length: |
| 264 | LOG("[%s solve] Error: solution is too long (%" PRIu8 ").\n" | ||
| 265 | "This is a bug, please report it.\n", | ||
| 266 | solver_name, moves->nmoves + moves->npremoves); | ||
| 267 | list->buf[0] = '\0'; | 249 | list->buf[0] = '\0'; |
| 268 | return NISSY_ERROR_UNKNOWN; | 250 | return NISSY_ERROR_UNKNOWN; |
| 269 | } | 251 | } |
diff --git a/src/utils/sleep.h b/src/utils/sleep.h index d618e9b..7cdd081 100644 --- a/src/utils/sleep.h +++ b/src/utils/sleep.h | |||
| @@ -1,3 +1,5 @@ | |||
| 1 | #define BASE_SLEEP_TIME 500 | ||
| 2 | |||
| 1 | STATIC void msleep(int); | 3 | STATIC void msleep(int); |
| 2 | 4 | ||
| 3 | #if defined(WIN32) | 5 | #if defined(WIN32) |
