aboutsummaryrefslogtreecommitdiff
path: root/src/solvers
diff options
context:
space:
mode:
authorSebastiano Tronto <sebastiano@tronto.net>2024-10-03 18:28:04 +0200
committerSebastiano Tronto <sebastiano@tronto.net>2024-10-03 18:28:04 +0200
commit9de887d8f178cec5693cafb03b8715804669f65e (patch)
treed908c65602a9e123182ea6e3bdd3a091205155d8 /src/solvers
parent4ee7739d78889cef33d0c60a870922398e0b5e31 (diff)
downloadnissy-core-9de887d8f178cec5693cafb03b8715804669f65e.tar.gz
nissy-core-9de887d8f178cec5693cafb03b8715804669f65e.zip
Improve gendata performance by replacing locks with atomic operations
Diffstat (limited to 'src/solvers')
-rw-r--r--src/solvers/h48/gendata_cocsep.h4
-rw-r--r--src/solvers/h48/gendata_h48.h91
-rw-r--r--src/solvers/h48/solve.h8
-rw-r--r--src/solvers/h48/solve_multithread.h4
-rw-r--r--src/solvers/h48/stats.h8
5 files changed, 53 insertions, 62 deletions
diff --git a/src/solvers/h48/gendata_cocsep.h b/src/solvers/h48/gendata_cocsep.h
index 262793b..5f0fae9 100644
--- a/src/solvers/h48/gendata_cocsep.h
+++ b/src/solvers/h48/gendata_cocsep.h
@@ -27,7 +27,7 @@ STATIC size_t gendata_cocsep(void *, uint64_t *, cube_t *);
27STATIC uint32_t gendata_cocsep_dfs(cocsep_dfs_arg_t *); 27STATIC uint32_t gendata_cocsep_dfs(cocsep_dfs_arg_t *);
28STATIC void getdistribution_cocsep(const uint32_t *, uint64_t [static 21]); 28STATIC void getdistribution_cocsep(const uint32_t *, uint64_t [static 21]);
29 29
30STATIC_INLINE int8_t get_h48_cdata(cube_t, uint32_t *, uint32_t *); 30STATIC_INLINE int8_t get_h48_cdata(cube_t, const uint32_t *, uint32_t *);
31 31
32/* 32/*
33Each element of the cocsep table is a uint32_t used as follows: 33Each element of the cocsep table is a uint32_t used as follows:
@@ -182,7 +182,7 @@ set_visited(uint8_t *a, int64_t i)
182} 182}
183 183
184STATIC_INLINE int8_t 184STATIC_INLINE int8_t
185get_h48_cdata(cube_t cube, uint32_t *cocsepdata, uint32_t *cdata) 185get_h48_cdata(cube_t cube, const uint32_t *cocsepdata, uint32_t *cdata)
186{ 186{
187 int64_t coord; 187 int64_t coord;
188 188
diff --git a/src/solvers/h48/gendata_h48.h b/src/solvers/h48/gendata_h48.h
index 75b7abf..c977109 100644
--- a/src/solvers/h48/gendata_h48.h
+++ b/src/solvers/h48/gendata_h48.h
@@ -54,7 +54,7 @@ typedef struct {
54typedef struct { 54typedef struct {
55 uint8_t depth; 55 uint8_t depth;
56 uint32_t *cocsepdata; 56 uint32_t *cocsepdata;
57 uint8_t *table; 57 _Atomic uint8_t *table;
58 uint64_t *selfsim; 58 uint64_t *selfsim;
59 cube_t *crep; 59 cube_t *crep;
60 uint64_t start; 60 uint64_t start;
@@ -72,7 +72,7 @@ typedef struct {
72 uint8_t base; 72 uint8_t base;
73 uint8_t shortdepth; 73 uint8_t shortdepth;
74 uint32_t *cocsepdata; 74 uint32_t *cocsepdata;
75 uint8_t *table; 75 _Atomic uint8_t *table;
76 uint64_t *selfsim; 76 uint64_t *selfsim;
77 cube_t *crep; 77 cube_t *crep;
78 h48map_t *shortcubes; 78 h48map_t *shortcubes;
@@ -89,7 +89,7 @@ typedef struct {
89 uint8_t k; 89 uint8_t k;
90 uint32_t *cocsepdata; 90 uint32_t *cocsepdata;
91 uint64_t *selfsim; 91 uint64_t *selfsim;
92 uint8_t *table; 92 _Atomic uint8_t *table;
93 pthread_mutex_t **table_mutex; 93 pthread_mutex_t **table_mutex;
94} gendata_h48_mark_t; 94} gendata_h48_mark_t;
95 95
@@ -107,13 +107,13 @@ STATIC tableinfo_t makeinfo_h48k2(gendata_h48_arg_t *);
107STATIC void getdistribution_h48(const uint8_t *, 107STATIC void getdistribution_h48(const uint8_t *,
108 uint64_t [static INFO_DISTRIBUTION_LEN], uint8_t, uint8_t); 108 uint64_t [static INFO_DISTRIBUTION_LEN], uint8_t, uint8_t);
109 109
110STATIC uint32_t *get_cocsepdata_ptr(const void *); 110STATIC const uint32_t *get_cocsepdata_constptr(const void *);
111STATIC uint8_t *get_h48data_ptr(const void *); 111STATIC const uint8_t *get_h48data_constptr(const void *);
112 112
113STATIC_INLINE uint8_t get_h48_pval(const uint8_t *, int64_t, uint8_t); 113STATIC_INLINE uint8_t get_h48_pval(const uint8_t *, int64_t, uint8_t);
114STATIC_INLINE void set_h48_pval(uint8_t *, int64_t, uint8_t, uint8_t); 114STATIC_INLINE void set_h48_pval(_Atomic uint8_t *, int64_t, uint8_t, uint8_t);
115STATIC_INLINE uint8_t get_h48_bound( 115STATIC_INLINE uint8_t get_h48_bound(
116 cube_t, uint32_t, uint8_t, uint8_t, uint8_t *); 116 cube_t, uint32_t, uint8_t, uint8_t, const uint8_t *);
117 117
118size_t gendata_h48_derive(uint8_t, const void *, void *); 118size_t gendata_h48_derive(uint8_t, const void *, void *);
119 119
@@ -209,7 +209,7 @@ gendata_h48_error:
209STATIC size_t 209STATIC size_t
210gendata_h48h0k4(gendata_h48_arg_t *arg) 210gendata_h48h0k4(gendata_h48_arg_t *arg)
211{ 211{
212 uint8_t *table; 212 _Atomic uint8_t *table;
213 int64_t sc, done, d, h48max; 213 int64_t sc, done, d, h48max;
214 uint64_t t, tt, isize, cc; 214 uint64_t t, tt, isize, cc;
215 h48h0k4_bfs_arg_t bfsarg[THREADS]; 215 h48h0k4_bfs_arg_t bfsarg[THREADS];
@@ -234,7 +234,7 @@ gendata_h48h0k4(gendata_h48_arg_t *arg)
234 .next = 0, 234 .next = 0,
235 }; 235 };
236 236
237 table = (uint8_t *)arg->h48buf + INFOSIZE; 237 table = (_Atomic uint8_t *)arg->h48buf + INFOSIZE;
238 memset(table, 0xFF, H48_TABLESIZE(0, 4)); 238 memset(table, 0xFF, H48_TABLESIZE(0, 4));
239 239
240 h48max = (int64_t)H48_COORDMAX(0); 240 h48max = (int64_t)H48_COORDMAX(0);
@@ -289,26 +289,13 @@ gendata_h48h0k4_return_size:
289 return H48_TABLESIZE(0, 4) + INFOSIZE; 289 return H48_TABLESIZE(0, 4) + INFOSIZE;
290} 290}
291 291
292/*
293TODO: the following function suffers from a big performance loss (about 40%)
294because of all the mutex locking. It is possible to reduce the first lock
295(at the beginning of the outermost for loop) by caching the next few items at
296once and then looping over the cached elements. But for the second one (inner
297loop) the access is non-sequential, so this cannot be done.
298
299However, in both cases in theory we do not care if we are reading the old
300value or the updated one. Depending on the compiler guarantees on concurrent
301memory access, we may be fine just removing the locks altogether.
302
303It is probably possible to solve part of this by using atomics.
304*/
305STATIC void * 292STATIC void *
306gendata_h48h0k4_runthread(void *arg) 293gendata_h48h0k4_runthread(void *arg)
307{ 294{
308 static const uint8_t breakpoint = 10; /* Hand-picked optimal */ 295 static const uint8_t breakpoint = 10; /* Hand-picked optimal */
309 296
310 uint8_t c, m; 297 uint8_t c, m;
311 uint64_t i, d, mutex; 298 uint64_t i, d;
312 int64_t j; 299 int64_t j;
313 cube_t cube, moved; 300 cube_t cube, moved;
314 gendata_h48_mark_t markarg; 301 gendata_h48_mark_t markarg;
@@ -331,10 +318,7 @@ gendata_h48h0k4_runthread(void *arg)
331 * Otherwise, scan all neighbors of unvisited coordinates. 318 * Otherwise, scan all neighbors of unvisited coordinates.
332 */ 319 */
333 for (i = bfsarg->start, d = 0; i < bfsarg->end; i++) { 320 for (i = bfsarg->start, d = 0; i < bfsarg->end; i++) {
334 mutex = H48_INDEX(i, 4) % CHUNKS; 321 c = get_h48_pval((uint8_t *)bfsarg->table, i, 4);
335 pthread_mutex_lock(bfsarg->table_mutex[mutex]);
336 c = get_h48_pval(bfsarg->table, i, 4);
337 pthread_mutex_unlock(bfsarg->table_mutex[mutex]);
338 322
339 if ((bfsarg->depth < breakpoint && c != bfsarg->depth - 1) || 323 if ((bfsarg->depth < breakpoint && c != bfsarg->depth - 1) ||
340 (bfsarg->depth >= breakpoint && c != 0xF)) 324 (bfsarg->depth >= breakpoint && c != 0xF))
@@ -344,10 +328,7 @@ gendata_h48h0k4_runthread(void *arg)
344 for (m = 0; m < 18; m++) { 328 for (m = 0; m < 18; m++) {
345 moved = move(cube, m); 329 moved = move(cube, m);
346 j = coord_h48(moved, bfsarg->cocsepdata, 0); 330 j = coord_h48(moved, bfsarg->cocsepdata, 0);
347 mutex = H48_INDEX(j, 4) % CHUNKS; 331 c = get_h48_pval((uint8_t *)bfsarg->table, j, 4);
348 pthread_mutex_lock(bfsarg->table_mutex[mutex]);
349 c = get_h48_pval(bfsarg->table, j, 4);
350 pthread_mutex_unlock(bfsarg->table_mutex[mutex]);
351 if (bfsarg->depth < breakpoint) { 332 if (bfsarg->depth < breakpoint) {
352 if (c <= bfsarg->depth) 333 if (c <= bfsarg->depth)
353 continue; 334 continue;
@@ -392,7 +373,8 @@ gendata_h48k2(gendata_h48_arg_t *arg)
392 [11] = 10 373 [11] = 10
393 }; 374 };
394 375
395 uint8_t t, *table; 376 uint8_t t;
377 _Atomic uint8_t *table;
396 int64_t j; 378 int64_t j;
397 uint64_t i, ii, inext, count; 379 uint64_t i, ii, inext, count;
398 h48map_t shortcubes; 380 h48map_t shortcubes;
@@ -404,7 +386,7 @@ gendata_h48k2(gendata_h48_arg_t *arg)
404 if (arg->buf == NULL) 386 if (arg->buf == NULL)
405 goto gendata_h48k2_return_size; 387 goto gendata_h48k2_return_size;
406 388
407 table = (uint8_t *)arg->h48buf + INFOSIZE; 389 table = (_Atomic uint8_t *)arg->h48buf + INFOSIZE;
408 if (arg->buf != NULL) 390 if (arg->buf != NULL)
409 memset(table, 0xFF, H48_TABLESIZE(arg->h, arg->k)); 391 memset(table, 0xFF, H48_TABLESIZE(arg->h, arg->k));
410 392
@@ -456,7 +438,7 @@ gendata_h48k2(gendata_h48_arg_t *arg)
456 438
457 /* TODO: inline into mark */ 439 /* TODO: inline into mark */
458 for (j = 0; j < H48_COORDMAX(arg->h); j++) { 440 for (j = 0; j < H48_COORDMAX(arg->h); j++) {
459 t = get_h48_pval(table, j, 2); 441 t = get_h48_pval((uint8_t *)table, j, 2);
460 arg->info.distribution[t]++; 442 arg->info.distribution[t]++;
461 } 443 }
462 444
@@ -595,7 +577,7 @@ gendata_h48_mark(gendata_h48_mark_t *arg)
595 coord = coord_h48(arg->cube, arg->cocsepdata, arg->h); 577 coord = coord_h48(arg->cube, arg->cocsepdata, arg->h);
596 mutex = H48_INDEX(coord, arg->k) % CHUNKS; 578 mutex = H48_INDEX(coord, arg->k) % CHUNKS;
597 pthread_mutex_lock(arg->table_mutex[mutex]); 579 pthread_mutex_lock(arg->table_mutex[mutex]);
598 oldval = get_h48_pval(arg->table, coord, arg->k); 580 oldval = get_h48_pval((uint8_t *)arg->table, coord, arg->k);
599 newval = (uint8_t)MAX(arg->depth, 0); 581 newval = (uint8_t)MAX(arg->depth, 0);
600 d += newval < oldval; 582 d += newval < oldval;
601 set_h48_pval(arg->table, coord, arg->k, MIN(oldval, newval)); 583 set_h48_pval(arg->table, coord, arg->k, MIN(oldval, newval));
@@ -618,7 +600,7 @@ gendata_h48k2_dfs_stop(cube_t cube, int8_t depth, h48k2_dfs_arg_t *arg)
618 coord = coord_h48(cube, arg->cocsepdata, arg->h); 600 coord = coord_h48(cube, arg->cocsepdata, arg->h);
619 mutex = H48_INDEX(coord, arg->k) % CHUNKS; 601 mutex = H48_INDEX(coord, arg->k) % CHUNKS;
620 pthread_mutex_lock(arg->table_mutex[mutex]); 602 pthread_mutex_lock(arg->table_mutex[mutex]);
621 oldval = get_h48_pval(arg->table, coord, arg->k); 603 oldval = get_h48_pval((uint8_t *)arg->table, coord, arg->k);
622 pthread_mutex_unlock(arg->table_mutex[mutex]); 604 pthread_mutex_unlock(arg->table_mutex[mutex]);
623 return oldval <= depth; 605 return oldval <= depth;
624 } else { 606 } else {
@@ -690,14 +672,14 @@ getdistribution_h48(
690 } 672 }
691} 673}
692 674
693STATIC uint32_t * 675STATIC const uint32_t *
694get_cocsepdata_ptr(const void *data) 676get_cocsepdata_constptr(const void *data)
695{ 677{
696 return (uint32_t *)((char *)data + INFOSIZE); 678 return (uint32_t *)((char *)data + INFOSIZE);
697} 679}
698 680
699STATIC uint8_t * 681STATIC const uint8_t *
700get_h48data_ptr(const void *data) 682get_h48data_constptr(const void *data)
701{ 683{
702 return (uint8_t *)data + COCSEP_FULLSIZE + INFOSIZE; 684 return (uint8_t *)data + COCSEP_FULLSIZE + INFOSIZE;
703} 685}
@@ -709,15 +691,20 @@ get_h48_pval(const uint8_t *table, int64_t i, uint8_t k)
709} 691}
710 692
711STATIC_INLINE void 693STATIC_INLINE void
712set_h48_pval(uint8_t *table, int64_t i, uint8_t k, uint8_t val) 694set_h48_pval(_Atomic uint8_t *table, int64_t i, uint8_t k, uint8_t val)
713{ 695{
714 table[H48_INDEX(i, k)] = (table[H48_INDEX(i, k)] & (~H48_MASK(i, k))) 696 table[H48_INDEX(i, k)] = (table[H48_INDEX(i, k)] & (~H48_MASK(i, k)))
715 | (val << H48_SHIFT(i, k)); 697 | (val << H48_SHIFT(i, k));
716} 698}
717 699
718STATIC_INLINE uint8_t 700STATIC_INLINE uint8_t
719get_h48_bound(cube_t cube, uint32_t cdata, uint8_t h, uint8_t k, uint8_t *table) 701get_h48_bound(
720{ 702 cube_t cube,
703 uint32_t cdata,
704 uint8_t h,
705 uint8_t k,
706 const uint8_t *table
707) {
721 int64_t coord; 708 int64_t coord;
722 709
723 coord = coord_h48_edges(cube, COCLASS(cdata), TTREP(cdata), h); 710 coord = coord_h48_edges(cube, COCLASS(cdata), TTREP(cdata), h);
@@ -728,7 +715,9 @@ size_t
728gendata_h48_derive(uint8_t h, const void *fulltable, void *buf) 715gendata_h48_derive(uint8_t h, const void *fulltable, void *buf)
729{ 716{
730 size_t cocsepsize, h48size; 717 size_t cocsepsize, h48size;
731 uint8_t val_full, val_derive, *h48full, *h48derive; 718 uint8_t val_full, val_derive;
719 const uint8_t *h48full;
720 _Atomic uint8_t *h48derive;
732 int64_t i, j, h48max; 721 int64_t i, j, h48max;
733 gendata_h48_arg_t arg; 722 gendata_h48_arg_t arg;
734 tableinfo_t cocsepinfo, fulltableinfo; 723 tableinfo_t cocsepinfo, fulltableinfo;
@@ -750,7 +739,7 @@ gendata_h48_derive(uint8_t h, const void *fulltable, void *buf)
750 /* Technically this step is redundant, except that we 739 /* Technically this step is redundant, except that we
751 need selfsim and crep */ 740 need selfsim and crep */
752 cocsepsize = gendata_cocsep(buf, arg.selfsim, arg.crep); 741 cocsepsize = gendata_cocsep(buf, arg.selfsim, arg.crep);
753 arg.h48buf = (uint8_t *)buf + cocsepsize; 742 arg.h48buf = (_Atomic uint8_t *)buf + cocsepsize;
754 h48size = H48_TABLESIZE(h, arg.k) + INFOSIZE; 743 h48size = H48_TABLESIZE(h, arg.k) + INFOSIZE;
755 744
756 if (buf == NULL) 745 if (buf == NULL)
@@ -768,8 +757,8 @@ gendata_h48_derive(uint8_t h, const void *fulltable, void *buf)
768 goto gendata_h48_derive_error; 757 goto gendata_h48_derive_error;
769 } 758 }
770 759
771 h48full = (uint8_t *)fulltable + cocsepsize + INFOSIZE; 760 h48full = (const uint8_t *)fulltable + cocsepsize + INFOSIZE;
772 h48derive = (uint8_t *)arg.h48buf + INFOSIZE; 761 h48derive = (_Atomic uint8_t *)arg.h48buf + INFOSIZE;
773 memset(h48derive, 0xFF, H48_TABLESIZE(h, arg.k)); 762 memset(h48derive, 0xFF, H48_TABLESIZE(h, arg.k));
774 memset(arg.info.distribution, 0, 763 memset(arg.info.distribution, 0,
775 INFO_DISTRIBUTION_LEN * sizeof(uint64_t)); 764 INFO_DISTRIBUTION_LEN * sizeof(uint64_t));
@@ -780,11 +769,13 @@ gendata_h48_derive(uint8_t h, const void *fulltable, void *buf)
780 LOG("Processing %" PRId64 "th coordinate\n", i); 769 LOG("Processing %" PRId64 "th coordinate\n", i);
781 j = i >> (int64_t)(fulltableinfo.h48h - h); 770 j = i >> (int64_t)(fulltableinfo.h48h - h);
782 val_full = get_h48_pval(h48full, i, arg.k); 771 val_full = get_h48_pval(h48full, i, arg.k);
783 val_derive = get_h48_pval(h48derive, j, arg.k); 772 val_derive = get_h48_pval((uint8_t *)h48derive, j, arg.k);
784 set_h48_pval(h48derive, j, arg.k, MIN(val_full, val_derive)); 773 set_h48_pval(
774 h48derive, j, arg.k, MIN(val_full, val_derive));
785 } 775 }
786 776
787 getdistribution_h48(h48derive, arg.info.distribution, h, arg.k); 777 getdistribution_h48(
778 (uint8_t *)h48derive, arg.info.distribution, h, arg.k);
788 779
789 if (!writetableinfo(&arg.info, arg.h48buf)) { 780 if (!writetableinfo(&arg.info, arg.h48buf)) {
790 LOG("gendata_h48_derive: could not write info for table\n"); 781 LOG("gendata_h48_derive: could not write info for table\n");
diff --git a/src/solvers/h48/solve.h b/src/solvers/h48/solve.h
index c2dce91..3948b15 100644
--- a/src/solvers/h48/solve.h
+++ b/src/solvers/h48/solve.h
@@ -8,8 +8,8 @@ typedef struct {
8 int64_t maxsolutions; 8 int64_t maxsolutions;
9 uint8_t h; 9 uint8_t h;
10 uint8_t k; 10 uint8_t k;
11 uint32_t *cocsepdata; 11 const uint32_t *cocsepdata;
12 uint8_t *h48data; 12 const uint8_t *h48data;
13 char **nextsol; 13 char **nextsol;
14 uint8_t nissbranch; 14 uint8_t nissbranch;
15 int8_t npremoves; 15 int8_t npremoves;
@@ -183,8 +183,8 @@ solve_h48(
183 .maxsolutions = maxsolutions, 183 .maxsolutions = maxsolutions,
184 .h = info.h48h, 184 .h = info.h48h,
185 .k = info.bits, 185 .k = info.bits,
186 .cocsepdata = get_cocsepdata_ptr(data), 186 .cocsepdata = get_cocsepdata_constptr(data),
187 .h48data = get_h48data_ptr(data), 187 .h48data = get_h48data_constptr(data),
188 .nextsol = &solutions 188 .nextsol = &solutions
189 }; 189 };
190 190
diff --git a/src/solvers/h48/solve_multithread.h b/src/solvers/h48/solve_multithread.h
index 86171a9..766d84a 100644
--- a/src/solvers/h48/solve_multithread.h
+++ b/src/solvers/h48/solve_multithread.h
@@ -258,8 +258,8 @@ solve_h48_multithread(
258 .maxsolutions = maxsolutions, 258 .maxsolutions = maxsolutions,
259 .h = info.h48h, 259 .h = info.h48h,
260 .k = info.bits, 260 .k = info.bits,
261 .cocsepdata = get_cocsepdata_ptr(data), 261 .cocsepdata = get_cocsepdata_constptr(data),
262 .h48data = get_h48data_ptr(data), 262 .h48data = get_h48data_constptr(data),
263 .nextsol = &solutions}; 263 .nextsol = &solutions};
264 264
265 task_queue_t q; 265 task_queue_t q;
diff --git a/src/solvers/h48/stats.h b/src/solvers/h48/stats.h
index 6e78ab5..ca4b72e 100644
--- a/src/solvers/h48/stats.h
+++ b/src/solvers/h48/stats.h
@@ -10,8 +10,8 @@ typedef struct {
10 int8_t nmoves; 10 int8_t nmoves;
11 int8_t depth; 11 int8_t depth;
12 uint8_t moves[MAXLEN]; 12 uint8_t moves[MAXLEN];
13 uint32_t *cocsepdata; 13 const uint32_t *cocsepdata;
14 uint8_t *h48data; 14 const uint8_t *h48data;
15 char *s; 15 char *s;
16} dfsarg_solveh48stats_t; 16} dfsarg_solveh48stats_t;
17 17
@@ -80,8 +80,8 @@ solve_h48stats(
80 80
81 arg = (dfsarg_solveh48stats_t) { 81 arg = (dfsarg_solveh48stats_t) {
82 .cube = cube, 82 .cube = cube,
83 .cocsepdata = get_cocsepdata_ptr(data), 83 .cocsepdata = get_cocsepdata_constptr(data),
84 .h48data = get_h48data_ptr(data), 84 .h48data = get_h48data_constptr(data),
85 .s = solutions 85 .s = solutions
86 }; 86 };
87 87

Generated with cgit - Back to sebastiano.tronto.net