1 /* bench-slope.c - for libgcrypt
2 * Copyright (C) 2013 Jussi Kivilinna <jussi.kivilinna@iki.fi>
3 *
4 * This file is part of Libgcrypt.
5 *
6 * Libgcrypt is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser general Public License as
8 * published by the Free Software Foundation; either version 2.1 of
9 * the License, or (at your option) any later version.
10 *
11 * Libgcrypt is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this program; if not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <stdarg.h>
26 #include <assert.h>
27 #include <time.h>
28
29 #ifdef _GCRYPT_IN_LIBGCRYPT
30 # include "../src/gcrypt-int.h"
31 # include "../compat/libcompat.h"
32 #else
33 # include <gcrypt.h>
34 #endif
35
36 #ifndef STR
37 #define STR(v) #v
38 #define STR2(v) STR(v)
39 #endif
40
41 #define PGM "bench-slope"
42 #include "t-common.h"
43
44 static int verbose;
45 static int csv_mode;
46 static int unaligned_mode;
47 static int num_measurement_repetitions;
48
49 /* CPU Ghz value provided by user, allows constructing cycles/byte and other
50 results. */
51 static double cpu_ghz = -1;
52
53 /* Attempt to autodetect CPU Ghz. */
54 static int auto_ghz;
55
56 /* Whether we are running as part of the regression test suite. */
57 static int in_regression_test;
58
59 /* The name of the currently printed section. */
60 static char *current_section_name;
61 /* The name of the currently printed algorithm. */
62 static char *current_algo_name;
63 /* The name of the currently printed mode. */
64 static char *current_mode_name;
65
66
67 /* Currently used CPU Ghz (either user input or auto-detected. */
68 static double bench_ghz;
69
70 /* Current accuracy of auto-detected CPU Ghz. */
71 static double bench_ghz_diff;
72
73
74 /*************************************** Default parameters for measurements. */
75
76 /* Start at small buffer size, to get reasonable timer calibration for fast
77 * implementations (AES-NI etc). Sixteen selected to support the largest block
78 * size of current set cipher blocks. */
79 #define BUF_START_SIZE 16
80
81 /* From ~0 to ~4kbytes give comparable results with results from academia
82 * (SUPERCOP). */
83 #define BUF_END_SIZE (BUF_START_SIZE + 4096)
84
85 /* With 128 byte steps, we get (4096)/64 = 64 data points. */
86 #define BUF_STEP_SIZE 64
87
88 /* Number of repeated measurements at each data point. The median of these
89 * measurements is selected as data point further analysis. */
90 #define NUM_MEASUREMENT_REPETITIONS 64
91
92 /* Target accuracy for auto-detected CPU Ghz. */
93 #define AUTO_GHZ_TARGET_DIFF (5e-5)
94
95 /**************************************************** High-resolution timers. */
96
97 /* This benchmarking module needs needs high resolution timer. */
98 #undef NO_GET_NSEC_TIME
99 #if defined(_WIN32)
100 struct nsec_time
101 {
102 LARGE_INTEGER perf_count;
103 };
104
105 static void
get_nsec_time(struct nsec_time * t)106 get_nsec_time (struct nsec_time *t)
107 {
108 BOOL ok;
109
110 ok = QueryPerformanceCounter (&t->perf_count);
111 assert (ok);
112 }
113
114 static double
get_time_nsec_diff(struct nsec_time * start,struct nsec_time * end)115 get_time_nsec_diff (struct nsec_time *start, struct nsec_time *end)
116 {
117 static double nsecs_per_count = 0.0;
118 double nsecs;
119
120 if (nsecs_per_count == 0.0)
121 {
122 LARGE_INTEGER perf_freq;
123 BOOL ok;
124
125 /* Get counts per second. */
126 ok = QueryPerformanceFrequency (&perf_freq);
127 assert (ok);
128
129 nsecs_per_count = 1.0 / perf_freq.QuadPart;
130 nsecs_per_count *= 1000000.0 * 1000.0; /* sec => nsec */
131
132 assert (nsecs_per_count > 0.0);
133 }
134
135 nsecs = end->perf_count.QuadPart - start->perf_count.QuadPart; /* counts */
136 nsecs *= nsecs_per_count; /* counts * (nsecs / count) => nsecs */
137
138 return nsecs;
139 }
140 #elif defined(HAVE_CLOCK_GETTIME)
141 struct nsec_time
142 {
143 struct timespec ts;
144 };
145
146 static void
get_nsec_time(struct nsec_time * t)147 get_nsec_time (struct nsec_time *t)
148 {
149 int err;
150
151 err = clock_gettime (CLOCK_REALTIME, &t->ts);
152 assert (err == 0);
153 }
154
155 static double
get_time_nsec_diff(struct nsec_time * start,struct nsec_time * end)156 get_time_nsec_diff (struct nsec_time *start, struct nsec_time *end)
157 {
158 double nsecs;
159
160 nsecs = end->ts.tv_sec - start->ts.tv_sec;
161 nsecs *= 1000000.0 * 1000.0; /* sec => nsec */
162
163 /* This way we don't have to care if tv_nsec unsigned or signed. */
164 if (end->ts.tv_nsec >= start->ts.tv_nsec)
165 nsecs += end->ts.tv_nsec - start->ts.tv_nsec;
166 else
167 nsecs -= start->ts.tv_nsec - end->ts.tv_nsec;
168
169 return nsecs;
170 }
171 #elif defined(HAVE_GETTIMEOFDAY)
172 struct nsec_time
173 {
174 struct timeval tv;
175 };
176
177 static void
get_nsec_time(struct nsec_time * t)178 get_nsec_time (struct nsec_time *t)
179 {
180 int err;
181
182 err = gettimeofday (&t->tv, NULL);
183 assert (err == 0);
184 }
185
186 static double
get_time_nsec_diff(struct nsec_time * start,struct nsec_time * end)187 get_time_nsec_diff (struct nsec_time *start, struct nsec_time *end)
188 {
189 double nsecs;
190
191 nsecs = end->tv.tv_sec - start->tv.tv_sec;
192 nsecs *= 1000000; /* sec => µsec */
193
194 /* This way we don't have to care if tv_usec unsigned or signed. */
195 if (end->tv.tv_usec >= start->tv.tv_usec)
196 nsecs += end->tv.tv_usec - start->tv.tv_usec;
197 else
198 nsecs -= start->tv.tv_usec - end->tv.tv_usec;
199
200 nsecs *= 1000; /* µsec => nsec */
201
202 return nsecs;
203 }
204 #else
205 #define NO_GET_NSEC_TIME 1
206 #endif
207
208
209 /* If no high resolution timer found, provide dummy bench-slope. */
210 #ifdef NO_GET_NSEC_TIME
211
212
213 int
main(void)214 main (void)
215 {
216 /* No nsec timer => SKIP test. */
217 return 77;
218 }
219
220
221 #else /* !NO_GET_NSEC_TIME */
222
223
224 /********************************************** Slope benchmarking framework. */
225
226 struct bench_obj
227 {
228 const struct bench_ops *ops;
229
230 unsigned int num_measure_repetitions;
231 unsigned int min_bufsize;
232 unsigned int max_bufsize;
233 unsigned int step_size;
234
235 void *priv;
236 void *hd;
237 };
238
239 typedef int (*const bench_initialize_t) (struct bench_obj * obj);
240 typedef void (*const bench_finalize_t) (struct bench_obj * obj);
241 typedef void (*const bench_do_run_t) (struct bench_obj * obj, void *buffer,
242 size_t buflen);
243
244 struct bench_ops
245 {
246 bench_initialize_t initialize;
247 bench_finalize_t finalize;
248 bench_do_run_t do_run;
249 };
250
251
252 double
get_slope(double (* const get_x)(unsigned int idx,void * priv),void * get_x_priv,double y_points[],unsigned int npoints,double * overhead)253 get_slope (double (*const get_x) (unsigned int idx, void *priv),
254 void *get_x_priv, double y_points[], unsigned int npoints,
255 double *overhead)
256 {
257 double sumx, sumy, sumx2, sumy2, sumxy;
258 unsigned int i;
259 double b, a;
260
261 sumx = sumy = sumx2 = sumy2 = sumxy = 0;
262
263 for (i = 0; i < npoints; i++)
264 {
265 double x, y;
266
267 x = get_x (i, get_x_priv); /* bytes */
268 y = y_points[i]; /* nsecs */
269
270 sumx += x;
271 sumy += y;
272 sumx2 += x * x;
273 /*sumy2 += y * y;*/
274 sumxy += x * y;
275 }
276
277 b = (npoints * sumxy - sumx * sumy) / (npoints * sumx2 - sumx * sumx);
278 a = (sumy - b * sumx) / npoints;
279
280 if (overhead)
281 *overhead = a; /* nsecs */
282
283 return b; /* nsecs per byte */
284 }
285
286
287 double
get_bench_obj_point_x(unsigned int idx,void * priv)288 get_bench_obj_point_x (unsigned int idx, void *priv)
289 {
290 struct bench_obj *obj = priv;
291 return (double) (obj->min_bufsize + (idx * obj->step_size));
292 }
293
294
295 unsigned int
get_num_measurements(struct bench_obj * obj)296 get_num_measurements (struct bench_obj *obj)
297 {
298 unsigned int buf_range = obj->max_bufsize - obj->min_bufsize;
299 unsigned int num = buf_range / obj->step_size + 1;
300
301 while (obj->min_bufsize + (num * obj->step_size) > obj->max_bufsize)
302 num--;
303
304 return num + 1;
305 }
306
307
308 static int
double_cmp(const void * _a,const void * _b)309 double_cmp (const void *_a, const void *_b)
310 {
311 const double *a, *b;
312
313 a = _a;
314 b = _b;
315
316 if (*a > *b)
317 return 1;
318 if (*a < *b)
319 return -1;
320 return 0;
321 }
322
323
324 double
do_bench_obj_measurement(struct bench_obj * obj,void * buffer,size_t buflen,double * measurement_raw,unsigned int loop_iterations)325 do_bench_obj_measurement (struct bench_obj *obj, void *buffer, size_t buflen,
326 double *measurement_raw,
327 unsigned int loop_iterations)
328 {
329 const unsigned int num_repetitions = obj->num_measure_repetitions;
330 const bench_do_run_t do_run = obj->ops->do_run;
331 struct nsec_time start, end;
332 unsigned int rep, loop;
333 double res;
334
335 if (num_repetitions < 1 || loop_iterations < 1)
336 return 0.0;
337
338 for (rep = 0; rep < num_repetitions; rep++)
339 {
340 get_nsec_time (&start);
341
342 for (loop = 0; loop < loop_iterations; loop++)
343 do_run (obj, buffer, buflen);
344
345 get_nsec_time (&end);
346
347 measurement_raw[rep] = get_time_nsec_diff (&start, &end);
348 }
349
350 /* Return median of repeated measurements. */
351 qsort (measurement_raw, num_repetitions, sizeof (measurement_raw[0]),
352 double_cmp);
353
354 if (num_repetitions % 2 == 1)
355 return measurement_raw[num_repetitions / 2];
356
357 res = measurement_raw[num_repetitions / 2]
358 + measurement_raw[num_repetitions / 2 - 1];
359 return res / 2;
360 }
361
362
363 unsigned int
adjust_loop_iterations_to_timer_accuracy(struct bench_obj * obj,void * buffer,double * measurement_raw)364 adjust_loop_iterations_to_timer_accuracy (struct bench_obj *obj, void *buffer,
365 double *measurement_raw)
366 {
367 const double increase_thres = 3.0;
368 double tmp, nsecs;
369 unsigned int loop_iterations;
370 unsigned int test_bufsize;
371
372 test_bufsize = obj->min_bufsize;
373 if (test_bufsize == 0)
374 test_bufsize += obj->step_size;
375
376 loop_iterations = 0;
377 do
378 {
379 /* Increase loop iterations until we get other results than zero. */
380 nsecs =
381 do_bench_obj_measurement (obj, buffer, test_bufsize,
382 measurement_raw, ++loop_iterations);
383 }
384 while (nsecs < 1.0 - 0.1);
385 do
386 {
387 /* Increase loop iterations until we get reasonable increase for elapsed time. */
388 tmp =
389 do_bench_obj_measurement (obj, buffer, test_bufsize,
390 measurement_raw, ++loop_iterations);
391 }
392 while (tmp < nsecs * (increase_thres - 0.1));
393
394 return loop_iterations;
395 }
396
397
398 /* Benchmark and return linear regression slope in nanoseconds per byte. */
399 double
slope_benchmark(struct bench_obj * obj)400 slope_benchmark (struct bench_obj *obj)
401 {
402 unsigned int num_measurements;
403 double *measurements = NULL;
404 double *measurement_raw = NULL;
405 double slope, overhead;
406 unsigned int loop_iterations, midx, i;
407 unsigned char *real_buffer = NULL;
408 unsigned char *buffer;
409 size_t cur_bufsize;
410 int err;
411
412 err = obj->ops->initialize (obj);
413 if (err < 0)
414 return -1;
415
416 num_measurements = get_num_measurements (obj);
417 measurements = calloc (num_measurements, sizeof (*measurements));
418 if (!measurements)
419 goto err_free;
420
421 measurement_raw =
422 calloc (obj->num_measure_repetitions, sizeof (*measurement_raw));
423 if (!measurement_raw)
424 goto err_free;
425
426 if (num_measurements < 1 || obj->num_measure_repetitions < 1 ||
427 obj->max_bufsize < 1 || obj->min_bufsize > obj->max_bufsize)
428 goto err_free;
429
430 real_buffer = malloc (obj->max_bufsize + 128 + unaligned_mode);
431 if (!real_buffer)
432 goto err_free;
433 /* Get aligned buffer */
434 buffer = real_buffer;
435 buffer += 128 - ((real_buffer - (unsigned char *) 0) & (128 - 1));
436 if (unaligned_mode)
437 buffer += unaligned_mode; /* Make buffer unaligned */
438
439 for (i = 0; i < obj->max_bufsize; i++)
440 buffer[i] = 0x55 ^ (-i);
441
442 /* Adjust number of loop iterations up to timer accuracy. */
443 loop_iterations = adjust_loop_iterations_to_timer_accuracy (obj, buffer,
444 measurement_raw);
445
446 /* Perform measurements */
447 for (midx = 0, cur_bufsize = obj->min_bufsize;
448 cur_bufsize <= obj->max_bufsize; cur_bufsize += obj->step_size, midx++)
449 {
450 measurements[midx] =
451 do_bench_obj_measurement (obj, buffer, cur_bufsize, measurement_raw,
452 loop_iterations);
453 measurements[midx] /= loop_iterations;
454 }
455
456 assert (midx == num_measurements);
457
458 slope =
459 get_slope (&get_bench_obj_point_x, obj, measurements, num_measurements,
460 &overhead);
461
462 free (measurement_raw);
463 free (measurements);
464 free (real_buffer);
465 obj->ops->finalize (obj);
466
467 return slope;
468
469 err_free:
470 if (measurement_raw)
471 free (measurement_raw);
472 if (measurements)
473 free (measurements);
474 if (real_buffer)
475 free (real_buffer);
476 obj->ops->finalize (obj);
477
478 return -1;
479 }
480
481 /********************************************* CPU frequency auto-detection. */
482
483 static int
auto_ghz_init(struct bench_obj * obj)484 auto_ghz_init (struct bench_obj *obj)
485 {
486 obj->min_bufsize = 16;
487 obj->max_bufsize = 64 + obj->min_bufsize;
488 obj->step_size = 8;
489 obj->num_measure_repetitions = 16;
490
491 return 0;
492 }
493
494 static void
auto_ghz_free(struct bench_obj * obj)495 auto_ghz_free (struct bench_obj *obj)
496 {
497 (void)obj;
498 }
499
500 static void
auto_ghz_bench(struct bench_obj * obj,void * buf,size_t buflen)501 auto_ghz_bench (struct bench_obj *obj, void *buf, size_t buflen)
502 {
503 (void)obj;
504 (void)buf;
505
506 buflen *= 1024;
507
508 /* Turbo frequency detection benchmark. Without CPU turbo-boost, this
509 * function will give cycles/iteration result 1024.0 on high-end CPUs.
510 * With turbo, result will be less and can be used detect turbo-clock. */
511
512 #ifdef HAVE_GCC_ASM_VOLATILE_MEMORY
513 /* Auto-ghz operation takes two CPU cycles to perform. Memory barriers
514 * are used to prevent compiler from optimizing this loop away. */
515 #define AUTO_GHZ_OPERATION \
516 asm volatile ("":"+r"(buflen)::"memory"); \
517 buflen ^= 1; \
518 asm volatile ("":"+r"(buflen)::"memory"); \
519 buflen -= 2
520 #else
521 /* TODO: Needs alternative way of preventing compiler optimizations.
522 * Mix of XOR and subtraction appears to do the trick for now. */
523 #define AUTO_GHZ_OPERATION \
524 buflen ^= 1; \
525 buflen -= 2
526 #endif
527
528 #define AUTO_GHZ_OPERATION_2 \
529 AUTO_GHZ_OPERATION; \
530 AUTO_GHZ_OPERATION
531
532 #define AUTO_GHZ_OPERATION_4 \
533 AUTO_GHZ_OPERATION_2; \
534 AUTO_GHZ_OPERATION_2
535
536 #define AUTO_GHZ_OPERATION_8 \
537 AUTO_GHZ_OPERATION_4; \
538 AUTO_GHZ_OPERATION_4
539
540 #define AUTO_GHZ_OPERATION_16 \
541 AUTO_GHZ_OPERATION_8; \
542 AUTO_GHZ_OPERATION_8
543
544 #define AUTO_GHZ_OPERATION_32 \
545 AUTO_GHZ_OPERATION_16; \
546 AUTO_GHZ_OPERATION_16
547
548 #define AUTO_GHZ_OPERATION_64 \
549 AUTO_GHZ_OPERATION_32; \
550 AUTO_GHZ_OPERATION_32
551
552 #define AUTO_GHZ_OPERATION_128 \
553 AUTO_GHZ_OPERATION_64; \
554 AUTO_GHZ_OPERATION_64
555
556 do
557 {
558 /* 1024 auto-ghz operations per loop, total 2048 instructions. */
559 AUTO_GHZ_OPERATION_128; AUTO_GHZ_OPERATION_128;
560 AUTO_GHZ_OPERATION_128; AUTO_GHZ_OPERATION_128;
561 AUTO_GHZ_OPERATION_128; AUTO_GHZ_OPERATION_128;
562 AUTO_GHZ_OPERATION_128; AUTO_GHZ_OPERATION_128;
563 }
564 while (buflen);
565 }
566
567 static struct bench_ops auto_ghz_detect_ops = {
568 &auto_ghz_init,
569 &auto_ghz_free,
570 &auto_ghz_bench
571 };
572
573
574 double
get_auto_ghz(void)575 get_auto_ghz (void)
576 {
577 struct bench_obj obj = { 0 };
578 double nsecs_per_iteration;
579 double cycles_per_iteration;
580
581 obj.ops = &auto_ghz_detect_ops;
582
583 nsecs_per_iteration = slope_benchmark (&obj);
584
585 cycles_per_iteration = nsecs_per_iteration * cpu_ghz;
586
587 /* Adjust CPU Ghz so that cycles per iteration would give '1024.0'. */
588
589 return cpu_ghz * 1024 / cycles_per_iteration;
590 }
591
592
593 double
do_slope_benchmark(struct bench_obj * obj)594 do_slope_benchmark (struct bench_obj *obj)
595 {
596 double ret;
597
598 if (!auto_ghz)
599 {
600 /* Perform measurement without autodetection of CPU frequency. */
601
602 ret = slope_benchmark (obj);
603
604 bench_ghz = cpu_ghz;
605 bench_ghz_diff = 0;
606 }
607 else
608 {
609 double target_diff = AUTO_GHZ_TARGET_DIFF;
610 double cpu_auto_ghz_before;
611 double cpu_auto_ghz_after;
612 double nsecs_per_iteration;
613 double diff;
614 unsigned int try_count = 0;
615
616 /* Perform measurement with CPU frequency autodetection. */
617
618 do
619 {
620 /* Repeat measurement until CPU turbo frequency has stabilized. */
621
622 if (try_count++ > 4)
623 {
624 /* Too much frequency instability on the system, relax target
625 * accuracy. */
626
627 try_count = 0;
628 target_diff *= 2;
629 }
630
631 cpu_auto_ghz_before = get_auto_ghz ();
632
633 nsecs_per_iteration = slope_benchmark (obj);
634
635 cpu_auto_ghz_after = get_auto_ghz ();
636
637 diff = 1.0 - (cpu_auto_ghz_before / cpu_auto_ghz_after);
638 diff = diff < 0 ? -diff : diff;
639 }
640 while (diff > target_diff);
641
642 ret = nsecs_per_iteration;
643
644 bench_ghz = (cpu_auto_ghz_before + cpu_auto_ghz_after) / 2;
645 bench_ghz_diff = diff;
646 }
647
648 return ret;
649 }
650
651
652 /********************************************************** Printing results. */
653
654 static void
double_to_str(char * out,size_t outlen,double value)655 double_to_str (char *out, size_t outlen, double value)
656 {
657 const char *fmt;
658
659 if (value < 1.0)
660 fmt = "%.3f";
661 else if (value < 100.0)
662 fmt = "%.2f";
663 else if (value < 1000.0)
664 fmt = "%.1f";
665 else
666 fmt = "%.0f";
667
668 snprintf (out, outlen, fmt, value);
669 }
670
671 static void
bench_print_result_csv(double nsecs_per_byte)672 bench_print_result_csv (double nsecs_per_byte)
673 {
674 double cycles_per_byte, mbytes_per_sec;
675 char nsecpbyte_buf[16];
676 char mbpsec_buf[16];
677 char cpbyte_buf[16];
678 char mhz_buf[16];
679 char mhz_diff_buf[32];
680
681 strcpy (mhz_diff_buf, "");
682 *cpbyte_buf = 0;
683 *mhz_buf = 0;
684
685 double_to_str (nsecpbyte_buf, sizeof (nsecpbyte_buf), nsecs_per_byte);
686
687 /* If user didn't provide CPU speed, we cannot show cycles/byte results. */
688 if (bench_ghz > 0.0)
689 {
690 cycles_per_byte = nsecs_per_byte * bench_ghz;
691 double_to_str (cpbyte_buf, sizeof (cpbyte_buf), cycles_per_byte);
692 double_to_str (mhz_buf, sizeof (mhz_buf), bench_ghz * 1000);
693 if (auto_ghz && bench_ghz_diff * 1000 >= 1)
694 {
695 snprintf(mhz_diff_buf, sizeof(mhz_diff_buf), ",%.0f,Mhz-diff",
696 bench_ghz_diff * 1000);
697 }
698 }
699
700 mbytes_per_sec =
701 (1000.0 * 1000.0 * 1000.0) / (nsecs_per_byte * 1024 * 1024);
702 double_to_str (mbpsec_buf, sizeof (mbpsec_buf), mbytes_per_sec);
703
704 /* We print two empty fields to allow for future enhancements. */
705 if (auto_ghz)
706 {
707 printf ("%s,%s,%s,,,%s,ns/B,%s,MiB/s,%s,c/B,%s,Mhz%s\n",
708 current_section_name,
709 current_algo_name? current_algo_name : "",
710 current_mode_name? current_mode_name : "",
711 nsecpbyte_buf,
712 mbpsec_buf,
713 cpbyte_buf,
714 mhz_buf,
715 mhz_diff_buf);
716 }
717 else
718 {
719 printf ("%s,%s,%s,,,%s,ns/B,%s,MiB/s,%s,c/B\n",
720 current_section_name,
721 current_algo_name? current_algo_name : "",
722 current_mode_name? current_mode_name : "",
723 nsecpbyte_buf,
724 mbpsec_buf,
725 cpbyte_buf);
726 }
727 }
728
729 static void
bench_print_result_std(double nsecs_per_byte)730 bench_print_result_std (double nsecs_per_byte)
731 {
732 double cycles_per_byte, mbytes_per_sec;
733 char nsecpbyte_buf[16];
734 char mbpsec_buf[16];
735 char cpbyte_buf[16];
736 char mhz_buf[16];
737 char mhz_diff_buf[32];
738
739 strcpy (mhz_diff_buf, "");
740
741 double_to_str (nsecpbyte_buf, sizeof (nsecpbyte_buf), nsecs_per_byte);
742
743 /* If user didn't provide CPU speed, we cannot show cycles/byte results. */
744 if (bench_ghz > 0.0)
745 {
746 cycles_per_byte = nsecs_per_byte * bench_ghz;
747 double_to_str (cpbyte_buf, sizeof (cpbyte_buf), cycles_per_byte);
748 double_to_str (mhz_buf, sizeof (mhz_buf), bench_ghz * 1000);
749 if (auto_ghz && bench_ghz_diff * 1000 >= 0.5)
750 {
751 snprintf(mhz_diff_buf, sizeof(mhz_diff_buf), "±%.0f",
752 bench_ghz_diff * 1000);
753 }
754 }
755 else
756 {
757 strcpy (cpbyte_buf, "-");
758 strcpy (mhz_buf, "-");
759 }
760
761 mbytes_per_sec =
762 (1000.0 * 1000.0 * 1000.0) / (nsecs_per_byte * 1024 * 1024);
763 double_to_str (mbpsec_buf, sizeof (mbpsec_buf), mbytes_per_sec);
764
765 if (auto_ghz)
766 {
767 printf ("%9s ns/B %9s MiB/s %9s c/B %9s%s\n",
768 nsecpbyte_buf, mbpsec_buf, cpbyte_buf, mhz_buf, mhz_diff_buf);
769 }
770 else
771 {
772 printf ("%9s ns/B %9s MiB/s %9s c/B\n",
773 nsecpbyte_buf, mbpsec_buf, cpbyte_buf);
774 }
775 }
776
777 static void
bench_print_result(double nsecs_per_byte)778 bench_print_result (double nsecs_per_byte)
779 {
780 if (csv_mode)
781 bench_print_result_csv (nsecs_per_byte);
782 else
783 bench_print_result_std (nsecs_per_byte);
784 }
785
786 static void
bench_print_section(const char * section_name,const char * print_name)787 bench_print_section (const char *section_name, const char *print_name)
788 {
789 if (csv_mode)
790 {
791 gcry_free (current_section_name);
792 current_section_name = gcry_xstrdup (section_name);
793 }
794 else
795 printf ("%s:\n", print_name);
796 }
797
798 static void
bench_print_header(int algo_width,const char * algo_name)799 bench_print_header (int algo_width, const char *algo_name)
800 {
801 if (csv_mode)
802 {
803 gcry_free (current_algo_name);
804 current_algo_name = gcry_xstrdup (algo_name);
805 }
806 else
807 {
808 if (algo_width < 0)
809 printf (" %-*s | ", -algo_width, algo_name);
810 else
811 printf (" %-*s | ", algo_width, algo_name);
812
813 if (auto_ghz)
814 printf ("%14s %15s %13s %9s\n", "nanosecs/byte", "mebibytes/sec",
815 "cycles/byte", "auto Mhz");
816 else
817 printf ("%14s %15s %13s\n", "nanosecs/byte", "mebibytes/sec",
818 "cycles/byte");
819 }
820 }
821
822 static void
bench_print_algo(int algo_width,const char * algo_name)823 bench_print_algo (int algo_width, const char *algo_name)
824 {
825 if (csv_mode)
826 {
827 gcry_free (current_algo_name);
828 current_algo_name = gcry_xstrdup (algo_name);
829 }
830 else
831 {
832 if (algo_width < 0)
833 printf (" %-*s | ", -algo_width, algo_name);
834 else
835 printf (" %-*s | ", algo_width, algo_name);
836 }
837 }
838
839 static void
bench_print_mode(int width,const char * mode_name)840 bench_print_mode (int width, const char *mode_name)
841 {
842 if (csv_mode)
843 {
844 gcry_free (current_mode_name);
845 current_mode_name = gcry_xstrdup (mode_name);
846 }
847 else
848 {
849 if (width < 0)
850 printf (" %-*s | ", -width, mode_name);
851 else
852 printf (" %*s | ", width, mode_name);
853 fflush (stdout);
854 }
855 }
856
857 static void
bench_print_footer(int algo_width)858 bench_print_footer (int algo_width)
859 {
860 if (!csv_mode)
861 printf (" %-*s =\n", algo_width, "");
862 }
863
864
865 /********************************************************* Cipher benchmarks. */
866
867 struct bench_cipher_mode
868 {
869 int mode;
870 const char *name;
871 struct bench_ops *ops;
872
873 int algo;
874 };
875
876
877 static int
bench_encrypt_init(struct bench_obj * obj)878 bench_encrypt_init (struct bench_obj *obj)
879 {
880 struct bench_cipher_mode *mode = obj->priv;
881 gcry_cipher_hd_t hd;
882 int err, keylen;
883
884 obj->min_bufsize = BUF_START_SIZE;
885 obj->max_bufsize = BUF_END_SIZE;
886 obj->step_size = BUF_STEP_SIZE;
887 obj->num_measure_repetitions = num_measurement_repetitions;
888
889 err = gcry_cipher_open (&hd, mode->algo, mode->mode, 0);
890 if (err)
891 {
892 fprintf (stderr, PGM ": error opening cipher `%s'\n",
893 gcry_cipher_algo_name (mode->algo));
894 exit (1);
895 }
896
897 keylen = gcry_cipher_get_algo_keylen (mode->algo);
898 if (keylen)
899 {
900 char key[keylen];
901 int i;
902
903 for (i = 0; i < keylen; i++)
904 key[i] = 0x33 ^ (11 - i);
905
906 err = gcry_cipher_setkey (hd, key, keylen);
907 if (err)
908 {
909 fprintf (stderr, PGM ": gcry_cipher_setkey failed: %s\n",
910 gpg_strerror (err));
911 gcry_cipher_close (hd);
912 exit (1);
913 }
914 }
915 else
916 {
917 fprintf (stderr, PGM ": failed to get key length for algorithm `%s'\n",
918 gcry_cipher_algo_name (mode->algo));
919 gcry_cipher_close (hd);
920 exit (1);
921 }
922
923 obj->hd = hd;
924
925 return 0;
926 }
927
928 static void
bench_encrypt_free(struct bench_obj * obj)929 bench_encrypt_free (struct bench_obj *obj)
930 {
931 gcry_cipher_hd_t hd = obj->hd;
932
933 gcry_cipher_close (hd);
934 }
935
936 static void
bench_encrypt_do_bench(struct bench_obj * obj,void * buf,size_t buflen)937 bench_encrypt_do_bench (struct bench_obj *obj, void *buf, size_t buflen)
938 {
939 gcry_cipher_hd_t hd = obj->hd;
940 int err;
941
942 err = gcry_cipher_reset (hd);
943 if (!err)
944 err = gcry_cipher_encrypt (hd, buf, buflen, buf, buflen);
945 if (err)
946 {
947 fprintf (stderr, PGM ": gcry_cipher_encrypt failed: %s\n",
948 gpg_strerror (err));
949 gcry_cipher_close (hd);
950 exit (1);
951 }
952 }
953
954 static void
bench_decrypt_do_bench(struct bench_obj * obj,void * buf,size_t buflen)955 bench_decrypt_do_bench (struct bench_obj *obj, void *buf, size_t buflen)
956 {
957 gcry_cipher_hd_t hd = obj->hd;
958 int err;
959
960 err = gcry_cipher_reset (hd);
961 if (!err)
962 err = gcry_cipher_decrypt (hd, buf, buflen, buf, buflen);
963 if (err)
964 {
965 fprintf (stderr, PGM ": gcry_cipher_encrypt failed: %s\n",
966 gpg_strerror (err));
967 gcry_cipher_close (hd);
968 exit (1);
969 }
970 }
971
972 static struct bench_ops encrypt_ops = {
973 &bench_encrypt_init,
974 &bench_encrypt_free,
975 &bench_encrypt_do_bench
976 };
977
978 static struct bench_ops decrypt_ops = {
979 &bench_encrypt_init,
980 &bench_encrypt_free,
981 &bench_decrypt_do_bench
982 };
983
984
985 static int
bench_xts_encrypt_init(struct bench_obj * obj)986 bench_xts_encrypt_init (struct bench_obj *obj)
987 {
988 struct bench_cipher_mode *mode = obj->priv;
989 gcry_cipher_hd_t hd;
990 int err, keylen;
991
992 obj->min_bufsize = BUF_START_SIZE;
993 obj->max_bufsize = BUF_END_SIZE;
994 obj->step_size = BUF_STEP_SIZE;
995 obj->num_measure_repetitions = num_measurement_repetitions;
996
997 err = gcry_cipher_open (&hd, mode->algo, mode->mode, 0);
998 if (err)
999 {
1000 fprintf (stderr, PGM ": error opening cipher `%s'\n",
1001 gcry_cipher_algo_name (mode->algo));
1002 exit (1);
1003 }
1004
1005 /* Double key-length for XTS. */
1006 keylen = gcry_cipher_get_algo_keylen (mode->algo) * 2;
1007 if (keylen)
1008 {
1009 char key[keylen];
1010 int i;
1011
1012 for (i = 0; i < keylen; i++)
1013 key[i] = 0x33 ^ (11 - i);
1014
1015 err = gcry_cipher_setkey (hd, key, keylen);
1016 if (err)
1017 {
1018 fprintf (stderr, PGM ": gcry_cipher_setkey failed: %s\n",
1019 gpg_strerror (err));
1020 gcry_cipher_close (hd);
1021 exit (1);
1022 }
1023 }
1024 else
1025 {
1026 fprintf (stderr, PGM ": failed to get key length for algorithm `%s'\n",
1027 gcry_cipher_algo_name (mode->algo));
1028 gcry_cipher_close (hd);
1029 exit (1);
1030 }
1031
1032 obj->hd = hd;
1033
1034 return 0;
1035 }
1036
1037 static struct bench_ops xts_encrypt_ops = {
1038 &bench_xts_encrypt_init,
1039 &bench_encrypt_free,
1040 &bench_encrypt_do_bench
1041 };
1042
1043 static struct bench_ops xts_decrypt_ops = {
1044 &bench_xts_encrypt_init,
1045 &bench_encrypt_free,
1046 &bench_decrypt_do_bench
1047 };
1048
1049
1050 static void
bench_ccm_encrypt_do_bench(struct bench_obj * obj,void * buf,size_t buflen)1051 bench_ccm_encrypt_do_bench (struct bench_obj *obj, void *buf, size_t buflen)
1052 {
1053 gcry_cipher_hd_t hd = obj->hd;
1054 int err;
1055 char tag[8];
1056 char nonce[11] = { 0x80, 0x01, };
1057 u64 params[3];
1058
1059 gcry_cipher_setiv (hd, nonce, sizeof (nonce));
1060
1061 /* Set CCM lengths */
1062 params[0] = buflen;
1063 params[1] = 0; /*aadlen */
1064 params[2] = sizeof (tag);
1065 err =
1066 gcry_cipher_ctl (hd, GCRYCTL_SET_CCM_LENGTHS, params, sizeof (params));
1067 if (err)
1068 {
1069 fprintf (stderr, PGM ": gcry_cipher_ctl failed: %s\n",
1070 gpg_strerror (err));
1071 gcry_cipher_close (hd);
1072 exit (1);
1073 }
1074
1075 err = gcry_cipher_encrypt (hd, buf, buflen, buf, buflen);
1076 if (err)
1077 {
1078 fprintf (stderr, PGM ": gcry_cipher_encrypt failed: %s\n",
1079 gpg_strerror (err));
1080 gcry_cipher_close (hd);
1081 exit (1);
1082 }
1083
1084 err = gcry_cipher_gettag (hd, tag, sizeof (tag));
1085 if (err)
1086 {
1087 fprintf (stderr, PGM ": gcry_cipher_gettag failed: %s\n",
1088 gpg_strerror (err));
1089 gcry_cipher_close (hd);
1090 exit (1);
1091 }
1092 }
1093
1094 static void
bench_ccm_decrypt_do_bench(struct bench_obj * obj,void * buf,size_t buflen)1095 bench_ccm_decrypt_do_bench (struct bench_obj *obj, void *buf, size_t buflen)
1096 {
1097 gcry_cipher_hd_t hd = obj->hd;
1098 int err;
1099 char tag[8] = { 0, };
1100 char nonce[11] = { 0x80, 0x01, };
1101 u64 params[3];
1102
1103 gcry_cipher_setiv (hd, nonce, sizeof (nonce));
1104
1105 /* Set CCM lengths */
1106 params[0] = buflen;
1107 params[1] = 0; /*aadlen */
1108 params[2] = sizeof (tag);
1109 err =
1110 gcry_cipher_ctl (hd, GCRYCTL_SET_CCM_LENGTHS, params, sizeof (params));
1111 if (err)
1112 {
1113 fprintf (stderr, PGM ": gcry_cipher_ctl failed: %s\n",
1114 gpg_strerror (err));
1115 gcry_cipher_close (hd);
1116 exit (1);
1117 }
1118
1119 err = gcry_cipher_decrypt (hd, buf, buflen, buf, buflen);
1120 if (err)
1121 {
1122 fprintf (stderr, PGM ": gcry_cipher_encrypt failed: %s\n",
1123 gpg_strerror (err));
1124 gcry_cipher_close (hd);
1125 exit (1);
1126 }
1127
1128 err = gcry_cipher_checktag (hd, tag, sizeof (tag));
1129 if (gpg_err_code (err) == GPG_ERR_CHECKSUM)
1130 err = gpg_error (GPG_ERR_NO_ERROR);
1131 if (err)
1132 {
1133 fprintf (stderr, PGM ": gcry_cipher_gettag failed: %s\n",
1134 gpg_strerror (err));
1135 gcry_cipher_close (hd);
1136 exit (1);
1137 }
1138 }
1139
1140 static void
bench_ccm_authenticate_do_bench(struct bench_obj * obj,void * buf,size_t buflen)1141 bench_ccm_authenticate_do_bench (struct bench_obj *obj, void *buf,
1142 size_t buflen)
1143 {
1144 gcry_cipher_hd_t hd = obj->hd;
1145 int err;
1146 char tag[8] = { 0, };
1147 char nonce[11] = { 0x80, 0x01, };
1148 u64 params[3];
1149 char data = 0xff;
1150
1151 gcry_cipher_setiv (hd, nonce, sizeof (nonce));
1152
1153 /* Set CCM lengths */
1154 params[0] = sizeof (data); /*datalen */
1155 params[1] = buflen; /*aadlen */
1156 params[2] = sizeof (tag);
1157 err =
1158 gcry_cipher_ctl (hd, GCRYCTL_SET_CCM_LENGTHS, params, sizeof (params));
1159 if (err)
1160 {
1161 fprintf (stderr, PGM ": gcry_cipher_ctl failed: %s\n",
1162 gpg_strerror (err));
1163 gcry_cipher_close (hd);
1164 exit (1);
1165 }
1166
1167 err = gcry_cipher_authenticate (hd, buf, buflen);
1168 if (err)
1169 {
1170 fprintf (stderr, PGM ": gcry_cipher_authenticate failed: %s\n",
1171 gpg_strerror (err));
1172 gcry_cipher_close (hd);
1173 exit (1);
1174 }
1175
1176 err = gcry_cipher_encrypt (hd, &data, sizeof (data), &data, sizeof (data));
1177 if (err)
1178 {
1179 fprintf (stderr, PGM ": gcry_cipher_encrypt failed: %s\n",
1180 gpg_strerror (err));
1181 gcry_cipher_close (hd);
1182 exit (1);
1183 }
1184
1185 err = gcry_cipher_gettag (hd, tag, sizeof (tag));
1186 if (err)
1187 {
1188 fprintf (stderr, PGM ": gcry_cipher_gettag failed: %s\n",
1189 gpg_strerror (err));
1190 gcry_cipher_close (hd);
1191 exit (1);
1192 }
1193 }
1194
1195 static struct bench_ops ccm_encrypt_ops = {
1196 &bench_encrypt_init,
1197 &bench_encrypt_free,
1198 &bench_ccm_encrypt_do_bench
1199 };
1200
1201 static struct bench_ops ccm_decrypt_ops = {
1202 &bench_encrypt_init,
1203 &bench_encrypt_free,
1204 &bench_ccm_decrypt_do_bench
1205 };
1206
1207 static struct bench_ops ccm_authenticate_ops = {
1208 &bench_encrypt_init,
1209 &bench_encrypt_free,
1210 &bench_ccm_authenticate_do_bench
1211 };
1212
1213
1214 static void
bench_aead_encrypt_do_bench(struct bench_obj * obj,void * buf,size_t buflen,const char * nonce,size_t noncelen)1215 bench_aead_encrypt_do_bench (struct bench_obj *obj, void *buf, size_t buflen,
1216 const char *nonce, size_t noncelen)
1217 {
1218 gcry_cipher_hd_t hd = obj->hd;
1219 int err;
1220 char tag[16];
1221
1222 gcry_cipher_setiv (hd, nonce, noncelen);
1223
1224 gcry_cipher_final (hd);
1225 err = gcry_cipher_encrypt (hd, buf, buflen, buf, buflen);
1226 if (err)
1227 {
1228 fprintf (stderr, PGM ": gcry_cipher_encrypt failed: %s\n",
1229 gpg_strerror (err));
1230 gcry_cipher_close (hd);
1231 exit (1);
1232 }
1233
1234 err = gcry_cipher_gettag (hd, tag, sizeof (tag));
1235 if (err)
1236 {
1237 fprintf (stderr, PGM ": gcry_cipher_gettag failed: %s\n",
1238 gpg_strerror (err));
1239 gcry_cipher_close (hd);
1240 exit (1);
1241 }
1242 }
1243
1244 static void
bench_aead_decrypt_do_bench(struct bench_obj * obj,void * buf,size_t buflen,const char * nonce,size_t noncelen)1245 bench_aead_decrypt_do_bench (struct bench_obj *obj, void *buf, size_t buflen,
1246 const char *nonce, size_t noncelen)
1247 {
1248 gcry_cipher_hd_t hd = obj->hd;
1249 int err;
1250 char tag[16] = { 0, };
1251
1252 gcry_cipher_setiv (hd, nonce, noncelen);
1253
1254 gcry_cipher_final (hd);
1255 err = gcry_cipher_decrypt (hd, buf, buflen, buf, buflen);
1256 if (err)
1257 {
1258 fprintf (stderr, PGM ": gcry_cipher_encrypt failed: %s\n",
1259 gpg_strerror (err));
1260 gcry_cipher_close (hd);
1261 exit (1);
1262 }
1263
1264 err = gcry_cipher_checktag (hd, tag, sizeof (tag));
1265 if (gpg_err_code (err) == GPG_ERR_CHECKSUM)
1266 err = gpg_error (GPG_ERR_NO_ERROR);
1267 if (err)
1268 {
1269 fprintf (stderr, PGM ": gcry_cipher_gettag failed: %s\n",
1270 gpg_strerror (err));
1271 gcry_cipher_close (hd);
1272 exit (1);
1273 }
1274 }
1275
1276 static void
bench_aead_authenticate_do_bench(struct bench_obj * obj,void * buf,size_t buflen,const char * nonce,size_t noncelen)1277 bench_aead_authenticate_do_bench (struct bench_obj *obj, void *buf,
1278 size_t buflen, const char *nonce,
1279 size_t noncelen)
1280 {
1281 gcry_cipher_hd_t hd = obj->hd;
1282 int err;
1283 char tag[16] = { 0, };
1284 char data = 0xff;
1285
1286 err = gcry_cipher_setiv (hd, nonce, noncelen);
1287 if (err)
1288 {
1289 fprintf (stderr, PGM ": gcry_cipher_setiv failed: %s\n",
1290 gpg_strerror (err));
1291 gcry_cipher_close (hd);
1292 exit (1);
1293 }
1294
1295 err = gcry_cipher_authenticate (hd, buf, buflen);
1296 if (err)
1297 {
1298 fprintf (stderr, PGM ": gcry_cipher_authenticate failed: %s\n",
1299 gpg_strerror (err));
1300 gcry_cipher_close (hd);
1301 exit (1);
1302 }
1303
1304 gcry_cipher_final (hd);
1305 err = gcry_cipher_encrypt (hd, &data, sizeof (data), &data, sizeof (data));
1306 if (err)
1307 {
1308 fprintf (stderr, PGM ": gcry_cipher_encrypt failed: %s\n",
1309 gpg_strerror (err));
1310 gcry_cipher_close (hd);
1311 exit (1);
1312 }
1313
1314 err = gcry_cipher_gettag (hd, tag, sizeof (tag));
1315 if (err)
1316 {
1317 fprintf (stderr, PGM ": gcry_cipher_gettag failed: %s\n",
1318 gpg_strerror (err));
1319 gcry_cipher_close (hd);
1320 exit (1);
1321 }
1322 }
1323
1324
1325 static void
bench_gcm_encrypt_do_bench(struct bench_obj * obj,void * buf,size_t buflen)1326 bench_gcm_encrypt_do_bench (struct bench_obj *obj, void *buf,
1327 size_t buflen)
1328 {
1329 char nonce[12] = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce,
1330 0xdb, 0xad, 0xde, 0xca, 0xf8, 0x88 };
1331 bench_aead_encrypt_do_bench (obj, buf, buflen, nonce, sizeof(nonce));
1332 }
1333
1334 static void
bench_gcm_decrypt_do_bench(struct bench_obj * obj,void * buf,size_t buflen)1335 bench_gcm_decrypt_do_bench (struct bench_obj *obj, void *buf,
1336 size_t buflen)
1337 {
1338 char nonce[12] = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce,
1339 0xdb, 0xad, 0xde, 0xca, 0xf8, 0x88 };
1340 bench_aead_decrypt_do_bench (obj, buf, buflen, nonce, sizeof(nonce));
1341 }
1342
1343 static void
bench_gcm_authenticate_do_bench(struct bench_obj * obj,void * buf,size_t buflen)1344 bench_gcm_authenticate_do_bench (struct bench_obj *obj, void *buf,
1345 size_t buflen)
1346 {
1347 char nonce[12] = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce,
1348 0xdb, 0xad, 0xde, 0xca, 0xf8, 0x88 };
1349 bench_aead_authenticate_do_bench (obj, buf, buflen, nonce, sizeof(nonce));
1350 }
1351
1352 static struct bench_ops gcm_encrypt_ops = {
1353 &bench_encrypt_init,
1354 &bench_encrypt_free,
1355 &bench_gcm_encrypt_do_bench
1356 };
1357
1358 static struct bench_ops gcm_decrypt_ops = {
1359 &bench_encrypt_init,
1360 &bench_encrypt_free,
1361 &bench_gcm_decrypt_do_bench
1362 };
1363
1364 static struct bench_ops gcm_authenticate_ops = {
1365 &bench_encrypt_init,
1366 &bench_encrypt_free,
1367 &bench_gcm_authenticate_do_bench
1368 };
1369
1370
1371 static void
bench_ocb_encrypt_do_bench(struct bench_obj * obj,void * buf,size_t buflen)1372 bench_ocb_encrypt_do_bench (struct bench_obj *obj, void *buf,
1373 size_t buflen)
1374 {
1375 char nonce[15] = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce,
1376 0xdb, 0xad, 0xde, 0xca, 0xf8, 0x88,
1377 0x00, 0x00, 0x01 };
1378 bench_aead_encrypt_do_bench (obj, buf, buflen, nonce, sizeof(nonce));
1379 }
1380
1381 static void
bench_ocb_decrypt_do_bench(struct bench_obj * obj,void * buf,size_t buflen)1382 bench_ocb_decrypt_do_bench (struct bench_obj *obj, void *buf,
1383 size_t buflen)
1384 {
1385 char nonce[15] = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce,
1386 0xdb, 0xad, 0xde, 0xca, 0xf8, 0x88,
1387 0x00, 0x00, 0x01 };
1388 bench_aead_decrypt_do_bench (obj, buf, buflen, nonce, sizeof(nonce));
1389 }
1390
1391 static void
bench_ocb_authenticate_do_bench(struct bench_obj * obj,void * buf,size_t buflen)1392 bench_ocb_authenticate_do_bench (struct bench_obj *obj, void *buf,
1393 size_t buflen)
1394 {
1395 char nonce[15] = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce,
1396 0xdb, 0xad, 0xde, 0xca, 0xf8, 0x88,
1397 0x00, 0x00, 0x01 };
1398 bench_aead_authenticate_do_bench (obj, buf, buflen, nonce, sizeof(nonce));
1399 }
1400
1401 static struct bench_ops ocb_encrypt_ops = {
1402 &bench_encrypt_init,
1403 &bench_encrypt_free,
1404 &bench_ocb_encrypt_do_bench
1405 };
1406
1407 static struct bench_ops ocb_decrypt_ops = {
1408 &bench_encrypt_init,
1409 &bench_encrypt_free,
1410 &bench_ocb_decrypt_do_bench
1411 };
1412
1413 static struct bench_ops ocb_authenticate_ops = {
1414 &bench_encrypt_init,
1415 &bench_encrypt_free,
1416 &bench_ocb_authenticate_do_bench
1417 };
1418
1419 static void
bench_eax_encrypt_do_bench(struct bench_obj * obj,void * buf,size_t buflen)1420 bench_eax_encrypt_do_bench (struct bench_obj *obj, void *buf,
1421 size_t buflen)
1422 {
1423 char nonce[16] = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce,
1424 0xdb, 0xad, 0xde, 0xca, 0xf8, 0x88,
1425 0x00, 0x00, 0x01, 0x00 };
1426 bench_aead_encrypt_do_bench (obj, buf, buflen, nonce, sizeof(nonce));
1427 }
1428
1429 static void
bench_eax_decrypt_do_bench(struct bench_obj * obj,void * buf,size_t buflen)1430 bench_eax_decrypt_do_bench (struct bench_obj *obj, void *buf,
1431 size_t buflen)
1432 {
1433 char nonce[16] = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce,
1434 0xdb, 0xad, 0xde, 0xca, 0xf8, 0x88,
1435 0x00, 0x00, 0x01, 0x00 };
1436 bench_aead_decrypt_do_bench (obj, buf, buflen, nonce, sizeof(nonce));
1437 }
1438
1439 static void
bench_eax_authenticate_do_bench(struct bench_obj * obj,void * buf,size_t buflen)1440 bench_eax_authenticate_do_bench (struct bench_obj *obj, void *buf,
1441 size_t buflen)
1442 {
1443 char nonce[16] = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce,
1444 0xdb, 0xad, 0xde, 0xca, 0xf8, 0x88,
1445 0x00, 0x00, 0x01, 0x00 };
1446 bench_aead_authenticate_do_bench (obj, buf, buflen, nonce, sizeof(nonce));
1447 }
1448
1449 static struct bench_ops eax_encrypt_ops = {
1450 &bench_encrypt_init,
1451 &bench_encrypt_free,
1452 &bench_eax_encrypt_do_bench
1453 };
1454
1455 static struct bench_ops eax_decrypt_ops = {
1456 &bench_encrypt_init,
1457 &bench_encrypt_free,
1458 &bench_eax_decrypt_do_bench
1459 };
1460
1461 static struct bench_ops eax_authenticate_ops = {
1462 &bench_encrypt_init,
1463 &bench_encrypt_free,
1464 &bench_eax_authenticate_do_bench
1465 };
1466
1467 static void
bench_poly1305_encrypt_do_bench(struct bench_obj * obj,void * buf,size_t buflen)1468 bench_poly1305_encrypt_do_bench (struct bench_obj *obj, void *buf,
1469 size_t buflen)
1470 {
1471 char nonce[8] = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad };
1472 bench_aead_encrypt_do_bench (obj, buf, buflen, nonce, sizeof(nonce));
1473 }
1474
1475 static void
bench_poly1305_decrypt_do_bench(struct bench_obj * obj,void * buf,size_t buflen)1476 bench_poly1305_decrypt_do_bench (struct bench_obj *obj, void *buf,
1477 size_t buflen)
1478 {
1479 char nonce[8] = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad };
1480 bench_aead_decrypt_do_bench (obj, buf, buflen, nonce, sizeof(nonce));
1481 }
1482
1483 static void
bench_poly1305_authenticate_do_bench(struct bench_obj * obj,void * buf,size_t buflen)1484 bench_poly1305_authenticate_do_bench (struct bench_obj *obj, void *buf,
1485 size_t buflen)
1486 {
1487 char nonce[8] = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad };
1488 bench_aead_authenticate_do_bench (obj, buf, buflen, nonce, sizeof(nonce));
1489 }
1490
1491 static struct bench_ops poly1305_encrypt_ops = {
1492 &bench_encrypt_init,
1493 &bench_encrypt_free,
1494 &bench_poly1305_encrypt_do_bench
1495 };
1496
1497 static struct bench_ops poly1305_decrypt_ops = {
1498 &bench_encrypt_init,
1499 &bench_encrypt_free,
1500 &bench_poly1305_decrypt_do_bench
1501 };
1502
1503 static struct bench_ops poly1305_authenticate_ops = {
1504 &bench_encrypt_init,
1505 &bench_encrypt_free,
1506 &bench_poly1305_authenticate_do_bench
1507 };
1508
1509
1510 static struct bench_cipher_mode cipher_modes[] = {
1511 {GCRY_CIPHER_MODE_ECB, "ECB enc", &encrypt_ops},
1512 {GCRY_CIPHER_MODE_ECB, "ECB dec", &decrypt_ops},
1513 {GCRY_CIPHER_MODE_CBC, "CBC enc", &encrypt_ops},
1514 {GCRY_CIPHER_MODE_CBC, "CBC dec", &decrypt_ops},
1515 {GCRY_CIPHER_MODE_CFB, "CFB enc", &encrypt_ops},
1516 {GCRY_CIPHER_MODE_CFB, "CFB dec", &decrypt_ops},
1517 {GCRY_CIPHER_MODE_OFB, "OFB enc", &encrypt_ops},
1518 {GCRY_CIPHER_MODE_OFB, "OFB dec", &decrypt_ops},
1519 {GCRY_CIPHER_MODE_CTR, "CTR enc", &encrypt_ops},
1520 {GCRY_CIPHER_MODE_CTR, "CTR dec", &decrypt_ops},
1521 {GCRY_CIPHER_MODE_XTS, "XTS enc", &xts_encrypt_ops},
1522 {GCRY_CIPHER_MODE_XTS, "XTS dec", &xts_decrypt_ops},
1523 {GCRY_CIPHER_MODE_CCM, "CCM enc", &ccm_encrypt_ops},
1524 {GCRY_CIPHER_MODE_CCM, "CCM dec", &ccm_decrypt_ops},
1525 {GCRY_CIPHER_MODE_CCM, "CCM auth", &ccm_authenticate_ops},
1526 {GCRY_CIPHER_MODE_EAX, "EAX enc", &eax_encrypt_ops},
1527 {GCRY_CIPHER_MODE_EAX, "EAX dec", &eax_decrypt_ops},
1528 {GCRY_CIPHER_MODE_EAX, "EAX auth", &eax_authenticate_ops},
1529 {GCRY_CIPHER_MODE_GCM, "GCM enc", &gcm_encrypt_ops},
1530 {GCRY_CIPHER_MODE_GCM, "GCM dec", &gcm_decrypt_ops},
1531 {GCRY_CIPHER_MODE_GCM, "GCM auth", &gcm_authenticate_ops},
1532 {GCRY_CIPHER_MODE_OCB, "OCB enc", &ocb_encrypt_ops},
1533 {GCRY_CIPHER_MODE_OCB, "OCB dec", &ocb_decrypt_ops},
1534 {GCRY_CIPHER_MODE_OCB, "OCB auth", &ocb_authenticate_ops},
1535 {GCRY_CIPHER_MODE_POLY1305, "POLY1305 enc", &poly1305_encrypt_ops},
1536 {GCRY_CIPHER_MODE_POLY1305, "POLY1305 dec", &poly1305_decrypt_ops},
1537 {GCRY_CIPHER_MODE_POLY1305, "POLY1305 auth", &poly1305_authenticate_ops},
1538 {0},
1539 };
1540
1541
1542 static void
cipher_bench_one(int algo,struct bench_cipher_mode * pmode)1543 cipher_bench_one (int algo, struct bench_cipher_mode *pmode)
1544 {
1545 struct bench_cipher_mode mode = *pmode;
1546 struct bench_obj obj = { 0 };
1547 double result;
1548 unsigned int blklen;
1549
1550 mode.algo = algo;
1551
1552 /* Check if this mode is ok */
1553 blklen = gcry_cipher_get_algo_blklen (algo);
1554 if (!blklen)
1555 return;
1556
1557 /* Stream cipher? Only test with "ECB" and POLY1305. */
1558 if (blklen == 1 && (mode.mode != GCRY_CIPHER_MODE_ECB &&
1559 mode.mode != GCRY_CIPHER_MODE_POLY1305))
1560 return;
1561 if (blklen == 1 && mode.mode == GCRY_CIPHER_MODE_ECB)
1562 {
1563 mode.mode = GCRY_CIPHER_MODE_STREAM;
1564 mode.name = mode.ops == &encrypt_ops ? "STREAM enc" : "STREAM dec";
1565 }
1566
1567 /* Poly1305 has restriction for cipher algorithm */
1568 if (mode.mode == GCRY_CIPHER_MODE_POLY1305 && algo != GCRY_CIPHER_CHACHA20)
1569 return;
1570
1571 /* CCM has restrictions for block-size */
1572 if (mode.mode == GCRY_CIPHER_MODE_CCM && blklen != GCRY_CCM_BLOCK_LEN)
1573 return;
1574
1575 /* GCM has restrictions for block-size */
1576 if (mode.mode == GCRY_CIPHER_MODE_GCM && blklen != GCRY_GCM_BLOCK_LEN)
1577 return;
1578
1579 /* XTS has restrictions for block-size */
1580 if (mode.mode == GCRY_CIPHER_MODE_XTS && blklen != GCRY_XTS_BLOCK_LEN)
1581 return;
1582
1583 /* Our OCB implementation has restrictions for block-size. */
1584 if (mode.mode == GCRY_CIPHER_MODE_OCB && blklen != GCRY_OCB_BLOCK_LEN)
1585 return;
1586
1587 bench_print_mode (14, mode.name);
1588
1589 obj.ops = mode.ops;
1590 obj.priv = &mode;
1591
1592 result = do_slope_benchmark (&obj);
1593
1594 bench_print_result (result);
1595 }
1596
1597
1598 static void
_cipher_bench(int algo)1599 _cipher_bench (int algo)
1600 {
1601 const char *algoname;
1602 int i;
1603
1604 algoname = gcry_cipher_algo_name (algo);
1605
1606 bench_print_header (14, algoname);
1607
1608 for (i = 0; cipher_modes[i].mode; i++)
1609 cipher_bench_one (algo, &cipher_modes[i]);
1610
1611 bench_print_footer (14);
1612 }
1613
1614
1615 void
cipher_bench(char ** argv,int argc)1616 cipher_bench (char **argv, int argc)
1617 {
1618 int i, algo;
1619
1620 bench_print_section ("cipher", "Cipher");
1621
1622 if (argv && argc)
1623 {
1624 for (i = 0; i < argc; i++)
1625 {
1626 algo = gcry_cipher_map_name (argv[i]);
1627 if (algo)
1628 _cipher_bench (algo);
1629 }
1630 }
1631 else
1632 {
1633 for (i = 1; i < 400; i++)
1634 if (!gcry_cipher_test_algo (i))
1635 _cipher_bench (i);
1636 }
1637 }
1638
1639
1640 /*********************************************************** Hash benchmarks. */
1641
1642 struct bench_hash_mode
1643 {
1644 const char *name;
1645 struct bench_ops *ops;
1646
1647 int algo;
1648 };
1649
1650
1651 static int
bench_hash_init(struct bench_obj * obj)1652 bench_hash_init (struct bench_obj *obj)
1653 {
1654 struct bench_hash_mode *mode = obj->priv;
1655 gcry_md_hd_t hd;
1656 int err;
1657
1658 obj->min_bufsize = BUF_START_SIZE;
1659 obj->max_bufsize = BUF_END_SIZE;
1660 obj->step_size = BUF_STEP_SIZE;
1661 obj->num_measure_repetitions = num_measurement_repetitions;
1662
1663 err = gcry_md_open (&hd, mode->algo, 0);
1664 if (err)
1665 {
1666 fprintf (stderr, PGM ": error opening hash `%s'\n",
1667 gcry_md_algo_name (mode->algo));
1668 exit (1);
1669 }
1670
1671 obj->hd = hd;
1672
1673 return 0;
1674 }
1675
1676 static void
bench_hash_free(struct bench_obj * obj)1677 bench_hash_free (struct bench_obj *obj)
1678 {
1679 gcry_md_hd_t hd = obj->hd;
1680
1681 gcry_md_close (hd);
1682 }
1683
1684 static void
bench_hash_do_bench(struct bench_obj * obj,void * buf,size_t buflen)1685 bench_hash_do_bench (struct bench_obj *obj, void *buf, size_t buflen)
1686 {
1687 gcry_md_hd_t hd = obj->hd;
1688
1689 gcry_md_reset (hd);
1690 gcry_md_write (hd, buf, buflen);
1691 gcry_md_final (hd);
1692 }
1693
1694 static struct bench_ops hash_ops = {
1695 &bench_hash_init,
1696 &bench_hash_free,
1697 &bench_hash_do_bench
1698 };
1699
1700
1701 static struct bench_hash_mode hash_modes[] = {
1702 {"", &hash_ops},
1703 {0},
1704 };
1705
1706
1707 static void
hash_bench_one(int algo,struct bench_hash_mode * pmode)1708 hash_bench_one (int algo, struct bench_hash_mode *pmode)
1709 {
1710 struct bench_hash_mode mode = *pmode;
1711 struct bench_obj obj = { 0 };
1712 double result;
1713
1714 mode.algo = algo;
1715
1716 if (mode.name[0] == '\0')
1717 bench_print_algo (-14, gcry_md_algo_name (algo));
1718 else
1719 bench_print_algo (14, mode.name);
1720
1721 obj.ops = mode.ops;
1722 obj.priv = &mode;
1723
1724 result = do_slope_benchmark (&obj);
1725
1726 bench_print_result (result);
1727 }
1728
1729 static void
_hash_bench(int algo)1730 _hash_bench (int algo)
1731 {
1732 int i;
1733
1734 for (i = 0; hash_modes[i].name; i++)
1735 hash_bench_one (algo, &hash_modes[i]);
1736 }
1737
1738 void
hash_bench(char ** argv,int argc)1739 hash_bench (char **argv, int argc)
1740 {
1741 int i, algo;
1742
1743 bench_print_section ("hash", "Hash");
1744 bench_print_header (14, "");
1745
1746 if (argv && argc)
1747 {
1748 for (i = 0; i < argc; i++)
1749 {
1750 algo = gcry_md_map_name (argv[i]);
1751 if (algo)
1752 _hash_bench (algo);
1753 }
1754 }
1755 else
1756 {
1757 for (i = 1; i < 400; i++)
1758 if (!gcry_md_test_algo (i))
1759 _hash_bench (i);
1760 }
1761
1762 bench_print_footer (14);
1763 }
1764
1765
1766 /************************************************************ MAC benchmarks. */
1767
1768 struct bench_mac_mode
1769 {
1770 const char *name;
1771 struct bench_ops *ops;
1772
1773 int algo;
1774 };
1775
1776
1777 static int
bench_mac_init(struct bench_obj * obj)1778 bench_mac_init (struct bench_obj *obj)
1779 {
1780 struct bench_mac_mode *mode = obj->priv;
1781 gcry_mac_hd_t hd;
1782 int err;
1783 unsigned int keylen;
1784 void *key;
1785
1786 obj->min_bufsize = BUF_START_SIZE;
1787 obj->max_bufsize = BUF_END_SIZE;
1788 obj->step_size = BUF_STEP_SIZE;
1789 obj->num_measure_repetitions = num_measurement_repetitions;
1790
1791 keylen = gcry_mac_get_algo_keylen (mode->algo);
1792 if (keylen == 0)
1793 keylen = 32;
1794 key = malloc (keylen);
1795 if (!key)
1796 {
1797 fprintf (stderr, PGM ": couldn't allocate %d bytes\n", keylen);
1798 exit (1);
1799 }
1800 memset(key, 42, keylen);
1801
1802 err = gcry_mac_open (&hd, mode->algo, 0, NULL);
1803 if (err)
1804 {
1805 fprintf (stderr, PGM ": error opening mac `%s'\n",
1806 gcry_mac_algo_name (mode->algo));
1807 free (key);
1808 exit (1);
1809 }
1810
1811 err = gcry_mac_setkey (hd, key, keylen);
1812 if (err)
1813 {
1814 fprintf (stderr, PGM ": error setting key for mac `%s'\n",
1815 gcry_mac_algo_name (mode->algo));
1816 free (key);
1817 exit (1);
1818 }
1819
1820 switch (mode->algo)
1821 {
1822 default:
1823 break;
1824 case GCRY_MAC_POLY1305_AES:
1825 case GCRY_MAC_POLY1305_CAMELLIA:
1826 case GCRY_MAC_POLY1305_TWOFISH:
1827 case GCRY_MAC_POLY1305_SERPENT:
1828 case GCRY_MAC_POLY1305_SEED:
1829 gcry_mac_setiv (hd, key, 16);
1830 break;
1831 }
1832
1833 obj->hd = hd;
1834
1835 free (key);
1836 return 0;
1837 }
1838
1839 static void
bench_mac_free(struct bench_obj * obj)1840 bench_mac_free (struct bench_obj *obj)
1841 {
1842 gcry_mac_hd_t hd = obj->hd;
1843
1844 gcry_mac_close (hd);
1845 }
1846
1847 static void
bench_mac_do_bench(struct bench_obj * obj,void * buf,size_t buflen)1848 bench_mac_do_bench (struct bench_obj *obj, void *buf, size_t buflen)
1849 {
1850 gcry_mac_hd_t hd = obj->hd;
1851 size_t bs;
1852 char b;
1853
1854 gcry_mac_reset (hd);
1855 gcry_mac_write (hd, buf, buflen);
1856 bs = sizeof(b);
1857 gcry_mac_read (hd, &b, &bs);
1858 }
1859
1860 static struct bench_ops mac_ops = {
1861 &bench_mac_init,
1862 &bench_mac_free,
1863 &bench_mac_do_bench
1864 };
1865
1866
1867 static struct bench_mac_mode mac_modes[] = {
1868 {"", &mac_ops},
1869 {0},
1870 };
1871
1872
1873 static void
mac_bench_one(int algo,struct bench_mac_mode * pmode)1874 mac_bench_one (int algo, struct bench_mac_mode *pmode)
1875 {
1876 struct bench_mac_mode mode = *pmode;
1877 struct bench_obj obj = { 0 };
1878 double result;
1879
1880 mode.algo = algo;
1881
1882 if (mode.name[0] == '\0')
1883 bench_print_algo (-18, gcry_mac_algo_name (algo));
1884 else
1885 bench_print_algo (18, mode.name);
1886
1887 obj.ops = mode.ops;
1888 obj.priv = &mode;
1889
1890 result = do_slope_benchmark (&obj);
1891
1892 bench_print_result (result);
1893 }
1894
1895 static void
_mac_bench(int algo)1896 _mac_bench (int algo)
1897 {
1898 int i;
1899
1900 for (i = 0; mac_modes[i].name; i++)
1901 mac_bench_one (algo, &mac_modes[i]);
1902 }
1903
1904 void
mac_bench(char ** argv,int argc)1905 mac_bench (char **argv, int argc)
1906 {
1907 int i, algo;
1908
1909 bench_print_section ("mac", "MAC");
1910 bench_print_header (18, "");
1911
1912 if (argv && argc)
1913 {
1914 for (i = 0; i < argc; i++)
1915 {
1916 algo = gcry_mac_map_name (argv[i]);
1917 if (algo)
1918 _mac_bench (algo);
1919 }
1920 }
1921 else
1922 {
1923 for (i = 1; i < 600; i++)
1924 if (!gcry_mac_test_algo (i))
1925 _mac_bench (i);
1926 }
1927
1928 bench_print_footer (18);
1929 }
1930
1931
1932 /************************************************************ KDF benchmarks. */
1933
1934 struct bench_kdf_mode
1935 {
1936 struct bench_ops *ops;
1937
1938 int algo;
1939 int subalgo;
1940 };
1941
1942
1943 static int
bench_kdf_init(struct bench_obj * obj)1944 bench_kdf_init (struct bench_obj *obj)
1945 {
1946 struct bench_kdf_mode *mode = obj->priv;
1947
1948 if (mode->algo == GCRY_KDF_PBKDF2)
1949 {
1950 obj->min_bufsize = 2;
1951 obj->max_bufsize = 2 * 32;
1952 obj->step_size = 2;
1953 }
1954
1955 obj->num_measure_repetitions = num_measurement_repetitions;
1956
1957 return 0;
1958 }
1959
1960 static void
bench_kdf_free(struct bench_obj * obj)1961 bench_kdf_free (struct bench_obj *obj)
1962 {
1963 (void)obj;
1964 }
1965
1966 static void
bench_kdf_do_bench(struct bench_obj * obj,void * buf,size_t buflen)1967 bench_kdf_do_bench (struct bench_obj *obj, void *buf, size_t buflen)
1968 {
1969 struct bench_kdf_mode *mode = obj->priv;
1970 char keybuf[16];
1971
1972 (void)buf;
1973
1974 if (mode->algo == GCRY_KDF_PBKDF2)
1975 {
1976 gcry_kdf_derive("qwerty", 6, mode->algo, mode->subalgo, "01234567", 8,
1977 buflen, sizeof(keybuf), keybuf);
1978 }
1979 }
1980
1981 static struct bench_ops kdf_ops = {
1982 &bench_kdf_init,
1983 &bench_kdf_free,
1984 &bench_kdf_do_bench
1985 };
1986
1987
1988 static void
kdf_bench_one(int algo,int subalgo)1989 kdf_bench_one (int algo, int subalgo)
1990 {
1991 struct bench_kdf_mode mode = { &kdf_ops };
1992 struct bench_obj obj = { 0 };
1993 double nsecs_per_iteration;
1994 double cycles_per_iteration;
1995 char algo_name[32];
1996 char nsecpiter_buf[16];
1997 char cpiter_buf[16];
1998 char mhz_buf[16];
1999
2000 mode.algo = algo;
2001 mode.subalgo = subalgo;
2002
2003 switch (subalgo)
2004 {
2005 case GCRY_MD_CRC32:
2006 case GCRY_MD_CRC32_RFC1510:
2007 case GCRY_MD_CRC24_RFC2440:
2008 case GCRY_MD_MD4:
2009 /* Skip CRC32s. */
2010 return;
2011 }
2012
2013 if (gcry_md_get_algo_dlen (subalgo) == 0)
2014 {
2015 /* Skip XOFs */
2016 return;
2017 }
2018
2019 *algo_name = 0;
2020
2021 if (algo == GCRY_KDF_PBKDF2)
2022 {
2023 snprintf (algo_name, sizeof(algo_name), "PBKDF2-HMAC-%s",
2024 gcry_md_algo_name (subalgo));
2025 }
2026
2027 bench_print_algo (-24, algo_name);
2028
2029 obj.ops = mode.ops;
2030 obj.priv = &mode;
2031
2032 nsecs_per_iteration = do_slope_benchmark (&obj);
2033
2034 strcpy(cpiter_buf, csv_mode ? "" : "-");
2035 strcpy(mhz_buf, csv_mode ? "" : "-");
2036
2037 double_to_str (nsecpiter_buf, sizeof (nsecpiter_buf), nsecs_per_iteration);
2038
2039 /* If user didn't provide CPU speed, we cannot show cycles/iter results. */
2040 if (bench_ghz > 0.0)
2041 {
2042 cycles_per_iteration = nsecs_per_iteration * bench_ghz;
2043 double_to_str (cpiter_buf, sizeof (cpiter_buf), cycles_per_iteration);
2044 double_to_str (mhz_buf, sizeof (mhz_buf), bench_ghz * 1000);
2045 }
2046
2047 if (csv_mode)
2048 {
2049 if (auto_ghz)
2050 printf ("%s,%s,%s,,,,,,,,,%s,ns/iter,%s,c/iter,%s,Mhz\n",
2051 current_section_name,
2052 current_algo_name ? current_algo_name : "",
2053 current_mode_name ? current_mode_name : "",
2054 nsecpiter_buf,
2055 cpiter_buf,
2056 mhz_buf);
2057 else
2058 printf ("%s,%s,%s,,,,,,,,,%s,ns/iter,%s,c/iter\n",
2059 current_section_name,
2060 current_algo_name ? current_algo_name : "",
2061 current_mode_name ? current_mode_name : "",
2062 nsecpiter_buf,
2063 cpiter_buf);
2064 }
2065 else
2066 {
2067 if (auto_ghz)
2068 printf ("%14s %13s %9s\n", nsecpiter_buf, cpiter_buf, mhz_buf);
2069 else
2070 printf ("%14s %13s\n", nsecpiter_buf, cpiter_buf);
2071 }
2072 }
2073
2074 void
kdf_bench(char ** argv,int argc)2075 kdf_bench (char **argv, int argc)
2076 {
2077 char algo_name[32];
2078 int i, j;
2079
2080 bench_print_section ("kdf", "KDF");
2081
2082 if (!csv_mode)
2083 {
2084 printf (" %-*s | ", 24, "");
2085 if (auto_ghz)
2086 printf ("%14s %13s %9s\n", "nanosecs/iter", "cycles/iter", "auto Mhz");
2087 else
2088 printf ("%14s %13s\n", "nanosecs/iter", "cycles/iter");
2089 }
2090
2091 if (argv && argc)
2092 {
2093 for (i = 0; i < argc; i++)
2094 {
2095 for (j = 1; j < 400; j++)
2096 {
2097 if (gcry_md_test_algo (j))
2098 continue;
2099
2100 snprintf (algo_name, sizeof(algo_name), "PBKDF2-HMAC-%s",
2101 gcry_md_algo_name (j));
2102
2103 if (!strcmp(argv[i], algo_name))
2104 kdf_bench_one (GCRY_KDF_PBKDF2, j);
2105 }
2106 }
2107 }
2108 else
2109 {
2110 for (i = 1; i < 400; i++)
2111 if (!gcry_md_test_algo (i))
2112 kdf_bench_one (GCRY_KDF_PBKDF2, i);
2113 }
2114
2115 bench_print_footer (24);
2116 }
2117
2118
2119 /************************************************************** Main program. */
2120
2121 void
print_help(void)2122 print_help (void)
2123 {
2124 static const char *help_lines[] = {
2125 "usage: bench-slope [options] [hash|mac|cipher|kdf [algonames]]",
2126 "",
2127 " options:",
2128 " --cpu-mhz <mhz> Set CPU speed for calculating cycles",
2129 " per bytes results. Set as \"auto\"",
2130 " for auto-detection of CPU speed.",
2131 " --disable-hwf <features> Disable hardware acceleration feature(s)",
2132 " for benchmarking.",
2133 " --repetitions <n> Use N repetitions (default "
2134 STR2(NUM_MEASUREMENT_REPETITIONS) ")",
2135 " --unaligned Use unaligned input buffers.",
2136 " --csv Use CSV output format",
2137 NULL
2138 };
2139 const char **line;
2140
2141 for (line = help_lines; *line; line++)
2142 fprintf (stdout, "%s\n", *line);
2143 }
2144
2145
2146 /* Warm up CPU. */
2147 static void
warm_up_cpu(void)2148 warm_up_cpu (void)
2149 {
2150 struct nsec_time start, end;
2151
2152 get_nsec_time (&start);
2153 do
2154 {
2155 get_nsec_time (&end);
2156 }
2157 while (get_time_nsec_diff (&start, &end) < 1000.0 * 1000.0 * 1000.0);
2158 }
2159
2160
2161 int
main(int argc,char ** argv)2162 main (int argc, char **argv)
2163 {
2164 int last_argc = -1;
2165
2166 if (argc)
2167 {
2168 argc--;
2169 argv++;
2170 }
2171
2172 /* We skip this test if we are running under the test suite (no args
2173 and srcdir defined) and GCRYPT_NO_BENCHMARKS is set. */
2174 if (!argc && getenv ("srcdir") && getenv ("GCRYPT_NO_BENCHMARKS"))
2175 exit (77);
2176
2177 if (getenv ("GCRYPT_IN_REGRESSION_TEST"))
2178 {
2179 in_regression_test = 1;
2180 num_measurement_repetitions = 2;
2181 }
2182 else
2183 num_measurement_repetitions = NUM_MEASUREMENT_REPETITIONS;
2184
2185 while (argc && last_argc != argc)
2186 {
2187 last_argc = argc;
2188
2189 if (!strcmp (*argv, "--"))
2190 {
2191 argc--;
2192 argv++;
2193 break;
2194 }
2195 else if (!strcmp (*argv, "--help"))
2196 {
2197 print_help ();
2198 exit (0);
2199 }
2200 else if (!strcmp (*argv, "--verbose"))
2201 {
2202 verbose++;
2203 argc--;
2204 argv++;
2205 }
2206 else if (!strcmp (*argv, "--debug"))
2207 {
2208 verbose += 2;
2209 debug++;
2210 argc--;
2211 argv++;
2212 }
2213 else if (!strcmp (*argv, "--csv"))
2214 {
2215 csv_mode = 1;
2216 argc--;
2217 argv++;
2218 }
2219 else if (!strcmp (*argv, "--unaligned"))
2220 {
2221 unaligned_mode = 1;
2222 argc--;
2223 argv++;
2224 }
2225 else if (!strcmp (*argv, "--disable-hwf"))
2226 {
2227 argc--;
2228 argv++;
2229 if (argc)
2230 {
2231 if (gcry_control (GCRYCTL_DISABLE_HWF, *argv, NULL))
2232 fprintf (stderr,
2233 PGM
2234 ": unknown hardware feature `%s' - option ignored\n",
2235 *argv);
2236 argc--;
2237 argv++;
2238 }
2239 }
2240 else if (!strcmp (*argv, "--cpu-mhz"))
2241 {
2242 argc--;
2243 argv++;
2244 if (argc)
2245 {
2246 if (!strcmp (*argv, "auto"))
2247 {
2248 auto_ghz = 1;
2249 }
2250 else
2251 {
2252 cpu_ghz = atof (*argv);
2253 cpu_ghz /= 1000; /* Mhz => Ghz */
2254 }
2255
2256 argc--;
2257 argv++;
2258 }
2259 }
2260 else if (!strcmp (*argv, "--repetitions"))
2261 {
2262 argc--;
2263 argv++;
2264 if (argc)
2265 {
2266 num_measurement_repetitions = atof (*argv);
2267 if (num_measurement_repetitions < 2)
2268 {
2269 fprintf (stderr,
2270 PGM
2271 ": value for --repetitions too small - using %d\n",
2272 NUM_MEASUREMENT_REPETITIONS);
2273 num_measurement_repetitions = NUM_MEASUREMENT_REPETITIONS;
2274 }
2275 argc--;
2276 argv++;
2277 }
2278 }
2279 }
2280
2281 xgcry_control ((GCRYCTL_SET_VERBOSITY, (int) verbose));
2282
2283 if (!gcry_check_version (GCRYPT_VERSION))
2284 {
2285 fprintf (stderr, PGM ": version mismatch; pgm=%s, library=%s\n",
2286 GCRYPT_VERSION, gcry_check_version (NULL));
2287 exit (1);
2288 }
2289
2290 if (debug)
2291 xgcry_control ((GCRYCTL_SET_DEBUG_FLAGS, 1u, 0));
2292
2293 xgcry_control ((GCRYCTL_DISABLE_SECMEM, 0));
2294 xgcry_control ((GCRYCTL_INITIALIZATION_FINISHED, 0));
2295 xgcry_control ((GCRYCTL_ENABLE_QUICK_RANDOM, 0));
2296
2297 if (in_regression_test)
2298 fputs ("Note: " PGM " running in quick regression test mode.\n", stdout);
2299
2300 if (!argc)
2301 {
2302 warm_up_cpu ();
2303 hash_bench (NULL, 0);
2304 mac_bench (NULL, 0);
2305 cipher_bench (NULL, 0);
2306 kdf_bench (NULL, 0);
2307 }
2308 else if (!strcmp (*argv, "hash"))
2309 {
2310 argc--;
2311 argv++;
2312
2313 warm_up_cpu ();
2314 hash_bench ((argc == 0) ? NULL : argv, argc);
2315 }
2316 else if (!strcmp (*argv, "mac"))
2317 {
2318 argc--;
2319 argv++;
2320
2321 warm_up_cpu ();
2322 mac_bench ((argc == 0) ? NULL : argv, argc);
2323 }
2324 else if (!strcmp (*argv, "cipher"))
2325 {
2326 argc--;
2327 argv++;
2328
2329 warm_up_cpu ();
2330 cipher_bench ((argc == 0) ? NULL : argv, argc);
2331 }
2332 else if (!strcmp (*argv, "kdf"))
2333 {
2334 argc--;
2335 argv++;
2336
2337 warm_up_cpu ();
2338 kdf_bench ((argc == 0) ? NULL : argv, argc);
2339 }
2340 else
2341 {
2342 fprintf (stderr, PGM ": unknown argument: %s\n", *argv);
2343 print_help ();
2344 }
2345
2346 return 0;
2347 }
2348
2349 #endif /* !NO_GET_NSEC_TIME */
2350