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