OSDN Git Service

e37db76b483f071813ed9a5d4f627c17c5cd3acd
[mhash384/mhash384.git] / tools / GenTables / src / gen_table_xor.c
1 /* ----------------------------------------------------------------------------------------------- */
2 /* MHash-384 - Generate tables utility program                                                     */
3 /* Copyright(c) 2016-2017 LoRd_MuldeR <mulder2@gmx.de>                                             */
4 /*                                                                                                 */
5 /* Permission is hereby granted, free of charge, to any person obtaining a copy of this software   */
6 /* and associated documentation files(the "Software"), to deal in the Software without             */
7 /* restriction, including without limitation the rights to use, copy, modify, merge, publish,      */
8 /* distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the */
9 /* Software is furnished to do so, subject to the following conditions:                            */
10 /*                                                                                                 */
11 /* The above copyright notice and this permission notice shall be included in all copies or        */
12 /* substantial portions of the Software.                                                           */
13 /*                                                                                                 */
14 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING   */
15 /* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND      */
16 /* NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,     */
17 /* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,  */
18 /* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.         */
19 /* ----------------------------------------------------------------------------------------------- */
20
21 #include "common.h"
22 #include "thread_utils.h"
23 #include "twister.h"
24 #include "boxmuller.h"
25
26 #include <stdio.h>
27 #include <stdint.h>
28 #include <string.h>
29 #include <time.h>
30 #include <stdbool.h>
31 #include <io.h>
32 #include <float.h>
33 #include <math.h>
34 #include <intrin.h>
35
36 //-----------------------------------------------------------------------------
37 // Const
38 //-----------------------------------------------------------------------------
39
40 #define HASH_LEN 384U
41 #define DISTANCE_MIN 182U
42
43 #define THREAD_COUNT 8U
44
45 #undef ENABLE_STATS
46 #undef ENABLE_TRACE
47
48 #define ROW_NUM (UINT8_MAX+2)           /*total number of rows*/
49 #define ROW_LEN (HASH_LEN / CHAR_BIT)   /*number of bits per row*/
50
51 #define __DISTANCE_STR(X) #X
52 #define _DISTANCE_STR(X) __DISTANCE_STR(X)
53 #define DISTANCE_STR _DISTANCE_STR(DISTANCE_MIN)
54
55 #define MAGIC_NUMBER 0x3C6058A7C1132CB2ui64
56 #define THREAD_ID (pthread_getw32threadid_np(pthread_self()))
57
58 //-----------------------------------------------------------------------------
59 // Globals
60 //-----------------------------------------------------------------------------
61
62 static uint8_t g_table[ROW_NUM][ROW_LEN];
63 static uint8_t g_thread_buffer[THREAD_COUNT][ROW_LEN];
64
65 static size_t g_spinpos = 0;
66 static char SPINNER[4] = { '/', '-', '\\', '|' };
67
68 #ifdef ENABLE_STATS
69 static volatile long long g_stat_too_hi = 0i64;
70 static volatile long long g_stat_too_lo = 0i64;
71 #endif //ENABLE_STATS
72
73 //-----------------------------------------------------------------------------
74 // Utility Functions
75 //-----------------------------------------------------------------------------
76
77 #ifdef ENABLE_TRACE
78 #define TRACE(X, ...) printf("[%04X] " X "\n", THREAD_ID, __VA_ARGS__)
79 #else
80 #define TRACE(X, ...) __noop()
81 #endif
82
83 static inline void print_row(uint8_t *const row_buffer)
84 {
85         for (size_t w = 0; w < ROW_LEN; ++w)
86         {
87                 printf("%02X", row_buffer[w]);
88         }
89         puts("");
90 }
91
92 static inline void flip_bit_at(uint8_t *const row_buffer, const size_t pos)
93 {
94         row_buffer[pos >> 3] ^= ((uint8_t)(1U << (pos & 0x7)));
95 }
96
97 static inline void flip_rand_n(uint8_t *const row_buffer, twister_t *const rand, const uint32_t n)
98 {
99         bool taken[HASH_LEN];
100         memset(&taken, 0, sizeof(bool) * HASH_LEN);
101         for (uint32_t i = 0; i < n; ++i)
102         {
103                 size_t next;
104                 do
105                 {
106                         next = next_rand_range(rand, HASH_LEN);
107                 }
108                 while (taken[next]);
109                 flip_bit_at(row_buffer, next);
110                 taken[next] = true;
111         }
112 }
113
114 static inline bool check_distance_rows(const uint32_t distance_max, const size_t index_1, const size_t index_2)
115 {
116         const uint32_t dist = hamming_distance(&g_table[index_1][0], &g_table[index_2][0], ROW_LEN);
117         return (dist <= distance_max) && (dist >= DISTANCE_MIN);
118 }
119
120 static inline uint32_t check_distance_buff(const uint32_t distance_max, const size_t index, const uint8_t *const row_buffer, const uint32_t limit)
121 {
122         uint32_t error = 0U;
123 #ifdef ENABLE_STATS
124         bool reason;
125 #endif //ENABLE_STATS
126         for (size_t k = 0; k < index; k++)
127         {
128
129                 const uint32_t dist = hamming_distance(&g_table[k][0], row_buffer, ROW_LEN);
130                 if (dist > distance_max)
131                 {
132                         const uint32_t current = dist - distance_max;
133                         if (current > error)
134                         {
135 #ifdef ENABLE_STATS
136                                 reason = false;
137 #endif //ENABLE_STATS
138                                 if ((error = current) >= limit)
139                                 {
140                                         break; /*early termination*/
141                                 }
142                         }
143                 }
144                 else if (dist < DISTANCE_MIN)
145                 {
146                         const uint32_t current = DISTANCE_MIN - dist;
147                         if (current > error)
148                         {
149 #ifdef ENABLE_STATS
150                                 reason = true;
151 #endif //ENABLE_STATS
152                                 if ((error = current) >= limit)
153                                 {
154                                         break; /*early termination*/
155                                 }
156                         }
157                 }
158         }
159 #ifdef ENABLE_STATS
160         _InterlockedIncrement64(reason ? &g_stat_too_lo : &g_stat_too_hi);
161 #endif //ENABLE_STATS
162         return error;
163 }
164
165 static dump_table(FILE *out)
166 {
167         fputs("uint8_t MHASH_384_TABLE_XOR[UINT8_MAX+2][MHASH_384_LEN] =\n{\n", out);
168         for (size_t i = 0; i < ROW_NUM; i++)
169         {
170                 fputs("\t{ ", out);
171                 for (size_t j = 0; j < ROW_LEN; j++)
172                 {
173                         if (j > 0)
174                         {
175                                 fputc(',', out);
176                         }
177                         fprintf(out, "0x%02X", g_table[i][j]);
178                 }
179                 fprintf(out, " }%s /*%02X*/\n", (i != (ROW_NUM - 1)) ? "," : " ", (uint32_t)(i % 0x100));
180         }
181         fputs("};\n", out);
182 }
183
184 //-----------------------------------------------------------------------------
185 // Thread function
186 //-----------------------------------------------------------------------------
187
188 typedef struct
189 {
190         size_t index;
191         uint8_t *row_buffer;
192         sem_t *stop;
193         pthread_mutex_t *mutex;
194         volatile long *distance_max;
195 }
196 thread_data_t;
197
198 static void* thread_main(void *const param)
199 {
200         const thread_data_t *const data = ((const thread_data_t*)param);
201         twister_t rand;
202         bxmller_t bxmller;
203         uint8_t temp[ROW_LEN];
204         for(;;)
205         {
206                 const uint32_t distance_max = (uint32_t)*data->distance_max;
207                 TRACE("Maximum distance: %u", distance_max);
208                 rand_init(&rand, make_seed());
209                 gaussian_noise_init(&bxmller);
210                 rand_next_bytes(&rand, data->row_buffer, ROW_LEN);
211                 uint32_t error = check_distance_buff(distance_max, data->index, data->row_buffer, HASH_LEN);
212                 if(error > 0U)
213                 {
214                         for (int32_t round = 0; round < 4999; ++round)
215                         {
216                                 if (!(round & 0x3FF))
217                                 {
218                                         if (SEM_TRYWAIT(data->stop))
219                                         {
220                                                 return NULL;
221                                         }
222                                 }
223                                 for (size_t rand_loop = 0; rand_loop < 99991U; ++rand_loop)
224                                 {
225                                         rand_next_bytes(&rand, temp, ROW_LEN);
226                                         const uint32_t next_error = check_distance_buff(distance_max, data->index, temp, error);
227                                         if (next_error < error)
228                                         {
229                                                 round = -1;
230                                                 memcpy(data->row_buffer, temp, sizeof(uint8_t) * ROW_LEN);
231                                                 if (!((error = next_error) > 0U))
232                                                 {
233                                                         TRACE("Success by rand-init <<<---");
234                                                         goto success;
235                                                 }
236                                         }
237                                 }
238                         }
239                         for (int32_t round = 0; round < 743; ++round)
240                         {
241                                 TRACE("Optimizer round %u of 743", round);
242                                 if (!round)
243                                 {
244                                         for (size_t xchg_pos = 0U; xchg_pos < ROW_LEN; ++xchg_pos)
245                                         {
246                                                 uint8_t value = (uint8_t) rand_next_uint(&rand);
247                                                 uint8_t original = data->row_buffer[xchg_pos];
248                                                 for (size_t xchg_cnt = 0U; xchg_cnt <= UINT8_MAX; ++xchg_cnt, ++value)
249                                                 {
250                                                         data->row_buffer[xchg_pos] = value;
251                                                         const uint32_t next_error = check_distance_buff(distance_max, data->index, data->row_buffer, error);
252                                                         if (next_error < error)
253                                                         {
254                                                                 TRACE("Improved by xchg-byte");
255                                                                 original = value;
256                                                                 round = -1;
257                                                                 if (!((error = next_error) > 0U))
258                                                                 {
259                                                                         TRACE("Success by xchg-byte <<<---");
260                                                                         goto success;
261                                                                 }
262                                                         }
263                                                 }
264                                                 data->row_buffer[xchg_pos] = original;
265                                         }
266                                         for (size_t flip_pos_w = 0U; flip_pos_w < HASH_LEN; ++flip_pos_w)
267                                         {
268                                                 if (SEM_TRYWAIT(data->stop))
269                                                 {
270                                                         return NULL;
271                                                 }
272                                                 flip_bit_at(data->row_buffer, flip_pos_w);
273                                                 bool revert_w = true;
274                                                 const uint32_t next_error = check_distance_buff(distance_max, data->index, data->row_buffer, error);
275                                                 if (next_error < error)
276                                                 {
277                                                         TRACE("Improved by flip-1");
278                                                         revert_w = false;
279                                                         round = -1;
280                                                         if (!((error = next_error) > 0U))
281                                                         {
282                                                                 TRACE("success by flip-1 <<<---");
283                                                                 goto success;
284                                                         }
285                                                 }
286                                                 for (size_t flip_pos_x = flip_pos_w + 1U; flip_pos_x < HASH_LEN; ++flip_pos_x)
287                                                 {
288                                                         flip_bit_at(data->row_buffer, flip_pos_x);
289                                                         bool revert_x = true;
290                                                         const uint32_t next_error = check_distance_buff(distance_max, data->index, data->row_buffer, error);
291                                                         if (next_error < error)
292                                                         {
293                                                                 TRACE("Improved by flip-2");
294                                                                 revert_w = false;
295                                                                 revert_x = false;
296                                                                 round = -1;
297                                                                 if (!((error = next_error) > 0U))
298                                                                 {
299                                                                         TRACE("success by flip-2 <<<---");
300                                                                         goto success;
301                                                                 }
302                                                         }
303                                                         for (size_t flip_pos_y = flip_pos_x + 1U; flip_pos_y < HASH_LEN; ++flip_pos_y)
304                                                         {
305                                                                 flip_bit_at(data->row_buffer, flip_pos_y);
306                                                                 bool revert_y = true;
307                                                                 const uint32_t next_error = check_distance_buff(distance_max, data->index, data->row_buffer, error);
308                                                                 if (next_error < error)
309                                                                 {
310                                                                         TRACE("Improved by flip-3");
311                                                                         revert_w = false;
312                                                                         revert_x = false;
313                                                                         revert_y = false;
314                                                                         round = -1;
315                                                                         if (!((error = next_error) > 0U))
316                                                                         {
317                                                                                 TRACE("success by flip-3 <<<---");
318                                                                                 goto success;
319                                                                         }
320                                                                 }
321                                                                 for (size_t flip_pos_z = flip_pos_y + 1U; flip_pos_z < HASH_LEN; ++flip_pos_z)
322                                                                 {
323                                                                         flip_bit_at(data->row_buffer, flip_pos_z);
324                                                                         const uint32_t next_error = check_distance_buff(distance_max, data->index, data->row_buffer, error);
325                                                                         if (next_error < error)
326                                                                         {
327                                                                                 TRACE("Improved by flip-4");
328                                                                                 revert_w = false;
329                                                                                 revert_x = false;
330                                                                                 revert_y = false;
331                                                                                 round = -1;
332                                                                                 if (!((error = next_error) > 0U))
333                                                                                 {
334                                                                                         TRACE("success by flip-4 <<<---");
335                                                                                         goto success;
336                                                                                 }
337                                                                         }
338                                                                         else
339                                                                         {
340                                                                                 flip_bit_at(data->row_buffer, flip_pos_z);
341                                                                         }
342                                                                 }
343                                                                 if (revert_y)
344                                                                 {
345                                                                         flip_bit_at(data->row_buffer, flip_pos_y);
346                                                                 }
347                                                         }
348                                                         if (revert_x)
349                                                         {
350                                                                 flip_bit_at(data->row_buffer, flip_pos_x);
351                                                         }
352                                                 }
353                                                 if (revert_w)
354                                                 {
355                                                         flip_bit_at(data->row_buffer, flip_pos_w);
356                                                 }
357                                         }
358                                 }
359                                 for (size_t rand_mode = 0; rand_mode < 4U; ++rand_mode)
360                                 {
361                                         memcpy(temp, &data->row_buffer, sizeof(uint8_t) * ROW_LEN);
362                                         for (size_t rand_loop = 0; rand_loop < 12007U; ++rand_loop)
363                                         {
364                                                 switch (rand_mode)
365                                                 {
366                                                 case 0U:
367                                                         rand_next_bytes(&rand, &temp[0U], ROW_LEN / 2U);
368                                                         break;
369                                                 case 1U:
370                                                         rand_next_bytes(&rand, &temp[ROW_LEN / 2U], ROW_LEN / 2U);
371                                                         break;
372                                                 case 2U:
373                                                         rand_next_bytes(&rand, &temp[0U], ROW_LEN / 4U);
374                                                         rand_next_bytes(&rand, &temp[ROW_LEN / 2U], ROW_LEN / 4U);
375                                                         break;
376                                                 case 3U:
377                                                         rand_next_bytes(&rand, &temp[ROW_LEN / 4U], ROW_LEN / 4U);
378                                                         rand_next_bytes(&rand, &temp[3U * (ROW_LEN / 4U)], ROW_LEN / 4U);
379                                                         break;
380                                                 default:
381                                                         abort();
382                                                 }
383                                                 const uint32_t next_error = check_distance_buff(distance_max, data->index, temp, error);
384                                                 if (next_error < error)
385                                                 {
386                                                         TRACE("Improved by rand-replace #%zu", rand_mode);
387                                                         round = -1;
388                                                         memcpy(data->row_buffer, temp, sizeof(uint8_t) * ROW_LEN);
389                                                         if (!((error = next_error) > 0U))
390                                                         {
391                                                                 TRACE("Success by rand-replace <<<---");
392                                                                 goto success;
393                                                         }
394                                                 }
395                                         }
396                                 }
397                                 for (size_t refine_loop = 0; refine_loop < 9973U; ++refine_loop)
398                                 {
399                                         if (!(refine_loop & 0x3FF))
400                                         {
401                                                 if (SEM_TRYWAIT(data->stop))
402                                                 {
403                                                         return NULL;
404                                                 }
405                                         }
406                                         const uint32_t flip_count = gaussian_noise_next(&rand, &bxmller, 3.14159, 5U, HASH_LEN);
407                                         for (size_t refine_step = 0; refine_step < 997U; ++refine_step)
408                                         {
409                                                 memcpy(temp, data->row_buffer, sizeof(uint8_t) * ROW_LEN);
410                                                 flip_rand_n(temp, &rand, flip_count);
411                                                 const uint32_t next_error = check_distance_buff(distance_max, data->index, temp, error);
412                                                 if (next_error < error)
413                                                 {
414                                                         TRACE("Improved by rand-flip (%u)", flip_count);
415                                                         round = -1;
416                                                         memcpy(data->row_buffer, temp, sizeof(uint8_t) * ROW_LEN);
417                                                         if (!((error = next_error) > 0U))
418                                                         {
419                                                                 TRACE("Success by rand-flip (%u) <<<---", flip_count);
420                                                                 goto success;
421                                                         }
422                                                 }
423                                         }
424                                 }
425                         }
426                         TRACE("Restarting");
427                         _InterlockedCompareExchange(data->distance_max, min(distance_max + 1U, HASH_LEN), distance_max);
428                 }
429                 else
430                 {
431                         break; /*success*/
432                 }
433         }
434
435 success:
436         if (check_distance_buff(*data->distance_max, data->index, data->row_buffer, HASH_LEN))
437         {
438                 fprintf(stderr, "ERROR MISCOMPARE!\n");
439                 abort();
440         }
441
442         MUTEX_LOCK(data->mutex);
443         if (SEM_TRYWAIT(data->stop))
444         {
445                 MUTEX_UNLOCK(data->mutex);
446                 return NULL;
447         }
448
449         SEM_POST(data->stop, THREAD_COUNT);
450         MUTEX_UNLOCK(data->mutex);
451         return data->row_buffer; /*success*/
452 }
453
454 static void* thread_spin(void *const param)
455 {
456         unsigned long delay = 1U;
457         sem_t *const stop = ((sem_t*)param);
458         for (;;)
459         {
460                 if (SEM_TRYWAIT(stop))
461                 {
462                         printf("\b\b\b[!]");
463                         return NULL;
464                 }
465                 _sleep(delay);
466                 if (delay >= 500)
467                 {
468 #ifdef ENABLE_STATS
469                         const long long s_too_lo = g_stat_too_lo, s_too_hi = g_stat_too_hi;
470                         const long long s_too_ac = s_too_lo + s_too_hi;
471                         printf("Too low: %lld (%.2f), too high: %lld (%.2f)\n", s_too_lo, s_too_lo / ((double)s_too_ac), s_too_hi, s_too_hi / ((double)s_too_ac));
472 #endif //ENABLE_STATS
473                         printf("\b\b\b[%c]", SPINNER[g_spinpos]);
474                         g_spinpos = (g_spinpos + 1) % 4;
475                 }
476                 else
477                 {
478                         delay *= 2U;
479                 }
480         }
481 }
482
483 //-----------------------------------------------------------------------------
484 // Save / Load
485 //-----------------------------------------------------------------------------
486
487 static bool save_table_data(const wchar_t *const filename, const size_t rows_completed_in, const uint32_t current_dist_max)
488 {
489         wchar_t filename_temp[_MAX_PATH];
490         swprintf_s(filename_temp, _MAX_PATH, L"%s~%X", filename, make_seed());
491         FILE *const file = _wfopen(filename_temp, L"wb");
492         if (file)
493         {
494                 bool success = true;
495                 const uint64_t magic_number = MAGIC_NUMBER;
496                 const uint32_t hash_len = HASH_LEN, distance_min = DISTANCE_MIN, distance_max = current_dist_max, rows_completed = (uint32_t)rows_completed_in;
497                 fwrite(&magic_number, sizeof(uint64_t), 1, file);
498                 fwrite(&hash_len, sizeof(uint32_t), 1, file);
499                 fwrite(&distance_min, sizeof(uint32_t), 1, file);
500                 fwrite(&distance_max, sizeof(uint32_t), 1, file);
501                 fwrite(&rows_completed, sizeof(uint32_t), 1, file);
502                 for (uint32_t i = 0; i < rows_completed; ++i)
503                 {
504                         const uint32_t checksum = adler32(&g_table[i][0], ROW_LEN);
505                         fwrite(&checksum, sizeof(uint32_t), 1, file);
506                         fwrite(&g_table[i][0], sizeof(uint8_t), ROW_LEN, file);
507                 }
508                 if (ferror(file))
509                 {
510                         printf("ERROR: Failed to write table data!\n");
511                         success = false;
512                 }
513                 fclose(file);
514                 if (success)
515                 {
516                         for (size_t i = 0; i < 42; ++i)
517                         {
518                                 if (_wremove(filename))
519                                 {
520                                         if (errno != ENOENT)
521                                         {
522                                                 printf("ERROR: Failed to delete existing file!\n");
523                                                 sched_yield();
524                                                 continue;
525                                         }
526                                 }
527                                 break;
528                         }
529                         if (_wrename(filename_temp, filename))
530                         {
531                                 printf("ERROR: Failed to rename temp file!\n");
532                                 success = false;
533                         }
534                 }
535                 else
536                 {
537                         _wremove(filename_temp);
538                 }
539                 return success;
540         }
541         else
542         {
543                 printf("ERROR: Failed to open table file for writing!\n");
544                 return false;
545         }
546 }
547
548 static bool load_table_data(const wchar_t *const filename, size_t *const rows_completed_out, volatile long *const dist_max_out)
549 {
550         FILE *const file = _wfopen(filename, L"rb");
551         if (file)
552         {
553                 bool success = true;
554                 uint64_t magic_number;
555                 uint32_t hash_len, distance_min, distance_max, rows_completed;
556                 fread(&magic_number, sizeof(uint64_t), 1, file);
557                 fread(&hash_len, sizeof(uint32_t), 1, file);
558                 fread(&distance_min, sizeof(uint32_t), 1, file);
559                 fread(&distance_max, sizeof(uint32_t), 1, file);
560                 fread(&rows_completed, sizeof(uint32_t), 1, file);
561                 if (ferror(file) || feof(file))
562                 {
563                         printf("ERROR: Failed to read the table header!\n");
564                         success = false;
565                         goto failed;
566                 }
567                 if (magic_number != MAGIC_NUMBER)
568                 {
569                         printf("ERROR: Table file format could not be recognized!\n");
570                         success = false;
571                         goto failed;
572                 }
573                 if ((hash_len != HASH_LEN) || (distance_min != DISTANCE_MIN) || (distance_max > HASH_LEN) || (rows_completed > ROW_NUM))
574                 {
575                         printf("ERROR: Table properties are incompatibe with this instance!\n");
576                         success = false;
577                         goto failed;
578                 }
579                 for (size_t i = 0; i < rows_completed; ++i)
580                 {
581                         uint32_t checksum_expected;
582                         if ((fread(&checksum_expected, sizeof(uint32_t), 1, file) != 1) || (fread(&g_table[i][0], sizeof(uint8_t), ROW_LEN, file) != ROW_LEN))
583                         {
584                                 printf("ERROR: Failed to read table data from file!\n");
585                                 success = false;
586                                 goto failed;
587                         }
588                         if (adler32(&g_table[i][0], ROW_LEN) != checksum_expected)
589                         {
590                                 printf("ERROR: Table checksum does *not* match table contents!\n");
591                                 success = false;
592                                 goto failed;
593                         }
594                         for (size_t j = 0; j < i; j++)
595                         {
596                                 if (!check_distance_rows(distance_max, i, j))
597                                 {
598                                         printf("ERROR: Table distance verification has failed!\n");
599                                         success = false;
600                                         goto failed;
601                                 }
602                         }
603                 }
604         failed:
605                 fclose(file);
606                 if (success && rows_completed_out)
607                 {
608                         *rows_completed_out = (size_t)rows_completed;
609                         *dist_max_out = (long)distance_max;
610                 }
611                 return success;
612         }
613         else
614         {
615                 printf("ERROR: Failed to open table file for reading!\n");
616                 return false;
617         }
618 }
619
620 //-----------------------------------------------------------------------------
621 // MAIN
622 //-----------------------------------------------------------------------------
623
624 int wmain(int argc, wchar_t *argv[])
625 {
626         pthread_t thread_id[THREAD_COUNT + 1];
627         thread_data_t thread_data[THREAD_COUNT];
628         sem_t stop_flag;
629         pthread_mutex_t stop_mutex;
630         FILE *file_out = NULL;
631         size_t initial_row_index = 0;
632         volatile long distance_max = DISTANCE_MIN;
633
634         printf("MHash GenTableXOR [%s]\n\n", __DATE__);
635         printf("HashLen: %d, Distance Min: %d, Threads: %d\n\n", HASH_LEN, DISTANCE_MIN, THREAD_COUNT);
636
637         if ((HASH_LEN % (8 * sizeof(uint32_t))) != 0)
638         {
639                 crit_exit("FATAL: Hash length must be a multiple of 32 bits!");
640         }
641
642         if (argc < 2)
643         {
644                 printf("Table file not specified!\n\n");
645                 printf("Usage:\n");
646                 printf("   GenTables_XOR.exe <table_file>\n\n");
647                 return 1;
648         }
649
650         for (size_t i = 0; i < ROW_NUM; i++)
651         {
652                 memset(&g_table[i][0], 0, sizeof(uint8_t) * ROW_LEN);
653         }
654
655         memset(&thread_id, 0, sizeof(pthread_t) * (THREAD_COUNT + 1));
656         memset(&thread_data, 0, sizeof(thread_data_t) * THREAD_COUNT);
657         for (size_t t = 0; t < THREAD_COUNT; t++)
658         {
659                 memset(&g_thread_buffer[t][0], 0, sizeof(uint8_t) * ROW_LEN);
660         }
661
662         SEM_INIT(&stop_flag);
663         MUTEX_INIT(&stop_mutex);
664
665         if (_waccess(argv[1], 4) == 0)
666         {
667                 printf("Loading existing table data and proceeding...\n");
668                 if (!load_table_data(argv[1], &initial_row_index, &distance_max))
669                 {
670                         return 1;
671                 }
672         }
673
674         for (size_t i = initial_row_index; i < ROW_NUM; i++)
675         {
676                 char time_string[64];
677                 printf("\aRow %03u of %03u [%c]", (uint32_t)(i+1U), ROW_NUM, SPINNER[g_spinpos]);
678                 g_spinpos = (g_spinpos + 1) % 4;
679 #ifdef ENABLE_STATS
680                 g_stat_too_hi = g_stat_too_lo = 0i64;
681 #endif //INCREMENT_STAT
682
683                 PTHREAD_CREATE(&thread_id[THREAD_COUNT], NULL, thread_spin, &stop_flag);
684                 for (size_t t = 0; t < THREAD_COUNT; t++)
685                 {
686                         thread_data[t].index = i;
687                         thread_data[t].row_buffer = &g_thread_buffer[t][0];
688                         thread_data[t].stop = &stop_flag;
689                         thread_data[t].mutex = &stop_mutex;
690                         thread_data[t].distance_max = &distance_max;
691                         PTHREAD_CREATE(&thread_id[t], NULL, thread_main, &thread_data[t]);
692                         PTHREAD_SET_PRIORITY(thread_id[t], -15);
693                 }
694
695                 for (size_t t = 0; t < THREAD_COUNT; t++)
696                 {
697                         void *return_value = NULL;
698                         PTHREAD_JOIN(thread_id[t], &return_value);
699                         if (return_value)
700                         {
701                                 memcpy(&g_table[i][0], return_value, sizeof(uint8_t) * ROW_LEN);
702                         }
703                 }
704
705                 PTHREAD_JOIN(thread_id[THREAD_COUNT], NULL);
706                 get_time_str(time_string, 64);
707                 printf("\b\b\b[#] - %s\n", time_string);
708
709                 if (!save_table_data(argv[1], i + 1U, distance_max))
710                 {
711                         return 1; /*failed to save current table data*/
712                 }
713         }
714
715         printf("\n-----\n\n");
716
717         dump_table(stdout);
718         if (fopen_s(&file_out, "table_XOR." DISTANCE_STR ".txt", "w") == 0)
719         {
720                 dump_table(file_out);
721                 fclose(file_out);
722         }
723
724         printf("\n-----\n\n");
725
726         for (size_t i = 0; i < ROW_NUM; i++)
727         {
728                 for (size_t j = 0; j < ROW_NUM; j++)
729                 {
730                         if (i == j)
731                         {
732                                 continue;
733                         }
734                         if (!check_distance_rows(distance_max, i, j))
735                         {
736                                 crit_exit("FATAL: Table verification has failed!");
737                         }
738                 }
739         }
740
741         SEM_DESTROY(&stop_flag);
742         MUTEX_DESTROY(&stop_mutex);
743
744         printf("COMPLETED.\n\n");
745         system("shutdown /s /t 180");
746         return getchar();
747 }