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