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