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