Add Poly1305 MAC
[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
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 get_nsec_time (struct nsec_time *t)
133 {
134   int err;
135
136   err = clock_gettime (CLOCK_REALTIME, &t->ts);
137   assert (err == 0);
138 }
139
140 static double
141 get_time_nsec_diff (struct nsec_time *start, struct nsec_time *end)
142 {
143   double nsecs;
144
145   nsecs = end->ts.tv_sec - start->ts.tv_sec;
146   nsecs *= 1000000.0 * 1000.0;  /* sec => nsec */
147
148   /* This way we don't have to care if tv_nsec unsigned or signed. */
149   if (end->ts.tv_nsec >= start->ts.tv_nsec)
150     nsecs += end->ts.tv_nsec - start->ts.tv_nsec;
151   else
152     nsecs -= start->ts.tv_nsec - end->ts.tv_nsec;
153
154   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 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   sumx = sumy = sumx2 = sumy2 = sumxy = 0;
246
247   for (i = 0; i < npoints; i++)
248     {
249       double x, y;
250
251       x = get_x (i, get_x_priv);        /* bytes */
252       y = y_points[i];          /* nsecs */
253
254       sumx += x;
255       sumy += y;
256       sumx2 += x * x;
257       /*sumy2 += y * y;*/
258       sumxy += x * y;
259     }
260
261   b = (npoints * sumxy - sumx * sumy) / (npoints * sumx2 - sumx * sumx);
262   a = (sumy - b * sumx) / npoints;
263
264   if (overhead)
265     *overhead = a;              /* nsecs */
266
267   return b;                     /* nsecs per byte */
268 }
269
270
271 double
272 get_bench_obj_point_x (unsigned int idx, void *priv)
273 {
274   struct bench_obj *obj = priv;
275   return (double) (obj->min_bufsize + (idx * obj->step_size));
276 }
277
278
279 unsigned int
280 get_num_measurements (struct bench_obj *obj)
281 {
282   unsigned int buf_range = obj->max_bufsize - obj->min_bufsize;
283   unsigned int num = buf_range / obj->step_size + 1;
284
285   while (obj->min_bufsize + (num * obj->step_size) > obj->max_bufsize)
286     num--;
287
288   return num + 1;
289 }
290
291
292 static int
293 double_cmp (const void *_a, const void *_b)
294 {
295   const double *a, *b;
296
297   a = _a;
298   b = _b;
299
300   if (*a > *b)
301     return 1;
302   if (*a < *b)
303     return -1;
304   return 0;
305 }
306
307
308 double
309 do_bench_obj_measurement (struct bench_obj *obj, void *buffer, size_t buflen,
310                           double *measurement_raw,
311                           unsigned int loop_iterations)
312 {
313   const unsigned int num_repetitions = obj->num_measure_repetitions;
314   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   if (num_repetitions < 1 || loop_iterations < 1)
320     return 0.0;
321
322   for (rep = 0; rep < num_repetitions; rep++)
323     {
324       get_nsec_time (&start);
325
326       for (loop = 0; loop < loop_iterations; loop++)
327         do_run (obj, buffer, buflen);
328
329       get_nsec_time (&end);
330
331       measurement_raw[rep] = get_time_nsec_diff (&start, &end);
332     }
333
334   /* Return median of repeated measurements. */
335   qsort (measurement_raw, num_repetitions, sizeof (measurement_raw[0]),
336          double_cmp);
337
338   if (num_repetitions % 2 == 1)
339     return measurement_raw[num_repetitions / 2];
340
341   res = measurement_raw[num_repetitions / 2]
342     + measurement_raw[num_repetitions / 2 - 1];
343   return res / 2;
344 }
345
346
347 unsigned int
348 adjust_loop_iterations_to_timer_accuracy (struct bench_obj *obj, void *buffer,
349                                           double *measurement_raw)
350 {
351   const double increase_thres = 3.0;
352   double tmp, nsecs;
353   unsigned int loop_iterations;
354   unsigned int test_bufsize;
355
356   test_bufsize = obj->min_bufsize;
357   if (test_bufsize == 0)
358     test_bufsize += obj->step_size;
359
360   loop_iterations = 0;
361   do
362     {
363       /* Increase loop iterations until we get other results than zero.  */
364       nsecs =
365         do_bench_obj_measurement (obj, buffer, test_bufsize,
366                                   measurement_raw, ++loop_iterations);
367     }
368   while (nsecs < 1.0 - 0.1);
369   do
370     {
371       /* Increase loop iterations until we get reasonable increase for elapsed time.  */
372       tmp =
373         do_bench_obj_measurement (obj, buffer, test_bufsize,
374                                   measurement_raw, ++loop_iterations);
375     }
376   while (tmp < nsecs * (increase_thres - 0.1));
377
378   return loop_iterations;
379 }
380
381
382 /* Benchmark and return linear regression slope in nanoseconds per byte.  */
383 double
384 do_slope_benchmark (struct bench_obj *obj)
385 {
386   unsigned int num_measurements;
387   double *measurements = NULL;
388   double *measurement_raw = NULL;
389   double slope, overhead;
390   unsigned int loop_iterations, midx, i;
391   unsigned char *real_buffer = NULL;
392   unsigned char *buffer;
393   size_t cur_bufsize;
394   int err;
395
396   err = obj->ops->initialize (obj);
397   if (err < 0)
398     return -1;
399
400   num_measurements = get_num_measurements (obj);
401   measurements = calloc (num_measurements, sizeof (*measurements));
402   if (!measurements)
403     goto err_free;
404
405   measurement_raw =
406     calloc (obj->num_measure_repetitions, sizeof (*measurement_raw));
407   if (!measurement_raw)
408     goto err_free;
409
410   if (num_measurements < 1 || obj->num_measure_repetitions < 1 ||
411       obj->max_bufsize < 1 || obj->min_bufsize > obj->max_bufsize)
412     goto err_free;
413
414   real_buffer = malloc (obj->max_bufsize + 128);
415   if (!real_buffer)
416     goto err_free;
417   /* Get aligned buffer */
418   buffer = real_buffer;
419   buffer += 128 - ((real_buffer - (unsigned char *) 0) & (128 - 1));
420
421   for (i = 0; i < obj->max_bufsize; i++)
422     buffer[i] = 0x55 ^ (-i);
423
424   /* Adjust number of loop iterations up to timer accuracy.  */
425   loop_iterations = adjust_loop_iterations_to_timer_accuracy (obj, buffer,
426                                                               measurement_raw);
427
428   /* Perform measurements */
429   for (midx = 0, cur_bufsize = obj->min_bufsize;
430        cur_bufsize <= obj->max_bufsize; cur_bufsize += obj->step_size, midx++)
431     {
432       measurements[midx] =
433         do_bench_obj_measurement (obj, buffer, cur_bufsize, measurement_raw,
434                                   loop_iterations);
435       measurements[midx] /= loop_iterations;
436     }
437
438   assert (midx == num_measurements);
439
440   slope =
441     get_slope (&get_bench_obj_point_x, obj, measurements, num_measurements,
442                &overhead);
443
444   free (measurement_raw);
445   free (real_buffer);
446   obj->ops->finalize (obj);
447
448   return slope;
449
450 err_free:
451   if (measurement_raw)
452     free (measurement_raw);
453   if (measurements)
454     free (measurements);
455   if (real_buffer)
456     free (real_buffer);
457   obj->ops->finalize (obj);
458
459   return -1;
460 }
461
462
463 /********************************************************** Printing results. */
464
465 static void
466 double_to_str (char *out, size_t outlen, double value)
467 {
468   const char *fmt;
469
470   if (value < 1.0)
471     fmt = "%.3f";
472   else if (value < 100.0)
473     fmt = "%.2f";
474   else
475     fmt = "%.1f";
476
477   snprintf (out, outlen, fmt, value);
478 }
479
480 static void
481 bench_print_result_csv (double nsecs_per_byte)
482 {
483   double cycles_per_byte, mbytes_per_sec;
484   char nsecpbyte_buf[16];
485   char mbpsec_buf[16];
486   char cpbyte_buf[16];
487
488   *cpbyte_buf = 0;
489
490   double_to_str (nsecpbyte_buf, sizeof (nsecpbyte_buf), nsecs_per_byte);
491
492   /* If user didn't provide CPU speed, we cannot show cycles/byte results.  */
493   if (cpu_ghz > 0.0)
494     {
495       cycles_per_byte = nsecs_per_byte * cpu_ghz;
496       double_to_str (cpbyte_buf, sizeof (cpbyte_buf), cycles_per_byte);
497     }
498
499   mbytes_per_sec =
500     (1000.0 * 1000.0 * 1000.0) / (nsecs_per_byte * 1024 * 1024);
501   double_to_str (mbpsec_buf, sizeof (mbpsec_buf), mbytes_per_sec);
502
503   /* We print two empty fields to allow for future enhancements.  */
504   printf ("%s,%s,%s,,,%s,ns/B,%s,MiB/s,%s,c/B\n",
505           current_section_name,
506           current_algo_name? current_algo_name : "",
507           current_mode_name? current_mode_name : "",
508           nsecpbyte_buf,
509           mbpsec_buf,
510           cpbyte_buf);
511
512 }
513
514 static void
515 bench_print_result_std (double nsecs_per_byte)
516 {
517   double cycles_per_byte, mbytes_per_sec;
518   char nsecpbyte_buf[16];
519   char mbpsec_buf[16];
520   char cpbyte_buf[16];
521
522   strcpy (cpbyte_buf, "-");
523
524   double_to_str (nsecpbyte_buf, sizeof (nsecpbyte_buf), nsecs_per_byte);
525
526   /* If user didn't provide CPU speed, we cannot show cycles/byte results.  */
527   if (cpu_ghz > 0.0)
528     {
529       cycles_per_byte = nsecs_per_byte * cpu_ghz;
530       double_to_str (cpbyte_buf, sizeof (cpbyte_buf), cycles_per_byte);
531     }
532
533   mbytes_per_sec =
534     (1000.0 * 1000.0 * 1000.0) / (nsecs_per_byte * 1024 * 1024);
535   double_to_str (mbpsec_buf, sizeof (mbpsec_buf), mbytes_per_sec);
536
537   strncat (nsecpbyte_buf, " ns/B", sizeof (nsecpbyte_buf) - 1);
538   strncat (mbpsec_buf, " MiB/s", sizeof (mbpsec_buf) - 1);
539   strncat (cpbyte_buf, " c/B", sizeof (cpbyte_buf) - 1);
540
541   printf ("%14s %15s %13s\n", nsecpbyte_buf, mbpsec_buf, cpbyte_buf);
542 }
543
544 static void
545 bench_print_result (double nsecs_per_byte)
546 {
547   if (csv_mode)
548     bench_print_result_csv (nsecs_per_byte);
549   else
550     bench_print_result_std (nsecs_per_byte);
551 }
552
553 static void
554 bench_print_section (const char *section_name, const char *print_name)
555 {
556   if (csv_mode)
557     {
558       gcry_free (current_section_name);
559       current_section_name = gcry_xstrdup (section_name);
560     }
561   else
562     printf ("%s:\n", print_name);
563 }
564
565 static void
566 bench_print_header (int algo_width, const char *algo_name)
567 {
568   if (csv_mode)
569     {
570       gcry_free (current_algo_name);
571       current_algo_name = gcry_xstrdup (algo_name);
572     }
573   else
574     {
575       if (algo_width < 0)
576         printf (" %-*s | ", -algo_width, algo_name);
577       else
578         printf (" %-*s | ", algo_width, algo_name);
579       printf ("%14s %15s %13s\n", "nanosecs/byte", "mebibytes/sec",
580               "cycles/byte");
581     }
582 }
583
584 static void
585 bench_print_algo (int algo_width, const char *algo_name)
586 {
587   if (csv_mode)
588     {
589       gcry_free (current_algo_name);
590       current_algo_name = gcry_xstrdup (algo_name);
591     }
592   else
593     {
594       if (algo_width < 0)
595         printf (" %-*s | ", -algo_width, algo_name);
596       else
597         printf (" %-*s | ", algo_width, algo_name);
598     }
599 }
600
601 static void
602 bench_print_mode (int width, const char *mode_name)
603 {
604   if (csv_mode)
605     {
606       gcry_free (current_mode_name);
607       current_mode_name = gcry_xstrdup (mode_name);
608     }
609   else
610     {
611       if (width < 0)
612         printf (" %-*s | ", -width, mode_name);
613       else
614         printf (" %*s | ", width, mode_name);
615       fflush (stdout);
616     }
617 }
618
619 static void
620 bench_print_footer (int algo_width)
621 {
622   if (!csv_mode)
623     printf (" %-*s =\n", algo_width, "");
624 }
625
626
627 /********************************************************* Cipher benchmarks. */
628
629 struct bench_cipher_mode
630 {
631   int mode;
632   const char *name;
633   struct bench_ops *ops;
634
635   int algo;
636 };
637
638
639 static int
640 bench_encrypt_init (struct bench_obj *obj)
641 {
642   struct bench_cipher_mode *mode = obj->priv;
643   gcry_cipher_hd_t hd;
644   int err, keylen;
645
646   obj->min_bufsize = BUF_START_SIZE;
647   obj->max_bufsize = BUF_END_SIZE;
648   obj->step_size = BUF_STEP_SIZE;
649   obj->num_measure_repetitions = num_measurement_repetitions;
650
651   err = gcry_cipher_open (&hd, mode->algo, mode->mode, 0);
652   if (err)
653     {
654       fprintf (stderr, PGM ": error opening cipher `%s'\n",
655                gcry_cipher_algo_name (mode->algo));
656       exit (1);
657     }
658
659   keylen = gcry_cipher_get_algo_keylen (mode->algo);
660   if (keylen)
661     {
662       char key[keylen];
663       int i;
664
665       for (i = 0; i < keylen; i++)
666         key[i] = 0x33 ^ (11 - i);
667
668       err = gcry_cipher_setkey (hd, key, keylen);
669       if (err)
670         {
671           fprintf (stderr, PGM ": gcry_cipher_setkey failed: %s\n",
672                    gpg_strerror (err));
673           gcry_cipher_close (hd);
674           exit (1);
675         }
676     }
677   else
678     {
679       fprintf (stderr, PGM ": failed to get key length for algorithm `%s'\n",
680                gcry_cipher_algo_name (mode->algo));
681       gcry_cipher_close (hd);
682       exit (1);
683     }
684
685   obj->priv = hd;
686
687   return 0;
688 }
689
690 static void
691 bench_encrypt_free (struct bench_obj *obj)
692 {
693   gcry_cipher_hd_t hd = obj->priv;
694
695   gcry_cipher_close (hd);
696 }
697
698 static void
699 bench_encrypt_do_bench (struct bench_obj *obj, void *buf, size_t buflen)
700 {
701   gcry_cipher_hd_t hd = obj->priv;
702   int err;
703
704   err = gcry_cipher_encrypt (hd, buf, buflen, buf, buflen);
705   if (err)
706     {
707       fprintf (stderr, PGM ": gcry_cipher_encrypt failed: %s\n",
708                gpg_strerror (err));
709       gcry_cipher_close (hd);
710       exit (1);
711     }
712 }
713
714 static void
715 bench_decrypt_do_bench (struct bench_obj *obj, void *buf, size_t buflen)
716 {
717   gcry_cipher_hd_t hd = obj->priv;
718   int err;
719
720   err = gcry_cipher_decrypt (hd, buf, buflen, buf, buflen);
721   if (err)
722     {
723       fprintf (stderr, PGM ": gcry_cipher_encrypt failed: %s\n",
724                gpg_strerror (err));
725       gcry_cipher_close (hd);
726       exit (1);
727     }
728 }
729
730 static struct bench_ops encrypt_ops = {
731   &bench_encrypt_init,
732   &bench_encrypt_free,
733   &bench_encrypt_do_bench
734 };
735
736 static struct bench_ops decrypt_ops = {
737   &bench_encrypt_init,
738   &bench_encrypt_free,
739   &bench_decrypt_do_bench
740 };
741
742
743 #ifdef HAVE_U64_TYPEDEF
744 static void
745 bench_ccm_encrypt_do_bench (struct bench_obj *obj, void *buf, size_t buflen)
746 {
747   gcry_cipher_hd_t hd = obj->priv;
748   int err;
749   char tag[8];
750   char nonce[11] = { 0x80, 0x01, };
751   u64 params[3];
752
753   gcry_cipher_setiv (hd, nonce, sizeof (nonce));
754
755   /* Set CCM lengths */
756   params[0] = buflen;
757   params[1] = 0;                /*aadlen */
758   params[2] = sizeof (tag);
759   err =
760     gcry_cipher_ctl (hd, GCRYCTL_SET_CCM_LENGTHS, params, sizeof (params));
761   if (err)
762     {
763       fprintf (stderr, PGM ": gcry_cipher_ctl failed: %s\n",
764                gpg_strerror (err));
765       gcry_cipher_close (hd);
766       exit (1);
767     }
768
769   err = gcry_cipher_encrypt (hd, buf, buflen, buf, buflen);
770   if (err)
771     {
772       fprintf (stderr, PGM ": gcry_cipher_encrypt failed: %s\n",
773                gpg_strerror (err));
774       gcry_cipher_close (hd);
775       exit (1);
776     }
777
778   err = gcry_cipher_gettag (hd, tag, sizeof (tag));
779   if (err)
780     {
781       fprintf (stderr, PGM ": gcry_cipher_gettag failed: %s\n",
782                gpg_strerror (err));
783       gcry_cipher_close (hd);
784       exit (1);
785     }
786 }
787
788 static void
789 bench_ccm_decrypt_do_bench (struct bench_obj *obj, void *buf, size_t buflen)
790 {
791   gcry_cipher_hd_t hd = obj->priv;
792   int err;
793   char tag[8] = { 0, };
794   char nonce[11] = { 0x80, 0x01, };
795   u64 params[3];
796
797   gcry_cipher_setiv (hd, nonce, sizeof (nonce));
798
799   /* Set CCM lengths */
800   params[0] = buflen;
801   params[1] = 0;                /*aadlen */
802   params[2] = sizeof (tag);
803   err =
804     gcry_cipher_ctl (hd, GCRYCTL_SET_CCM_LENGTHS, params, sizeof (params));
805   if (err)
806     {
807       fprintf (stderr, PGM ": gcry_cipher_ctl failed: %s\n",
808                gpg_strerror (err));
809       gcry_cipher_close (hd);
810       exit (1);
811     }
812
813   err = gcry_cipher_decrypt (hd, buf, buflen, buf, buflen);
814   if (err)
815     {
816       fprintf (stderr, PGM ": gcry_cipher_encrypt failed: %s\n",
817                gpg_strerror (err));
818       gcry_cipher_close (hd);
819       exit (1);
820     }
821
822   err = gcry_cipher_checktag (hd, tag, sizeof (tag));
823   if (gpg_err_code (err) == GPG_ERR_CHECKSUM)
824     err = gpg_error (GPG_ERR_NO_ERROR);
825   if (err)
826     {
827       fprintf (stderr, PGM ": gcry_cipher_gettag failed: %s\n",
828                gpg_strerror (err));
829       gcry_cipher_close (hd);
830       exit (1);
831     }
832 }
833
834 static void
835 bench_ccm_authenticate_do_bench (struct bench_obj *obj, void *buf,
836                                  size_t buflen)
837 {
838   gcry_cipher_hd_t hd = obj->priv;
839   int err;
840   char tag[8] = { 0, };
841   char nonce[11] = { 0x80, 0x01, };
842   u64 params[3];
843   char data = 0xff;
844
845   gcry_cipher_setiv (hd, nonce, sizeof (nonce));
846
847   /* Set CCM lengths */
848   params[0] = sizeof (data);    /*datalen */
849   params[1] = buflen;           /*aadlen */
850   params[2] = sizeof (tag);
851   err =
852     gcry_cipher_ctl (hd, GCRYCTL_SET_CCM_LENGTHS, params, sizeof (params));
853   if (err)
854     {
855       fprintf (stderr, PGM ": gcry_cipher_ctl failed: %s\n",
856                gpg_strerror (err));
857       gcry_cipher_close (hd);
858       exit (1);
859     }
860
861   err = gcry_cipher_authenticate (hd, buf, buflen);
862   if (err)
863     {
864       fprintf (stderr, PGM ": gcry_cipher_authenticate failed: %s\n",
865                gpg_strerror (err));
866       gcry_cipher_close (hd);
867       exit (1);
868     }
869
870   err = gcry_cipher_encrypt (hd, &data, sizeof (data), &data, sizeof (data));
871   if (err)
872     {
873       fprintf (stderr, PGM ": gcry_cipher_encrypt failed: %s\n",
874                gpg_strerror (err));
875       gcry_cipher_close (hd);
876       exit (1);
877     }
878
879   err = gcry_cipher_gettag (hd, tag, sizeof (tag));
880   if (err)
881     {
882       fprintf (stderr, PGM ": gcry_cipher_gettag failed: %s\n",
883                gpg_strerror (err));
884       gcry_cipher_close (hd);
885       exit (1);
886     }
887 }
888
889 static struct bench_ops ccm_encrypt_ops = {
890   &bench_encrypt_init,
891   &bench_encrypt_free,
892   &bench_ccm_encrypt_do_bench
893 };
894
895 static struct bench_ops ccm_decrypt_ops = {
896   &bench_encrypt_init,
897   &bench_encrypt_free,
898   &bench_ccm_decrypt_do_bench
899 };
900
901 static struct bench_ops ccm_authenticate_ops = {
902   &bench_encrypt_init,
903   &bench_encrypt_free,
904   &bench_ccm_authenticate_do_bench
905 };
906 #endif /*HAVE_U64_TYPEDEF*/
907
908
909 static void
910 bench_gcm_encrypt_do_bench (struct bench_obj *obj, void *buf, size_t buflen)
911 {
912   gcry_cipher_hd_t hd = obj->priv;
913   int err;
914   char tag[16];
915   char nonce[12] = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce,
916                      0xdb, 0xad, 0xde, 0xca, 0xf8, 0x88, };
917
918   gcry_cipher_setiv (hd, nonce, sizeof (nonce));
919
920   err = gcry_cipher_encrypt (hd, buf, buflen, buf, buflen);
921   if (err)
922     {
923       fprintf (stderr, PGM ": gcry_cipher_encrypt failed: %s\n",
924            gpg_strerror (err));
925       gcry_cipher_close (hd);
926       exit (1);
927     }
928
929   err = gcry_cipher_gettag (hd, tag, sizeof (tag));
930   if (err)
931     {
932       fprintf (stderr, PGM ": gcry_cipher_gettag failed: %s\n",
933            gpg_strerror (err));
934       gcry_cipher_close (hd);
935       exit (1);
936     }
937 }
938
939 static void
940 bench_gcm_decrypt_do_bench (struct bench_obj *obj, void *buf, size_t buflen)
941 {
942   gcry_cipher_hd_t hd = obj->priv;
943   int err;
944   char tag[16] = { 0, };
945   char nonce[12] = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce,
946                      0xdb, 0xad, 0xde, 0xca, 0xf8, 0x88, };
947
948   gcry_cipher_setiv (hd, nonce, sizeof (nonce));
949
950   err = gcry_cipher_decrypt (hd, buf, buflen, buf, buflen);
951   if (err)
952     {
953       fprintf (stderr, PGM ": gcry_cipher_encrypt failed: %s\n",
954            gpg_strerror (err));
955       gcry_cipher_close (hd);
956       exit (1);
957     }
958
959   err = gcry_cipher_checktag (hd, tag, sizeof (tag));
960   if (gpg_err_code (err) == GPG_ERR_CHECKSUM)
961     err = gpg_error (GPG_ERR_NO_ERROR);
962   if (err)
963     {
964       fprintf (stderr, PGM ": gcry_cipher_gettag failed: %s\n",
965            gpg_strerror (err));
966       gcry_cipher_close (hd);
967       exit (1);
968     }
969 }
970
971 static void
972 bench_gcm_authenticate_do_bench (struct bench_obj *obj, void *buf,
973            size_t buflen)
974 {
975   gcry_cipher_hd_t hd = obj->priv;
976   int err;
977   char tag[16] = { 0, };
978   char nonce[12] = { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce,
979                      0xdb, 0xad, 0xde, 0xca, 0xf8, 0x88, };
980   char data = 0xff;
981
982   gcry_cipher_setiv (hd, nonce, sizeof (nonce));
983
984   err = gcry_cipher_authenticate (hd, buf, buflen);
985   if (err)
986     {
987       fprintf (stderr, PGM ": gcry_cipher_authenticate failed: %s\n",
988            gpg_strerror (err));
989       gcry_cipher_close (hd);
990       exit (1);
991     }
992
993   err = gcry_cipher_encrypt (hd, &data, sizeof (data), &data, sizeof (data));
994   if (err)
995     {
996       fprintf (stderr, PGM ": gcry_cipher_encrypt failed: %s\n",
997            gpg_strerror (err));
998       gcry_cipher_close (hd);
999       exit (1);
1000     }
1001
1002   err = gcry_cipher_gettag (hd, tag, sizeof (tag));
1003   if (err)
1004     {
1005       fprintf (stderr, PGM ": gcry_cipher_gettag failed: %s\n",
1006            gpg_strerror (err));
1007       gcry_cipher_close (hd);
1008       exit (1);
1009     }
1010 }
1011
1012 static struct bench_ops gcm_encrypt_ops = {
1013   &bench_encrypt_init,
1014   &bench_encrypt_free,
1015   &bench_gcm_encrypt_do_bench
1016 };
1017
1018 static struct bench_ops gcm_decrypt_ops = {
1019   &bench_encrypt_init,
1020   &bench_encrypt_free,
1021   &bench_gcm_decrypt_do_bench
1022 };
1023
1024 static struct bench_ops gcm_authenticate_ops = {
1025   &bench_encrypt_init,
1026   &bench_encrypt_free,
1027   &bench_gcm_authenticate_do_bench
1028 };
1029
1030
1031 static struct bench_cipher_mode cipher_modes[] = {
1032   {GCRY_CIPHER_MODE_ECB, "ECB enc", &encrypt_ops},
1033   {GCRY_CIPHER_MODE_ECB, "ECB dec", &decrypt_ops},
1034   {GCRY_CIPHER_MODE_CBC, "CBC enc", &encrypt_ops},
1035   {GCRY_CIPHER_MODE_CBC, "CBC dec", &decrypt_ops},
1036   {GCRY_CIPHER_MODE_CFB, "CFB enc", &encrypt_ops},
1037   {GCRY_CIPHER_MODE_CFB, "CFB dec", &decrypt_ops},
1038   {GCRY_CIPHER_MODE_OFB, "OFB enc", &encrypt_ops},
1039   {GCRY_CIPHER_MODE_OFB, "OFB dec", &decrypt_ops},
1040   {GCRY_CIPHER_MODE_CTR, "CTR enc", &encrypt_ops},
1041   {GCRY_CIPHER_MODE_CTR, "CTR dec", &decrypt_ops},
1042 #ifdef HAVE_U64_TYPEDEF
1043   {GCRY_CIPHER_MODE_CCM, "CCM enc", &ccm_encrypt_ops},
1044   {GCRY_CIPHER_MODE_CCM, "CCM dec", &ccm_decrypt_ops},
1045   {GCRY_CIPHER_MODE_CCM, "CCM auth", &ccm_authenticate_ops},
1046 #endif
1047   {GCRY_CIPHER_MODE_GCM, "GCM enc", &gcm_encrypt_ops},
1048   {GCRY_CIPHER_MODE_GCM, "GCM dec", &gcm_decrypt_ops},
1049   {GCRY_CIPHER_MODE_GCM, "GCM auth", &gcm_authenticate_ops},
1050   {0},
1051 };
1052
1053
1054 static void
1055 cipher_bench_one (int algo, struct bench_cipher_mode *pmode)
1056 {
1057   struct bench_cipher_mode mode = *pmode;
1058   struct bench_obj obj = { 0 };
1059   double result;
1060   unsigned int blklen;
1061
1062   mode.algo = algo;
1063
1064   /* Check if this mode is ok */
1065   blklen = gcry_cipher_get_algo_blklen (algo);
1066   if (!blklen)
1067     return;
1068
1069   /* Stream cipher? Only test with ECB. */
1070   if (blklen == 1 && mode.mode != GCRY_CIPHER_MODE_ECB)
1071     return;
1072   if (blklen == 1 && mode.mode == GCRY_CIPHER_MODE_ECB)
1073     {
1074       mode.mode = GCRY_CIPHER_MODE_STREAM;
1075       mode.name = mode.ops == &encrypt_ops ? "STREAM enc" : "STREAM dec";
1076     }
1077
1078   /* CCM has restrictions for block-size */
1079   if (mode.mode == GCRY_CIPHER_MODE_CCM && blklen != GCRY_CCM_BLOCK_LEN)
1080     return;
1081
1082   /* CCM has restrictions for block-size */
1083   if (mode.mode == GCRY_CIPHER_MODE_GCM && blklen != GCRY_GCM_BLOCK_LEN)
1084     return;
1085
1086   bench_print_mode (14, mode.name);
1087
1088   obj.ops = mode.ops;
1089   obj.priv = &mode;
1090
1091   result = do_slope_benchmark (&obj);
1092
1093   bench_print_result (result);
1094 }
1095
1096
1097 static void
1098 _cipher_bench (int algo)
1099 {
1100   const char *algoname;
1101   int i;
1102
1103   algoname = gcry_cipher_algo_name (algo);
1104
1105   bench_print_header (14, algoname);
1106
1107   for (i = 0; cipher_modes[i].mode; i++)
1108     cipher_bench_one (algo, &cipher_modes[i]);
1109
1110   bench_print_footer (14);
1111 }
1112
1113
1114 void
1115 cipher_bench (char **argv, int argc)
1116 {
1117   int i, algo;
1118
1119   bench_print_section ("cipher", "Cipher");
1120
1121   if (argv && argc)
1122     {
1123       for (i = 0; i < argc; i++)
1124         {
1125           algo = gcry_cipher_map_name (argv[i]);
1126           if (algo)
1127             _cipher_bench (algo);
1128         }
1129     }
1130   else
1131     {
1132       for (i = 1; i < 400; i++)
1133         if (!gcry_cipher_test_algo (i))
1134           _cipher_bench (i);
1135     }
1136 }
1137
1138
1139 /*********************************************************** Hash benchmarks. */
1140
1141 struct bench_hash_mode
1142 {
1143   const char *name;
1144   struct bench_ops *ops;
1145
1146   int algo;
1147 };
1148
1149
1150 static int
1151 bench_hash_init (struct bench_obj *obj)
1152 {
1153   struct bench_hash_mode *mode = obj->priv;
1154   gcry_md_hd_t hd;
1155   int err;
1156
1157   obj->min_bufsize = BUF_START_SIZE;
1158   obj->max_bufsize = BUF_END_SIZE;
1159   obj->step_size = BUF_STEP_SIZE;
1160   obj->num_measure_repetitions = num_measurement_repetitions;
1161
1162   err = gcry_md_open (&hd, mode->algo, 0);
1163   if (err)
1164     {
1165       fprintf (stderr, PGM ": error opening hash `%s'\n",
1166                gcry_md_algo_name (mode->algo));
1167       exit (1);
1168     }
1169
1170   obj->priv = hd;
1171
1172   return 0;
1173 }
1174
1175 static void
1176 bench_hash_free (struct bench_obj *obj)
1177 {
1178   gcry_md_hd_t hd = obj->priv;
1179
1180   gcry_md_close (hd);
1181 }
1182
1183 static void
1184 bench_hash_do_bench (struct bench_obj *obj, void *buf, size_t buflen)
1185 {
1186   gcry_md_hd_t hd = obj->priv;
1187
1188   gcry_md_reset (hd);
1189   gcry_md_write (hd, buf, buflen);
1190   gcry_md_final (hd);
1191 }
1192
1193 static struct bench_ops hash_ops = {
1194   &bench_hash_init,
1195   &bench_hash_free,
1196   &bench_hash_do_bench
1197 };
1198
1199
1200 static struct bench_hash_mode hash_modes[] = {
1201   {"", &hash_ops},
1202   {0},
1203 };
1204
1205
1206 static void
1207 hash_bench_one (int algo, struct bench_hash_mode *pmode)
1208 {
1209   struct bench_hash_mode mode = *pmode;
1210   struct bench_obj obj = { 0 };
1211   double result;
1212
1213   mode.algo = algo;
1214
1215   if (mode.name[0] == '\0')
1216     bench_print_algo (-14, gcry_md_algo_name (algo));
1217   else
1218     bench_print_algo (14, mode.name);
1219
1220   obj.ops = mode.ops;
1221   obj.priv = &mode;
1222
1223   result = do_slope_benchmark (&obj);
1224
1225   bench_print_result (result);
1226 }
1227
1228 static void
1229 _hash_bench (int algo)
1230 {
1231   int i;
1232
1233   for (i = 0; hash_modes[i].name; i++)
1234     hash_bench_one (algo, &hash_modes[i]);
1235 }
1236
1237 void
1238 hash_bench (char **argv, int argc)
1239 {
1240   int i, algo;
1241
1242   bench_print_section ("hash", "Hash");
1243   bench_print_header (14, "");
1244
1245   if (argv && argc)
1246     {
1247       for (i = 0; i < argc; i++)
1248         {
1249           algo = gcry_md_map_name (argv[i]);
1250           if (algo)
1251             _hash_bench (algo);
1252         }
1253     }
1254   else
1255     {
1256       for (i = 1; i < 400; i++)
1257         if (!gcry_md_test_algo (i))
1258           _hash_bench (i);
1259     }
1260
1261   bench_print_footer (14);
1262 }
1263
1264
1265 /************************************************************ MAC benchmarks. */
1266
1267 struct bench_mac_mode
1268 {
1269   const char *name;
1270   struct bench_ops *ops;
1271
1272   int algo;
1273 };
1274
1275
1276 static int
1277 bench_mac_init (struct bench_obj *obj)
1278 {
1279   struct bench_mac_mode *mode = obj->priv;
1280   gcry_mac_hd_t hd;
1281   int err;
1282   unsigned int keylen;
1283   void *key;
1284
1285   obj->min_bufsize = BUF_START_SIZE;
1286   obj->max_bufsize = BUF_END_SIZE;
1287   obj->step_size = BUF_STEP_SIZE;
1288   obj->num_measure_repetitions = num_measurement_repetitions;
1289
1290   keylen = gcry_mac_get_algo_keylen (mode->algo);
1291   if (keylen == 0)
1292     keylen = 32;
1293   key = malloc (keylen);
1294   if (!key)
1295     {
1296       fprintf (stderr, PGM ": couldn't allocate %d bytes\n", keylen);
1297       exit (1);
1298     }
1299   memset(key, 42, keylen);
1300
1301   err = gcry_mac_open (&hd, mode->algo, 0, NULL);
1302   if (err)
1303     {
1304       fprintf (stderr, PGM ": error opening mac `%s'\n",
1305                gcry_mac_algo_name (mode->algo));
1306       free (key);
1307       exit (1);
1308     }
1309
1310   err = gcry_mac_setkey (hd, key, keylen);
1311   free (key);
1312   if (err)
1313     {
1314       fprintf (stderr, PGM ": error setting key for mac `%s'\n",
1315                gcry_mac_algo_name (mode->algo));
1316       exit (1);
1317     }
1318
1319   obj->priv = hd;
1320
1321   return 0;
1322 }
1323
1324 static void
1325 bench_mac_free (struct bench_obj *obj)
1326 {
1327   gcry_mac_hd_t hd = obj->priv;
1328
1329   gcry_mac_close (hd);
1330 }
1331
1332 static void
1333 bench_mac_do_bench (struct bench_obj *obj, void *buf, size_t buflen)
1334 {
1335   gcry_mac_hd_t hd = obj->priv;
1336   size_t bs;
1337   char b;
1338
1339   gcry_mac_reset (hd);
1340   gcry_mac_write (hd, buf, buflen);
1341   bs = sizeof(b);
1342   gcry_mac_read (hd, &b, &bs);
1343 }
1344
1345 static struct bench_ops mac_ops = {
1346   &bench_mac_init,
1347   &bench_mac_free,
1348   &bench_mac_do_bench
1349 };
1350
1351
1352 static struct bench_mac_mode mac_modes[] = {
1353   {"", &mac_ops},
1354   {0},
1355 };
1356
1357
1358 static void
1359 mac_bench_one (int algo, struct bench_mac_mode *pmode)
1360 {
1361   struct bench_mac_mode mode = *pmode;
1362   struct bench_obj obj = { 0 };
1363   double result;
1364
1365   mode.algo = algo;
1366
1367   if (mode.name[0] == '\0')
1368     bench_print_algo (-18, gcry_mac_algo_name (algo));
1369   else
1370     bench_print_algo (18, mode.name);
1371
1372   obj.ops = mode.ops;
1373   obj.priv = &mode;
1374
1375   result = do_slope_benchmark (&obj);
1376
1377   bench_print_result (result);
1378 }
1379
1380 static void
1381 _mac_bench (int algo)
1382 {
1383   int i;
1384
1385   for (i = 0; mac_modes[i].name; i++)
1386     mac_bench_one (algo, &mac_modes[i]);
1387 }
1388
1389 void
1390 mac_bench (char **argv, int argc)
1391 {
1392   int i, algo;
1393
1394   bench_print_section ("mac", "MAC");
1395   bench_print_header (18, "");
1396
1397   if (argv && argc)
1398     {
1399       for (i = 0; i < argc; i++)
1400         {
1401           algo = gcry_mac_map_name (argv[i]);
1402           if (algo)
1403             _mac_bench (algo);
1404         }
1405     }
1406   else
1407     {
1408       for (i = 1; i < 600; i++)
1409         if (!gcry_mac_test_algo (i))
1410           _mac_bench (i);
1411     }
1412
1413   bench_print_footer (18);
1414 }
1415
1416
1417 /************************************************************** Main program. */
1418
1419 void
1420 print_help (void)
1421 {
1422   static const char *help_lines[] = {
1423     "usage: bench-slope [options] [hash|mac|cipher [algonames]]",
1424     "",
1425     " options:",
1426     "   --cpu-mhz <mhz>           Set CPU speed for calculating cycles",
1427     "                             per bytes results.",
1428     "   --disable-hwf <features>  Disable hardware acceleration feature(s)",
1429     "                             for benchmarking.",
1430     "   --repetitions <n>         Use N repetitions (default "
1431                                      STR2(NUM_MEASUREMENT_REPETITIONS) ")",
1432     "   --csv                     Use CSV output format",
1433     NULL
1434   };
1435   const char **line;
1436
1437   for (line = help_lines; *line; line++)
1438     fprintf (stdout, "%s\n", *line);
1439 }
1440
1441
1442 /* Warm up CPU.  */
1443 static void
1444 warm_up_cpu (void)
1445 {
1446   struct nsec_time start, end;
1447
1448   get_nsec_time (&start);
1449   do
1450     {
1451       get_nsec_time (&end);
1452     }
1453   while (get_time_nsec_diff (&start, &end) < 1000.0 * 1000.0 * 1000.0);
1454 }
1455
1456
1457 int
1458 main (int argc, char **argv)
1459 {
1460   int last_argc = -1;
1461   int debug = 0;
1462
1463   if (argc)
1464     {
1465       argc--;
1466       argv++;
1467     }
1468
1469   /* We skip this test if we are running under the test suite (no args
1470      and srcdir defined) and GCRYPT_NO_BENCHMARKS is set.  */
1471   if (!argc && getenv ("srcdir") && getenv ("GCRYPT_NO_BENCHMARKS"))
1472     exit (77);
1473
1474   if (getenv ("GCRYPT_IN_REGRESSION_TEST"))
1475     {
1476       in_regression_test = 1;
1477       num_measurement_repetitions = 2;
1478     }
1479   else
1480     num_measurement_repetitions = NUM_MEASUREMENT_REPETITIONS;
1481
1482   while (argc && last_argc != argc)
1483     {
1484       last_argc = argc;
1485
1486       if (!strcmp (*argv, "--"))
1487         {
1488           argc--;
1489           argv++;
1490           break;
1491         }
1492       else if (!strcmp (*argv, "--help"))
1493         {
1494           print_help ();
1495           exit (0);
1496         }
1497       else if (!strcmp (*argv, "--verbose"))
1498         {
1499           verbose++;
1500           argc--;
1501           argv++;
1502         }
1503       else if (!strcmp (*argv, "--debug"))
1504         {
1505           verbose += 2;
1506           debug++;
1507           argc--;
1508           argv++;
1509         }
1510       else if (!strcmp (*argv, "--csv"))
1511         {
1512           csv_mode = 1;
1513           argc--;
1514           argv++;
1515         }
1516       else if (!strcmp (*argv, "--disable-hwf"))
1517         {
1518           argc--;
1519           argv++;
1520           if (argc)
1521             {
1522               if (gcry_control (GCRYCTL_DISABLE_HWF, *argv, NULL))
1523                 fprintf (stderr,
1524                          PGM
1525                          ": unknown hardware feature `%s' - option ignored\n",
1526                          *argv);
1527               argc--;
1528               argv++;
1529             }
1530         }
1531       else if (!strcmp (*argv, "--cpu-mhz"))
1532         {
1533           argc--;
1534           argv++;
1535           if (argc)
1536             {
1537               cpu_ghz = atof (*argv);
1538               cpu_ghz /= 1000;  /* Mhz => Ghz */
1539
1540               argc--;
1541               argv++;
1542             }
1543         }
1544       else if (!strcmp (*argv, "--repetitions"))
1545         {
1546           argc--;
1547           argv++;
1548           if (argc)
1549             {
1550               num_measurement_repetitions = atof (*argv);
1551               if (num_measurement_repetitions < 2)
1552                 {
1553                   fprintf (stderr,
1554                            PGM
1555                            ": value for --repetitions too small - using %d\n",
1556                            NUM_MEASUREMENT_REPETITIONS);
1557                   num_measurement_repetitions = NUM_MEASUREMENT_REPETITIONS;
1558                 }
1559               argc--;
1560               argv++;
1561             }
1562         }
1563     }
1564
1565   gcry_control (GCRYCTL_SET_VERBOSITY, (int) verbose);
1566
1567   if (!gcry_check_version (GCRYPT_VERSION))
1568     {
1569       fprintf (stderr, PGM ": version mismatch; pgm=%s, library=%s\n",
1570                GCRYPT_VERSION, gcry_check_version (NULL));
1571       exit (1);
1572     }
1573
1574   if (debug)
1575     gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1u, 0);
1576
1577   gcry_control (GCRYCTL_DISABLE_SECMEM, 0);
1578   gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
1579   gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
1580
1581   if (in_regression_test)
1582     fputs ("Note: " PGM " running in quick regression test mode.\n", stdout);
1583
1584   if (!argc)
1585     {
1586       warm_up_cpu ();
1587       hash_bench (NULL, 0);
1588       mac_bench (NULL, 0);
1589       cipher_bench (NULL, 0);
1590     }
1591   else if (!strcmp (*argv, "hash"))
1592     {
1593       argc--;
1594       argv++;
1595
1596       warm_up_cpu ();
1597       hash_bench ((argc == 0) ? NULL : argv, argc);
1598     }
1599   else if (!strcmp (*argv, "mac"))
1600     {
1601       argc--;
1602       argv++;
1603
1604       warm_up_cpu ();
1605       mac_bench ((argc == 0) ? NULL : argv, argc);
1606     }
1607   else if (!strcmp (*argv, "cipher"))
1608     {
1609       argc--;
1610       argv++;
1611
1612       warm_up_cpu ();
1613       cipher_bench ((argc == 0) ? NULL : argv, argc);
1614     }
1615   else
1616     {
1617       fprintf (stderr, PGM ": unknown argument: %s\n", *argv);
1618       print_help ();
1619     }
1620
1621   return 0;
1622 }
1623
1624 #endif /* !NO_GET_NSEC_TIME */