Line data Source code
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 : /* Whether we are running as part of the regression test suite. */
54 : static int in_regression_test;
55 :
56 : /* The name of the currently printed section. */
57 : static char *current_section_name;
58 : /* The name of the currently printed algorithm. */
59 : static char *current_algo_name;
60 : /* The name of the currently printed mode. */
61 : static char *current_mode_name;
62 :
63 :
64 : /*************************************** Default parameters for measurements. */
65 :
66 : /* Start at small buffer size, to get reasonable timer calibration for fast
67 : * implementations (AES-NI etc). Sixteen selected to support the largest block
68 : * size of current set cipher blocks. */
69 : #define BUF_START_SIZE 16
70 :
71 : /* From ~0 to ~4kbytes give comparable results with results from academia
72 : * (SUPERCOP). */
73 : #define BUF_END_SIZE (BUF_START_SIZE + 4096)
74 :
75 : /* With 128 byte steps, we get (4096)/64 = 64 data points. */
76 : #define BUF_STEP_SIZE 64
77 :
78 : /* Number of repeated measurements at each data point. The median of these
79 : * measurements is selected as data point further analysis. */
80 : #define NUM_MEASUREMENT_REPETITIONS 64
81 :
82 : /**************************************************** High-resolution timers. */
83 :
84 : /* This benchmarking module needs needs high resolution timer. */
85 : #undef NO_GET_NSEC_TIME
86 : #if defined(_WIN32)
87 : struct nsec_time
88 : {
89 : LARGE_INTEGER perf_count;
90 : };
91 :
92 : static void
93 : get_nsec_time (struct nsec_time *t)
94 : {
95 : BOOL ok;
96 :
97 : ok = QueryPerformanceCounter (&t->perf_count);
98 : assert (ok);
99 : }
100 :
101 : static double
102 : get_time_nsec_diff (struct nsec_time *start, struct nsec_time *end)
103 : {
104 : static double nsecs_per_count = 0.0;
105 : double nsecs;
106 :
107 : if (nsecs_per_count == 0.0)
108 : {
109 : LARGE_INTEGER perf_freq;
110 : BOOL ok;
111 :
112 : /* Get counts per second. */
113 : ok = QueryPerformanceFrequency (&perf_freq);
114 : assert (ok);
115 :
116 : nsecs_per_count = 1.0 / perf_freq.QuadPart;
117 : nsecs_per_count *= 1000000.0 * 1000.0; /* sec => nsec */
118 :
119 : assert (nsecs_per_count > 0.0);
120 : }
121 :
122 : nsecs = end->perf_count.QuadPart - start->perf_count.QuadPart; /* counts */
123 : nsecs *= nsecs_per_count; /* counts * (nsecs / count) => nsecs */
124 :
125 : return nsecs;
126 : }
127 : #elif defined(HAVE_CLOCK_GETTIME)
128 : struct nsec_time
129 : {
130 : struct timespec ts;
131 : };
132 :
133 : static void
134 28197130 : get_nsec_time (struct nsec_time *t)
135 : {
136 : int err;
137 :
138 28197130 : err = clock_gettime (CLOCK_REALTIME, &t->ts);
139 28197130 : assert (err == 0);
140 28197130 : }
141 :
142 : static double
143 28140783 : get_time_nsec_diff (struct nsec_time *start, struct nsec_time *end)
144 : {
145 : double nsecs;
146 :
147 28140783 : nsecs = end->ts.tv_sec - start->ts.tv_sec;
148 28140783 : nsecs *= 1000000.0 * 1000.0; /* sec => nsec */
149 :
150 : /* This way we don't have to care if tv_nsec unsigned or signed. */
151 28140783 : if (end->ts.tv_nsec >= start->ts.tv_nsec)
152 23251882 : nsecs += end->ts.tv_nsec - start->ts.tv_nsec;
153 : else
154 4888901 : nsecs -= start->ts.tv_nsec - end->ts.tv_nsec;
155 :
156 28140783 : return nsecs;
157 : }
158 : #elif defined(HAVE_GETTIMEOFDAY)
159 : struct nsec_time
160 : {
161 : struct timeval tv;
162 : };
163 :
164 : static void
165 : get_nsec_time (struct nsec_time *t)
166 : {
167 : int err;
168 :
169 : err = gettimeofday (&t->tv, NULL);
170 : assert (err == 0);
171 : }
172 :
173 : static double
174 : get_time_nsec_diff (struct nsec_time *start, struct nsec_time *end)
175 : {
176 : double nsecs;
177 :
178 : nsecs = end->tv.tv_sec - start->tv.tv_sec;
179 : nsecs *= 1000000; /* sec => µsec */
180 :
181 : /* This way we don't have to care if tv_usec unsigned or signed. */
182 : if (end->tv.tv_usec >= start->tv.tv_usec)
183 : nsecs += end->tv.tv_usec - start->tv.tv_usec;
184 : else
185 : nsecs -= start->tv.tv_usec - end->tv.tv_usec;
186 :
187 : nsecs *= 1000; /* µsec => nsec */
188 :
189 : return nsecs;
190 : }
191 : #else
192 : #define NO_GET_NSEC_TIME 1
193 : #endif
194 :
195 :
196 : /* If no high resolution timer found, provide dummy bench-slope. */
197 : #ifdef NO_GET_NSEC_TIME
198 :
199 :
200 : int
201 : main (void)
202 : {
203 : /* No nsec timer => SKIP test. */
204 : return 77;
205 : }
206 :
207 :
208 : #else /* !NO_GET_NSEC_TIME */
209 :
210 :
211 : /********************************************** Slope benchmarking framework. */
212 :
213 : struct bench_obj
214 : {
215 : const struct bench_ops *ops;
216 :
217 : unsigned int num_measure_repetitions;
218 : unsigned int min_bufsize;
219 : unsigned int max_bufsize;
220 : unsigned int step_size;
221 :
222 : void *priv;
223 : };
224 :
225 : typedef int (*const bench_initialize_t) (struct bench_obj * obj);
226 : typedef void (*const bench_finalize_t) (struct bench_obj * obj);
227 : typedef void (*const bench_do_run_t) (struct bench_obj * obj, void *buffer,
228 : size_t buflen);
229 :
230 : struct bench_ops
231 : {
232 : bench_initialize_t initialize;
233 : bench_finalize_t finalize;
234 : bench_do_run_t do_run;
235 : };
236 :
237 :
238 : double
239 402 : get_slope (double (*const get_x) (unsigned int idx, void *priv),
240 : void *get_x_priv, double y_points[], unsigned int npoints,
241 : double *overhead)
242 : {
243 : double sumx, sumy, sumx2, sumy2, sumxy;
244 : unsigned int i;
245 : double b, a;
246 :
247 402 : sumx = sumy = sumx2 = sumy2 = sumxy = 0;
248 :
249 25905 : for (i = 0; i < npoints; i++)
250 : {
251 : double x, y;
252 :
253 25503 : x = get_x (i, get_x_priv); /* bytes */
254 25503 : y = y_points[i]; /* nsecs */
255 :
256 25503 : sumx += x;
257 25503 : sumy += y;
258 25503 : sumx2 += x * x;
259 : /*sumy2 += y * y;*/
260 25503 : sumxy += x * y;
261 : }
262 :
263 402 : b = (npoints * sumxy - sumx * sumy) / (npoints * sumx2 - sumx * sumx);
264 402 : a = (sumy - b * sumx) / npoints;
265 :
266 402 : if (overhead)
267 402 : *overhead = a; /* nsecs */
268 :
269 402 : return b; /* nsecs per byte */
270 : }
271 :
272 :
273 : double
274 25503 : get_bench_obj_point_x (unsigned int idx, void *priv)
275 : {
276 25503 : struct bench_obj *obj = priv;
277 25503 : return (double) (obj->min_bufsize + (idx * obj->step_size));
278 : }
279 :
280 :
281 : unsigned int
282 402 : get_num_measurements (struct bench_obj *obj)
283 : {
284 402 : unsigned int buf_range = obj->max_bufsize - obj->min_bufsize;
285 402 : unsigned int num = buf_range / obj->step_size + 1;
286 :
287 1206 : while (obj->min_bufsize + (num * obj->step_size) > obj->max_bufsize)
288 402 : num--;
289 :
290 402 : return num + 1;
291 : }
292 :
293 :
294 : static int
295 28173 : double_cmp (const void *_a, const void *_b)
296 : {
297 : const double *a, *b;
298 :
299 28173 : a = _a;
300 28173 : b = _b;
301 :
302 28173 : if (*a > *b)
303 16780 : return 1;
304 11393 : if (*a < *b)
305 11308 : return -1;
306 85 : return 0;
307 : }
308 :
309 :
310 : double
311 28173 : do_bench_obj_measurement (struct bench_obj *obj, void *buffer, size_t buflen,
312 : double *measurement_raw,
313 : unsigned int loop_iterations)
314 : {
315 28173 : const unsigned int num_repetitions = obj->num_measure_repetitions;
316 28173 : const bench_do_run_t do_run = obj->ops->do_run;
317 : struct nsec_time start, end;
318 : unsigned int rep, loop;
319 : double res;
320 :
321 28173 : if (num_repetitions < 1 || loop_iterations < 1)
322 0 : return 0.0;
323 :
324 84519 : for (rep = 0; rep < num_repetitions; rep++)
325 : {
326 56346 : get_nsec_time (&start);
327 :
328 424802 : for (loop = 0; loop < loop_iterations; loop++)
329 368456 : do_run (obj, buffer, buflen);
330 :
331 56346 : get_nsec_time (&end);
332 :
333 56346 : measurement_raw[rep] = get_time_nsec_diff (&start, &end);
334 : }
335 :
336 : /* Return median of repeated measurements. */
337 28173 : qsort (measurement_raw, num_repetitions, sizeof (measurement_raw[0]),
338 : double_cmp);
339 :
340 28173 : if (num_repetitions % 2 == 1)
341 0 : return measurement_raw[num_repetitions / 2];
342 :
343 56346 : res = measurement_raw[num_repetitions / 2]
344 28173 : + measurement_raw[num_repetitions / 2 - 1];
345 28173 : return res / 2;
346 : }
347 :
348 :
349 : unsigned int
350 402 : adjust_loop_iterations_to_timer_accuracy (struct bench_obj *obj, void *buffer,
351 : double *measurement_raw)
352 : {
353 402 : const double increase_thres = 3.0;
354 : double tmp, nsecs;
355 : unsigned int loop_iterations;
356 : unsigned int test_bufsize;
357 :
358 402 : test_bufsize = obj->min_bufsize;
359 402 : if (test_bufsize == 0)
360 0 : test_bufsize += obj->step_size;
361 :
362 402 : loop_iterations = 0;
363 : do
364 : {
365 : /* Increase loop iterations until we get other results than zero. */
366 804 : nsecs =
367 402 : do_bench_obj_measurement (obj, buffer, test_bufsize,
368 : measurement_raw, ++loop_iterations);
369 : }
370 402 : while (nsecs < 1.0 - 0.1);
371 : do
372 : {
373 : /* Increase loop iterations until we get reasonable increase for elapsed time. */
374 4536 : tmp =
375 2268 : do_bench_obj_measurement (obj, buffer, test_bufsize,
376 : measurement_raw, ++loop_iterations);
377 : }
378 2268 : while (tmp < nsecs * (increase_thres - 0.1));
379 :
380 402 : return loop_iterations;
381 : }
382 :
383 :
384 : /* Benchmark and return linear regression slope in nanoseconds per byte. */
385 : double
386 402 : do_slope_benchmark (struct bench_obj *obj)
387 : {
388 : unsigned int num_measurements;
389 402 : double *measurements = NULL;
390 402 : double *measurement_raw = NULL;
391 : double slope, overhead;
392 : unsigned int loop_iterations, midx, i;
393 402 : unsigned char *real_buffer = NULL;
394 : unsigned char *buffer;
395 : size_t cur_bufsize;
396 : int err;
397 :
398 402 : err = obj->ops->initialize (obj);
399 402 : if (err < 0)
400 0 : return -1;
401 :
402 402 : num_measurements = get_num_measurements (obj);
403 402 : measurements = calloc (num_measurements, sizeof (*measurements));
404 402 : if (!measurements)
405 0 : goto err_free;
406 :
407 402 : measurement_raw =
408 402 : calloc (obj->num_measure_repetitions, sizeof (*measurement_raw));
409 402 : if (!measurement_raw)
410 0 : goto err_free;
411 :
412 804 : if (num_measurements < 1 || obj->num_measure_repetitions < 1 ||
413 804 : obj->max_bufsize < 1 || obj->min_bufsize > obj->max_bufsize)
414 : goto err_free;
415 :
416 402 : real_buffer = malloc (obj->max_bufsize + 128 + unaligned_mode);
417 402 : if (!real_buffer)
418 0 : goto err_free;
419 : /* Get aligned buffer */
420 402 : buffer = real_buffer;
421 402 : buffer += 128 - ((real_buffer - (unsigned char *) 0) & (128 - 1));
422 402 : if (unaligned_mode)
423 0 : buffer += unaligned_mode; /* Make buffer unaligned */
424 :
425 1576514 : for (i = 0; i < obj->max_bufsize; i++)
426 1576112 : buffer[i] = 0x55 ^ (-i);
427 :
428 : /* Adjust number of loop iterations up to timer accuracy. */
429 402 : loop_iterations = adjust_loop_iterations_to_timer_accuracy (obj, buffer,
430 : measurement_raw);
431 :
432 : /* Perform measurements */
433 26307 : for (midx = 0, cur_bufsize = obj->min_bufsize;
434 25503 : cur_bufsize <= obj->max_bufsize; cur_bufsize += obj->step_size, midx++)
435 : {
436 51006 : measurements[midx] =
437 25503 : do_bench_obj_measurement (obj, buffer, cur_bufsize, measurement_raw,
438 : loop_iterations);
439 25503 : measurements[midx] /= loop_iterations;
440 : }
441 :
442 402 : assert (midx == num_measurements);
443 :
444 402 : slope =
445 : get_slope (&get_bench_obj_point_x, obj, measurements, num_measurements,
446 : &overhead);
447 :
448 402 : free (measurement_raw);
449 402 : free (measurements);
450 402 : free (real_buffer);
451 402 : obj->ops->finalize (obj);
452 :
453 402 : return slope;
454 :
455 : err_free:
456 0 : if (measurement_raw)
457 0 : free (measurement_raw);
458 0 : if (measurements)
459 0 : free (measurements);
460 0 : if (real_buffer)
461 0 : free (real_buffer);
462 0 : obj->ops->finalize (obj);
463 :
464 0 : return -1;
465 : }
466 :
467 :
468 : /********************************************************** Printing results. */
469 :
470 : static void
471 785 : double_to_str (char *out, size_t outlen, double value)
472 : {
473 : const char *fmt;
474 :
475 785 : if (value < 1.0)
476 52 : fmt = "%.3f";
477 733 : else if (value < 100.0)
478 507 : fmt = "%.2f";
479 : else
480 226 : fmt = "%.1f";
481 :
482 785 : snprintf (out, outlen, fmt, value);
483 785 : }
484 :
485 : static void
486 0 : bench_print_result_csv (double nsecs_per_byte)
487 : {
488 : double cycles_per_byte, mbytes_per_sec;
489 : char nsecpbyte_buf[16];
490 : char mbpsec_buf[16];
491 : char cpbyte_buf[16];
492 :
493 0 : *cpbyte_buf = 0;
494 :
495 0 : double_to_str (nsecpbyte_buf, sizeof (nsecpbyte_buf), nsecs_per_byte);
496 :
497 : /* If user didn't provide CPU speed, we cannot show cycles/byte results. */
498 0 : if (cpu_ghz > 0.0)
499 : {
500 0 : cycles_per_byte = nsecs_per_byte * cpu_ghz;
501 0 : double_to_str (cpbyte_buf, sizeof (cpbyte_buf), cycles_per_byte);
502 : }
503 :
504 0 : mbytes_per_sec =
505 0 : (1000.0 * 1000.0 * 1000.0) / (nsecs_per_byte * 1024 * 1024);
506 0 : double_to_str (mbpsec_buf, sizeof (mbpsec_buf), mbytes_per_sec);
507 :
508 : /* We print two empty fields to allow for future enhancements. */
509 0 : printf ("%s,%s,%s,,,%s,ns/B,%s,MiB/s,%s,c/B\n",
510 : current_section_name,
511 0 : current_algo_name? current_algo_name : "",
512 0 : current_mode_name? current_mode_name : "",
513 : nsecpbyte_buf,
514 : mbpsec_buf,
515 : cpbyte_buf);
516 :
517 0 : }
518 :
519 : static void
520 383 : bench_print_result_std (double nsecs_per_byte)
521 : {
522 : double cycles_per_byte, mbytes_per_sec;
523 : char nsecpbyte_buf[16];
524 : char mbpsec_buf[16];
525 : char cpbyte_buf[16];
526 :
527 383 : double_to_str (nsecpbyte_buf, sizeof (nsecpbyte_buf), nsecs_per_byte);
528 :
529 : /* If user didn't provide CPU speed, we cannot show cycles/byte results. */
530 383 : if (cpu_ghz > 0.0)
531 : {
532 0 : cycles_per_byte = nsecs_per_byte * cpu_ghz;
533 0 : double_to_str (cpbyte_buf, sizeof (cpbyte_buf), cycles_per_byte);
534 : }
535 : else
536 383 : strcpy (cpbyte_buf, "-");
537 :
538 383 : mbytes_per_sec =
539 383 : (1000.0 * 1000.0 * 1000.0) / (nsecs_per_byte * 1024 * 1024);
540 383 : double_to_str (mbpsec_buf, sizeof (mbpsec_buf), mbytes_per_sec);
541 :
542 383 : printf ("%9s ns/B %9s MiB/s %9s c/B\n",
543 : nsecpbyte_buf, mbpsec_buf, cpbyte_buf);
544 383 : }
545 :
546 : static void
547 383 : bench_print_result (double nsecs_per_byte)
548 : {
549 383 : if (csv_mode)
550 0 : bench_print_result_csv (nsecs_per_byte);
551 : else
552 383 : bench_print_result_std (nsecs_per_byte);
553 383 : }
554 :
555 : static void
556 4 : bench_print_section (const char *section_name, const char *print_name)
557 : {
558 4 : if (csv_mode)
559 : {
560 0 : gcry_free (current_section_name);
561 0 : current_section_name = gcry_xstrdup (section_name);
562 : }
563 : else
564 4 : printf ("%s:\n", print_name);
565 4 : }
566 :
567 : static void
568 26 : bench_print_header (int algo_width, const char *algo_name)
569 : {
570 26 : if (csv_mode)
571 : {
572 0 : gcry_free (current_algo_name);
573 0 : current_algo_name = gcry_xstrdup (algo_name);
574 : }
575 : else
576 : {
577 26 : if (algo_width < 0)
578 0 : printf (" %-*s | ", -algo_width, algo_name);
579 : else
580 26 : printf (" %-*s | ", algo_width, algo_name);
581 26 : printf ("%14s %15s %13s\n", "nanosecs/byte", "mebibytes/sec",
582 : "cycles/byte");
583 : }
584 26 : }
585 :
586 : static void
587 83 : bench_print_algo (int algo_width, const char *algo_name)
588 : {
589 83 : if (csv_mode)
590 : {
591 0 : gcry_free (current_algo_name);
592 0 : current_algo_name = gcry_xstrdup (algo_name);
593 : }
594 : else
595 : {
596 83 : if (algo_width < 0)
597 83 : printf (" %-*s | ", -algo_width, algo_name);
598 : else
599 0 : printf (" %-*s | ", algo_width, algo_name);
600 : }
601 83 : }
602 :
603 : static void
604 319 : bench_print_mode (int width, const char *mode_name)
605 : {
606 319 : if (csv_mode)
607 : {
608 0 : gcry_free (current_mode_name);
609 0 : current_mode_name = gcry_xstrdup (mode_name);
610 : }
611 : else
612 : {
613 319 : if (width < 0)
614 0 : printf (" %-*s | ", -width, mode_name);
615 : else
616 319 : printf (" %*s | ", width, mode_name);
617 319 : fflush (stdout);
618 : }
619 319 : }
620 :
621 : static void
622 27 : bench_print_footer (int algo_width)
623 : {
624 27 : if (!csv_mode)
625 27 : printf (" %-*s =\n", algo_width, "");
626 27 : }
627 :
628 :
629 : /********************************************************* Cipher benchmarks. */
630 :
631 : struct bench_cipher_mode
632 : {
633 : int mode;
634 : const char *name;
635 : struct bench_ops *ops;
636 :
637 : int algo;
638 : };
639 :
640 :
641 : static int
642 319 : bench_encrypt_init (struct bench_obj *obj)
643 : {
644 319 : struct bench_cipher_mode *mode = obj->priv;
645 : gcry_cipher_hd_t hd;
646 : int err, keylen;
647 :
648 319 : obj->min_bufsize = BUF_START_SIZE;
649 319 : obj->max_bufsize = BUF_END_SIZE;
650 319 : obj->step_size = BUF_STEP_SIZE;
651 319 : obj->num_measure_repetitions = num_measurement_repetitions;
652 :
653 319 : err = gcry_cipher_open (&hd, mode->algo, mode->mode, 0);
654 319 : if (err)
655 : {
656 0 : fprintf (stderr, PGM ": error opening cipher `%s'\n",
657 : gcry_cipher_algo_name (mode->algo));
658 0 : exit (1);
659 : }
660 :
661 319 : keylen = gcry_cipher_get_algo_keylen (mode->algo);
662 319 : if (keylen)
663 319 : {
664 319 : char key[keylen];
665 : int i;
666 :
667 7289 : for (i = 0; i < keylen; i++)
668 6970 : key[i] = 0x33 ^ (11 - i);
669 :
670 319 : err = gcry_cipher_setkey (hd, key, keylen);
671 319 : if (err)
672 : {
673 0 : fprintf (stderr, PGM ": gcry_cipher_setkey failed: %s\n",
674 : gpg_strerror (err));
675 0 : gcry_cipher_close (hd);
676 0 : exit (1);
677 : }
678 : }
679 : else
680 : {
681 0 : fprintf (stderr, PGM ": failed to get key length for algorithm `%s'\n",
682 : gcry_cipher_algo_name (mode->algo));
683 0 : gcry_cipher_close (hd);
684 0 : exit (1);
685 : }
686 :
687 319 : obj->priv = hd;
688 :
689 319 : return 0;
690 : }
691 :
692 : static void
693 319 : bench_encrypt_free (struct bench_obj *obj)
694 : {
695 319 : gcry_cipher_hd_t hd = obj->priv;
696 :
697 319 : gcry_cipher_close (hd);
698 319 : }
699 :
700 : static void
701 125924 : bench_encrypt_do_bench (struct bench_obj *obj, void *buf, size_t buflen)
702 : {
703 125924 : gcry_cipher_hd_t hd = obj->priv;
704 : int err;
705 :
706 125924 : err = gcry_cipher_encrypt (hd, buf, buflen, buf, buflen);
707 125924 : if (err)
708 : {
709 0 : fprintf (stderr, PGM ": gcry_cipher_encrypt failed: %s\n",
710 : gpg_strerror (err));
711 0 : gcry_cipher_close (hd);
712 0 : exit (1);
713 : }
714 125924 : }
715 :
716 : static void
717 105746 : bench_decrypt_do_bench (struct bench_obj *obj, void *buf, size_t buflen)
718 : {
719 105746 : gcry_cipher_hd_t hd = obj->priv;
720 : int err;
721 :
722 105746 : err = gcry_cipher_decrypt (hd, buf, buflen, buf, buflen);
723 105746 : if (err)
724 : {
725 0 : fprintf (stderr, PGM ": gcry_cipher_encrypt failed: %s\n",
726 : gpg_strerror (err));
727 0 : gcry_cipher_close (hd);
728 0 : exit (1);
729 : }
730 105746 : }
731 :
732 : static struct bench_ops encrypt_ops = {
733 : &bench_encrypt_init,
734 : &bench_encrypt_free,
735 : &bench_encrypt_do_bench
736 : };
737 :
738 : static struct bench_ops decrypt_ops = {
739 : &bench_encrypt_init,
740 : &bench_encrypt_free,
741 : &bench_decrypt_do_bench
742 : };
743 :
744 :
745 : static void
746 14232 : bench_ccm_encrypt_do_bench (struct bench_obj *obj, void *buf, size_t buflen)
747 : {
748 14232 : gcry_cipher_hd_t hd = obj->priv;
749 : int err;
750 : char tag[8];
751 14232 : char nonce[11] = { 0x80, 0x01, };
752 : u64 params[3];
753 :
754 14232 : gcry_cipher_setiv (hd, nonce, sizeof (nonce));
755 :
756 : /* Set CCM lengths */
757 14232 : params[0] = buflen;
758 14232 : params[1] = 0; /*aadlen */
759 14232 : params[2] = sizeof (tag);
760 14232 : err =
761 14232 : gcry_cipher_ctl (hd, GCRYCTL_SET_CCM_LENGTHS, params, sizeof (params));
762 14232 : if (err)
763 : {
764 0 : fprintf (stderr, PGM ": gcry_cipher_ctl failed: %s\n",
765 : gpg_strerror (err));
766 0 : gcry_cipher_close (hd);
767 0 : exit (1);
768 : }
769 :
770 14232 : err = gcry_cipher_encrypt (hd, buf, buflen, buf, buflen);
771 14232 : if (err)
772 : {
773 0 : fprintf (stderr, PGM ": gcry_cipher_encrypt failed: %s\n",
774 : gpg_strerror (err));
775 0 : gcry_cipher_close (hd);
776 0 : exit (1);
777 : }
778 :
779 14232 : err = gcry_cipher_gettag (hd, tag, sizeof (tag));
780 14232 : if (err)
781 : {
782 0 : fprintf (stderr, PGM ": gcry_cipher_gettag failed: %s\n",
783 : gpg_strerror (err));
784 0 : gcry_cipher_close (hd);
785 0 : exit (1);
786 : }
787 14232 : }
788 :
789 : static void
790 8518 : bench_ccm_decrypt_do_bench (struct bench_obj *obj, void *buf, size_t buflen)
791 : {
792 8518 : gcry_cipher_hd_t hd = obj->priv;
793 : int err;
794 8518 : char tag[8] = { 0, };
795 8518 : char nonce[11] = { 0x80, 0x01, };
796 : u64 params[3];
797 :
798 8518 : gcry_cipher_setiv (hd, nonce, sizeof (nonce));
799 :
800 : /* Set CCM lengths */
801 8518 : params[0] = buflen;
802 8518 : params[1] = 0; /*aadlen */
803 8518 : params[2] = sizeof (tag);
804 8518 : err =
805 8518 : gcry_cipher_ctl (hd, GCRYCTL_SET_CCM_LENGTHS, params, sizeof (params));
806 8518 : if (err)
807 : {
808 0 : fprintf (stderr, PGM ": gcry_cipher_ctl failed: %s\n",
809 : gpg_strerror (err));
810 0 : gcry_cipher_close (hd);
811 0 : exit (1);
812 : }
813 :
814 8518 : err = gcry_cipher_decrypt (hd, buf, buflen, buf, buflen);
815 8518 : if (err)
816 : {
817 0 : fprintf (stderr, PGM ": gcry_cipher_encrypt failed: %s\n",
818 : gpg_strerror (err));
819 0 : gcry_cipher_close (hd);
820 0 : exit (1);
821 : }
822 :
823 8518 : err = gcry_cipher_checktag (hd, tag, sizeof (tag));
824 8518 : if (gpg_err_code (err) == GPG_ERR_CHECKSUM)
825 8518 : err = gpg_error (GPG_ERR_NO_ERROR);
826 8518 : if (err)
827 : {
828 0 : fprintf (stderr, PGM ": gcry_cipher_gettag failed: %s\n",
829 : gpg_strerror (err));
830 0 : gcry_cipher_close (hd);
831 0 : exit (1);
832 : }
833 8518 : }
834 :
835 : static void
836 7616 : bench_ccm_authenticate_do_bench (struct bench_obj *obj, void *buf,
837 : size_t buflen)
838 : {
839 7616 : gcry_cipher_hd_t hd = obj->priv;
840 : int err;
841 7616 : char tag[8] = { 0, };
842 7616 : char nonce[11] = { 0x80, 0x01, };
843 : u64 params[3];
844 7616 : char data = 0xff;
845 :
846 7616 : gcry_cipher_setiv (hd, nonce, sizeof (nonce));
847 :
848 : /* Set CCM lengths */
849 7616 : params[0] = sizeof (data); /*datalen */
850 7616 : params[1] = buflen; /*aadlen */
851 7616 : params[2] = sizeof (tag);
852 7616 : err =
853 7616 : gcry_cipher_ctl (hd, GCRYCTL_SET_CCM_LENGTHS, params, sizeof (params));
854 7616 : if (err)
855 : {
856 0 : fprintf (stderr, PGM ": gcry_cipher_ctl failed: %s\n",
857 : gpg_strerror (err));
858 0 : gcry_cipher_close (hd);
859 0 : exit (1);
860 : }
861 :
862 7616 : err = gcry_cipher_authenticate (hd, buf, buflen);
863 7616 : if (err)
864 : {
865 0 : fprintf (stderr, PGM ": gcry_cipher_authenticate failed: %s\n",
866 : gpg_strerror (err));
867 0 : gcry_cipher_close (hd);
868 0 : exit (1);
869 : }
870 :
871 7616 : err = gcry_cipher_encrypt (hd, &data, sizeof (data), &data, sizeof (data));
872 7616 : if (err)
873 : {
874 0 : fprintf (stderr, PGM ": gcry_cipher_encrypt failed: %s\n",
875 : gpg_strerror (err));
876 0 : gcry_cipher_close (hd);
877 0 : exit (1);
878 : }
879 :
880 7616 : err = gcry_cipher_gettag (hd, tag, sizeof (tag));
881 7616 : if (err)
882 : {
883 0 : fprintf (stderr, PGM ": gcry_cipher_gettag failed: %s\n",
884 : gpg_strerror (err));
885 0 : gcry_cipher_close (hd);
886 0 : exit (1);
887 : }
888 7616 : }
889 :
890 : static struct bench_ops ccm_encrypt_ops = {
891 : &bench_encrypt_init,
892 : &bench_encrypt_free,
893 : &bench_ccm_encrypt_do_bench
894 : };
895 :
896 : static struct bench_ops ccm_decrypt_ops = {
897 : &bench_encrypt_init,
898 : &bench_encrypt_free,
899 : &bench_ccm_decrypt_do_bench
900 : };
901 :
902 : static struct bench_ops ccm_authenticate_ops = {
903 : &bench_encrypt_init,
904 : &bench_encrypt_free,
905 : &bench_ccm_authenticate_do_bench
906 : };
907 :
908 :
909 : static void
910 21722 : bench_aead_encrypt_do_bench (struct bench_obj *obj, void *buf, size_t buflen,
911 : const char *nonce, size_t noncelen)
912 : {
913 21722 : gcry_cipher_hd_t hd = obj->priv;
914 : int err;
915 : char tag[16];
916 :
917 21722 : gcry_cipher_setiv (hd, nonce, noncelen);
918 :
919 21722 : gcry_cipher_final (hd);
920 21722 : err = gcry_cipher_encrypt (hd, buf, buflen, buf, buflen);
921 21722 : if (err)
922 : {
923 0 : fprintf (stderr, PGM ": gcry_cipher_encrypt failed: %s\n",
924 : gpg_strerror (err));
925 0 : gcry_cipher_close (hd);
926 0 : exit (1);
927 : }
928 :
929 21722 : err = gcry_cipher_gettag (hd, tag, sizeof (tag));
930 21722 : if (err)
931 : {
932 0 : fprintf (stderr, PGM ": gcry_cipher_gettag failed: %s\n",
933 : gpg_strerror (err));
934 0 : gcry_cipher_close (hd);
935 0 : exit (1);
936 : }
937 21722 : }
938 :
939 : static void
940 15466 : bench_aead_decrypt_do_bench (struct bench_obj *obj, void *buf, size_t buflen,
941 : const char *nonce, size_t noncelen)
942 : {
943 15466 : gcry_cipher_hd_t hd = obj->priv;
944 : int err;
945 15466 : char tag[16] = { 0, };
946 :
947 15466 : gcry_cipher_setiv (hd, nonce, noncelen);
948 :
949 15466 : gcry_cipher_final (hd);
950 15466 : err = gcry_cipher_decrypt (hd, buf, buflen, buf, buflen);
951 15466 : if (err)
952 : {
953 0 : fprintf (stderr, PGM ": gcry_cipher_encrypt failed: %s\n",
954 : gpg_strerror (err));
955 0 : gcry_cipher_close (hd);
956 0 : exit (1);
957 : }
958 :
959 15466 : err = gcry_cipher_checktag (hd, tag, sizeof (tag));
960 15466 : if (gpg_err_code (err) == GPG_ERR_CHECKSUM)
961 15466 : err = gpg_error (GPG_ERR_NO_ERROR);
962 15466 : if (err)
963 : {
964 0 : fprintf (stderr, PGM ": gcry_cipher_gettag failed: %s\n",
965 : gpg_strerror (err));
966 0 : gcry_cipher_close (hd);
967 0 : exit (1);
968 : }
969 15466 : }
970 :
971 : static void
972 16600 : bench_aead_authenticate_do_bench (struct bench_obj *obj, void *buf,
973 : size_t buflen, const char *nonce,
974 : size_t noncelen)
975 : {
976 16600 : gcry_cipher_hd_t hd = obj->priv;
977 : int err;
978 16600 : char tag[16] = { 0, };
979 16600 : char data = 0xff;
980 :
981 16600 : err = gcry_cipher_setiv (hd, nonce, noncelen);
982 16600 : if (err)
983 : {
984 0 : fprintf (stderr, PGM ": gcry_cipher_setiv failed: %s\n",
985 : gpg_strerror (err));
986 0 : gcry_cipher_close (hd);
987 0 : exit (1);
988 : }
989 :
990 16600 : err = gcry_cipher_authenticate (hd, buf, buflen);
991 16600 : if (err)
992 : {
993 0 : fprintf (stderr, PGM ": gcry_cipher_authenticate failed: %s\n",
994 : gpg_strerror (err));
995 0 : gcry_cipher_close (hd);
996 0 : exit (1);
997 : }
998 :
999 16600 : gcry_cipher_final (hd);
1000 16600 : err = gcry_cipher_encrypt (hd, &data, sizeof (data), &data, sizeof (data));
1001 16600 : if (err)
1002 : {
1003 0 : fprintf (stderr, PGM ": gcry_cipher_encrypt failed: %s\n",
1004 : gpg_strerror (err));
1005 0 : gcry_cipher_close (hd);
1006 0 : exit (1);
1007 : }
1008 :
1009 16600 : err = gcry_cipher_gettag (hd, tag, sizeof (tag));
1010 16600 : if (err)
1011 : {
1012 0 : fprintf (stderr, PGM ": gcry_cipher_gettag failed: %s\n",
1013 : gpg_strerror (err));
1014 0 : gcry_cipher_close (hd);
1015 0 : exit (1);
1016 : }
1017 16600 : }
1018 :
1019 :
1020 : static void
1021 11566 : bench_gcm_encrypt_do_bench (struct bench_obj *obj, void *buf,
1022 : size_t buflen)
1023 : {
1024 11566 : char nonce[12] = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce,
1025 : 0xdb, 0xad, 0xde, 0xca, 0xf8, 0x88 };
1026 11566 : bench_aead_encrypt_do_bench (obj, buf, buflen, nonce, sizeof(nonce));
1027 11566 : }
1028 :
1029 : static void
1030 7746 : bench_gcm_decrypt_do_bench (struct bench_obj *obj, void *buf,
1031 : size_t buflen)
1032 : {
1033 7746 : char nonce[12] = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce,
1034 : 0xdb, 0xad, 0xde, 0xca, 0xf8, 0x88 };
1035 7746 : bench_aead_decrypt_do_bench (obj, buf, buflen, nonce, sizeof(nonce));
1036 7746 : }
1037 :
1038 : static void
1039 8740 : bench_gcm_authenticate_do_bench (struct bench_obj *obj, void *buf,
1040 : size_t buflen)
1041 : {
1042 8740 : char nonce[12] = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce,
1043 : 0xdb, 0xad, 0xde, 0xca, 0xf8, 0x88 };
1044 8740 : bench_aead_authenticate_do_bench (obj, buf, buflen, nonce, sizeof(nonce));
1045 8740 : }
1046 :
1047 : static struct bench_ops gcm_encrypt_ops = {
1048 : &bench_encrypt_init,
1049 : &bench_encrypt_free,
1050 : &bench_gcm_encrypt_do_bench
1051 : };
1052 :
1053 : static struct bench_ops gcm_decrypt_ops = {
1054 : &bench_encrypt_init,
1055 : &bench_encrypt_free,
1056 : &bench_gcm_decrypt_do_bench
1057 : };
1058 :
1059 : static struct bench_ops gcm_authenticate_ops = {
1060 : &bench_encrypt_init,
1061 : &bench_encrypt_free,
1062 : &bench_gcm_authenticate_do_bench
1063 : };
1064 :
1065 :
1066 : static void
1067 8896 : bench_ocb_encrypt_do_bench (struct bench_obj *obj, void *buf,
1068 : size_t buflen)
1069 : {
1070 8896 : char nonce[15] = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce,
1071 : 0xdb, 0xad, 0xde, 0xca, 0xf8, 0x88,
1072 : 0x00, 0x00, 0x01 };
1073 8896 : bench_aead_encrypt_do_bench (obj, buf, buflen, nonce, sizeof(nonce));
1074 8896 : }
1075 :
1076 : static void
1077 7180 : bench_ocb_decrypt_do_bench (struct bench_obj *obj, void *buf,
1078 : size_t buflen)
1079 : {
1080 7180 : char nonce[15] = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce,
1081 : 0xdb, 0xad, 0xde, 0xca, 0xf8, 0x88,
1082 : 0x00, 0x00, 0x01 };
1083 7180 : bench_aead_decrypt_do_bench (obj, buf, buflen, nonce, sizeof(nonce));
1084 7180 : }
1085 :
1086 : static void
1087 7180 : bench_ocb_authenticate_do_bench (struct bench_obj *obj, void *buf,
1088 : size_t buflen)
1089 : {
1090 7180 : char nonce[15] = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce,
1091 : 0xdb, 0xad, 0xde, 0xca, 0xf8, 0x88,
1092 : 0x00, 0x00, 0x01 };
1093 7180 : bench_aead_authenticate_do_bench (obj, buf, buflen, nonce, sizeof(nonce));
1094 7180 : }
1095 :
1096 : static struct bench_ops ocb_encrypt_ops = {
1097 : &bench_encrypt_init,
1098 : &bench_encrypt_free,
1099 : &bench_ocb_encrypt_do_bench
1100 : };
1101 :
1102 : static struct bench_ops ocb_decrypt_ops = {
1103 : &bench_encrypt_init,
1104 : &bench_encrypt_free,
1105 : &bench_ocb_decrypt_do_bench
1106 : };
1107 :
1108 : static struct bench_ops ocb_authenticate_ops = {
1109 : &bench_encrypt_init,
1110 : &bench_encrypt_free,
1111 : &bench_ocb_authenticate_do_bench
1112 : };
1113 :
1114 :
1115 : static void
1116 1260 : bench_poly1305_encrypt_do_bench (struct bench_obj *obj, void *buf,
1117 : size_t buflen)
1118 : {
1119 1260 : char nonce[8] = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad };
1120 1260 : bench_aead_encrypt_do_bench (obj, buf, buflen, nonce, sizeof(nonce));
1121 1260 : }
1122 :
1123 : static void
1124 540 : bench_poly1305_decrypt_do_bench (struct bench_obj *obj, void *buf,
1125 : size_t buflen)
1126 : {
1127 540 : char nonce[8] = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad };
1128 540 : bench_aead_decrypt_do_bench (obj, buf, buflen, nonce, sizeof(nonce));
1129 540 : }
1130 :
1131 : static void
1132 680 : bench_poly1305_authenticate_do_bench (struct bench_obj *obj, void *buf,
1133 : size_t buflen)
1134 : {
1135 680 : char nonce[8] = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad };
1136 680 : bench_aead_authenticate_do_bench (obj, buf, buflen, nonce, sizeof(nonce));
1137 680 : }
1138 :
1139 : static struct bench_ops poly1305_encrypt_ops = {
1140 : &bench_encrypt_init,
1141 : &bench_encrypt_free,
1142 : &bench_poly1305_encrypt_do_bench
1143 : };
1144 :
1145 : static struct bench_ops poly1305_decrypt_ops = {
1146 : &bench_encrypt_init,
1147 : &bench_encrypt_free,
1148 : &bench_poly1305_decrypt_do_bench
1149 : };
1150 :
1151 : static struct bench_ops poly1305_authenticate_ops = {
1152 : &bench_encrypt_init,
1153 : &bench_encrypt_free,
1154 : &bench_poly1305_authenticate_do_bench
1155 : };
1156 :
1157 :
1158 : static struct bench_cipher_mode cipher_modes[] = {
1159 : {GCRY_CIPHER_MODE_ECB, "ECB enc", &encrypt_ops},
1160 : {GCRY_CIPHER_MODE_ECB, "ECB dec", &decrypt_ops},
1161 : {GCRY_CIPHER_MODE_CBC, "CBC enc", &encrypt_ops},
1162 : {GCRY_CIPHER_MODE_CBC, "CBC dec", &decrypt_ops},
1163 : {GCRY_CIPHER_MODE_CFB, "CFB enc", &encrypt_ops},
1164 : {GCRY_CIPHER_MODE_CFB, "CFB dec", &decrypt_ops},
1165 : {GCRY_CIPHER_MODE_OFB, "OFB enc", &encrypt_ops},
1166 : {GCRY_CIPHER_MODE_OFB, "OFB dec", &decrypt_ops},
1167 : {GCRY_CIPHER_MODE_CTR, "CTR enc", &encrypt_ops},
1168 : {GCRY_CIPHER_MODE_CTR, "CTR dec", &decrypt_ops},
1169 : {GCRY_CIPHER_MODE_CCM, "CCM enc", &ccm_encrypt_ops},
1170 : {GCRY_CIPHER_MODE_CCM, "CCM dec", &ccm_decrypt_ops},
1171 : {GCRY_CIPHER_MODE_CCM, "CCM auth", &ccm_authenticate_ops},
1172 : {GCRY_CIPHER_MODE_GCM, "GCM enc", &gcm_encrypt_ops},
1173 : {GCRY_CIPHER_MODE_GCM, "GCM dec", &gcm_decrypt_ops},
1174 : {GCRY_CIPHER_MODE_GCM, "GCM auth", &gcm_authenticate_ops},
1175 : {GCRY_CIPHER_MODE_OCB, "OCB enc", &ocb_encrypt_ops},
1176 : {GCRY_CIPHER_MODE_OCB, "OCB dec", &ocb_decrypt_ops},
1177 : {GCRY_CIPHER_MODE_OCB, "OCB auth", &ocb_authenticate_ops},
1178 : {GCRY_CIPHER_MODE_POLY1305, "POLY1305 enc", &poly1305_encrypt_ops},
1179 : {GCRY_CIPHER_MODE_POLY1305, "POLY1305 dec", &poly1305_decrypt_ops},
1180 : {GCRY_CIPHER_MODE_POLY1305, "POLY1305 auth", &poly1305_authenticate_ops},
1181 : {0},
1182 : };
1183 :
1184 :
1185 : static void
1186 528 : cipher_bench_one (int algo, struct bench_cipher_mode *pmode)
1187 : {
1188 528 : struct bench_cipher_mode mode = *pmode;
1189 528 : struct bench_obj obj = { 0 };
1190 : double result;
1191 : unsigned int blklen;
1192 :
1193 528 : mode.algo = algo;
1194 :
1195 : /* Check if this mode is ok */
1196 528 : blklen = gcry_cipher_get_algo_blklen (algo);
1197 528 : if (!blklen)
1198 209 : return;
1199 :
1200 : /* Stream cipher? Only test with "ECB" and POLY1305. */
1201 608 : if (blklen == 1 && (mode.mode != GCRY_CIPHER_MODE_ECB &&
1202 80 : mode.mode != GCRY_CIPHER_MODE_POLY1305))
1203 68 : return;
1204 460 : if (blklen == 1 && mode.mode == GCRY_CIPHER_MODE_ECB)
1205 : {
1206 8 : mode.mode = GCRY_CIPHER_MODE_STREAM;
1207 8 : mode.name = mode.ops == &encrypt_ops ? "STREAM enc" : "STREAM dec";
1208 : }
1209 :
1210 : /* Poly1305 has restriction for cipher algorithm */
1211 460 : if (mode.mode == GCRY_CIPHER_MODE_POLY1305 && algo != GCRY_CIPHER_CHACHA20)
1212 69 : return;
1213 :
1214 : /* CCM has restrictions for block-size */
1215 391 : if (mode.mode == GCRY_CIPHER_MODE_CCM && blklen != GCRY_CCM_BLOCK_LEN)
1216 24 : return;
1217 :
1218 : /* GCM has restrictions for block-size */
1219 367 : if (mode.mode == GCRY_CIPHER_MODE_GCM && blklen != GCRY_GCM_BLOCK_LEN)
1220 24 : return;
1221 :
1222 : /* Our OCB implementaion has restrictions for block-size. */
1223 343 : if (mode.mode == GCRY_CIPHER_MODE_OCB && blklen != 16)
1224 24 : return;
1225 :
1226 319 : bench_print_mode (14, mode.name);
1227 :
1228 319 : obj.ops = mode.ops;
1229 319 : obj.priv = &mode;
1230 :
1231 319 : result = do_slope_benchmark (&obj);
1232 :
1233 319 : bench_print_result (result);
1234 : }
1235 :
1236 :
1237 : static void
1238 24 : _cipher_bench (int algo)
1239 : {
1240 : const char *algoname;
1241 : int i;
1242 :
1243 24 : algoname = gcry_cipher_algo_name (algo);
1244 :
1245 24 : bench_print_header (14, algoname);
1246 :
1247 552 : for (i = 0; cipher_modes[i].mode; i++)
1248 528 : cipher_bench_one (algo, &cipher_modes[i]);
1249 :
1250 24 : bench_print_footer (14);
1251 24 : }
1252 :
1253 :
1254 : void
1255 1 : cipher_bench (char **argv, int argc)
1256 : {
1257 : int i, algo;
1258 :
1259 1 : bench_print_section ("cipher", "Cipher");
1260 :
1261 1 : if (argv && argc)
1262 : {
1263 0 : for (i = 0; i < argc; i++)
1264 : {
1265 0 : algo = gcry_cipher_map_name (argv[i]);
1266 0 : if (algo)
1267 0 : _cipher_bench (algo);
1268 : }
1269 : }
1270 : else
1271 : {
1272 400 : for (i = 1; i < 400; i++)
1273 399 : if (!gcry_cipher_test_algo (i))
1274 24 : _cipher_bench (i);
1275 : }
1276 1 : }
1277 :
1278 :
1279 : /*********************************************************** Hash benchmarks. */
1280 :
1281 : struct bench_hash_mode
1282 : {
1283 : const char *name;
1284 : struct bench_ops *ops;
1285 :
1286 : int algo;
1287 : };
1288 :
1289 :
1290 : static int
1291 25 : bench_hash_init (struct bench_obj *obj)
1292 : {
1293 25 : struct bench_hash_mode *mode = obj->priv;
1294 : gcry_md_hd_t hd;
1295 : int err;
1296 :
1297 25 : obj->min_bufsize = BUF_START_SIZE;
1298 25 : obj->max_bufsize = BUF_END_SIZE;
1299 25 : obj->step_size = BUF_STEP_SIZE;
1300 25 : obj->num_measure_repetitions = num_measurement_repetitions;
1301 :
1302 25 : err = gcry_md_open (&hd, mode->algo, 0);
1303 25 : if (err)
1304 : {
1305 0 : fprintf (stderr, PGM ": error opening hash `%s'\n",
1306 : gcry_md_algo_name (mode->algo));
1307 0 : exit (1);
1308 : }
1309 :
1310 25 : obj->priv = hd;
1311 :
1312 25 : return 0;
1313 : }
1314 :
1315 : static void
1316 25 : bench_hash_free (struct bench_obj *obj)
1317 : {
1318 25 : gcry_md_hd_t hd = obj->priv;
1319 :
1320 25 : gcry_md_close (hd);
1321 25 : }
1322 :
1323 : static void
1324 22364 : bench_hash_do_bench (struct bench_obj *obj, void *buf, size_t buflen)
1325 : {
1326 22364 : gcry_md_hd_t hd = obj->priv;
1327 :
1328 22364 : gcry_md_reset (hd);
1329 22364 : gcry_md_write (hd, buf, buflen);
1330 22364 : gcry_md_final (hd);
1331 22364 : }
1332 :
1333 : static struct bench_ops hash_ops = {
1334 : &bench_hash_init,
1335 : &bench_hash_free,
1336 : &bench_hash_do_bench
1337 : };
1338 :
1339 :
1340 : static struct bench_hash_mode hash_modes[] = {
1341 : {"", &hash_ops},
1342 : {0},
1343 : };
1344 :
1345 :
1346 : static void
1347 25 : hash_bench_one (int algo, struct bench_hash_mode *pmode)
1348 : {
1349 25 : struct bench_hash_mode mode = *pmode;
1350 25 : struct bench_obj obj = { 0 };
1351 : double result;
1352 :
1353 25 : mode.algo = algo;
1354 :
1355 25 : if (mode.name[0] == '\0')
1356 25 : bench_print_algo (-14, gcry_md_algo_name (algo));
1357 : else
1358 0 : bench_print_algo (14, mode.name);
1359 :
1360 25 : obj.ops = mode.ops;
1361 25 : obj.priv = &mode;
1362 :
1363 25 : result = do_slope_benchmark (&obj);
1364 :
1365 25 : bench_print_result (result);
1366 25 : }
1367 :
1368 : static void
1369 25 : _hash_bench (int algo)
1370 : {
1371 : int i;
1372 :
1373 50 : for (i = 0; hash_modes[i].name; i++)
1374 25 : hash_bench_one (algo, &hash_modes[i]);
1375 25 : }
1376 :
1377 : void
1378 1 : hash_bench (char **argv, int argc)
1379 : {
1380 : int i, algo;
1381 :
1382 1 : bench_print_section ("hash", "Hash");
1383 1 : bench_print_header (14, "");
1384 :
1385 1 : if (argv && argc)
1386 : {
1387 0 : for (i = 0; i < argc; i++)
1388 : {
1389 0 : algo = gcry_md_map_name (argv[i]);
1390 0 : if (algo)
1391 0 : _hash_bench (algo);
1392 : }
1393 : }
1394 : else
1395 : {
1396 400 : for (i = 1; i < 400; i++)
1397 399 : if (!gcry_md_test_algo (i))
1398 25 : _hash_bench (i);
1399 : }
1400 :
1401 1 : bench_print_footer (14);
1402 1 : }
1403 :
1404 :
1405 : /************************************************************ MAC benchmarks. */
1406 :
1407 : struct bench_mac_mode
1408 : {
1409 : const char *name;
1410 : struct bench_ops *ops;
1411 :
1412 : int algo;
1413 : };
1414 :
1415 :
1416 : static int
1417 39 : bench_mac_init (struct bench_obj *obj)
1418 : {
1419 39 : struct bench_mac_mode *mode = obj->priv;
1420 : gcry_mac_hd_t hd;
1421 : int err;
1422 : unsigned int keylen;
1423 : void *key;
1424 :
1425 39 : obj->min_bufsize = BUF_START_SIZE;
1426 39 : obj->max_bufsize = BUF_END_SIZE;
1427 39 : obj->step_size = BUF_STEP_SIZE;
1428 39 : obj->num_measure_repetitions = num_measurement_repetitions;
1429 :
1430 39 : keylen = gcry_mac_get_algo_keylen (mode->algo);
1431 39 : if (keylen == 0)
1432 0 : keylen = 32;
1433 39 : key = malloc (keylen);
1434 39 : if (!key)
1435 : {
1436 0 : fprintf (stderr, PGM ": couldn't allocate %d bytes\n", keylen);
1437 0 : exit (1);
1438 : }
1439 39 : memset(key, 42, keylen);
1440 :
1441 39 : err = gcry_mac_open (&hd, mode->algo, 0, NULL);
1442 39 : if (err)
1443 : {
1444 0 : fprintf (stderr, PGM ": error opening mac `%s'\n",
1445 : gcry_mac_algo_name (mode->algo));
1446 0 : free (key);
1447 0 : exit (1);
1448 : }
1449 :
1450 39 : err = gcry_mac_setkey (hd, key, keylen);
1451 39 : if (err)
1452 : {
1453 0 : fprintf (stderr, PGM ": error setting key for mac `%s'\n",
1454 : gcry_mac_algo_name (mode->algo));
1455 0 : free (key);
1456 0 : exit (1);
1457 : }
1458 :
1459 39 : switch (mode->algo)
1460 : {
1461 : default:
1462 34 : break;
1463 : case GCRY_MAC_POLY1305_AES:
1464 : case GCRY_MAC_POLY1305_CAMELLIA:
1465 : case GCRY_MAC_POLY1305_TWOFISH:
1466 : case GCRY_MAC_POLY1305_SERPENT:
1467 : case GCRY_MAC_POLY1305_SEED:
1468 5 : gcry_mac_setiv (hd, key, 16);
1469 5 : break;
1470 : }
1471 :
1472 39 : obj->priv = hd;
1473 :
1474 39 : free (key);
1475 39 : return 0;
1476 : }
1477 :
1478 : static void
1479 39 : bench_mac_free (struct bench_obj *obj)
1480 : {
1481 39 : gcry_mac_hd_t hd = obj->priv;
1482 :
1483 39 : gcry_mac_close (hd);
1484 39 : }
1485 :
1486 : static void
1487 24498 : bench_mac_do_bench (struct bench_obj *obj, void *buf, size_t buflen)
1488 : {
1489 24498 : gcry_mac_hd_t hd = obj->priv;
1490 : size_t bs;
1491 : char b;
1492 :
1493 24498 : gcry_mac_reset (hd);
1494 24498 : gcry_mac_write (hd, buf, buflen);
1495 24498 : bs = sizeof(b);
1496 24498 : gcry_mac_read (hd, &b, &bs);
1497 24498 : }
1498 :
1499 : static struct bench_ops mac_ops = {
1500 : &bench_mac_init,
1501 : &bench_mac_free,
1502 : &bench_mac_do_bench
1503 : };
1504 :
1505 :
1506 : static struct bench_mac_mode mac_modes[] = {
1507 : {"", &mac_ops},
1508 : {0},
1509 : };
1510 :
1511 :
1512 : static void
1513 39 : mac_bench_one (int algo, struct bench_mac_mode *pmode)
1514 : {
1515 39 : struct bench_mac_mode mode = *pmode;
1516 39 : struct bench_obj obj = { 0 };
1517 : double result;
1518 :
1519 39 : mode.algo = algo;
1520 :
1521 39 : if (mode.name[0] == '\0')
1522 39 : bench_print_algo (-18, gcry_mac_algo_name (algo));
1523 : else
1524 0 : bench_print_algo (18, mode.name);
1525 :
1526 39 : obj.ops = mode.ops;
1527 39 : obj.priv = &mode;
1528 :
1529 39 : result = do_slope_benchmark (&obj);
1530 :
1531 39 : bench_print_result (result);
1532 39 : }
1533 :
1534 : static void
1535 39 : _mac_bench (int algo)
1536 : {
1537 : int i;
1538 :
1539 78 : for (i = 0; mac_modes[i].name; i++)
1540 39 : mac_bench_one (algo, &mac_modes[i]);
1541 39 : }
1542 :
1543 : void
1544 1 : mac_bench (char **argv, int argc)
1545 : {
1546 : int i, algo;
1547 :
1548 1 : bench_print_section ("mac", "MAC");
1549 1 : bench_print_header (18, "");
1550 :
1551 1 : if (argv && argc)
1552 : {
1553 0 : for (i = 0; i < argc; i++)
1554 : {
1555 0 : algo = gcry_mac_map_name (argv[i]);
1556 0 : if (algo)
1557 0 : _mac_bench (algo);
1558 : }
1559 : }
1560 : else
1561 : {
1562 600 : for (i = 1; i < 600; i++)
1563 599 : if (!gcry_mac_test_algo (i))
1564 39 : _mac_bench (i);
1565 : }
1566 :
1567 1 : bench_print_footer (18);
1568 1 : }
1569 :
1570 :
1571 : /************************************************************ KDF benchmarks. */
1572 :
1573 : struct bench_kdf_mode
1574 : {
1575 : struct bench_ops *ops;
1576 :
1577 : int algo;
1578 : int subalgo;
1579 : };
1580 :
1581 :
1582 : static int
1583 19 : bench_kdf_init (struct bench_obj *obj)
1584 : {
1585 19 : struct bench_kdf_mode *mode = obj->priv;
1586 :
1587 19 : if (mode->algo == GCRY_KDF_PBKDF2)
1588 : {
1589 19 : obj->min_bufsize = 2;
1590 19 : obj->max_bufsize = 2 * 32;
1591 19 : obj->step_size = 2;
1592 : }
1593 :
1594 19 : obj->num_measure_repetitions = num_measurement_repetitions;
1595 :
1596 19 : return 0;
1597 : }
1598 :
1599 : static void
1600 19 : bench_kdf_free (struct bench_obj *obj)
1601 : {
1602 : (void)obj;
1603 19 : }
1604 :
1605 : static void
1606 5770 : bench_kdf_do_bench (struct bench_obj *obj, void *buf, size_t buflen)
1607 : {
1608 5770 : struct bench_kdf_mode *mode = obj->priv;
1609 : char keybuf[16];
1610 :
1611 : (void)buf;
1612 :
1613 5770 : if (mode->algo == GCRY_KDF_PBKDF2)
1614 : {
1615 5770 : gcry_kdf_derive("qwerty", 6, mode->algo, mode->subalgo, "01234567", 8,
1616 : buflen, sizeof(keybuf), keybuf);
1617 : }
1618 5770 : }
1619 :
1620 : static struct bench_ops kdf_ops = {
1621 : &bench_kdf_init,
1622 : &bench_kdf_free,
1623 : &bench_kdf_do_bench
1624 : };
1625 :
1626 :
1627 : static void
1628 25 : kdf_bench_one (int algo, int subalgo)
1629 : {
1630 25 : struct bench_kdf_mode mode = { &kdf_ops };
1631 25 : struct bench_obj obj = { 0 };
1632 : double nsecs_per_iteration;
1633 : double cycles_per_iteration;
1634 : char algo_name[32];
1635 : char nsecpiter_buf[16];
1636 : char cpiter_buf[16];
1637 :
1638 25 : mode.algo = algo;
1639 25 : mode.subalgo = subalgo;
1640 :
1641 25 : switch (subalgo)
1642 : {
1643 : case GCRY_MD_CRC32:
1644 : case GCRY_MD_CRC32_RFC1510:
1645 : case GCRY_MD_CRC24_RFC2440:
1646 : case GCRY_MD_MD4:
1647 : /* Skip CRC32s. */
1648 10 : return;
1649 : }
1650 :
1651 21 : if (gcry_md_get_algo_dlen (subalgo) == 0)
1652 : {
1653 : /* Skip XOFs */
1654 2 : return;
1655 : }
1656 :
1657 19 : *algo_name = 0;
1658 :
1659 19 : if (algo == GCRY_KDF_PBKDF2)
1660 : {
1661 19 : snprintf (algo_name, sizeof(algo_name), "PBKDF2-HMAC-%s",
1662 : gcry_md_algo_name (subalgo));
1663 : }
1664 :
1665 19 : bench_print_algo (-24, algo_name);
1666 :
1667 19 : obj.ops = mode.ops;
1668 19 : obj.priv = &mode;
1669 :
1670 19 : nsecs_per_iteration = do_slope_benchmark (&obj);
1671 :
1672 19 : strcpy(cpiter_buf, csv_mode ? "" : "-");
1673 :
1674 19 : double_to_str (nsecpiter_buf, sizeof (nsecpiter_buf), nsecs_per_iteration);
1675 :
1676 : /* If user didn't provide CPU speed, we cannot show cycles/iter results. */
1677 19 : if (cpu_ghz > 0.0)
1678 : {
1679 0 : cycles_per_iteration = nsecs_per_iteration * cpu_ghz;
1680 0 : double_to_str (cpiter_buf, sizeof (cpiter_buf), cycles_per_iteration);
1681 : }
1682 :
1683 19 : if (csv_mode)
1684 : {
1685 0 : printf ("%s,%s,%s,,,,,,,,,%s,ns/iter,%s,c/iter\n",
1686 : current_section_name,
1687 0 : current_algo_name ? current_algo_name : "",
1688 0 : current_mode_name ? current_mode_name : "",
1689 : nsecpiter_buf,
1690 : cpiter_buf);
1691 : }
1692 : else
1693 : {
1694 19 : printf ("%14s %13s\n", nsecpiter_buf, cpiter_buf);
1695 : }
1696 : }
1697 :
1698 : void
1699 1 : kdf_bench (char **argv, int argc)
1700 : {
1701 : char algo_name[32];
1702 : int i, j;
1703 :
1704 1 : bench_print_section ("kdf", "KDF");
1705 :
1706 1 : if (!csv_mode)
1707 : {
1708 1 : printf (" %-*s | ", 24, "");
1709 1 : printf ("%14s %13s\n", "nanosecs/iter", "cycles/iter");
1710 : }
1711 :
1712 1 : if (argv && argc)
1713 : {
1714 0 : for (i = 0; i < argc; i++)
1715 : {
1716 0 : for (j = 1; j < 400; j++)
1717 : {
1718 0 : if (gcry_md_test_algo (j))
1719 0 : continue;
1720 :
1721 0 : snprintf (algo_name, sizeof(algo_name), "PBKDF2-HMAC-%s",
1722 : gcry_md_algo_name (j));
1723 :
1724 0 : if (!strcmp(argv[i], algo_name))
1725 0 : kdf_bench_one (GCRY_KDF_PBKDF2, j);
1726 : }
1727 : }
1728 : }
1729 : else
1730 : {
1731 400 : for (i = 1; i < 400; i++)
1732 399 : if (!gcry_md_test_algo (i))
1733 25 : kdf_bench_one (GCRY_KDF_PBKDF2, i);
1734 : }
1735 :
1736 1 : bench_print_footer (24);
1737 1 : }
1738 :
1739 :
1740 : /************************************************************** Main program. */
1741 :
1742 : void
1743 0 : print_help (void)
1744 : {
1745 : static const char *help_lines[] = {
1746 : "usage: bench-slope [options] [hash|mac|cipher|kdf [algonames]]",
1747 : "",
1748 : " options:",
1749 : " --cpu-mhz <mhz> Set CPU speed for calculating cycles",
1750 : " per bytes results.",
1751 : " --disable-hwf <features> Disable hardware acceleration feature(s)",
1752 : " for benchmarking.",
1753 : " --repetitions <n> Use N repetitions (default "
1754 : STR2(NUM_MEASUREMENT_REPETITIONS) ")",
1755 : " --unaligned Use unaligned input buffers.",
1756 : " --csv Use CSV output format",
1757 : NULL
1758 : };
1759 : const char **line;
1760 :
1761 0 : for (line = help_lines; *line; line++)
1762 0 : fprintf (stdout, "%s\n", *line);
1763 0 : }
1764 :
1765 :
1766 : /* Warm up CPU. */
1767 : static void
1768 1 : warm_up_cpu (void)
1769 : {
1770 : struct nsec_time start, end;
1771 :
1772 1 : get_nsec_time (&start);
1773 : do
1774 : {
1775 28084437 : get_nsec_time (&end);
1776 : }
1777 28084437 : while (get_time_nsec_diff (&start, &end) < 1000.0 * 1000.0 * 1000.0);
1778 1 : }
1779 :
1780 :
1781 : int
1782 1 : main (int argc, char **argv)
1783 : {
1784 1 : int last_argc = -1;
1785 :
1786 1 : if (argc)
1787 : {
1788 1 : argc--;
1789 1 : argv++;
1790 : }
1791 :
1792 : /* We skip this test if we are running under the test suite (no args
1793 : and srcdir defined) and GCRYPT_NO_BENCHMARKS is set. */
1794 1 : if (!argc && getenv ("srcdir") && getenv ("GCRYPT_NO_BENCHMARKS"))
1795 0 : exit (77);
1796 :
1797 1 : if (getenv ("GCRYPT_IN_REGRESSION_TEST"))
1798 : {
1799 1 : in_regression_test = 1;
1800 1 : num_measurement_repetitions = 2;
1801 : }
1802 : else
1803 0 : num_measurement_repetitions = NUM_MEASUREMENT_REPETITIONS;
1804 :
1805 2 : while (argc && last_argc != argc)
1806 : {
1807 0 : last_argc = argc;
1808 :
1809 0 : if (!strcmp (*argv, "--"))
1810 : {
1811 0 : argc--;
1812 0 : argv++;
1813 0 : break;
1814 : }
1815 0 : else if (!strcmp (*argv, "--help"))
1816 : {
1817 0 : print_help ();
1818 0 : exit (0);
1819 : }
1820 0 : else if (!strcmp (*argv, "--verbose"))
1821 : {
1822 0 : verbose++;
1823 0 : argc--;
1824 0 : argv++;
1825 : }
1826 0 : else if (!strcmp (*argv, "--debug"))
1827 : {
1828 0 : verbose += 2;
1829 0 : debug++;
1830 0 : argc--;
1831 0 : argv++;
1832 : }
1833 0 : else if (!strcmp (*argv, "--csv"))
1834 : {
1835 0 : csv_mode = 1;
1836 0 : argc--;
1837 0 : argv++;
1838 : }
1839 0 : else if (!strcmp (*argv, "--unaligned"))
1840 : {
1841 0 : unaligned_mode = 1;
1842 0 : argc--;
1843 0 : argv++;
1844 : }
1845 0 : else if (!strcmp (*argv, "--disable-hwf"))
1846 : {
1847 0 : argc--;
1848 0 : argv++;
1849 0 : if (argc)
1850 : {
1851 0 : if (gcry_control (GCRYCTL_DISABLE_HWF, *argv, NULL))
1852 0 : fprintf (stderr,
1853 : PGM
1854 : ": unknown hardware feature `%s' - option ignored\n",
1855 : *argv);
1856 0 : argc--;
1857 0 : argv++;
1858 : }
1859 : }
1860 0 : else if (!strcmp (*argv, "--cpu-mhz"))
1861 : {
1862 0 : argc--;
1863 0 : argv++;
1864 0 : if (argc)
1865 : {
1866 0 : cpu_ghz = atof (*argv);
1867 0 : cpu_ghz /= 1000; /* Mhz => Ghz */
1868 :
1869 0 : argc--;
1870 0 : argv++;
1871 : }
1872 : }
1873 0 : else if (!strcmp (*argv, "--repetitions"))
1874 : {
1875 0 : argc--;
1876 0 : argv++;
1877 0 : if (argc)
1878 : {
1879 0 : num_measurement_repetitions = atof (*argv);
1880 0 : if (num_measurement_repetitions < 2)
1881 : {
1882 0 : fprintf (stderr,
1883 : PGM
1884 : ": value for --repetitions too small - using %d\n",
1885 : NUM_MEASUREMENT_REPETITIONS);
1886 0 : num_measurement_repetitions = NUM_MEASUREMENT_REPETITIONS;
1887 : }
1888 0 : argc--;
1889 0 : argv++;
1890 : }
1891 : }
1892 : }
1893 :
1894 1 : xgcry_control (GCRYCTL_SET_VERBOSITY, (int) verbose);
1895 :
1896 1 : if (!gcry_check_version (GCRYPT_VERSION))
1897 : {
1898 0 : fprintf (stderr, PGM ": version mismatch; pgm=%s, library=%s\n",
1899 : GCRYPT_VERSION, gcry_check_version (NULL));
1900 0 : exit (1);
1901 : }
1902 :
1903 1 : if (debug)
1904 0 : xgcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1u, 0);
1905 :
1906 1 : xgcry_control (GCRYCTL_DISABLE_SECMEM, 0);
1907 1 : xgcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
1908 1 : xgcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
1909 :
1910 1 : if (in_regression_test)
1911 1 : fputs ("Note: " PGM " running in quick regression test mode.\n", stdout);
1912 :
1913 1 : if (!argc)
1914 : {
1915 1 : warm_up_cpu ();
1916 1 : hash_bench (NULL, 0);
1917 1 : mac_bench (NULL, 0);
1918 1 : cipher_bench (NULL, 0);
1919 1 : kdf_bench (NULL, 0);
1920 : }
1921 0 : else if (!strcmp (*argv, "hash"))
1922 : {
1923 0 : argc--;
1924 0 : argv++;
1925 :
1926 0 : warm_up_cpu ();
1927 0 : hash_bench ((argc == 0) ? NULL : argv, argc);
1928 : }
1929 0 : else if (!strcmp (*argv, "mac"))
1930 : {
1931 0 : argc--;
1932 0 : argv++;
1933 :
1934 0 : warm_up_cpu ();
1935 0 : mac_bench ((argc == 0) ? NULL : argv, argc);
1936 : }
1937 0 : else if (!strcmp (*argv, "cipher"))
1938 : {
1939 0 : argc--;
1940 0 : argv++;
1941 :
1942 0 : warm_up_cpu ();
1943 0 : cipher_bench ((argc == 0) ? NULL : argv, argc);
1944 : }
1945 0 : else if (!strcmp (*argv, "kdf"))
1946 : {
1947 0 : argc--;
1948 0 : argv++;
1949 :
1950 0 : warm_up_cpu ();
1951 0 : kdf_bench ((argc == 0) ? NULL : argv, argc);
1952 : }
1953 : else
1954 : {
1955 0 : fprintf (stderr, PGM ": unknown argument: %s\n", *argv);
1956 0 : print_help ();
1957 : }
1958 :
1959 1 : return 0;
1960 : }
1961 :
1962 : #endif /* !NO_GET_NSEC_TIME */
|