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