LCOV - code coverage report
Current view: top level - tests - bench-slope.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 560 804 69.7 %
Date: 2017-03-02 16:44:37 Functions: 61 63 96.8 %

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

Generated by: LCOV version 1.13