LCOV - code coverage report
Current view: top level - tests - bench-slope.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 522 752 69.4 %
Date: 2016-12-15 12:59:22 Functions: 58 60 96.7 %

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

Generated by: LCOV version 1.12