Line data Source code
1 : /**
2 : * @file
3 : *
4 : * @brief The Order Preserving Minimal Perfect Hash Map C benchmark.
5 : *
6 : * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
7 : */
8 :
9 : // ==== DEFINE SECTION ====
10 : #define _GNU_SOURCE
11 : #define KDBRAND_BENCHMARK // allows the seed injection into Elektra
12 : // uncomment to use OPENMP and set USE_OPENMP in CMakeLists.txt
13 : //~ #define USE_OPENMP
14 :
15 : #ifdef USE_OPENMP
16 : // set here you number of threads
17 : #define NUMBEROFTHREADS 8
18 : #else
19 : #define NUMBEROFTHREADS 1
20 : #endif
21 :
22 : // ==== INCLUDE SECTION ====
23 : #include "benchmarks.h"
24 : #ifdef HAVE_HSEARCHR
25 : #include <search.h>
26 : #endif
27 :
28 : #ifdef USE_OPENMP
29 : #include <omp.h>
30 : #endif
31 :
32 : #include "../src/libs/elektra/opmphm.c"
33 : #include "../src/libs/elektra/opmphmpredictor.c"
34 : #include "../src/libs/elektra/rand.c"
35 : #include <sys/time.h>
36 :
37 : int32_t elektraRandBenchmarkInitSeed;
38 :
39 : // benchmarks helpers
40 : static int32_t * getRandomSeed (int32_t * seed);
41 : static FILE * openOutFileWithRPartitePostfix (const char * name, uint8_t r);
42 : static const char * getString (void * data);
43 : static size_t getPower (size_t p, size_t q);
44 : static int cmpInteger (const void * a, const void * b);
45 : // generate KeySets
46 : static KeySetShape * getKeySetShapes (void);
47 : const size_t numberOfShapes = 8;
48 :
49 :
50 : /**
51 : * General structure of a benchmark
52 : *
53 : * `name` is a unique name of the benchmark and `benchmarkF` is the independent function executing the benchmark.
54 : * Execute a benchmark with benchmark_opmphm `name`.
55 : */
56 : typedef struct
57 : {
58 : char * name;
59 : size_t numberOfSeedsNeeded;
60 : void (*benchmarkF) (char *);
61 : } Benchmark;
62 :
63 :
64 : /**
65 : * START ======================================= Measures the Opmphm Hash Function time ============================================== START
66 : *
67 : * This benchmark measures the time for hashing a whole KeySet, variegating in the size. Executed multiple times.
68 : *
69 : * The output has the following header: n;n;n;n;... (for each KeySetShape)
70 : *
71 : * This benchmark takes numberOfShapes * nCount seeds
72 : */
73 0 : static void benchmarkHashFunctionTime (char * name)
74 : {
75 0 : const size_t nCount = 4;
76 0 : const size_t n[] = { 10, 100, 1000, 10000 };
77 0 : const size_t runs = 11;
78 : // init results
79 0 : size_t * results = elektraMalloc (nCount * numberOfShapes * runs * sizeof (size_t));
80 0 : if (!results)
81 : {
82 0 : printExit ("malloc");
83 : }
84 : // benchmark
85 0 : printf ("Run Benchmark %s:\n", name);
86 0 : KeySetShape * keySetShapes = getKeySetShapes ();
87 0 : for (size_t i = 0; i < nCount; ++i)
88 : {
89 0 : for (size_t s = 0; s < numberOfShapes; ++s)
90 : {
91 0 : printf ("now at n: %zu/%zu shape: %zu/%zu\r", i, nCount, s, numberOfShapes);
92 0 : fflush (stdout);
93 : int32_t seed;
94 0 : if (getRandomSeed (&seed) != &seed) printExit ("Seed Parsing Error or feed me more seeds");
95 0 : KeySet * ks = generateKeySet (n[i], &seed, &keySetShapes[s]);
96 0 : for (size_t r = 0; r < runs; ++r)
97 : {
98 : Key * key;
99 0 : ksRewind (ks);
100 : struct timeval start;
101 : struct timeval end;
102 0 : __asm__("");
103 0 : gettimeofday (&start, 0);
104 0 : __asm__("");
105 : // measure
106 0 : while ((key = ksNext (ks)))
107 : {
108 0 : __asm__("");
109 0 : opmphmHashfunction (keyName (key), strlen (keyName (key)), 1337);
110 0 : __asm__("");
111 : }
112 0 : __asm__("");
113 0 : gettimeofday (&end, 0);
114 0 : __asm__("");
115 0 : results[i * (numberOfShapes * runs) + s * runs + r] =
116 0 : (end.tv_sec - start.tv_sec) * 1000000 + (end.tv_usec - start.tv_usec);
117 : }
118 0 : ksDel (ks);
119 : }
120 : }
121 0 : elektraFree (keySetShapes);
122 : // wirte out results
123 0 : FILE * out = openOutFileWithRPartitePostfix ("benchmark_opmphm_hashfunctiontime", 0);
124 0 : if (!out)
125 : {
126 0 : printExit ("open out file");
127 : }
128 : // print header
129 0 : for (size_t i = 0; i < nCount; ++i)
130 : {
131 0 : for (size_t s = 0; s < numberOfShapes; ++s)
132 : {
133 0 : if (!s && !i)
134 : {
135 0 : fprintf (out, "%zu", n[i]);
136 : }
137 : else
138 : {
139 0 : fprintf (out, ";%zu", n[i]);
140 : }
141 : }
142 : }
143 0 : fprintf (out, "\n");
144 : // print data
145 0 : for (size_t r = 0; r < runs; ++r)
146 : {
147 0 : for (size_t i = 0; i < nCount; ++i)
148 : {
149 0 : for (size_t s = 0; s < numberOfShapes; ++s)
150 : {
151 0 : if (!s && !i)
152 : {
153 0 : fprintf (out, "%zu", results[i * (numberOfShapes * runs) + s * runs + r]);
154 : }
155 : else
156 : {
157 0 : fprintf (out, ";%zu", results[i * (numberOfShapes * runs) + s * runs + r]);
158 : }
159 : }
160 : }
161 0 : fprintf (out, "\n");
162 : }
163 0 : fclose (out);
164 0 : elektraFree (results);
165 0 : }
166 : /**
167 : * END ========================================= Measures the Opmphm Hash Function time ================================================ END
168 : */
169 :
170 : /**
171 : * START ======================================================= Mapping ============================================================= START
172 : *
173 : * This benchmark counts the opmphmMapping (...) invocations until success, for each KeySet size (n) and space influencing parameter (c).
174 : * First the KeySets are build, for every KeySet size (n) there are numberOfShapes * keySetsPerShape KeySets.
175 : * Then the benchmarking for every KeySet size (n) and space influencing parameter (c) takes place, with a fixed set of seeds for
176 : * the opmphmMapping (...) invocations.
177 : * At the end the results are written out in the following format:
178 : *
179 : * trials;n_%zuc_%f;... (each n and c are unique)
180 : *
181 : * The number of needed seeds for this benchmarks is: nCount * numberOfShapes * keySetsPerShape (KeySets generation) + numberOfSeeds (tested
182 : * seeds)
183 : */
184 :
185 0 : static void benchmarkMappingCheckOpmphm (Opmphm * opmphm, OpmphmGraph * graph, size_t n, OpmphmInit * init, size_t mappings,
186 : size_t maxMappings)
187 : {
188 0 : if (n < 5 && mappings != maxMappings)
189 : {
190 : // assign
191 0 : if (opmphmAssignment (opmphm, graph, n, 1))
192 : {
193 0 : printExit ("check assignment failed");
194 : }
195 0 : for (size_t i = 0; i < n; ++i)
196 : {
197 0 : if (i != opmphmLookup (opmphm, n, init->getName (init->data[i])))
198 : {
199 0 : printExit ("check assignment failed");
200 : }
201 : }
202 0 : opmphmClear (opmphm);
203 : }
204 0 : }
205 :
206 0 : static void benchmarkMapping (char * name)
207 : {
208 0 : size_t rUniPar = 3;
209 0 : const size_t nCount = 15;
210 0 : const size_t n[] = { 10, 15, 20, 30, 40, 60, 80, 120, 160, 240, 320, 480, 640, 960, 1280 }; // 15
211 0 : const size_t cCount = 15;
212 0 : const double c[] = { 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5 }; // 15
213 0 : const size_t keySetsPerShape = 20;
214 0 : const size_t numberOfKeySets = nCount * numberOfShapes * keySetsPerShape;
215 :
216 0 : const size_t numberOfSeeds = 10000;
217 0 : const size_t maxMappings = 10; // the maximum trials for one opmphmMapping (...) invocation series.
218 :
219 : // init seed population, used for opmphmMapping (...) invocation.
220 0 : int32_t * seeds = elektraMalloc (numberOfSeeds * sizeof (int32_t));
221 0 : if (!seeds)
222 : {
223 0 : printExit ("malloc");
224 : }
225 : // get seeds
226 0 : for (size_t i = 0; i < numberOfSeeds; ++i)
227 : {
228 0 : if (getRandomSeed (&seeds[i]) != &seeds[i]) printExit ("Seed Parsing Error or feed me more seeds");
229 : }
230 :
231 : // init results
232 0 : size_t * results = elektraMalloc (nCount * cCount * maxMappings * sizeof (size_t));
233 0 : if (!results)
234 : {
235 0 : printExit ("malloc");
236 : }
237 0 : memset (results, 0, nCount * cCount * maxMappings * sizeof (size_t));
238 :
239 : // Generate all KeySets
240 0 : KeySetShape * keySetShapes = getKeySetShapes ();
241 0 : KeySet ** keySetsCache = elektraMalloc (numberOfKeySets * sizeof (KeySet *));
242 0 : if (!keySetsCache)
243 : {
244 0 : printExit ("malloc");
245 : }
246 0 : printf ("KeySet Cache Build:\n");
247 0 : for (size_t nI = 0; nI < nCount; ++nI)
248 : {
249 0 : printf ("now at: %zu/%zu\r", nI + 1, nCount);
250 0 : fflush (stdout);
251 0 : for (size_t shapeI = 0; shapeI < numberOfShapes; ++shapeI)
252 : {
253 0 : for (size_t ksPshapeI = 0; ksPshapeI < keySetsPerShape; ++ksPshapeI)
254 : {
255 : int32_t genSeed;
256 0 : if (getRandomSeed (&genSeed) != &genSeed) printExit ("Seed Parsing Error or feed me more seeds");
257 0 : keySetsCache[nI * (numberOfShapes * keySetsPerShape) + shapeI * keySetsPerShape + ksPshapeI] =
258 0 : generateKeySet (n[nI], &genSeed, &keySetShapes[shapeI]);
259 : }
260 : }
261 : }
262 :
263 0 : printf ("\nRun Benchmark %s:\n", name);
264 :
265 : #ifdef USE_OPENMP
266 : omp_set_num_threads (NUMBEROFTHREADS);
267 : // lock
268 : omp_lock_t writeLock;
269 : omp_init_lock (&writeLock);
270 : #endif
271 : // split
272 : if (numberOfSeeds % NUMBEROFTHREADS != 0) printExit ("seeds % NUMBEROFTHREADS != 0");
273 0 : size_t partSize = numberOfSeeds / NUMBEROFTHREADS;
274 :
275 : // init threads local results
276 : size_t * localResults[NUMBEROFTHREADS];
277 0 : for (size_t i = 0; i < NUMBEROFTHREADS; ++i)
278 : {
279 0 : localResults[i] = elektraMalloc (nCount * cCount * maxMappings * sizeof (size_t));
280 0 : if (!localResults[i])
281 : {
282 0 : printExit ("malloc");
283 : }
284 : }
285 :
286 : // for all nCount
287 0 : for (size_t nI = 0; nI < nCount; ++nI)
288 : {
289 : // and cCount
290 0 : for (size_t cI = 0; cI < cCount; ++cI)
291 : {
292 0 : printf ("now at: n = %zu/%zu c = %zu/%zu\r", nI + 1, nCount, cI + 1, cCount);
293 0 : fflush (stdout);
294 : // OPMPHM for all threads
295 : Opmphm * opmphms[NUMBEROFTHREADS];
296 : OpmphmGraph * graphs[NUMBEROFTHREADS];
297 0 : for (size_t i = 0; i < NUMBEROFTHREADS; ++i)
298 : {
299 0 : opmphms[i] = opmphmNew ();
300 0 : if (!opmphms[i]) printExit ("opmphm");
301 0 : graphs[i] = opmphmGraphNew (opmphms[i], rUniPar, n[nI], opmphmMinC (rUniPar) + c[cI]);
302 0 : if (!graphs[i]) printExit ("graph");
303 : }
304 : // OPMPHM
305 :
306 : // go through all KeySets from n
307 0 : for (size_t ksCacheI = 0; ksCacheI < numberOfShapes * keySetsPerShape; ++ksCacheI)
308 : {
309 0 : KeySet * ks = keySetsCache[nI * (numberOfShapes * keySetsPerShape) + ksCacheI];
310 : #ifdef USE_OPENMP
311 : #pragma omp parallel
312 : #endif
313 : {
314 0 : size_t threadI = 0;
315 : // OPMPHM
316 : OpmphmInit init;
317 0 : init.getName = getString;
318 0 : init.data = (void **) (ks->array);
319 : // OPMPHM
320 : #ifdef USE_OPENMP
321 : threadI = omp_get_thread_num ();
322 : #endif
323 : // reset local result
324 0 : memset (localResults[threadI], 0, nCount * cCount * maxMappings * sizeof (size_t));
325 :
326 : // try each seed part
327 0 : for (size_t seedI = threadI * partSize; seedI < (threadI + 1) * partSize; ++seedI)
328 : {
329 0 : size_t mappings = 0; // counts mapping invocations
330 : // OPMPHM
331 0 : init.initSeed = seeds[seedI];
332 : // fresh OpmphmGraph
333 0 : opmphmGraphClear (opmphms[threadI], graphs[threadI]);
334 : // do benchmark
335 : int ret;
336 : do
337 : {
338 0 : ret = opmphmMapping (opmphms[threadI], graphs[threadI], &init, n[nI]);
339 0 : ++mappings;
340 0 : } while (ret && mappings < maxMappings);
341 : // OPMPHM
342 0 : if (mappings < 1 || mappings > maxMappings)
343 : {
344 0 : printExit ("benchmarkSeedRangeMappingCount: mappings out of range");
345 : }
346 : // check opmphm
347 0 : benchmarkMappingCheckOpmphm (opmphms[threadI], graphs[threadI], n[nI], &init, mappings,
348 : maxMappings);
349 : // save result
350 : // shift, because 0 not used
351 0 : --mappings;
352 0 : ++localResults[threadI][nI * (cCount * maxMappings) + cI * maxMappings + mappings];
353 : }
354 : #ifdef USE_OPENMP
355 : // write local to global
356 : omp_set_lock (&writeLock);
357 : #endif
358 0 : for (size_t i = 0; i < nCount * cCount * maxMappings; ++i)
359 : {
360 0 : results[i] += localResults[threadI][i];
361 : }
362 : #ifdef USE_OPENMP
363 : omp_unset_lock (&writeLock);
364 : #endif
365 : }
366 : }
367 0 : for (size_t i = 0; i < NUMBEROFTHREADS; ++i)
368 : {
369 : // OPMPHM
370 0 : opmphmDel (opmphms[i]);
371 0 : opmphmGraphDel (graphs[i]);
372 : // OPMPHM
373 : }
374 : }
375 : // end for all nCount
376 : }
377 : #ifdef USE_OPENMP
378 : omp_destroy_lock (&writeLock);
379 : #endif
380 0 : for (size_t i = 0; i < NUMBEROFTHREADS; ++i)
381 : {
382 0 : free (localResults[i]);
383 : }
384 0 : printf ("\n");
385 :
386 : /*
387 : * results sanity check
388 : *
389 : * each n and c should have in sum (numberOfShapes * keySetsPerShape) for each KeySet times (numberOfSeeds) seeds trials
390 : */
391 0 : for (size_t nI = 0; nI < nCount; ++nI)
392 : {
393 0 : for (size_t cI = 0; cI < cCount; ++cI)
394 : {
395 : size_t sum = 0;
396 0 : for (size_t mappingI = 0; mappingI < maxMappings; ++mappingI)
397 : {
398 0 : sum += results[nI * (cCount * maxMappings) + cI * maxMappings + mappingI];
399 : }
400 0 : if (sum != numberOfShapes * keySetsPerShape * numberOfSeeds)
401 : {
402 0 : printExit ("benchmarkSeedRangeMappingCount: results sanity check failed");
403 : }
404 : }
405 : }
406 :
407 : // write out
408 0 : FILE * out = openOutFileWithRPartitePostfix ("benchmark_opmphm_mapping", rUniPar);
409 0 : if (!out)
410 : {
411 0 : printExit ("open out file");
412 : }
413 : // print header
414 0 : fprintf (out, "trials");
415 0 : for (size_t nI = 0; nI < nCount; ++nI)
416 : {
417 0 : for (size_t cI = 0; cI < cCount; ++cI)
418 : {
419 0 : fprintf (out, ";n_%zuc_%f", n[nI], opmphmMinC (rUniPar) + c[cI]);
420 : }
421 : }
422 0 : fprintf (out, "\n");
423 : // print data
424 0 : for (size_t mappingI = 0; mappingI < maxMappings; ++mappingI)
425 : {
426 0 : fprintf (out, "%zu", mappingI + 1); // unshift, because 0 is not a result
427 0 : for (size_t nI = 0; nI < nCount; ++nI)
428 : {
429 0 : for (size_t cI = 0; cI < cCount; ++cI)
430 : {
431 0 : fprintf (out, ";%zu", results[nI * (cCount * maxMappings) + cI * maxMappings + mappingI]);
432 : }
433 : }
434 0 : fprintf (out, "\n");
435 : }
436 :
437 : // cleanup
438 0 : for (size_t i = 0; i < numberOfKeySets; ++i)
439 : {
440 0 : ksDel (keySetsCache[i]);
441 : }
442 0 : elektraFree (keySetsCache);
443 0 : fclose (out);
444 0 : elektraFree (keySetShapes);
445 0 : elektraFree (seeds);
446 0 : elektraFree (results);
447 0 : }
448 :
449 : /**
450 : * END ========================================================= Mapping =============================================================== END
451 : */
452 :
453 : /**
454 : * START ============================================== Mapping with Optimization ==================================================== START
455 : *
456 : * This benchmark counts the opmphmMapping (...) invocations until success, for each KeySet size.
457 : * First the KeySets are build, for every KeySet size (n) there are numberOfShapes * keySetsPerShape KeySets.
458 : * Then the benchmarking for every KeySet size (n) takes place, with a fixed set of seeds for the opmphmMapping (...) invocations.
459 : * At the end the results are written out in the following format:
460 : *
461 : * trials;n_%zur_%uc_%f;... (each n is unique)
462 : *
463 : * The number of needed seeds for this benchmarks is: nCount * numberOfShapes * keySetsPerShape (KeySets generation) + numberOfSeeds (tested
464 : * seeds)
465 : */
466 :
467 0 : static void benchmarkMappingOpt (char * name)
468 : {
469 : // create the n array
470 0 : const size_t nCount = 132;
471 0 : size_t * n = elektraMalloc (nCount * sizeof (size_t));
472 0 : if (!n)
473 : {
474 0 : printExit ("malloc");
475 : }
476 : size_t controlCount = 0;
477 0 : for (size_t i = 2; i <= 38; ++i)
478 : {
479 0 : n[controlCount] = i;
480 0 : ++controlCount;
481 : }
482 0 : for (size_t i = 39; i <= 239; i = i + 5)
483 : {
484 0 : n[controlCount] = i;
485 0 : ++controlCount;
486 : }
487 0 : n[controlCount] = 240;
488 0 : ++controlCount;
489 0 : for (size_t i = 259; i <= 1279; i = i + 20)
490 : {
491 0 : n[controlCount] = i;
492 0 : ++controlCount;
493 : }
494 0 : n[controlCount] = 1280;
495 0 : ++controlCount;
496 0 : if (controlCount != nCount)
497 : {
498 0 : printExit ("controlCount != nCount");
499 : }
500 :
501 0 : const size_t keySetsPerShape = 70;
502 0 : const size_t numberOfKeySets = nCount * numberOfShapes * keySetsPerShape;
503 :
504 0 : const size_t numberOfSeeds = 20000;
505 0 : const size_t maxMappings = 10; // the maximum trials for one opmphmMapping (...) invocation series.
506 :
507 : // init seed population, used for opmphmMapping (...) invocation.
508 0 : int32_t * seeds = elektraMalloc (numberOfSeeds * sizeof (int32_t));
509 0 : if (!seeds)
510 : {
511 0 : printExit ("malloc");
512 : }
513 : // get seeds
514 0 : for (size_t i = 0; i < numberOfSeeds; ++i)
515 : {
516 0 : if (getRandomSeed (&seeds[i]) != &seeds[i]) printExit ("Seed Parsing Error or feed me more seeds");
517 : }
518 :
519 : // init results
520 0 : size_t * results = elektraMalloc (nCount * maxMappings * sizeof (size_t));
521 0 : if (!results)
522 : {
523 0 : printExit ("malloc");
524 : }
525 0 : memset (results, 0, nCount * maxMappings * sizeof (size_t));
526 :
527 : // Generate all KeySets
528 0 : KeySetShape * keySetShapes = getKeySetShapes ();
529 0 : KeySet ** keySetsCache = elektraMalloc (numberOfKeySets * sizeof (KeySet *));
530 0 : if (!keySetsCache)
531 : {
532 0 : printExit ("malloc");
533 : }
534 0 : printf ("KeySet Cache Build:\n");
535 0 : for (size_t nI = 0; nI < nCount; ++nI)
536 : {
537 0 : printf ("now at: %zu/%zu\r", nI + 1, nCount);
538 0 : fflush (stdout);
539 0 : for (size_t shapeI = 0; shapeI < numberOfShapes; ++shapeI)
540 : {
541 0 : for (size_t ksPshapeI = 0; ksPshapeI < keySetsPerShape; ++ksPshapeI)
542 : {
543 : int32_t genSeed;
544 0 : if (getRandomSeed (&genSeed) != &genSeed) printExit ("Seed Parsing Error or feed me more seeds");
545 0 : keySetsCache[nI * (numberOfShapes * keySetsPerShape) + shapeI * keySetsPerShape + ksPshapeI] =
546 0 : generateKeySet (n[nI], &genSeed, &keySetShapes[shapeI]);
547 : }
548 : }
549 : }
550 :
551 0 : printf ("\nRun Benchmark %s:\n", name);
552 :
553 : #ifdef USE_OPENMP
554 : omp_set_num_threads (NUMBEROFTHREADS);
555 : // lock
556 : omp_lock_t writeLock;
557 : omp_init_lock (&writeLock);
558 : #endif
559 : // split
560 : if (numberOfSeeds % NUMBEROFTHREADS != 0) printExit ("seeds % NUMBEROFTHREADS != 0");
561 0 : size_t partSize = numberOfSeeds / NUMBEROFTHREADS;
562 :
563 : // init threads local results
564 : size_t * localResults[NUMBEROFTHREADS];
565 0 : for (size_t i = 0; i < NUMBEROFTHREADS; ++i)
566 : {
567 0 : localResults[i] = elektraMalloc (nCount * maxMappings * sizeof (size_t));
568 0 : if (!localResults[i])
569 : {
570 0 : printExit ("malloc");
571 : }
572 : }
573 :
574 : // for all nCount
575 0 : for (size_t nI = 0; nI < nCount; ++nI)
576 : {
577 0 : printf ("now at: n = %zu/%zu\r", nI + 1, nCount);
578 0 : fflush (stdout);
579 : // OPMPHM for all threads
580 : Opmphm * opmphms[NUMBEROFTHREADS];
581 : OpmphmGraph * graphs[NUMBEROFTHREADS];
582 0 : for (size_t i = 0; i < NUMBEROFTHREADS; ++i)
583 : {
584 0 : opmphms[i] = opmphmNew ();
585 0 : if (!opmphms[i]) printExit ("opmphm");
586 0 : uint8_t r = opmphmOptR (n[nI]);
587 0 : graphs[i] = opmphmGraphNew (opmphms[i], r, n[nI], opmphmMinC (r) + opmphmOptC (n[nI]));
588 0 : if (!graphs[i]) printExit ("graph");
589 : }
590 : // OPMPHM
591 :
592 : // go through all KeySets from n
593 0 : for (size_t ksCacheI = 0; ksCacheI < numberOfShapes * keySetsPerShape; ++ksCacheI)
594 : {
595 0 : KeySet * ks = keySetsCache[nI * (numberOfShapes * keySetsPerShape) + ksCacheI];
596 : #ifdef USE_OPENMP
597 : #pragma omp parallel
598 : #endif
599 : {
600 0 : size_t threadI = 0;
601 : // OPMPHM
602 : OpmphmInit init;
603 0 : init.getName = getString;
604 0 : init.data = (void **) (ks->array);
605 : // OPMPHM
606 : #ifdef USE_OPENMP
607 : threadI = omp_get_thread_num ();
608 : #endif
609 : // reset local result
610 0 : memset (localResults[threadI], 0, nCount * maxMappings * sizeof (size_t));
611 :
612 : // try each seed part
613 0 : for (size_t seedI = threadI * partSize; seedI < (threadI + 1) * partSize; ++seedI)
614 : {
615 0 : size_t mappings = 0; // counts mapping invocations
616 : // OPMPHM
617 0 : init.initSeed = seeds[seedI];
618 : // fresh OpmphmGraph
619 0 : opmphmGraphClear (opmphms[threadI], graphs[threadI]);
620 : // do benchmark
621 : int ret;
622 : do
623 : {
624 0 : ret = opmphmMapping (opmphms[threadI], graphs[threadI], &init, n[nI]);
625 0 : ++mappings;
626 0 : } while (ret && mappings < maxMappings);
627 : // OPMPHM
628 0 : if (mappings < 1 || mappings > maxMappings)
629 : {
630 0 : printExit ("benchmarkSeedRangeMappingCount: mappings out of range");
631 : }
632 : // check assignment
633 0 : if (nI < 5 && mappings != maxMappings)
634 : {
635 : // assign
636 0 : if (opmphmAssignment (opmphms[threadI], graphs[threadI], n[nI], 1))
637 : {
638 0 : printExit ("check assignment failed");
639 : }
640 0 : for (size_t i = 0; i < n[nI]; ++i)
641 : {
642 0 : if (i != opmphmLookup (opmphms[threadI], n[nI], init.getName (init.data[i])))
643 : {
644 0 : printExit ("check assignment failed");
645 : }
646 : }
647 0 : opmphmClear (opmphms[threadI]);
648 : }
649 : // save result
650 : // shift, because 0 not used
651 0 : --mappings;
652 0 : ++localResults[threadI][nI * maxMappings + mappings];
653 : }
654 : #ifdef USE_OPENMP
655 : // write local to global
656 : omp_set_lock (&writeLock);
657 : #endif
658 0 : for (size_t i = 0; i < nCount * maxMappings; ++i)
659 : {
660 0 : results[i] += localResults[threadI][i];
661 : }
662 : #ifdef USE_OPENMP
663 : omp_unset_lock (&writeLock);
664 : #endif
665 : }
666 : }
667 0 : for (size_t i = 0; i < NUMBEROFTHREADS; ++i)
668 : {
669 : // OPMPHM
670 0 : opmphmDel (opmphms[i]);
671 0 : opmphmGraphDel (graphs[i]);
672 : // OPMPHM
673 : }
674 : // end for all nCount
675 : }
676 : #ifdef USE_OPENMP
677 : omp_destroy_lock (&writeLock);
678 : #endif
679 0 : for (size_t i = 0; i < NUMBEROFTHREADS; ++i)
680 : {
681 0 : free (localResults[i]);
682 : }
683 0 : printf ("\n");
684 :
685 : /*
686 : * results sanity check
687 : *
688 : * each n should have in sum (numberOfShapes * keySetsPerShape) for each KeySet times (numberOfSeeds) seeds trials
689 : */
690 0 : for (size_t nI = 0; nI < nCount; ++nI)
691 : {
692 : size_t sum = 0;
693 0 : for (size_t mappingI = 0; mappingI < maxMappings; ++mappingI)
694 : {
695 0 : sum += results[nI * maxMappings + mappingI];
696 : }
697 0 : if (sum != numberOfShapes * keySetsPerShape * numberOfSeeds)
698 : {
699 0 : printExit ("benchmarkSeedRangeMappingCount: results sanity check failed");
700 : }
701 : }
702 :
703 : // write out
704 0 : FILE * out = fopen ("benchmark_opmphm_mapping_opt.csv", "w");
705 0 : if (!out)
706 : {
707 0 : printExit ("open out file");
708 : }
709 : // print header
710 0 : fprintf (out, "trials");
711 0 : for (size_t nI = 0; nI < nCount; ++nI)
712 : {
713 0 : fprintf (out, ";n_%zur_%uc_%f", n[nI], opmphmOptR (n[nI]), opmphmMinC (opmphmOptR (n[nI])) + opmphmOptC (n[nI]));
714 : }
715 0 : fprintf (out, "\n");
716 : // print data
717 0 : for (size_t mappingI = 0; mappingI < maxMappings; ++mappingI)
718 : {
719 0 : fprintf (out, "%zu", mappingI + 1); // unshift, because 0 is not a result
720 0 : for (size_t nI = 0; nI < nCount; ++nI)
721 : {
722 0 : fprintf (out, ";%zu", results[nI * maxMappings + mappingI]);
723 : }
724 0 : fprintf (out, "\n");
725 : }
726 :
727 : // cleanup
728 0 : for (size_t i = 0; i < numberOfKeySets; ++i)
729 : {
730 0 : ksDel (keySetsCache[i]);
731 : }
732 0 : elektraFree (n);
733 0 : elektraFree (keySetsCache);
734 0 : fclose (out);
735 0 : elektraFree (keySetShapes);
736 0 : elektraFree (seeds);
737 0 : elektraFree (results);
738 0 : }
739 :
740 : /**
741 : * END ================================================ Mapping with Optimization ====================================================== END
742 : */
743 :
744 : /**
745 : * START ================================================== Mapping All Seeds ======================================================== START
746 : *
747 : * This benchmark counts the opmphmMapping (...) invocations until success, for each KeySet size and all seeds.
748 : * First the KeySets are build, for every KeySet size (n). Then the benchmarking for every KeySet size (n) takes place,
749 : * the seeds start at 1 and go to ELEKTRARANDMAX - 1 = 2147483646.
750 : * At the end the results are written out in the following format:
751 : *
752 : * trials;n_%zur_%uc_%f;... (each n is unique)
753 : *
754 : * The number of needed seeds for this benchmarks is: nCount (KeySets generation)
755 : */
756 :
757 0 : static void benchmarkMappingAllSeeds (char * name)
758 : {
759 : // create the n array
760 0 : const size_t nCount = 7;
761 0 : size_t * n = elektraMalloc (nCount * sizeof (size_t));
762 0 : if (!n)
763 : {
764 0 : printExit ("malloc");
765 : }
766 0 : n[0] = 9;
767 0 : n[1] = 29;
768 0 : n[2] = 49;
769 0 : n[3] = 69;
770 0 : n[4] = 89;
771 0 : n[5] = 109;
772 0 : n[6] = 129;
773 :
774 : // seeds limits
775 0 : const int32_t startSeed = 1;
776 0 : const int32_t endSeed = ELEKTRARANDMAX - 1; // = ELEKTRARANDMAX;
777 :
778 0 : const size_t maxMappings = 10; // the maximum trials for one opmphmMapping (...) invocation series.
779 :
780 : // init results
781 0 : size_t * results = elektraMalloc (nCount * maxMappings * sizeof (size_t));
782 0 : if (!results)
783 : {
784 0 : printExit ("malloc");
785 : }
786 0 : memset (results, 0, nCount * maxMappings * sizeof (size_t));
787 :
788 : // Generate all KeySets
789 0 : KeySetShape * keySetShapes = getKeySetShapes ();
790 0 : KeySet ** keySetsCache = elektraMalloc (nCount * sizeof (KeySet *));
791 0 : if (!keySetsCache)
792 : {
793 0 : printExit ("malloc");
794 : }
795 0 : for (size_t nI = 0; nI < nCount; ++nI)
796 : {
797 : int32_t genSeed;
798 0 : if (getRandomSeed (&genSeed) != &genSeed) printExit ("Seed Parsing Error or feed me more seeds");
799 0 : keySetsCache[nI] = generateKeySet (n[nI], &genSeed, &keySetShapes[0]); // shape 0 is shapefConstBinary with 0 parents
800 : }
801 :
802 0 : printf ("\nRun Benchmark %s:\n", name);
803 :
804 : #ifdef USE_OPENMP
805 : omp_set_num_threads (NUMBEROFTHREADS);
806 : // lock
807 : omp_lock_t writeLock;
808 : omp_init_lock (&writeLock);
809 : #endif
810 :
811 : // split the job
812 : int32_t partIntervals[NUMBEROFTHREADS * 2];
813 0 : int32_t onePart = (endSeed - startSeed) / NUMBEROFTHREADS;
814 0 : int32_t iterateIntervals = startSeed;
815 0 : for (size_t i = 0; i < NUMBEROFTHREADS; ++i)
816 : {
817 : if (i == NUMBEROFTHREADS - 1)
818 : {
819 : // give last thread the remaining seeds
820 0 : partIntervals[i * 2] = iterateIntervals;
821 0 : partIntervals[(i * 2) + 1] = endSeed;
822 : }
823 : else
824 : {
825 : partIntervals[i * 2] = iterateIntervals;
826 : partIntervals[(i * 2) + 1] = iterateIntervals + onePart - 1;
827 : iterateIntervals += onePart;
828 : }
829 : }
830 :
831 : // init threads local results
832 : size_t * localResults[NUMBEROFTHREADS];
833 0 : for (size_t i = 0; i < NUMBEROFTHREADS; ++i)
834 : {
835 0 : localResults[i] = elektraMalloc (nCount * maxMappings * sizeof (size_t));
836 0 : if (!localResults[i])
837 : {
838 0 : printExit ("malloc");
839 : }
840 : }
841 :
842 : // for all nCount
843 0 : for (size_t nI = 0; nI < nCount; ++nI)
844 : {
845 : // OPMPHM for all threads
846 : Opmphm * opmphms[NUMBEROFTHREADS];
847 : OpmphmGraph * graphs[NUMBEROFTHREADS];
848 0 : for (size_t i = 0; i < NUMBEROFTHREADS; ++i)
849 : {
850 0 : opmphms[i] = opmphmNew ();
851 0 : if (!opmphms[i]) printExit ("opmphm");
852 0 : uint8_t r = opmphmOptR (n[nI]);
853 0 : graphs[i] = opmphmGraphNew (opmphms[i], r, n[nI], opmphmMinC (r) + opmphmOptC (n[nI]));
854 0 : if (!graphs[i]) printExit ("graph");
855 : }
856 : // OPMPHM
857 :
858 0 : KeySet * ks = keySetsCache[nI];
859 : #ifdef USE_OPENMP
860 : #pragma omp parallel
861 : #endif
862 : {
863 0 : size_t threadI = 0;
864 : // OPMPHM
865 : OpmphmInit init;
866 0 : init.getName = getString;
867 0 : init.data = (void **) (ks->array);
868 : // OPMPHM
869 :
870 : #ifdef USE_OPENMP
871 : threadI = omp_get_thread_num ();
872 : #endif
873 : // reset local result
874 0 : memset (localResults[threadI], 0, nCount * maxMappings * sizeof (size_t));
875 :
876 : // try each seed part
877 0 : for (int32_t seed = partIntervals[threadI * 2];
878 0 : partIntervals[threadI * 2] <= seed && seed <= partIntervals[(threadI * 2) + 1]; ++seed)
879 : {
880 0 : if (threadI == 0 && (seed % 1000) == 0)
881 : {
882 0 : printf ("now at: n = %zu/%zu and seed %i from %i\r", nI + 1, nCount, seed, partIntervals[1]);
883 0 : fflush (stdout);
884 : }
885 0 : size_t mappings = 0; // counts mapping invocations
886 : // OPMPHM
887 0 : init.initSeed = seed;
888 : // fresh OpmphmGraph
889 0 : opmphmGraphClear (opmphms[threadI], graphs[threadI]);
890 : // do benchmark
891 : int ret;
892 : do
893 : {
894 0 : ret = opmphmMapping (opmphms[threadI], graphs[threadI], &init, n[nI]);
895 0 : ++mappings;
896 0 : } while (ret && mappings < maxMappings);
897 : // OPMPHM
898 0 : if (mappings < 1 || mappings > maxMappings)
899 : {
900 0 : printExit ("benchmarkSeedRangeMappingCount: mappings out of range");
901 : }
902 : // save result
903 : // shift, because 0 not used
904 0 : --mappings;
905 0 : ++localResults[threadI][nI * maxMappings + mappings];
906 : }
907 : #ifdef USE_OPENMP
908 : // write local to global
909 : omp_set_lock (&writeLock);
910 : #endif
911 0 : for (size_t i = 0; i < nCount * maxMappings; ++i)
912 : {
913 0 : results[i] += localResults[threadI][i];
914 : }
915 : #ifdef USE_OPENMP
916 : omp_unset_lock (&writeLock);
917 : #endif
918 : }
919 0 : for (size_t i = 0; i < NUMBEROFTHREADS; ++i)
920 : {
921 : // OPMPHM
922 0 : opmphmDel (opmphms[i]);
923 0 : opmphmGraphDel (graphs[i]);
924 : // OPMPHM
925 : }
926 : // end for all nCount
927 : }
928 : #ifdef USE_OPENMP
929 : omp_destroy_lock (&writeLock);
930 : #endif
931 0 : for (size_t i = 0; i < NUMBEROFTHREADS; ++i)
932 : {
933 0 : free (localResults[i]);
934 : }
935 0 : printf ("\n");
936 :
937 : /*
938 : * results sanity check
939 : *
940 : * each n should have in sum endSeed - startSeed + 1 trials
941 : */
942 0 : for (size_t nI = 0; nI < nCount; ++nI)
943 : {
944 : size_t sum = 0;
945 0 : for (size_t mappingI = 0; mappingI < maxMappings; ++mappingI)
946 : {
947 0 : sum += results[nI * maxMappings + mappingI];
948 : }
949 0 : if (sum != (size_t) endSeed - startSeed + 1)
950 : {
951 0 : printExit ("benchmarkSeedRangeMappingCount: results sanity check failed");
952 : }
953 : }
954 :
955 : // write out
956 0 : FILE * out = fopen ("benchmark_opmphm_mapping_allSeeds.csv", "w");
957 0 : if (!out)
958 : {
959 0 : printExit ("open out file");
960 : }
961 : // print header
962 0 : fprintf (out, "trials");
963 0 : for (size_t nI = 0; nI < nCount; ++nI)
964 : {
965 0 : fprintf (out, ";n_%zur_%uc_%f", n[nI], opmphmOptR (n[nI]), opmphmMinC (opmphmOptR (n[nI])) + opmphmOptC (n[nI]));
966 : }
967 0 : fprintf (out, "\n");
968 : // print data
969 0 : for (size_t mappingI = 0; mappingI < maxMappings; ++mappingI)
970 : {
971 0 : fprintf (out, "%zu", mappingI + 1); // unshift, because 0 is not a result
972 0 : for (size_t nI = 0; nI < nCount; ++nI)
973 : {
974 0 : fprintf (out, ";%zu", results[nI * maxMappings + mappingI]);
975 : }
976 0 : fprintf (out, "\n");
977 : }
978 :
979 : // cleanup
980 0 : for (size_t i = 0; i < nCount; ++i)
981 : {
982 0 : ksDel (keySetsCache[i]);
983 : }
984 0 : elektraFree (n);
985 0 : elektraFree (keySetsCache);
986 0 : fclose (out);
987 0 : elektraFree (keySetShapes);
988 0 : elektraFree (results);
989 0 : }
990 :
991 : /**
992 : * END ==================================================== Mapping All Seeds ========================================================== END
993 : */
994 :
995 : /**
996 : * START ================================================== OPMPHM Build Time ======================================================== START
997 : *
998 : * This benchmark measures the time of the OPMPHM build.
999 : * Uses all KeySet shapes except 6, for all n (KeySet size) a fixed set of seeds is used to build the OPMPHM.
1000 : * The keyset shape 6 is excluded, because previous evaluation had show that the results with that keyset shape
1001 : * where unusable, due to the unnatural long key names.
1002 : * For one n (KeySet size) ksPerN KeySets are used.
1003 : * The results are written out in the following format:
1004 : *
1005 : * n;ks;time
1006 : *
1007 : * The number of needed seeds for this benchmarks is: (numberOfShapes - 1) * ( numberOfSeeds + nCount * ksPerN )
1008 : */
1009 :
1010 : /**
1011 : * @brief Measures the OPMPHM build numberOfRepeats time and returns median
1012 : *
1013 : * @param ks the KeySet
1014 : * @param repeats array to store repeated measurements
1015 : * @param numberOfRepeats fields in repeats
1016 : *
1017 : * @retval median time
1018 : */
1019 0 : static size_t benchmarkOPMPHMBuildTimeMeasure (KeySet * ks, size_t * repeats, size_t numberOfRepeats)
1020 : {
1021 0 : for (size_t repeatsI = 0; repeatsI < numberOfRepeats; ++repeatsI)
1022 : {
1023 : // preparation for measurement
1024 : struct timeval start;
1025 : struct timeval end;
1026 0 : Key * keySearchFor = ks->array[0]; // just some key
1027 : Key * keyFound;
1028 : // fresh OPMPHM
1029 0 : if (ks->opmphm)
1030 : {
1031 0 : opmphmDel (ks->opmphm);
1032 0 : ks->opmphm = NULL;
1033 : }
1034 :
1035 : // START MEASUREMENT
1036 0 : __asm__("");
1037 0 : gettimeofday (&start, 0);
1038 0 : __asm__("");
1039 :
1040 0 : keyFound = ksLookup (ks, keySearchFor, KDB_O_OPMPHM | KDB_O_NOCASCADING);
1041 :
1042 0 : __asm__("");
1043 0 : gettimeofday (&end, 0);
1044 0 : __asm__("");
1045 : // END MEASUREMENT
1046 :
1047 : // save result
1048 0 : repeats[repeatsI] = (end.tv_sec - start.tv_sec) * 1000000 + (end.tv_usec - start.tv_usec);
1049 :
1050 : // sanity check
1051 0 : if (!opmphmIsBuild (ks->opmphm))
1052 : {
1053 0 : printExit ("Sanity Check Failed: OPMPHM not used");
1054 : }
1055 0 : if (keyFound != keySearchFor)
1056 : {
1057 0 : printExit ("Sanity Check Failed: found wrong Key");
1058 : }
1059 : }
1060 : // sort repeats
1061 0 : qsort (repeats, numberOfRepeats, sizeof (size_t), cmpInteger);
1062 0 : return repeats[numberOfRepeats / 2]; // take median
1063 : }
1064 :
1065 0 : void benchmarkOPMPHMBuildTime (char * name)
1066 : {
1067 0 : const size_t startN = 50;
1068 0 : const size_t stepN = 500;
1069 0 : const size_t endN = 20000;
1070 0 : const size_t ksPerN = 5;
1071 0 : const size_t numberOfSeeds = 51;
1072 0 : const size_t numberOfRepeats = 7;
1073 :
1074 : // check config
1075 : if (startN >= endN || startN == 0)
1076 : {
1077 : printExit ("startN >= endN || startN == 0");
1078 : }
1079 : if (numberOfRepeats % 2 == 0)
1080 : {
1081 : printExit ("numberOfRepeats is even");
1082 : }
1083 : if (numberOfSeeds % 2 == 0)
1084 : {
1085 : printExit ("numberOfSeeds is even");
1086 : }
1087 : if (ksPerN % 2 == 0)
1088 : {
1089 : printExit ("ksPerN is even");
1090 : }
1091 :
1092 : // calculate counts
1093 0 : size_t nCount = 0;
1094 0 : for (size_t nI = startN; nI <= endN; nI += stepN)
1095 : {
1096 0 : ++nCount;
1097 : }
1098 :
1099 : // memory allocation and initialization
1100 : // init seeds for mapping step in ksLookup (...)
1101 0 : int32_t * seeds = elektraMalloc (numberOfSeeds * sizeof (int32_t));
1102 0 : if (!seeds)
1103 : {
1104 0 : printExit ("malloc");
1105 : }
1106 : // init results
1107 0 : size_t * results = elektraMalloc (nCount * ksPerN * numberOfSeeds * sizeof (size_t));
1108 0 : if (!results)
1109 : {
1110 0 : printExit ("malloc");
1111 : }
1112 : // init repeats
1113 0 : size_t * repeats = elektraMalloc (numberOfRepeats * sizeof (size_t));
1114 0 : if (!repeats)
1115 : {
1116 0 : printExit ("malloc");
1117 : }
1118 : // init KeySetStorage
1119 0 : KeySet ** keySetStorage = elektraMalloc (ksPerN * sizeof (KeySet *));
1120 0 : if (!keySetStorage)
1121 : {
1122 0 : printExit ("malloc");
1123 : }
1124 :
1125 : // get KeySet shapes
1126 0 : KeySetShape * keySetShapes = getKeySetShapes ();
1127 :
1128 0 : printf ("Run Benchmark %s:\n", name);
1129 :
1130 : // for all KeySet shapes except 6
1131 0 : for (size_t shapeI = 0; shapeI < numberOfShapes; ++shapeI)
1132 : {
1133 0 : if (shapeI == 6)
1134 : {
1135 0 : continue;
1136 : }
1137 : // get seeds for mapping step in ksLookup (...)
1138 0 : for (size_t i = 0; i < numberOfSeeds; ++i)
1139 : {
1140 0 : if (getRandomSeed (&seeds[i]) != &seeds[i]) printExit ("Seed Parsing Error or feed me more seeds");
1141 : }
1142 :
1143 0 : KeySetShape * usedKeySetShape = &keySetShapes[shapeI];
1144 :
1145 : // for all Ns
1146 0 : for (size_t nI = startN; nI <= endN; nI += stepN)
1147 : {
1148 0 : printf ("now at: shape = %zu/%zu n = %zu/%zu\r", shapeI + 1, numberOfShapes, nI, endN);
1149 0 : fflush (stdout);
1150 :
1151 : // generate KeySets
1152 : int32_t genSeed;
1153 0 : for (size_t ksI = 0; ksI < ksPerN; ++ksI)
1154 : {
1155 0 : if (getRandomSeed (&genSeed) != &genSeed) printExit ("Seed Parsing Error or feed me more seeds");
1156 0 : keySetStorage[ksI] = generateKeySet (nI, &genSeed, usedKeySetShape);
1157 : }
1158 :
1159 : // for all seeds
1160 0 : for (size_t seedI = 0; seedI < numberOfSeeds; ++seedI)
1161 : {
1162 : // set seed to return by elektraRandGetInitSeed () in the lookup
1163 0 : elektraRandBenchmarkInitSeed = seeds[seedI];
1164 :
1165 : // for all KeySets in the storage
1166 0 : for (size_t ksI = 0; ksI < ksPerN; ++ksI)
1167 : {
1168 : // measure
1169 0 : size_t res = benchmarkOPMPHMBuildTimeMeasure (keySetStorage[ksI], repeats, numberOfRepeats);
1170 :
1171 : // store res
1172 0 : results[((nI - startN) / stepN) * ksPerN * numberOfSeeds + ksI * numberOfSeeds + seedI] = res;
1173 : }
1174 : }
1175 :
1176 : // free ks
1177 0 : for (size_t ksI = 0; ksI < ksPerN; ++ksI)
1178 : {
1179 0 : ksDel (keySetStorage[ksI]);
1180 : }
1181 : }
1182 :
1183 : // write out
1184 0 : FILE * out = openOutFileWithRPartitePostfix ("benchmark_opmphm_build_time", shapeI);
1185 0 : if (!out)
1186 : {
1187 0 : printExit ("open out file");
1188 : }
1189 : // print header
1190 0 : fprintf (out, "n;ks;time\n");
1191 : // print data
1192 0 : for (size_t nI = startN; nI <= endN; nI += stepN)
1193 : {
1194 0 : for (size_t ksI = 0; ksI < ksPerN; ++ksI)
1195 : {
1196 0 : for (size_t seedI = 0; seedI < numberOfSeeds; ++seedI)
1197 : {
1198 0 : fprintf (out, "%zu;%zu;%zu\n", nI, ksI,
1199 0 : results[((nI - startN) / stepN) * ksPerN * numberOfSeeds + ksI * numberOfSeeds + seedI]);
1200 : }
1201 : }
1202 : }
1203 :
1204 0 : fclose (out);
1205 : }
1206 0 : printf ("\n");
1207 :
1208 0 : elektraFree (repeats);
1209 0 : elektraFree (keySetStorage);
1210 0 : elektraFree (keySetShapes);
1211 0 : elektraFree (results);
1212 0 : elektraFree (seeds);
1213 0 : }
1214 :
1215 : /**
1216 : * END ==================================================== OPMPHM Build Time ========================================================== END
1217 : */
1218 :
1219 : /**
1220 : * START ================================================== OPMPHM Search Time ======================================================= START
1221 : *
1222 : * This benchmark measures the time of the OPMPHM search.
1223 : * Uses all KeySet shapes except 6, for one n (KeySet size) ksPerN KeySets are used.
1224 : * The keyset shape 6 is excluded, because previous evaluation had show that the results with that keyset shape
1225 : * where unusable, due to the unnatural long key names.
1226 : * Each measurement done with one KeySet is repeated numberOfRepeats time and summarized with the median.
1227 : * For one n (KeySet size) the ksPerN results are also summarized with the median.
1228 : * The results are written out in the following format:
1229 : *
1230 : * n;search_1;search_2;...;search_(numberOfSearches)
1231 : *
1232 : * The number of needed seeds for this benchmarks is: (numberOfShapes - 1) * nCount * ksPerN * (1 + searchesCount )
1233 : */
1234 :
1235 : /**
1236 : * @brief Measures the OPMPHM search time, for searches random Keys, repeats the measurement numberOfRepeats time and returns the media.
1237 : *
1238 : * The OPMPHM build will be triggerd if KDB_OPMPHM is set!
1239 : *
1240 : * @param ks the KeySet
1241 : * @param searches the number of searches to make
1242 : * @param searchSeed the random seed used to determine the Keys to search
1243 : * @param option the options passed to the ksLookup (...)
1244 : * @param repeats array to store repeated measurements
1245 : * @param numberOfRepeats fields in repeats
1246 : *
1247 : * @retval median time
1248 : */
1249 0 : static size_t benchmarkSearchTimeMeasure (KeySet * ks, size_t searches, int32_t searchSeed, option_t option, size_t * repeats,
1250 : size_t numberOfRepeats)
1251 : {
1252 0 : if (option & KDB_O_OPMPHM)
1253 : {
1254 : // trigger OPMPHM build if not build
1255 0 : if (!opmphmIsBuild (ks->opmphm))
1256 : {
1257 : // set seed to return by elektraRandGetInitSeed () in the lookup
1258 0 : elektraRandBenchmarkInitSeed = searchSeed;
1259 0 : (void) ksLookup (ks, ks->array[0], KDB_O_OPMPHM | KDB_O_NOCASCADING);
1260 0 : if (!opmphmIsBuild (ks->opmphm))
1261 : {
1262 0 : printExit ("trigger OPMPHM build");
1263 : }
1264 : }
1265 : }
1266 0 : for (size_t repeatsI = 0; repeatsI < numberOfRepeats; ++repeatsI)
1267 : {
1268 : // sanity checks
1269 0 : if (option & KDB_O_OPMPHM)
1270 : {
1271 0 : if (!opmphmIsBuild (ks->opmphm))
1272 : {
1273 0 : printExit ("Sanity Check Failed: OPMPHM not here");
1274 : }
1275 : }
1276 : else
1277 : {
1278 0 : if (ks->opmphm)
1279 : {
1280 0 : printExit ("Sanity Check Failed: OPMPHM here");
1281 : }
1282 : }
1283 :
1284 : // preparation for measurement
1285 : struct timeval start;
1286 : struct timeval end;
1287 : Key * keyFound;
1288 0 : int32_t actualSearchSeed = searchSeed;
1289 :
1290 : // START MEASUREMENT
1291 0 : __asm__("");
1292 0 : gettimeofday (&start, 0);
1293 0 : __asm__("");
1294 :
1295 0 : for (size_t s = 1; s <= searches; ++s)
1296 : {
1297 0 : keyFound = ksLookup (ks, ks->array[actualSearchSeed % ks->size], option);
1298 0 : if (!keyFound || keyFound != ks->array[actualSearchSeed % ks->size])
1299 : {
1300 0 : printExit ("Sanity Check Failed: found wrong Key");
1301 : }
1302 0 : elektraRand (&actualSearchSeed);
1303 : }
1304 :
1305 0 : __asm__("");
1306 0 : gettimeofday (&end, 0);
1307 0 : __asm__("");
1308 : // END MEASUREMENT
1309 :
1310 : // sanity checks
1311 0 : if (option & KDB_O_OPMPHM)
1312 : {
1313 0 : if (!opmphmIsBuild (ks->opmphm))
1314 : {
1315 0 : printExit ("Sanity Check Failed: OPMPHM not here");
1316 : }
1317 : }
1318 : else
1319 : {
1320 0 : if (ks->opmphm)
1321 : {
1322 0 : printExit ("Sanity Check Failed: OPMPHM here");
1323 : }
1324 : }
1325 :
1326 : // save result
1327 0 : repeats[repeatsI] = (end.tv_sec - start.tv_sec) * 1000000 + (end.tv_usec - start.tv_usec);
1328 : }
1329 : // sort repeats
1330 0 : qsort (repeats, numberOfRepeats, sizeof (size_t), cmpInteger);
1331 0 : return repeats[numberOfRepeats / 2]; // take median
1332 : }
1333 :
1334 : /**
1335 : * @brief Common part of search time benchmarks, used by benchmarkOPMPHMSearchTime and benchmarkBinarySearchTime.
1336 : *
1337 : * @param outFileName the output file name
1338 : * @param option the option to pass to the ksLookup (...)
1339 : */
1340 0 : static void benchmarkSearchTime (char * name, char * outFileName, option_t option)
1341 : {
1342 0 : const size_t startN = 50;
1343 0 : const size_t stepN = 500;
1344 0 : const size_t endN = 20000;
1345 0 : const size_t ksPerN = 3;
1346 0 : const size_t numberOfRepeats = 7;
1347 0 : const size_t startSearches = 500;
1348 0 : const size_t stepSearches = 500;
1349 0 : const size_t endSearches = 32000;
1350 :
1351 : // check config
1352 : if (startN >= endN || startN == 0)
1353 : {
1354 : printExit ("startN >= endN || startN == 0");
1355 : }
1356 : if (numberOfRepeats % 2 == 0)
1357 : {
1358 : printExit ("numberOfRepeats is even");
1359 : }
1360 : if (ksPerN % 2 == 0)
1361 : {
1362 : printExit ("ksPerN is even");
1363 : }
1364 :
1365 : // calculate counts
1366 0 : size_t nCount = 0;
1367 0 : for (size_t nI = startN; nI <= endN; nI += stepN)
1368 : {
1369 0 : ++nCount;
1370 : }
1371 : size_t searchesCount = 0;
1372 0 : for (size_t searchesI = startSearches; searchesI <= endSearches; searchesI += stepSearches)
1373 : {
1374 0 : ++searchesCount;
1375 : }
1376 :
1377 : // memory allocation and initialization
1378 : // init results
1379 0 : size_t * results = elektraMalloc (nCount * searchesCount * sizeof (size_t));
1380 0 : if (!results)
1381 : {
1382 0 : printExit ("malloc");
1383 : }
1384 : // init repeats
1385 0 : size_t * repeats = elektraMalloc (numberOfRepeats * sizeof (size_t));
1386 0 : if (!repeats)
1387 : {
1388 0 : printExit ("malloc");
1389 : }
1390 : // init partialResult
1391 0 : size_t * partialResult = elektraMalloc (ksPerN * searchesCount * sizeof (size_t));
1392 0 : if (!partialResult)
1393 : {
1394 0 : printExit ("malloc");
1395 : }
1396 : // init KeySetStorage
1397 0 : KeySet ** keySetStorage = elektraMalloc (ksPerN * sizeof (KeySet *));
1398 0 : if (!keySetStorage)
1399 : {
1400 0 : printExit ("malloc");
1401 : }
1402 :
1403 : // get KeySet shapes
1404 0 : KeySetShape * keySetShapes = getKeySetShapes ();
1405 :
1406 0 : printf ("Run Benchmark %s:\n", name);
1407 :
1408 : // for all KeySet shapes except 6
1409 0 : for (size_t shapeI = 0; shapeI < numberOfShapes; ++shapeI)
1410 : {
1411 0 : if (shapeI == 6)
1412 : {
1413 0 : continue;
1414 : }
1415 0 : KeySetShape * usedKeySetShape = &keySetShapes[shapeI];
1416 :
1417 : // for all Ns
1418 0 : for (size_t nI = startN; nI <= endN; nI += stepN)
1419 : {
1420 0 : printf ("now at: shape = %zu/%zu n = %zu/%zu\r", shapeI + 1, numberOfShapes, nI, endN);
1421 0 : fflush (stdout);
1422 :
1423 : // generate KeySets
1424 : int32_t genSeed;
1425 0 : for (size_t ksI = 0; ksI < ksPerN; ++ksI)
1426 : {
1427 0 : if (getRandomSeed (&genSeed) != &genSeed) printExit ("Seed Parsing Error or feed me more seeds");
1428 0 : keySetStorage[ksI] = generateKeySet (nI, &genSeed, usedKeySetShape);
1429 : }
1430 :
1431 : // for all number of searches
1432 0 : for (size_t searchesI = startSearches; searchesI <= endSearches; searchesI += stepSearches)
1433 : {
1434 0 : int32_t searchSeed = 1;
1435 0 : if (getRandomSeed (&searchSeed) != &searchSeed) printExit ("Seed Parsing Error or feed me more seeds");
1436 :
1437 : // for all KeySets in the storage
1438 0 : for (size_t ksI = 0; ksI < ksPerN; ++ksI)
1439 : {
1440 : // measure
1441 0 : size_t res = benchmarkSearchTimeMeasure (keySetStorage[ksI], searchesI, searchSeed, option, repeats,
1442 : numberOfRepeats);
1443 : // save partial result to summarize it with median
1444 0 : partialResult[((searchesI - startSearches) / stepSearches) * ksPerN + ksI] = res;
1445 : }
1446 : }
1447 : // sort partialResult and take median as final result
1448 0 : for (size_t searchesI = 0; searchesI < searchesCount; ++searchesI)
1449 : {
1450 0 : qsort (&partialResult[searchesI * ksPerN], ksPerN, sizeof (size_t), cmpInteger);
1451 0 : results[((nI - startN) / stepN) * searchesCount + searchesI] =
1452 0 : partialResult[searchesI * ksPerN + (ksPerN / 2)];
1453 : }
1454 :
1455 : // free ks
1456 0 : for (size_t ksI = 0; ksI < ksPerN; ++ksI)
1457 : {
1458 0 : ksDel (keySetStorage[ksI]);
1459 : }
1460 : }
1461 :
1462 : // write out
1463 0 : FILE * out = openOutFileWithRPartitePostfix (outFileName, shapeI);
1464 0 : if (!out)
1465 : {
1466 0 : printExit ("open out file");
1467 : }
1468 : // print header
1469 0 : fprintf (out, "n");
1470 0 : for (size_t searchesI = startSearches; searchesI <= endSearches; searchesI += stepSearches)
1471 : {
1472 0 : fprintf (out, ";search_%zu", searchesI);
1473 : }
1474 0 : fprintf (out, "\n");
1475 : // print data
1476 0 : for (size_t nI = startN; nI <= endN; nI += stepN)
1477 : {
1478 0 : fprintf (out, "%zu", nI);
1479 0 : for (size_t searchesI = startSearches; searchesI <= endSearches; searchesI += stepSearches)
1480 : {
1481 0 : fprintf (out, ";%zu",
1482 0 : results[((nI - startN) / stepN) * searchesCount + ((searchesI - startSearches) / stepSearches)]);
1483 : }
1484 0 : fprintf (out, "\n");
1485 : }
1486 :
1487 0 : fclose (out);
1488 : }
1489 0 : printf ("\n");
1490 :
1491 0 : elektraFree (repeats);
1492 0 : elektraFree (partialResult);
1493 0 : elektraFree (keySetStorage);
1494 0 : elektraFree (keySetShapes);
1495 0 : elektraFree (results);
1496 0 : }
1497 :
1498 0 : void benchmarkOPMPHMSearchTime (char * name)
1499 : {
1500 0 : benchmarkSearchTime (name, "benchmark_opmphm_search_time", KDB_O_OPMPHM | KDB_O_NOCASCADING);
1501 0 : }
1502 :
1503 : /**
1504 : * END ==================================================== OPMPHM Search Time ========================================================= END
1505 : */
1506 :
1507 : /**
1508 : * START ================================================= Binary search Time ======================================================== START
1509 : *
1510 : * This benchmark measures the time of the binary search.
1511 : * Uses all KeySet shapes except 6, for one n (KeySet size) ksPerN KeySets are used.
1512 : * The keyset shape 6 is excluded, because previous evaluation had show that the results with that keyset shape
1513 : * where unusable, due to the unnatural long key names.
1514 : * Each measurement done with one KeySet is repeated numberOfRepeats time and summarized with the median.
1515 : * For one n (KeySet size) the ksPerN results are also summarized with the median.
1516 : * The results are written out in the following format:
1517 : *
1518 : * n;search_1;search_2;...;search_(numberOfSearches)
1519 : *
1520 : * The number of needed seeds for this benchmarks is: (numberOfShapes - 1) * nCount * ksPerN * (1 + searchesCount )
1521 : */
1522 :
1523 0 : static void benchmarkBinarySearchTime (char * name)
1524 : {
1525 0 : benchmarkSearchTime (name, "benchmark_binary_search_time", KDB_O_NOCASCADING);
1526 0 : }
1527 :
1528 : /**
1529 : * END =================================================== Binary search Time ========================================================== END
1530 : */
1531 :
1532 : /**
1533 : * START ================================================= hsearch Build Time ======================================================== START
1534 : *
1535 : * This benchmark measures the time of the hsearch build.
1536 : * For one n (KeySet size) ksPerN KeySets are used, with different loads.
1537 : * This benchmark has a 10 strike policy, when 10 time the measured time is over 10000 the next KeySet shape is handled.
1538 : * The results are written out in the following format:
1539 : *
1540 : * n;ks;load;time
1541 : *
1542 : * The number of needed seeds for this benchmarks is: (numberOfShapes - 1) * nCount * ksPerN
1543 : */
1544 :
1545 : // clang-format off
1546 : // format bug
1547 : #ifdef HAVE_HSEARCHR
1548 : // clang-format on
1549 :
1550 : /**
1551 : * @brief Measures the hsearch build numberOfRepeats time and returns median
1552 : *
1553 : * @param ks the KeySet
1554 : * @param nI the KeySet size
1555 : * @param load the load
1556 : * @param repeats array to store repeated measurements
1557 : * @param numberOfRepeats fields in repeats
1558 : *
1559 : * @retval median time
1560 : */
1561 0 : static size_t benchmarkHsearchBuildTimeMeasure (KeySet * ks, size_t nI, double load, size_t * repeats, size_t numberOfRepeats)
1562 : {
1563 0 : for (size_t repeatsI = 0; repeatsI < numberOfRepeats; ++repeatsI)
1564 : {
1565 : // preparation for measurement
1566 : struct timeval start;
1567 : struct timeval end;
1568 : Key * key;
1569 0 : ksRewind (ks);
1570 : ENTRY e;
1571 : ENTRY * ep;
1572 : // fresh htab
1573 0 : struct hsearch_data * htab = elektraCalloc (sizeof (struct hsearch_data));
1574 0 : if (!htab)
1575 : {
1576 0 : printExit ("calloc");
1577 : }
1578 :
1579 : // START MEASUREMENT
1580 0 : __asm__("");
1581 0 : gettimeofday (&start, 0);
1582 0 : __asm__("");
1583 :
1584 0 : if (!hcreate_r (nI / load, htab))
1585 : {
1586 0 : printExit ("hcreate_r");
1587 : }
1588 :
1589 0 : while ((key = ksNext (ks)))
1590 : {
1591 0 : e.key = (char *) keyName (key);
1592 0 : e.data = key;
1593 0 : if (!hsearch_r (e, ENTER, &ep, htab))
1594 : {
1595 0 : printExit ("hsearch_r");
1596 : }
1597 : }
1598 :
1599 0 : __asm__("");
1600 0 : gettimeofday (&end, 0);
1601 0 : __asm__("");
1602 : // END MEASUREMENT
1603 :
1604 : // save result
1605 0 : repeats[repeatsI] = (end.tv_sec - start.tv_sec) * 1000000 + (end.tv_usec - start.tv_usec);
1606 :
1607 : // sanity check
1608 0 : ksRewind (ks);
1609 0 : while ((key = ksNext (ks)))
1610 : {
1611 0 : e.key = (char *) keyName (key);
1612 0 : if (!hsearch_r (e, FIND, &ep, htab))
1613 : {
1614 0 : printExit ("Sanity Check Failed: hsearch can not find element");
1615 : }
1616 : }
1617 :
1618 0 : hdestroy_r (htab);
1619 0 : elektraFree (htab);
1620 : }
1621 : // sort repeats
1622 0 : qsort (repeats, numberOfRepeats, sizeof (size_t), cmpInteger);
1623 0 : return repeats[numberOfRepeats / 2]; // take median
1624 : }
1625 :
1626 0 : void benchmarkHsearchBuildTime (char * name)
1627 : {
1628 0 : const size_t startN = 50;
1629 0 : const size_t stepN = 500;
1630 0 : const size_t endN = 20000;
1631 0 : const size_t ksPerN = 5;
1632 0 : const size_t numberOfRepeats = 7;
1633 0 : const size_t maxStrikes = 10;
1634 0 : const size_t strikeLimit = 10000;
1635 0 : const size_t numberOfLoads = 4;
1636 0 : double * loads = malloc (sizeof (double) * numberOfLoads);
1637 0 : if (!loads)
1638 : {
1639 0 : printExit ("malloc");
1640 : }
1641 0 : loads[0] = 1;
1642 0 : loads[1] = 0.75;
1643 0 : loads[2] = 0.5;
1644 0 : loads[3] = 0.25;
1645 :
1646 : // check config
1647 : if (startN >= endN || startN == 0)
1648 : {
1649 : printExit ("startN >= endN || startN == 0");
1650 : }
1651 : if (numberOfRepeats % 2 == 0)
1652 : {
1653 : printExit ("numberOfRepeats is even");
1654 : }
1655 : if (ksPerN % 2 == 0)
1656 : {
1657 : printExit ("ksPerN is even");
1658 : }
1659 :
1660 : // calculate counts
1661 0 : size_t nCount = 0;
1662 0 : for (size_t nI = startN; nI <= endN; nI += stepN)
1663 : {
1664 0 : ++nCount;
1665 : }
1666 :
1667 : // memory allocation and initialization
1668 : // init results
1669 0 : size_t * results = elektraMalloc (nCount * ksPerN * numberOfLoads * sizeof (size_t));
1670 0 : if (!results)
1671 : {
1672 0 : printExit ("malloc");
1673 : }
1674 : // init repeats
1675 0 : size_t * repeats = elektraMalloc (numberOfRepeats * sizeof (size_t));
1676 0 : if (!repeats)
1677 : {
1678 0 : printExit ("malloc");
1679 : }
1680 : // init KeySetStorage
1681 0 : KeySet ** keySetStorage = elektraMalloc (ksPerN * sizeof (KeySet *));
1682 0 : if (!keySetStorage)
1683 : {
1684 0 : printExit ("malloc");
1685 : }
1686 :
1687 : // get KeySet shapes
1688 0 : KeySetShape * keySetShapes = getKeySetShapes ();
1689 :
1690 0 : printf ("Run Benchmark %s:\n", name);
1691 :
1692 : // for all KeySet shapes except 6
1693 0 : for (size_t shapeI = 0; shapeI < numberOfShapes; ++shapeI)
1694 : {
1695 0 : if (shapeI == 6)
1696 : {
1697 0 : continue;
1698 : }
1699 0 : KeySetShape * usedKeySetShape = &keySetShapes[shapeI];
1700 0 : size_t strikes = 0;
1701 :
1702 : // for all Ns
1703 0 : for (size_t nI = startN; nI <= endN; nI += stepN)
1704 : {
1705 0 : printf ("now at: shape = %zu/%zu n = %zu/%zu\r", shapeI + 1, numberOfShapes, nI, endN);
1706 0 : fflush (stdout);
1707 :
1708 : // generate KeySets
1709 : int32_t genSeed;
1710 0 : for (size_t ksI = 0; ksI < ksPerN; ++ksI)
1711 : {
1712 0 : if (getRandomSeed (&genSeed) != &genSeed) printExit ("Seed Parsing Error or feed me more seeds");
1713 0 : keySetStorage[ksI] = generateKeySet (nI, &genSeed, usedKeySetShape);
1714 : }
1715 :
1716 : // for all loads
1717 0 : for (size_t loadI = 0; loadI < numberOfLoads; ++loadI)
1718 : {
1719 : // for all KeySets in the storage
1720 0 : for (size_t ksI = 0; ksI < ksPerN; ++ksI)
1721 : {
1722 : // measure
1723 0 : size_t res = benchmarkHsearchBuildTimeMeasure (keySetStorage[ksI], nI, loads[loadI], repeats,
1724 : numberOfRepeats);
1725 : // strike policy
1726 0 : if (res > strikeLimit)
1727 : {
1728 0 : ++strikes;
1729 0 : if (strikes >= maxStrikes)
1730 : {
1731 0 : ksI = ksPerN;
1732 0 : loadI = numberOfLoads;
1733 0 : nI = endN + 1;
1734 0 : printf ("shape %zu is out!\n", shapeI);
1735 : }
1736 : }
1737 : else
1738 : {
1739 0 : strikes = 0;
1740 : // save only non strike values
1741 0 : results[((nI - startN) / stepN) * ksPerN * numberOfLoads + ksI * numberOfLoads + loadI] =
1742 : res;
1743 : }
1744 : }
1745 : }
1746 :
1747 : // free ks
1748 0 : for (size_t ksI = 0; ksI < ksPerN; ++ksI)
1749 : {
1750 0 : ksDel (keySetStorage[ksI]);
1751 : }
1752 : }
1753 :
1754 : // write out
1755 0 : FILE * out = openOutFileWithRPartitePostfix ("benchmark_hsearch_build_time", shapeI);
1756 0 : if (!out)
1757 : {
1758 0 : printExit ("open out file");
1759 : }
1760 : // print header
1761 0 : fprintf (out, "n;ks;load;time\n");
1762 : // print data
1763 0 : for (size_t nI = startN; nI <= endN; nI += stepN)
1764 : {
1765 0 : for (size_t ksI = 0; ksI < ksPerN; ++ksI)
1766 : {
1767 0 : for (size_t loadI = 0; loadI < numberOfLoads; ++loadI)
1768 : {
1769 0 : fprintf (out, "%zu;%zu;%f;%zu\n", nI, ksI, loads[loadI],
1770 0 : results[((nI - startN) / stepN) * ksPerN * numberOfLoads + ksI * numberOfLoads + loadI]);
1771 : }
1772 : }
1773 : }
1774 :
1775 0 : fclose (out);
1776 : }
1777 0 : printf ("\n");
1778 :
1779 0 : elektraFree (repeats);
1780 0 : elektraFree (keySetStorage);
1781 0 : elektraFree (loads);
1782 0 : elektraFree (keySetShapes);
1783 0 : elektraFree (results);
1784 0 : }
1785 :
1786 : #endif
1787 :
1788 : /**
1789 : * END =================================================== hsearch Build Time ========================================================== END
1790 : */
1791 :
1792 : /**
1793 : * START =================================================== Prediction Time ========================================================= START
1794 : *
1795 : * This benchmark measures the time from `numberOfSequences` lookup sequences, with the modified branch predictor and the binary search.
1796 : * All KeySet shapes except 6 where used.
1797 : * The keyset shape 6 is excluded, because previous evaluation had show that the results with that keyset shape
1798 : * where unusable, due to the unnatural long key names.
1799 : * For all `n` `patternsPerN` lookup patterns are created. With a length of `numberOfSequences`.
1800 : * The KeySet shapes rotate through the lookup patterns.
1801 : * Two entries of the pattern entries use one seed (31 bit), this works because max n is 10000.
1802 : * log_2 (opmphmPredictorWorthOpmphm(10000)) * 2) < 15 bit
1803 : * log_2 (15000) * 2) < 15 bit
1804 : *
1805 : * n;predictiontime;binarysearchtime
1806 : *
1807 : * The number of needed seeds for this benchmarks is: nCount * patternsPerN * ( numberOfSequences/2 + 1 + numberOfSequences )
1808 : */
1809 :
1810 0 : static void benchmarkPredictionTime (char * name)
1811 : {
1812 0 : const size_t numberOfRepeats = 5;
1813 0 : const size_t numberOfSequences = 66;
1814 0 : const size_t patternsPerN = 999;
1815 : // create the n array
1816 0 : const size_t nCount = 35;
1817 0 : size_t * n = elektraMalloc (nCount * sizeof (size_t));
1818 0 : if (!n)
1819 : {
1820 0 : printExit ("malloc");
1821 : }
1822 : size_t controlCount = 0;
1823 0 : for (size_t i = 100; i < 1000; i += 100)
1824 : {
1825 0 : n[controlCount] = i;
1826 0 : ++controlCount;
1827 : }
1828 0 : for (size_t i = 1000; i < 5000; i += 200)
1829 : {
1830 0 : n[controlCount] = i;
1831 0 : ++controlCount;
1832 : }
1833 0 : for (size_t i = 5000; i <= 10000; i += 1000)
1834 : {
1835 0 : n[controlCount] = i;
1836 0 : ++controlCount;
1837 : }
1838 :
1839 : // check config
1840 0 : if (controlCount != nCount)
1841 : {
1842 0 : printExit ("controlCount != nCount");
1843 : }
1844 : if (numberOfRepeats % 2 == 0)
1845 : {
1846 : printExit ("numberOfRepeats is even");
1847 : }
1848 : if (patternsPerN % (numberOfShapes - 1) == 0)
1849 : {
1850 : printExit ("not all shapes used equally");
1851 : }
1852 :
1853 : // memory allocation and initialization
1854 : // init results
1855 0 : size_t * results = elektraMalloc (nCount * patternsPerN * 2 * sizeof (size_t)); // 2 prediction and binary search
1856 0 : if (!results)
1857 : {
1858 0 : printExit ("malloc");
1859 : }
1860 : // init repeats
1861 0 : size_t * repeats = elektraMalloc (numberOfRepeats * sizeof (size_t));
1862 0 : if (!repeats)
1863 : {
1864 0 : printExit ("malloc");
1865 : }
1866 : // init seeds
1867 0 : int32_t * seeds = elektraMalloc (numberOfSequences * sizeof (int32_t));
1868 0 : if (!seeds)
1869 : {
1870 0 : printExit ("malloc");
1871 : }
1872 : // init pattern
1873 0 : size_t * pattern = elektraMalloc (numberOfSequences * sizeof (size_t));
1874 0 : if (!pattern)
1875 : {
1876 0 : printExit ("malloc");
1877 : }
1878 :
1879 : // get KeySet shapes
1880 0 : KeySetShape * keySetShapes = getKeySetShapes ();
1881 :
1882 0 : printf ("Run Benchmark %s:\n", name);
1883 :
1884 : // for all n
1885 0 : for (size_t nI = 0; nI < nCount; ++nI)
1886 : {
1887 : // for all pattern per n
1888 0 : for (size_t pI = 0; pI < patternsPerN; ++pI)
1889 : {
1890 0 : printf ("now at: n = %zu/%zu pattern = %zu/%zu \r", nI + 1, nCount, pI + 1, patternsPerN);
1891 0 : fflush (stdout);
1892 : // create pattern, always two entries with one seed
1893 0 : for (size_t s = 0; s < numberOfSequences; s += 2)
1894 : {
1895 0 : int32_t genSeed = 0;
1896 0 : if (getRandomSeed (&genSeed) != &genSeed) printExit ("Seed Parsing Error or feed me more seeds");
1897 : // 15 bit each of the 31 bit seed
1898 0 : size_t sequnceLength1 = (genSeed >> 15) & 0x7FFF;
1899 0 : size_t sequnceLength0 = genSeed & 0x7FFF;
1900 0 : sequnceLength1 = sequnceLength1 % (opmphmPredictorWorthOpmphm (n[nI]) * 2 - 1);
1901 0 : sequnceLength0 = sequnceLength0 % (opmphmPredictorWorthOpmphm (n[nI]) * 2 - 1);
1902 0 : pattern[s + 1] = sequnceLength1 + 1;
1903 0 : pattern[s] = sequnceLength0 + 1;
1904 : }
1905 : // rotate through all KeySet shapes, except 6
1906 0 : size_t shapeI = patternsPerN % (numberOfShapes - 1);
1907 : if (shapeI == 6)
1908 : {
1909 : ++shapeI;
1910 : }
1911 0 : KeySetShape * usedKeySetShape = &keySetShapes[shapeI];
1912 :
1913 : // generate KeySet
1914 0 : int32_t genSeed = 0;
1915 0 : if (getRandomSeed (&genSeed) != &genSeed) printExit ("Seed Parsing Error or feed me more seeds");
1916 0 : KeySet * ks = generateKeySet (n[nI], &genSeed, usedKeySetShape);
1917 :
1918 : // get seeds for OPMPHM
1919 0 : for (size_t s = 0; s < numberOfSequences; ++s)
1920 : {
1921 0 : if (getRandomSeed (&seeds[s]) != &seeds[s]) printExit ("Seed Parsing Error or feed me more seeds");
1922 : }
1923 :
1924 : size_t resultPredition;
1925 : size_t resultBinarySearch;
1926 :
1927 : // benchmark prediction
1928 :
1929 : // repeat measurement numberOfRepeats time
1930 0 : for (size_t repeatsI = 0; repeatsI < numberOfRepeats; ++repeatsI)
1931 : {
1932 : // preparation for measurement
1933 : struct timeval start;
1934 : struct timeval end;
1935 : Key * keyFound;
1936 :
1937 : // START MEASUREMENT
1938 0 : __asm__("");
1939 0 : gettimeofday (&start, 0);
1940 0 : __asm__("");
1941 :
1942 : // for all sequences
1943 0 : for (size_t s = 0; s < numberOfSequences; ++s)
1944 : {
1945 : // seed used for key to lookup and OPMPHM
1946 0 : int32_t searchHashSeed = seeds[s];
1947 : // set seed to return by elektraRandGetInitSeed () in the lookup, in case of hashing
1948 0 : elektraRandBenchmarkInitSeed = searchHashSeed;
1949 :
1950 : // do the lookups
1951 0 : for (size_t lookups = 0; lookups < pattern[s]; ++lookups)
1952 : {
1953 0 : keyFound = ksLookup (ks, ks->array[searchHashSeed % ks->size], KDB_O_NOCASCADING);
1954 0 : if (!keyFound || keyFound != ks->array[searchHashSeed % ks->size])
1955 : {
1956 0 : printExit ("Sanity Check Failed: found wrong Key");
1957 : }
1958 0 : elektraRand (&searchHashSeed);
1959 : }
1960 0 : if (!ks->opmphmPredictor)
1961 : {
1962 0 : printExit ("Sanity Check Failed: no predictor used");
1963 : }
1964 : // simulate data change
1965 0 : ks->flags |= KS_FLAG_NAME_CHANGE;
1966 0 : if (ks->opmphm) opmphmClear (ks->opmphm);
1967 : }
1968 :
1969 0 : __asm__("");
1970 0 : gettimeofday (&end, 0);
1971 0 : __asm__("");
1972 : // END MEASUREMENT
1973 :
1974 : // save result
1975 0 : repeats[repeatsI] = (end.tv_sec - start.tv_sec) * 1000000 + (end.tv_usec - start.tv_usec);
1976 : }
1977 : // sort repeats
1978 0 : qsort (repeats, numberOfRepeats, sizeof (size_t), cmpInteger);
1979 0 : resultPredition = repeats[numberOfRepeats / 2];
1980 :
1981 : // benchmark binary search
1982 :
1983 : // repeat measurement numberOfRepeats time
1984 0 : for (size_t repeatsI = 0; repeatsI < numberOfRepeats; ++repeatsI)
1985 : {
1986 : // preparation for measurement
1987 : struct timeval start;
1988 : struct timeval end;
1989 : Key * keyFound;
1990 :
1991 : // START MEASUREMENT
1992 0 : __asm__("");
1993 0 : gettimeofday (&start, 0);
1994 0 : __asm__("");
1995 :
1996 : // for all sequences
1997 0 : for (size_t s = 0; s < numberOfSequences; ++s)
1998 : {
1999 : // seed used for key to lookup and OPMPHM
2000 0 : int32_t searchHashSeed = seeds[s];
2001 :
2002 : // do the lookups
2003 0 : for (size_t lookups = 0; lookups < pattern[s]; ++lookups)
2004 : {
2005 0 : keyFound = ksLookup (ks, ks->array[searchHashSeed % ks->size],
2006 : KDB_O_NOCASCADING | KDB_O_BINSEARCH);
2007 0 : if (!keyFound || keyFound != ks->array[searchHashSeed % ks->size])
2008 : {
2009 0 : printExit ("Sanity Check Failed: found wrong Key");
2010 : }
2011 0 : elektraRand (&searchHashSeed);
2012 : }
2013 : }
2014 :
2015 0 : __asm__("");
2016 0 : gettimeofday (&end, 0);
2017 0 : __asm__("");
2018 : // END MEASUREMENT
2019 :
2020 : // save result
2021 0 : repeats[repeatsI] = (end.tv_sec - start.tv_sec) * 1000000 + (end.tv_usec - start.tv_usec);
2022 : }
2023 : // sort repeats
2024 0 : qsort (repeats, numberOfRepeats, sizeof (size_t), cmpInteger);
2025 0 : resultBinarySearch = repeats[numberOfRepeats / 2];
2026 :
2027 0 : results[nI * patternsPerN * 2 + pI * 2] = resultPredition;
2028 0 : results[nI * patternsPerN * 2 + pI * 2 + 1] = resultBinarySearch;
2029 :
2030 0 : ksDel (ks);
2031 : }
2032 : }
2033 0 : printf ("\n");
2034 : // write out
2035 0 : FILE * out = openOutFileWithRPartitePostfix ("benchmark_prediction_time", opmphmPredictorHistoryMask >> 4); // shift 16 to 8 bit
2036 0 : if (!out)
2037 : {
2038 0 : printExit ("open out file");
2039 : }
2040 : // print header
2041 0 : fprintf (out, "n;predictiontime;binarysearchtime\n");
2042 0 : for (size_t nI = 0; nI < nCount; ++nI)
2043 : {
2044 0 : for (size_t pI = 0; pI < patternsPerN; ++pI)
2045 : {
2046 0 : size_t predictiontime = results[nI * patternsPerN * 2 + pI * 2];
2047 0 : size_t binarysearchtime = results[nI * patternsPerN * 2 + pI * 2 + 1];
2048 0 : fprintf (out, "%zu;%zu;%zu\n", n[nI], predictiontime, binarysearchtime);
2049 : }
2050 : }
2051 0 : fclose (out);
2052 :
2053 0 : elektraFree (n);
2054 0 : elektraFree (keySetShapes);
2055 0 : elektraFree (results);
2056 0 : elektraFree (repeats);
2057 0 : elektraFree (pattern);
2058 0 : elektraFree (seeds);
2059 0 : }
2060 :
2061 : /**
2062 : * END ===================================================== Prediction Time =========================================================== END
2063 : */
2064 :
2065 : /**
2066 : * START ================================================= Prints all KeySetShapes =================================================== START
2067 : */
2068 :
2069 0 : static void benchmarkPrintAllKeySetShapes (char * name)
2070 : {
2071 0 : printf ("%s\n", name);
2072 0 : const size_t n = 30;
2073 0 : int32_t seed = 47658589;
2074 0 : KeySetShape * keySetShapes = getKeySetShapes ();
2075 0 : for (size_t shapeId = 0; shapeId < numberOfShapes; ++shapeId)
2076 : {
2077 0 : int32_t s = seed;
2078 : //~ timeInit ();
2079 0 : KeySet * ks = generateKeySet (n, &s, &keySetShapes[shapeId]);
2080 : //~ timePrint ("generateKeySet:");
2081 : // print KS
2082 : if (1)
2083 : {
2084 0 : printf (" ======================= shapeId %zu =======================\n\n", shapeId);
2085 : Key * key;
2086 0 : ksRewind (ks);
2087 0 : while ((key = ksNext (ks)))
2088 : {
2089 0 : printf ("%s\n", keyName (key));
2090 : }
2091 0 : printf ("\n ======================== size %zd ========================\n\n", ksGetSize (ks));
2092 : }
2093 0 : ksDel (ks);
2094 : }
2095 0 : elektraFree (keySetShapes);
2096 0 : }
2097 :
2098 : /**
2099 : * END =================================================== Prints all KeySetShapes ===================================================== END
2100 : */
2101 :
2102 0 : int main (int argc, char ** argv)
2103 : {
2104 : // define all benchmarks
2105 0 : size_t benchmarksCount = 9;
2106 : #ifdef HAVE_HSEARCHR
2107 : // hsearchbuildtime
2108 0 : ++benchmarksCount;
2109 : #endif
2110 0 : Benchmark * benchmarks = elektraMalloc (benchmarksCount * sizeof (Benchmark));
2111 0 : if (!benchmarks)
2112 : {
2113 0 : printExit ("malloc");
2114 : }
2115 :
2116 : // hashfunctiontime
2117 0 : char * benchmarkNameHashFunctionTime = "hashfunctiontime";
2118 0 : benchmarks[0].name = benchmarkNameHashFunctionTime;
2119 0 : benchmarks[0].benchmarkF = benchmarkHashFunctionTime;
2120 0 : benchmarks[0].numberOfSeedsNeeded = 32;
2121 : // mapping
2122 0 : char * benchmarkNameMapping = "mapping";
2123 0 : benchmarks[1].name = benchmarkNameMapping;
2124 0 : benchmarks[1].benchmarkF = benchmarkMapping;
2125 0 : benchmarks[1].numberOfSeedsNeeded = 12400;
2126 : // mapping_opt
2127 0 : char * benchmarkNameMappingOpt = "mapping_opt";
2128 0 : benchmarks[2].name = benchmarkNameMappingOpt;
2129 0 : benchmarks[2].benchmarkF = benchmarkMappingOpt;
2130 0 : benchmarks[2].numberOfSeedsNeeded = 93920;
2131 : // mapping_allseeds
2132 0 : char * benchmarkNameMappingAllSeeds = "mapping_allseeds";
2133 0 : benchmarks[3].name = benchmarkNameMappingAllSeeds;
2134 0 : benchmarks[3].benchmarkF = benchmarkMappingAllSeeds;
2135 0 : benchmarks[3].numberOfSeedsNeeded = 7;
2136 : // printallkeysetshapes
2137 0 : char * benchmarkNamePrintAllKeySetShapes = "printallkeysetshapes";
2138 0 : benchmarks[4].name = benchmarkNamePrintAllKeySetShapes;
2139 0 : benchmarks[4].benchmarkF = benchmarkPrintAllKeySetShapes;
2140 0 : benchmarks[4].numberOfSeedsNeeded = 0;
2141 : // opmphmbuildtime
2142 0 : char * benchmarkNameOpmphmBuildTime = "opmphmbuildtime";
2143 0 : benchmarks[5].name = benchmarkNameOpmphmBuildTime;
2144 0 : benchmarks[5].benchmarkF = benchmarkOPMPHMBuildTime;
2145 0 : benchmarks[5].numberOfSeedsNeeded = 1757;
2146 : // opmphmsearchtime
2147 0 : char * benchmarkNameOpmphmSearchTime = "opmphmsearchtime";
2148 0 : benchmarks[6].name = benchmarkNameOpmphmSearchTime;
2149 0 : benchmarks[6].benchmarkF = benchmarkOPMPHMSearchTime;
2150 0 : benchmarks[6].numberOfSeedsNeeded = 54600;
2151 : // binarysearchtime
2152 0 : char * benchmarkNameBinarySearchTime = "binarysearchtime";
2153 0 : benchmarks[7].name = benchmarkNameBinarySearchTime;
2154 0 : benchmarks[7].benchmarkF = benchmarkBinarySearchTime;
2155 0 : benchmarks[7].numberOfSeedsNeeded = 54600;
2156 : // predictiontime
2157 0 : char * benchmarkNamePredictionTime = "predictiontime";
2158 0 : benchmarks[8].name = benchmarkNamePredictionTime;
2159 0 : benchmarks[8].benchmarkF = benchmarkPredictionTime;
2160 0 : benchmarks[8].numberOfSeedsNeeded = 3496500;
2161 : #ifdef HAVE_HSEARCHR
2162 : // hsearchbuildtime
2163 0 : char * benchmarkNameHsearchBuildTime = "hsearchbuildtime";
2164 0 : benchmarks[benchmarksCount - 1].name = benchmarkNameHsearchBuildTime;
2165 0 : benchmarks[benchmarksCount - 1].benchmarkF = benchmarkHsearchBuildTime;
2166 0 : benchmarks[benchmarksCount - 1].numberOfSeedsNeeded = 1400;
2167 : #endif
2168 :
2169 : // run benchmark
2170 0 : if (argc == 1)
2171 : {
2172 0 : fprintf (stderr, "Usage: cat <fileWithSeeds> | %s <benchmark>\n", argv[0]);
2173 0 : fprintf (stderr, "\nUse the generate-seeds script to generate <fileWithSeeds>, number of seeds according to:\n\n");
2174 0 : fprintf (stderr, "%-20s %10s\n", "<benchmark>", "seeds");
2175 0 : for (size_t i = 0; i < benchmarksCount; ++i)
2176 : {
2177 0 : fprintf (stderr, "%-20s %10zu\n", benchmarks[i].name, benchmarks[i].numberOfSeedsNeeded);
2178 : }
2179 0 : elektraFree (benchmarks);
2180 0 : return EXIT_FAILURE;
2181 : }
2182 0 : for (size_t i = 0; i < benchmarksCount; ++i)
2183 : {
2184 0 : if (!strncmp (benchmarks[i].name, argv[1], strlen (argv[1])))
2185 : {
2186 0 : benchmarks[i].benchmarkF (benchmarks[i].name);
2187 0 : elektraFree (benchmarks);
2188 0 : return EXIT_SUCCESS;
2189 : }
2190 : }
2191 0 : fprintf (stderr, "Error: %s is not a benchmark\n", argv[1]);
2192 0 : fprintf (stderr, "Available benchmarks:\n");
2193 0 : for (size_t i = 0; i < benchmarksCount; ++i)
2194 : {
2195 0 : fprintf (stderr, "* %s\n", benchmarks[i].name);
2196 : }
2197 0 : elektraFree (benchmarks);
2198 0 : return EXIT_FAILURE;
2199 : }
2200 :
2201 : /**
2202 : * Benchmark helpers
2203 : */
2204 :
2205 : /**
2206 : * @brief Read a seed from STDIN.
2207 : *
2208 : * @param seed storage for the read in seed
2209 : *
2210 : * @retval int32_t * on success
2211 : * @retval NULL on read or parse error
2212 : */
2213 0 : static int32_t * getRandomSeed (int32_t * seed)
2214 : {
2215 : // read from stdin
2216 : char data[10 + 2]; // min = 0, max = 2^32 - 1, len(2^32 - 1) = 10 + '\n' + '\0'
2217 0 : if (fgets (data, 12, stdin) != data)
2218 : {
2219 : return NULL;
2220 : }
2221 : // eliminate newline
2222 : char * c;
2223 0 : for (c = data; *c != '\n'; ++c)
2224 : ;
2225 0 : *c = '\0';
2226 : // prevent empty lines
2227 0 : if (strlen (data) == 0)
2228 : {
2229 : return NULL;
2230 : }
2231 : // convert to int
2232 : char * pEnd;
2233 0 : *seed = strtol (data, &pEnd, 10);
2234 0 : if (*pEnd != '\0')
2235 : {
2236 : return NULL;
2237 : }
2238 0 : return seed;
2239 : }
2240 :
2241 : /**
2242 : * @brief Opens file with OPMPHMR_PARTITE postfix.
2243 : *
2244 : * supports OPMPHMTUPLE < 100
2245 : *
2246 : * @param name name of the file
2247 : *
2248 : * @retval FILE * on success
2249 : * @retval NULL on error
2250 : */
2251 0 : static FILE * openOutFileWithRPartitePostfix (const char * name, uint8_t r)
2252 0 : {
2253 0 : const char * const format = "%u.csv";
2254 0 : char formatData[strlen (name) + strlen (format) + 1];
2255 0 : char filename[strlen (name) + strlen (format) + 1];
2256 0 : strcpy (formatData, name);
2257 0 : strcpy (&formatData[strlen (name)], format);
2258 0 : sprintf (filename, formatData, r);
2259 0 : FILE * out = fopen (filename, "w");
2260 0 : if (!out)
2261 : {
2262 : return NULL;
2263 : }
2264 0 : return out;
2265 : }
2266 :
2267 0 : static const char * getString (void * data)
2268 : {
2269 0 : return keyName ((Key *) data);
2270 : }
2271 :
2272 : /**
2273 : * @brief Power function.
2274 : *
2275 : * @param p basis
2276 : * @param q exponent
2277 : *
2278 : * @retval size_t p^q
2279 : */
2280 : static size_t getPower (size_t p, size_t q)
2281 : {
2282 0 : size_t result = 1;
2283 0 : for (size_t t = 0; t < q; ++t)
2284 : {
2285 0 : result *= p;
2286 : }
2287 : return result;
2288 : }
2289 :
2290 : /**
2291 : * @brief comparison between integers suitable as qsort callback.
2292 : *
2293 : * @param a first integer
2294 : * @param b second integer
2295 : *
2296 : */
2297 0 : static int cmpInteger (const void * a, const void * b)
2298 : {
2299 0 : if (*(size_t *) a < *(size_t *) b)
2300 : {
2301 : return -1;
2302 : }
2303 0 : else if (*(size_t *) a > *(size_t *) b)
2304 : {
2305 : return 1;
2306 : }
2307 : else
2308 : {
2309 0 : return 0;
2310 : }
2311 : }
2312 :
2313 : /**
2314 : * The Key Set shapes
2315 : */
2316 :
2317 :
2318 : /**
2319 : * every key name is unique and goes 1 level deep
2320 : */
2321 0 : static void shapefConstBinary (const size_t initSize ELEKTRA_UNUSED, size_t size ELEKTRA_UNUSED, size_t level ELEKTRA_UNUSED,
2322 : int32_t * seed ELEKTRA_UNUSED, KsShapeFunctionReturn * ret, void * data ELEKTRA_UNUSED)
2323 : {
2324 0 : ret->label = 0;
2325 0 : ret->subKeys = 0;
2326 0 : }
2327 : /**
2328 : * binary tree
2329 : */
2330 0 : static void shapefBinaryBranch (const size_t initSize, size_t size ELEKTRA_UNUSED, size_t level, int32_t * seed ELEKTRA_UNUSED,
2331 : KsShapeFunctionReturn * ret, void * data ELEKTRA_UNUSED)
2332 : {
2333 0 : size_t subKeys = 2;
2334 0 : ret->label = 0;
2335 0 : if (getPower (subKeys, level) > initSize)
2336 : {
2337 0 : ret->subKeys = 0;
2338 : }
2339 : else
2340 : {
2341 0 : ret->subKeys = subKeys;
2342 : }
2343 0 : }
2344 : /**
2345 : * every parent has n/branchfactor children
2346 : */
2347 0 : static void shapefDynamicBranch (const size_t initSize, size_t size ELEKTRA_UNUSED, size_t level, int32_t * seed ELEKTRA_UNUSED,
2348 : KsShapeFunctionReturn * ret, void * data ELEKTRA_UNUSED)
2349 : {
2350 0 : size_t branchRatio = 9;
2351 0 : ret->label = 0;
2352 0 : size_t subKeys = (initSize / branchRatio);
2353 0 : if (subKeys < 2)
2354 : {
2355 0 : subKeys = 2;
2356 : }
2357 0 : if (getPower (subKeys, level) > initSize)
2358 : {
2359 0 : ret->subKeys = 0;
2360 : }
2361 : else
2362 : {
2363 0 : ret->subKeys = subKeys;
2364 : }
2365 0 : }
2366 : /**
2367 : * all key names have a common start, startLevel length
2368 : */
2369 0 : static void shapefLateDynamicBranch (const size_t initSize, size_t size ELEKTRA_UNUSED, size_t level, int32_t * seed ELEKTRA_UNUSED,
2370 : KsShapeFunctionReturn * ret, void * data ELEKTRA_UNUSED)
2371 : {
2372 0 : size_t startLevel = 5;
2373 0 : size_t branchRatio = 9;
2374 0 : ret->label = 0;
2375 0 : if (level < startLevel)
2376 : {
2377 0 : ret->subKeys = 1;
2378 0 : return;
2379 : }
2380 0 : level -= startLevel;
2381 0 : size_t subKeys = (initSize / branchRatio);
2382 0 : if (subKeys < 2)
2383 : {
2384 0 : subKeys = 2;
2385 : }
2386 0 : if (getPower (subKeys, level) > initSize)
2387 : {
2388 0 : ret->subKeys = 0;
2389 : }
2390 : else
2391 : {
2392 0 : ret->subKeys = subKeys;
2393 : }
2394 : }
2395 : /**
2396 : * all key names have a common start and end
2397 : */
2398 0 : static void * shapeCommonStartEndInit (void)
2399 : {
2400 0 : uint8_t * data = elektraMalloc (sizeof (uint8_t));
2401 0 : if (!data)
2402 : {
2403 : return NULL;
2404 : }
2405 0 : *data = 0;
2406 0 : return data;
2407 : }
2408 0 : static void shapeCommonStartEndDel (void * data)
2409 : {
2410 0 : elektraFree (data);
2411 0 : }
2412 0 : static void shapefCommonStartEnd (const size_t initSize ELEKTRA_UNUSED, size_t size, size_t level, int32_t * seed ELEKTRA_UNUSED,
2413 : KsShapeFunctionReturn * ret, void * data)
2414 : {
2415 0 : size_t notCommonLevel = 4;
2416 0 : size_t maxLevel = 10;
2417 0 : if (level < notCommonLevel)
2418 : {
2419 : // creates common start
2420 0 : ret->subKeys = 1;
2421 0 : ret->label = 0;
2422 : }
2423 0 : else if (notCommonLevel == level)
2424 : {
2425 : // creates level with different names
2426 0 : ret->subKeys = size + 1;
2427 0 : ret->label = 0;
2428 : }
2429 0 : else if (level > notCommonLevel)
2430 : {
2431 0 : uint8_t * isLabelSet = data;
2432 0 : if (!*isLabelSet)
2433 : {
2434 : // creates common end
2435 0 : if (level == notCommonLevel + 1)
2436 : {
2437 : // set label
2438 0 : ret->label = 1;
2439 0 : ret->subKeys = 1;
2440 : }
2441 0 : else if (level == maxLevel)
2442 : {
2443 : // end of deep key
2444 0 : ret->label = 0;
2445 0 : ret->subKeys = 0;
2446 0 : *isLabelSet = 1;
2447 : }
2448 : else
2449 : {
2450 : // create deep key
2451 0 : ret->label = 0;
2452 0 : ret->subKeys = 1;
2453 : }
2454 : }
2455 : else
2456 : {
2457 : // use common end
2458 0 : ret->subKeys = -1;
2459 0 : ret->label = 1;
2460 : }
2461 : }
2462 0 : }
2463 : /**
2464 : * modules, level 1 keys same, one level 2 key stores the modules. Like system/elektra.
2465 : */
2466 0 : static void * shapeModulesInit (void)
2467 : {
2468 : // three boolean flags if the respective label where set, the fourth counts from 1 to 3 for label assignment
2469 0 : void * data = elektraMalloc (4 * sizeof (uint8_t));
2470 0 : if (!data)
2471 : {
2472 : return NULL;
2473 : }
2474 0 : uint8_t * d = data;
2475 0 : d[0] = 0;
2476 0 : d[1] = 0;
2477 0 : d[2] = 0;
2478 0 : d[3] = 1;
2479 0 : return data;
2480 : }
2481 0 : static void shapeModulesDel (void * data)
2482 : {
2483 0 : elektraFree (data);
2484 0 : }
2485 0 : static void shapefModules (const size_t initSize, size_t size ELEKTRA_UNUSED, size_t level, int32_t * seed ELEKTRA_UNUSED,
2486 : KsShapeFunctionReturn * ret, void * data)
2487 : {
2488 : // label 1 5 subKeys
2489 : // label 2 10 subKeys
2490 : // label 3 20 subKeys
2491 0 : ssize_t modulesKeys[3] = { 5, 10, 15 };
2492 0 : uint8_t * d = data;
2493 0 : uint8_t * firstSet = &d[0];
2494 0 : uint8_t * secondSet = &d[1];
2495 0 : uint8_t * thirdSet = &d[2];
2496 0 : uint8_t * assign = &d[3];
2497 0 : if (level == 1)
2498 : {
2499 : // common start, simulates elektra in system/elektra
2500 0 : ret->subKeys = 1;
2501 0 : ret->label = 0;
2502 : }
2503 0 : else if (level == 2)
2504 : {
2505 : // common name, simulates modules in system/elektra/modules
2506 : // calculates how many modules have space
2507 0 : ret->subKeys = 0;
2508 0 : ssize_t remainingSize = initSize;
2509 0 : uint8_t isSpace = 1;
2510 0 : uint8_t l = 0;
2511 0 : while (isSpace)
2512 : {
2513 0 : if (remainingSize - modulesKeys[l] < 0)
2514 : {
2515 : isSpace = 0;
2516 : }
2517 : else
2518 : {
2519 0 : remainingSize -= modulesKeys[l];
2520 0 : l = (l + 1) % 3;
2521 0 : ++ret->subKeys;
2522 : }
2523 : }
2524 : // add solo keys
2525 0 : ret->subKeys += remainingSize;
2526 0 : ret->label = 0;
2527 : }
2528 0 : else if (level == 3)
2529 : {
2530 : // give each modules ret->subKeys * 5 subKeys
2531 0 : if (!*firstSet)
2532 : {
2533 0 : ret->subKeys = 1;
2534 0 : ret->label = 1;
2535 0 : *firstSet = 1;
2536 : }
2537 0 : else if (!*secondSet)
2538 : {
2539 0 : ret->subKeys = 2;
2540 0 : ret->label = 2;
2541 0 : *secondSet = 1;
2542 : }
2543 0 : else if (!*thirdSet)
2544 : {
2545 0 : ret->subKeys = 3;
2546 0 : ret->label = 3;
2547 0 : *thirdSet = 1;
2548 : }
2549 : else
2550 : {
2551 : // assign
2552 0 : ret->subKeys = -1;
2553 0 : ret->label = *assign;
2554 0 : *assign = (*assign % 3) + 1;
2555 : }
2556 : }
2557 0 : else if (level == 4)
2558 : {
2559 : // the 5 in ret->subKeys * 5
2560 0 : ret->subKeys = 5;
2561 0 : ret->label = 0;
2562 : }
2563 : else
2564 : {
2565 : // terminate keys
2566 0 : ret->subKeys = 0;
2567 0 : ret->label = 0;
2568 : }
2569 0 : }
2570 : /**
2571 : * always wider, subKeys are incremented by one every level
2572 : */
2573 0 : static void shapefWide (const size_t initSize, size_t size ELEKTRA_UNUSED, size_t level, int32_t * seed ELEKTRA_UNUSED,
2574 : KsShapeFunctionReturn * ret, void * data ELEKTRA_UNUSED)
2575 : {
2576 0 : ret->label = 0;
2577 0 : size_t startSubKeys = 2;
2578 : // determine to which level it is possible to go
2579 0 : size_t l = 0; // level 0 should have 2 subs
2580 0 : size_t keysOnLevel = startSubKeys;
2581 0 : while (keysOnLevel <= initSize)
2582 : {
2583 0 : ++l;
2584 0 : keysOnLevel *= startSubKeys + l;
2585 : }
2586 0 : if (level < l)
2587 : {
2588 0 : ret->subKeys = startSubKeys + level;
2589 : }
2590 : else
2591 : {
2592 0 : ret->subKeys = 0;
2593 : }
2594 0 : }
2595 : /**
2596 : * always tighter, subKeys are decrementing by one every level till two is reached
2597 : */
2598 0 : static void shapefTight (const size_t initSize, size_t size ELEKTRA_UNUSED, size_t level, int32_t * seed ELEKTRA_UNUSED,
2599 : KsShapeFunctionReturn * ret, void * data ELEKTRA_UNUSED)
2600 : {
2601 0 : ret->label = 0;
2602 0 : size_t startSubKeys = 2;
2603 : // determine to which level it is possible to go
2604 0 : size_t l = 0; // level 0 should have 2 subs
2605 0 : size_t keysOnLevel = startSubKeys;
2606 0 : while (keysOnLevel <= initSize)
2607 : {
2608 0 : ++l;
2609 0 : keysOnLevel *= startSubKeys + l;
2610 : }
2611 0 : if (level < l)
2612 : {
2613 0 : ret->subKeys = startSubKeys + l - level - 1;
2614 : }
2615 : else
2616 : {
2617 0 : ret->subKeys = 0;
2618 : }
2619 0 : }
2620 :
2621 : /**
2622 : * @brief Set the shape functions and parameters together to get the KeySetShape population.
2623 : *
2624 : * @retval KeySetShape * on success
2625 : */
2626 0 : static KeySetShape * getKeySetShapes (void)
2627 : {
2628 0 : KeySetShape * out = elektraMalloc (sizeof (KeySetShape) * numberOfShapes);
2629 0 : if (!out) printExit ("malloc KeySetShapes");
2630 0 : size_t shapeCount = 0;
2631 : // shapefConstBinary
2632 0 : out[shapeCount].minWordLength = 1;
2633 0 : out[shapeCount].maxWordLength = 21;
2634 0 : out[shapeCount].special = 127;
2635 0 : out[shapeCount].parent = 0;
2636 0 : out[shapeCount].shapeInit = NULL;
2637 0 : out[shapeCount].shapef = shapefConstBinary;
2638 0 : out[shapeCount].shapeDel = NULL;
2639 0 : ++shapeCount;
2640 :
2641 : // shapefBinaryBranch
2642 0 : out[shapeCount].minWordLength = 1;
2643 0 : out[shapeCount].maxWordLength = 1;
2644 0 : out[shapeCount].special = 50;
2645 0 : out[shapeCount].parent = 7;
2646 0 : out[shapeCount].shapeInit = NULL;
2647 0 : out[shapeCount].shapef = shapefBinaryBranch;
2648 0 : out[shapeCount].shapeDel = NULL;
2649 0 : ++shapeCount;
2650 :
2651 : // shapefDynamicBranch
2652 0 : out[shapeCount].minWordLength = 1;
2653 0 : out[shapeCount].maxWordLength = 11;
2654 0 : out[shapeCount].special = 50;
2655 0 : out[shapeCount].parent = 7;
2656 0 : out[shapeCount].shapeInit = NULL;
2657 0 : out[shapeCount].shapef = shapefDynamicBranch;
2658 0 : out[shapeCount].shapeDel = NULL;
2659 0 : ++shapeCount;
2660 :
2661 : // shapefLateDynamicBranch
2662 0 : out[shapeCount].minWordLength = 1;
2663 0 : out[shapeCount].maxWordLength = 11;
2664 0 : out[shapeCount].special = 50;
2665 0 : out[shapeCount].parent = 7;
2666 0 : out[shapeCount].shapeInit = NULL;
2667 0 : out[shapeCount].shapef = shapefLateDynamicBranch;
2668 0 : out[shapeCount].shapeDel = NULL;
2669 0 : ++shapeCount;
2670 :
2671 : // shapefWide
2672 0 : out[shapeCount].minWordLength = 1;
2673 0 : out[shapeCount].maxWordLength = 11;
2674 0 : out[shapeCount].special = 50;
2675 0 : out[shapeCount].parent = 7;
2676 0 : out[shapeCount].shapeInit = NULL;
2677 0 : out[shapeCount].shapef = shapefWide;
2678 0 : out[shapeCount].shapeDel = NULL;
2679 0 : ++shapeCount;
2680 :
2681 : // shapefTight
2682 0 : out[shapeCount].minWordLength = 1;
2683 0 : out[shapeCount].maxWordLength = 11;
2684 0 : out[shapeCount].special = 50;
2685 0 : out[shapeCount].parent = 7;
2686 0 : out[shapeCount].shapeInit = NULL;
2687 0 : out[shapeCount].shapef = shapefTight;
2688 0 : out[shapeCount].shapeDel = NULL;
2689 0 : ++shapeCount;
2690 :
2691 : // shapefCommonStartEnd
2692 0 : out[shapeCount].minWordLength = 1;
2693 0 : out[shapeCount].maxWordLength = 21;
2694 0 : out[shapeCount].special = 50;
2695 0 : out[shapeCount].parent = 0;
2696 0 : out[shapeCount].shapeInit = shapeCommonStartEndInit;
2697 0 : out[shapeCount].shapef = shapefCommonStartEnd;
2698 0 : out[shapeCount].shapeDel = shapeCommonStartEndDel;
2699 0 : ++shapeCount;
2700 :
2701 : // shapefModules
2702 0 : out[shapeCount].minWordLength = 1;
2703 0 : out[shapeCount].maxWordLength = 11;
2704 0 : out[shapeCount].special = 50;
2705 0 : out[shapeCount].parent = 7;
2706 0 : out[shapeCount].shapeInit = shapeModulesInit;
2707 0 : out[shapeCount].shapef = shapefModules;
2708 0 : out[shapeCount].shapeDel = shapeModulesDel;
2709 0 : ++shapeCount;
2710 :
2711 : if (shapeCount != numberOfShapes) printExit ("shapeCount != numberOfShapes");
2712 0 : return out;
2713 : }
|