commit 4a88a686d5e08404080ed6954b70c0db252aa220
parent 9ac266c76f39620d8343e46ca41cb09d1534384c
Author: Sebastiano Tronto <sebastiano@tronto.net>
Date: Sat, 14 Dec 2024 11:59:22 +0100
Allow choosing number of threads when calling solve()
Diffstat:
10 files changed, 58 insertions(+), 21 deletions(-)
diff --git a/configure.sh b/configure.sh
@@ -14,7 +14,9 @@
# The string "architecture" must be one of "AVX2", "NEON" or "PORTABLE".
#
# THREADS=n
-# Choose how many threads to use for multi-threaded oerations.
+# The maximum number of threads to use for multi-threaded operations.
+# This is also used as default value in case an operation allows
+# specifying how many threads to use.
# By default, 8 threads will be used (TODO: in the future this will be
# determined base on the system).
# The number n must be between 1 and 128.
diff --git a/python/example.py b/python/example.py
@@ -23,7 +23,7 @@ data = bytearray(open("tables/" + solver, "rb").read())
cube = nissy.applymoves(nissy.solved_cube, "U F R2");
# Solve!
-solutions = nissy.solve(cube, solver, nissy.nissflag_normal, 0, 9, 3, -1, data)
+solutions = nissy.solve(cube, solver, nissy.nissflag_normal, 0, 9, 3, -1, 4, data)
# Print the solutions, one per line
print("Found ", len(solutions), " solutions:")
diff --git a/python/nissy_module.c b/python/nissy_module.c
@@ -306,7 +306,8 @@ checkdata(PyObject *self, PyObject *args)
}
PyDoc_STRVAR(solve_doc,
-"solve(cube, solver, nissflag, minmoves, maxmoves, maxsolutions, optimal, data)\n"
+"solve(cube, solver, nissflag, minmoves, maxmoves, maxsolutions,"
+" optimal, threads, data)\n"
"--\n\n"
"Solves the given 'cube' with the given 'solver' and other parameters."
"See the documentation for libnissy (in nissy.h) for details.\n"
@@ -319,6 +320,7 @@ PyDoc_STRVAR(solve_doc,
" - maxsolution: the maximum number of solutions to return\n"
" - optimal: the largest number of moves from the shortest solution"
"(set to -1 to ignore)\n"
+" - threads: the number of threads to use (0 for default)\n"
" - data: a bytearray containing the data for the solver\n"
"\n"
"Returns: a list with the solutions found\n"
@@ -328,20 +330,20 @@ solve(PyObject *self, PyObject *args)
{
long long result;
unsigned nissflag, minmoves, maxmoves, maxsolutions;
- int optimal, i, j, k;
+ int optimal, i, j, k, threads;
const char *cube, *solver;
char solutions[MAX_SOLUTIONS_SIZE];
long long stats[NISSY_SIZE_SOLVE_STATS];
PyByteArrayObject *data;
PyObject *list, *item;
- if (!PyArg_ParseTuple(args, "ssIIIIiY", &cube, &solver, &nissflag,
- &minmoves, &maxmoves, &maxsolutions, &optimal, &data))
+ if (!PyArg_ParseTuple(args, "ssIIIIiiY", &cube, &solver, &nissflag,
+ &minmoves, &maxmoves, &maxsolutions, &optimal, &threads, &data))
return NULL;
Py_BEGIN_ALLOW_THREADS
result = nissy_solve(cube, solver, nissflag, minmoves, maxmoves,
- maxsolutions, optimal, data->ob_alloc, data->ob_bytes,
+ maxsolutions, optimal, threads, data->ob_alloc, data->ob_bytes,
MAX_SOLUTIONS_SIZE, solutions, stats);
Py_END_ALLOW_THREADS
diff --git a/shell/shell.c b/shell/shell.c
@@ -28,6 +28,7 @@
#define FLAG_MAXMOVES "-M"
#define FLAG_OPTIMAL "-O"
#define FLAG_MAXSOLUTIONS "-n"
+#define FLAG_THREADS "-t"
#define INFO_CUBEFORMAT(cube) cube " must be given in B32 format."
#define INFO_MOVESFORMAT "The accepted moves are U, D, R, L, F and B, " \
@@ -54,6 +55,7 @@ typedef struct {
unsigned maxmoves;
unsigned optimal;
unsigned maxsolutions;
+ unsigned threads;
} args_t;
static int64_t compose_exec(args_t *);
@@ -88,6 +90,7 @@ static bool set_minmoves(int, char **, args_t *);
static bool set_maxmoves(int, char **, args_t *);
static bool set_optimal(int, char **, args_t *);
static bool set_maxsolutions(int, char **, args_t *);
+static bool set_threads(int, char **, args_t *);
static bool set_id(int, char **, args_t *);
static uint64_t rand64(void);
@@ -113,6 +116,7 @@ struct {
OPTION(FLAG_MAXMOVES, 1, set_maxmoves),
OPTION(FLAG_OPTIMAL, 1, set_optimal),
OPTION(FLAG_MAXSOLUTIONS, 1, set_maxsolutions),
+ OPTION(FLAG_THREADS, 1, set_threads),
OPTION(NULL, 0, NULL)
};
@@ -193,9 +197,10 @@ struct {
"solve",
"solve " FLAG_SOLVER " SOLVER"
"[" FLAG_MINMOVES " n] [" FLAG_MAXMOVES " N] "
- FLAG_CUBE " CUBE",
+ FLAG_CUBE " CUBE"
+ FLAG_THREADS " T",
"Solve the given CUBE using SOLVER, "
- "using at least n and at most N moves. "
+ "using at least n and at most N moves, and T threads. "
INFO_CUBEFORMAT("CUBE"),
solve_exec
),
@@ -475,7 +480,7 @@ solve_exec(args_t *args)
ret = nissy_solve(
args->cube, args->str_solver, nissflag, args->minmoves,
- args->maxmoves, args->maxsolutions, args->optimal,
+ args->maxmoves, args->maxsolutions, args->optimal, args->threads,
size, buf, SOLUTIONS_BUFFER_SIZE, solutions, stats);
free(buf);
@@ -557,6 +562,7 @@ parse_args(int argc, char **argv, args_t *args)
.maxmoves = 20,
.optimal = -1,
.maxsolutions = 1,
+ .threads = 0,
};
if (argc == 0) {
@@ -728,6 +734,12 @@ set_maxsolutions(int argc, char **argv, args_t *args)
return parse_uint(argv[0], &args->maxsolutions);
}
+static bool
+set_threads(int argc, char **argv, args_t *args)
+{
+ return parse_uint(argv[0], &args->threads);
+}
+
void
log_stderr(const char *str, ...)
{
diff --git a/src/nissy.c b/src/nissy.c
@@ -489,6 +489,7 @@ nissy_solve(
unsigned maxmoves,
unsigned maxsols,
int optimal,
+ int threads,
unsigned long long data_size,
const char data[data_size],
unsigned sols_size,
@@ -499,6 +500,7 @@ nissy_solve(
cube_t c;
long long parse_ret;
uint8_t h, k;
+ int t;
if (solver == NULL) {
LOG("Error: 'solver' argument is NULL\n");
@@ -522,10 +524,22 @@ nissy_solve(
return 0;
}
+ t = threads == 0 ? THREADS : threads;
+ if (t < 0) {
+ LOG("solve: 'threads' is negative. Please provide a "
+ "number of threads between 1 and %d\n", THREADS);
+ return NISSY_ERROR_OPTIONS;
+ }
+ if (t > THREADS) {
+ LOG("solve: 'threads' is above the maximum value of %d\n",
+ THREADS);
+ return NISSY_ERROR_OPTIONS;
+ }
+
if (!strncmp(solver, "h48", 3)) {
parse_ret = parse_h48_solver(solver, &h, &k);
if (parse_ret == NISSY_OK)
- return solve_h48(c, minmoves, maxmoves, maxsols,
+ return solve_h48(c, minmoves, maxmoves, maxsols, t,
data_size, data, sols_size, sols, stats);
else
return parse_ret;
diff --git a/src/nissy.h b/src/nissy.h
@@ -259,6 +259,9 @@ Parameters:
maxsols - The maximum number of solutions.
optimal - If set to a non-negative value, the maximum number of moves
above the optimal solution length.
+ threads - The number of threads to use. Must be less than or equalt to
+ the value of the compile-time constant THREADS. If set to 0,
+ the default value THREADS will be used.
data_size - The size of the data buffer.
data - The data for the solver. Can be computed with gendata.
sols_size - The size of the solutions buffer.
@@ -286,6 +289,7 @@ nissy_solve(
unsigned maxmoves,
unsigned maxsolutions,
int optimal,
+ int threads,
unsigned long long data_size,
const char data[data_size],
unsigned sols_size,
diff --git a/src/solvers/h48/solve.h b/src/solvers/h48/solve.h
@@ -38,6 +38,7 @@ typedef struct {
int64_t nodes_visited;
int64_t table_fallbacks;
int64_t table_lookups;
+ int threads;
int ntasks;
solve_h48_task_t *tasks;
int thread_id;
@@ -62,7 +63,7 @@ STATIC int64_t solve_h48_maketasks(
solve_h48_task_t [static STARTING_CUBES], int *);
STATIC void *solve_h48_runthread(void *);
STATIC int64_t solve_h48_dfs(dfsarg_solve_h48_t *);
-STATIC int64_t solve_h48(cube_t, int8_t, int8_t, uint64_t, uint64_t,
+STATIC int64_t solve_h48(cube_t, int8_t, int8_t, uint64_t, int, uint64_t,
const void *, uint64_t, char *, long long [static NISSY_SIZE_SOLVE_STATS]);
STATIC int64_t
@@ -316,7 +317,7 @@ solve_h48_runthread(void *arg)
dfsarg = (dfsarg_solve_h48_t *)arg;
cube = dfsarg->start_cube;
- for (i = dfsarg->thread_id; i < dfsarg->ntasks; i += THREADS) {
+ for (i = dfsarg->thread_id; i < dfsarg->ntasks; i += dfsarg->threads) {
task = dfsarg->tasks[i];
memcpy(dfsarg->moves, task.moves, STARTING_MOVES);
dfsarg->cube = cube;
@@ -407,6 +408,7 @@ solve_h48(
int8_t minmoves,
int8_t maxmoves,
uint64_t maxsolutions,
+ int threads,
uint64_t data_size,
const void *data,
uint64_t solutions_size,
@@ -461,7 +463,7 @@ solve_h48(
fallback2 = h48data + offset;
symmask = symmetry_mask(cube);
- for (i = 0; i < THREADS; i++) {
+ for (i = 0; i < threads; i++) {
arg[i] = (dfsarg_solve_h48_t) {
.start_cube = cube,
.cube = cube,
@@ -481,6 +483,7 @@ solve_h48(
.nodes_visited = 0,
.table_fallbacks = 0,
.table_lookups = 0,
+ .threads = threads,
.thread_id = i,
.solutions_mutex = &solutions_mutex,
};
@@ -505,7 +508,7 @@ solve_h48(
if (*arg[0].nsols >= (int64_t)maxsolutions)
goto solve_h48_done;
- for (i = 0; i < THREADS; i++) {
+ for (i = 0; i < threads; i++) {
arg[i].ntasks = ntasks;
arg[i].tasks = tasks;
}
@@ -520,12 +523,12 @@ solve_h48(
if (d >= 10)
LOG("Found %" PRId64 " solutions, searching at depth %"
PRId8 "\n", nsols, d);
- for (i = 0; i < THREADS; i++) {
+ for (i = 0; i < threads; i++) {
arg[i].depth = d;
pthread_create(
&thread[i], NULL, solve_h48_runthread, &arg[i]);
}
- for (i = 0; i < THREADS; i++)
+ for (i = 0; i < threads; i++)
pthread_join(thread[i], NULL);
}
@@ -534,7 +537,7 @@ solve_h48_done:
goto solve_h48_error_solutions_buffer;
nodes_visited = table_lookups = table_fallbacks = 0;
- for (i = 0; i < THREADS; i++) {
+ for (i = 0; i < threads; i++) {
nodes_visited += arg[i].nodes_visited;
table_fallbacks += arg[i].table_fallbacks;
table_lookups += arg[i].table_lookups;
diff --git a/tools/300_solve_small/solve_small.c b/tools/300_solve_small/solve_small.c
@@ -37,7 +37,7 @@ void run(void) {
continue;
}
n = nissy_solve(cube, solver, NISSY_NISSFLAG_NORMAL,
- 0, 20, 1, -1, size, buf, SOL_BUFFER_LEN, sol, stats);
+ 0, 20, 1, -1, 0, size, buf, SOL_BUFFER_LEN, sol, stats);
if (n == 0)
printf("No solution found\n");
else
diff --git a/tools/301_solve_file/solve_file.c b/tools/301_solve_file/solve_file.c
@@ -24,7 +24,7 @@ void run(void) {
continue;
}
nsols = nissy_solve(cube, solver, NISSY_NISSFLAG_NORMAL,
- 0, 20, 1, -1, size, buf, SOL_BUFFER_LEN, sol, stats);
+ 0, 20, 1, -1, 0, size, buf, SOL_BUFFER_LEN, sol, stats);
if (nsols == 0)
printf("No solution found\n");
else
diff --git a/tools/302_solve_multisol/solve_multisol.c b/tools/302_solve_multisol/solve_multisol.c
@@ -30,7 +30,7 @@ void run(void) {
continue;
}
n = nissy_solve(cube, solver, NISSY_NISSFLAG_NORMAL,
- 0, 20, nsol, -1, size, buf, SOL_BUFFER_LEN, sol, stats);
+ 0, 20, nsol, -1, 0, size, buf, SOL_BUFFER_LEN, sol, stats);
if (n == 0)
printf("No solution found\n");
else