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