[git] GCRYPT - branch, master, updated. libgcrypt-1.5.0-340-ge214e83

by Jussi Kivilinna cvs at cvs.gnupg.org
Mon Oct 28 15:11:49 CET 2013


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "The GNU crypto library".

The branch, master has been updated
       via  e214e8392671dd30e9c33260717b5e756debf3bf (commit)
      from  ebc8abfcb09d6106fcfce40f240a513e276f46e9 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit e214e8392671dd30e9c33260717b5e756debf3bf
Author: Jussi Kivilinna <jussi.kivilinna at iki.fi>
Date:   Sat Oct 26 15:00:48 2013 +0300

    Add new benchmarking utility, bench-slope
    
    * tests/Makefile.am (TESTS): Add 'bench-slope'.
    * tests/bench-slope.c: New.
    --
    
    Bench-slope is new benchmarking tool for libgcrypt for obtaining overheadless
    cycles/byte speed of cipher and hash algorithms. Tool measures the time each
    operation (hash/encrypt/decrypt/authentication) takes for different buffer
    sizes of from ~0kB to ~4kB and calculates the slope for these data points.
    The default output is then given as nanosecs/byte and mebibytes/sec. If user
    provides the speed of used CPU, tool also outputs cycles/byte result (CPU-Ghz *
    ns/B = c/B).
    
    Output without CPU speed (with ARM Cortex-A8):
    
    $ tests/bench-slope hash
    
    Hash:
                    |  nanosecs/byte   mebibytes/sec   cycles/byte
     MD5            |      7.35 ns/B     129.7 MiB/s         - c/B
     SHA1           |     12.30 ns/B     77.53 MiB/s         - c/B
     RIPEMD160      |     15.96 ns/B     59.77 MiB/s         - c/B
     TIGER192       |     55.55 ns/B     17.17 MiB/s         - c/B
     SHA256         |     24.38 ns/B     39.12 MiB/s         - c/B
     SHA384         |     34.24 ns/B     27.86 MiB/s         - c/B
     SHA512         |     34.19 ns/B     27.90 MiB/s         - c/B
     SHA224         |     24.38 ns/B     39.12 MiB/s         - c/B
     MD4            |      5.68 ns/B     168.0 MiB/s         - c/B
     CRC32          |      9.26 ns/B     103.0 MiB/s         - c/B
     CRC32RFC1510   |      9.20 ns/B     103.6 MiB/s         - c/B
     CRC24RFC2440   |     87.31 ns/B     10.92 MiB/s         - c/B
     WHIRLPOOL      |     253.3 ns/B      3.77 MiB/s         - c/B
     TIGER          |     55.55 ns/B     17.17 MiB/s         - c/B
     TIGER2         |     55.55 ns/B     17.17 MiB/s         - c/B
     GOSTR3411_94   |     212.0 ns/B      4.50 MiB/s         - c/B
     STRIBOG256     |     630.1 ns/B      1.51 MiB/s         - c/B
     STRIBOG512     |     630.1 ns/B      1.51 MiB/s         - c/B
                    =
    
    With CPU speed (with Intel i5-4570, 3.2Ghz when turbo-boost disabled):
    
    $ tests/bench-slope --cpu-mhz 3201 cipher arcfour blowfish aes
    Cipher:
     ARCFOUR        |  nanosecs/byte   mebibytes/sec   cycles/byte
         STREAM enc |      2.43 ns/B     392.1 MiB/s      7.79 c/B
         STREAM dec |      2.44 ns/B     390.2 MiB/s      7.82 c/B
                    =
     BLOWFISH       |  nanosecs/byte   mebibytes/sec   cycles/byte
            ECB enc |      7.62 ns/B     125.2 MiB/s     24.38 c/B
            ECB dec |      7.63 ns/B     125.0 MiB/s     24.43 c/B
            CBC enc |      9.18 ns/B     103.9 MiB/s     29.38 c/B
            CBC dec |      2.60 ns/B     366.2 MiB/s      8.34 c/B
            CFB enc |      9.17 ns/B     104.0 MiB/s     29.35 c/B
            CFB dec |      2.66 ns/B     358.1 MiB/s      8.53 c/B
            OFB enc |      8.97 ns/B     106.3 MiB/s     28.72 c/B
            OFB dec |      8.97 ns/B     106.3 MiB/s     28.71 c/B
            CTR enc |      2.60 ns/B     366.5 MiB/s      8.33 c/B
            CTR dec |      2.60 ns/B     367.1 MiB/s      8.32 c/B
                    =
     AES            |  nanosecs/byte   mebibytes/sec   cycles/byte
            ECB enc |     0.439 ns/B    2173.0 MiB/s      1.40 c/B
            ECB dec |     0.489 ns/B    1949.5 MiB/s      1.57 c/B
            CBC enc |      1.64 ns/B     580.8 MiB/s      5.26 c/B
            CBC dec |     0.219 ns/B    4357.6 MiB/s     0.701 c/B
            CFB enc |      1.53 ns/B     623.6 MiB/s      4.90 c/B
            CFB dec |     0.219 ns/B    4350.5 MiB/s     0.702 c/B
            OFB enc |      1.51 ns/B     629.9 MiB/s      4.85 c/B
            OFB dec |      1.51 ns/B     629.9 MiB/s      4.85 c/B
            CTR enc |     0.288 ns/B    3308.5 MiB/s     0.923 c/B
            CTR dec |     0.288 ns/B    3316.9 MiB/s     0.920 c/B
            CCM enc |      1.93 ns/B     493.8 MiB/s      6.18 c/B
            CCM dec |      1.93 ns/B     494.0 MiB/s      6.18 c/B
           CCM auth |      1.64 ns/B     580.1 MiB/s      5.26 c/B
                    =
    
    Note: It's highly recommented to disable turbo-boost and dynamic CPU frequency
    features when making these kind of measurements to reduce variance.
    
    Note: The results are maximum performance for each operation; the actual speed
    in application depends on various matters, such as: used buffer sizes, cache
    usage, etc.
    
    Signed-off-by: Jussi Kivilinna <jussi.kivilinna at iki.fi>

diff --git a/tests/Makefile.am b/tests/Makefile.am
index ac84e75..c9ba5f4 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -24,8 +24,8 @@ TESTS = version mpitests tsexp t-convert \
 	fips186-dsa aeswrap pkcs1v2 random dsa-rfc6979 t-ed25519
 
 
-# The last test to run.
-TESTS += benchmark
+# The last tests to run.
+TESTS += benchmark bench-slope
 
 
 # Need to include ../src in addition to top_srcdir because gcrypt.h is
diff --git a/tests/bench-slope.c b/tests/bench-slope.c
new file mode 100644
index 0000000..62543bc
--- /dev/null
+++ b/tests/bench-slope.c
@@ -0,0 +1,1172 @@
+/* bench-slope.c - for libgcrypt
+ * Copyright © 2013 Jussi Kivilinna <jussi.kivilinna at iki.fi>
+ *
+ * This file is part of Libgcrypt.
+ *
+ * Libgcrypt is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser general Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * Libgcrypt is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <assert.h>
+#include <time.h>
+
+#ifdef _GCRYPT_IN_LIBGCRYPT
+#include "../src/gcrypt-int.h"
+#include "../compat/libcompat.h"
+#else
+#include <gcrypt.h>
+#endif
+
+#define PGM "bench-slope"
+
+static int verbose;
+
+
+/* CPU Ghz value provided by user, allows constructing cycles/byte and other
+   results.  */
+static double cpu_ghz = -1;
+
+
+
+/*************************************** Default parameters for measurements. */
+
+/* Start at small buffer size, to get reasonable timer calibration for fast
+ * implementations (AES-NI etc). Sixteen selected to support the largest block
+ * size of current set cipher blocks. */
+#define BUF_START_SIZE			16
+
+/* From ~0 to ~4kbytes give comparable results with results from academia
+ * (SUPERCOP). */
+#define BUF_END_SIZE			(BUF_START_SIZE + 4096)
+
+/* With 128 byte steps, we get (4096)/128 = 32 data points. */
+#define BUF_STEP_SIZE			128
+
+/* Number of repeated measurements at each data point. The median of these
+ * measurements is selected as data point further analysis. */
+#define NUM_MEASUREMENT_REPETITIONS	32
+
+/**************************************************** High-resolution timers. */
+
+/* This benchmarking module needs needs high resolution timer.  */
+#undef NO_GET_NSEC_TIME
+#if defined(_WIN32)
+struct nsec_time
+{
+  LARGE_INTEGER perf_count;
+};
+
+static void
+get_nsec_time (struct nsec_time *t)
+{
+  BOOL ok;
+
+  ok = QueryPerformanceCounter (&t->perf_count);
+  assert (ok);
+}
+
+static double
+get_time_nsec_diff (struct nsec_time *start, struct nsec_time *end)
+{
+  static double nsecs_per_count = 0.0;
+  double nsecs;
+
+  if (nsecs_per_count == 0.0)
+    {
+      LARGE_INTEGER perf_freq;
+      BOOL ok;
+
+      /* Get counts per second. */
+      ok = QueryPerformanceFrequency (&perf_freq);
+      assert (ok);
+
+      nsecs_per_count = 1.0 / perf_freq.QuadPart;
+      nsecs_per_count *= 1000000.0 * 1000.0;	/* sec => nsec */
+
+      assert (nsecs_per_count > 0.0);
+    }
+
+  nsecs = end->perf_count.QuadPart - start->perf_count.QuadPart;	/* counts */
+  nsecs *= nsecs_per_count;	/* counts * (nsecs / count) => nsecs */
+
+  return nsecs;
+}
+#elif defined(HAVE_CLOCK_GETTIME)
+struct nsec_time
+{
+  struct timespec ts;
+};
+
+static void
+get_nsec_time (struct nsec_time *t)
+{
+  int err;
+
+  err = clock_gettime (CLOCK_REALTIME, &t->ts);
+  assert (err == 0);
+}
+
+static double
+get_time_nsec_diff (struct nsec_time *start, struct nsec_time *end)
+{
+  double nsecs;
+
+  nsecs = end->ts.tv_sec - start->ts.tv_sec;
+  nsecs *= 1000000.0 * 1000.0;	/* sec => nsec */
+
+  /* This way we don't have to care if tv_nsec unsigned or signed. */
+  if (end->ts.tv_nsec >= start->ts.tv_nsec)
+    nsecs += end->ts.tv_nsec - start->ts.tv_nsec;
+  else
+    nsecs -= start->ts.tv_nsec - end->ts.tv_nsec;
+
+  return nsecs;
+}
+#elif defined(HAVE_GETTIMEOFDAY)
+struct nsec_time
+{
+  struct timeval tv;
+};
+
+static void
+get_nsec_time (struct nsec_time *t)
+{
+  int err;
+
+  err = gettimeofday (&t->tv, NULL);
+  assert (err == 0);
+}
+
+static double
+get_time_nsec_diff (struct nsec_time *start, struct nsec_time *end)
+{
+  double nsecs;
+
+  nsecs = end->tv.tv_sec - start->tv.tv_sec;
+  nsecs *= 1000000;		/* sec => µsec */
+
+  /* This way we don't have to care if tv_usec unsigned or signed. */
+  if (end->tv.tv_usec >= start->tv.tv_usec)
+    nsecs += end->tv.tv_usec - start->tv.tv_usec;
+  else
+    nsecs -= start->tv.tv_usec - end->tv.tv_usec;
+
+  nsecs *= 1000;		/* µsec => nsec */
+
+  return nsecs;
+}
+#else
+#define NO_GET_NSEC_TIME 1
+#endif
+
+
+/* If no high resolution timer found, provide dummy bench-slope.  */
+#ifdef NO_GET_NSEC_TIME
+
+
+int
+main (void)
+{
+  /* No nsec timer => SKIP test. */
+  return 77;
+}
+
+
+#else /* !NO_GET_NSEC_TIME */
+
+
+/********************************************** Slope benchmarking framework. */
+
+struct bench_obj
+{
+  const struct bench_ops *ops;
+
+  unsigned int num_measure_repetitions;
+  unsigned int min_bufsize;
+  unsigned int max_bufsize;
+  unsigned int step_size;
+
+  void *priv;
+};
+
+typedef int (*const bench_initialize_t) (struct bench_obj * obj);
+typedef void (*const bench_finalize_t) (struct bench_obj * obj);
+typedef void (*const bench_do_run_t) (struct bench_obj * obj, void *buffer,
+				      size_t buflen);
+
+struct bench_ops
+{
+  bench_initialize_t initialize;
+  bench_finalize_t finalize;
+  bench_do_run_t do_run;
+};
+
+
+double
+get_slope (double (*const get_x) (unsigned int idx, void *priv),
+	   void *get_x_priv, double y_points[], unsigned int npoints,
+	   double *overhead)
+{
+  double sumx, sumy, sumx2, sumy2, sumxy;
+  unsigned int i;
+  double b, a;
+
+  sumx = sumy = sumx2 = sumy2 = sumxy = 0;
+
+  for (i = 0; i < npoints; i++)
+    {
+      double x, y;
+
+      x = get_x (i, get_x_priv);	/* bytes */
+      y = y_points[i];		/* nsecs */
+
+      sumx += x;
+      sumy += y;
+      sumx2 += x * x;
+      //sumy2 += y * y;
+      sumxy += x * y;
+    }
+
+  b = (npoints * sumxy - sumx * sumy) / (npoints * sumx2 - sumx * sumx);
+  a = (sumy - b * sumx) / npoints;
+
+  if (overhead)
+    *overhead = a;		/* nsecs */
+
+  return b;			/* nsecs per byte */
+}
+
+
+double
+get_bench_obj_point_x (unsigned int idx, void *priv)
+{
+  struct bench_obj *obj = priv;
+  return (double) (obj->min_bufsize + (idx * obj->step_size));
+}
+
+
+unsigned int
+get_num_measurements (struct bench_obj *obj)
+{
+  unsigned int buf_range = obj->max_bufsize - obj->min_bufsize;
+  unsigned int num = buf_range / obj->step_size + 1;
+
+  while (obj->min_bufsize + (num * obj->step_size) > obj->max_bufsize)
+    num--;
+
+  return num + 1;
+}
+
+
+static int
+double_cmp (const void *__a, const void *__b)
+{
+  const double *a, *b;
+
+  a = __a;
+  b = __b;
+
+  if (*a > *b)
+    return 1;
+  if (*a < *b)
+    return -1;
+  return 0;
+}
+
+
+double
+do_bench_obj_measurement (struct bench_obj *obj, void *buffer, size_t buflen,
+			  double *measurement_raw,
+			  unsigned int loop_iterations)
+{
+  const unsigned int num_repetitions = obj->num_measure_repetitions;
+  const bench_do_run_t do_run = obj->ops->do_run;
+  struct nsec_time start, end;
+  unsigned int rep, loop;
+  double res;
+
+  if (num_repetitions < 1 || loop_iterations < 1)
+    return 0.0;
+
+  for (rep = 0; rep < num_repetitions; rep++)
+    {
+      get_nsec_time (&start);
+
+      for (loop = 0; loop < loop_iterations; loop++)
+	do_run (obj, buffer, buflen);
+
+      get_nsec_time (&end);
+
+      measurement_raw[rep] = get_time_nsec_diff (&start, &end);
+    }
+
+  /* Return median of repeated measurements. */
+  qsort (measurement_raw, num_repetitions, sizeof (measurement_raw[0]),
+	 double_cmp);
+
+  if (num_repetitions % 2 == 1)
+    return measurement_raw[num_repetitions / 2];
+
+  res = measurement_raw[num_repetitions / 2]
+    + measurement_raw[num_repetitions / 2 - 1];
+  return res / 2;
+}
+
+
+unsigned int
+adjust_loop_iterations_to_timer_accuracy (struct bench_obj *obj, void *buffer,
+					  double *measurement_raw)
+{
+  const double increase_thres = 3.0;
+  double tmp, nsecs;
+  unsigned int loop_iterations;
+  unsigned int test_bufsize;
+
+  test_bufsize = obj->min_bufsize;
+  if (test_bufsize == 0)
+    test_bufsize += obj->step_size;
+
+  loop_iterations = 0;
+  do
+    {
+      /* Increase loop iterations until we get other results than zero.  */
+      nsecs =
+	do_bench_obj_measurement (obj, buffer, test_bufsize,
+				  measurement_raw, ++loop_iterations);
+    }
+  while (nsecs < 1.0 - 0.1);
+  do
+    {
+      /* Increase loop iterations until we get reasonable increase for elapsed time.  */
+      tmp =
+	do_bench_obj_measurement (obj, buffer, test_bufsize,
+				  measurement_raw, ++loop_iterations);
+    }
+  while (tmp < nsecs * (increase_thres - 0.1));
+
+  return loop_iterations;
+}
+
+
+/* Benchmark and return linear regression slope in nanoseconds per byte.  */
+double
+do_slope_benchmark (struct bench_obj *obj)
+{
+  unsigned int num_measurements;
+  double *measurements = NULL;
+  double *measurement_raw = NULL;
+  double slope, overhead;
+  unsigned int loop_iterations, midx, i;
+  unsigned char *real_buffer = NULL;
+  unsigned char *buffer;
+  size_t cur_bufsize;
+  int err;
+
+  err = obj->ops->initialize (obj);
+  if (err < 0)
+    return -1;
+
+  num_measurements = get_num_measurements (obj);
+  measurements = calloc (num_measurements, sizeof (*measurements));
+  if (!measurements)
+    goto err_free;
+
+  measurement_raw =
+    calloc (obj->num_measure_repetitions, sizeof (*measurement_raw));
+  if (!measurement_raw)
+    goto err_free;
+
+  if (num_measurements < 1 || obj->num_measure_repetitions < 1 ||
+      obj->max_bufsize < 1 || obj->min_bufsize > obj->max_bufsize)
+    goto err_free;
+
+  real_buffer = malloc (obj->max_bufsize + 128);
+  if (!real_buffer)
+    goto err_free;
+  /* Get aligned buffer */
+  buffer = real_buffer;
+  buffer += 128 - ((real_buffer - (unsigned char *) 0) & (128 - 1));
+
+  for (i = 0; i < obj->max_bufsize; i++)
+    buffer[i] = 0x55 ^ (-i);
+
+  /* Adjust number of loop iterations up to timer accuracy.  */
+  loop_iterations = adjust_loop_iterations_to_timer_accuracy (obj, buffer,
+							      measurement_raw);
+
+  /* Perform measurements */
+  for (midx = 0, cur_bufsize = obj->min_bufsize;
+       cur_bufsize <= obj->max_bufsize; cur_bufsize += obj->step_size, midx++)
+    {
+      measurements[midx] =
+	do_bench_obj_measurement (obj, buffer, cur_bufsize, measurement_raw,
+				  loop_iterations);
+      measurements[midx] /= loop_iterations;
+    }
+
+  assert (midx == num_measurements);
+
+  slope =
+    get_slope (&get_bench_obj_point_x, obj, measurements, num_measurements,
+	       &overhead);
+
+  free (measurement_raw);
+  free (real_buffer);
+  obj->ops->finalize (obj);
+
+  return slope;
+
+err_free:
+  if (measurement_raw)
+    free (measurement_raw);
+  if (measurements)
+    free (measurements);
+  if (real_buffer)
+    free (real_buffer);
+  obj->ops->finalize (obj);
+
+  return -1;
+}
+
+
+/********************************************************** Printing results. */
+
+static void
+double_to_str (char *out, size_t outlen, double value)
+{
+  const char *fmt;
+
+  if (value < 1.0)
+    fmt = "%.3f";
+  else if (value < 100.0)
+    fmt = "%.2f";
+  else
+    fmt = "%.1f";
+
+  snprintf (out, outlen, fmt, value);
+}
+
+static void
+bench_print_result (double nsecs_per_byte)
+{
+  double cycles_per_byte, mbytes_per_sec;
+  char nsecpbyte_buf[16];
+  char mbpsec_buf[16];
+  char cpbyte_buf[16];
+
+  strcpy (cpbyte_buf, "-");
+
+  double_to_str (nsecpbyte_buf, sizeof (nsecpbyte_buf), nsecs_per_byte);
+
+  /* If user didn't provide CPU speed, we cannot show cycles/byte results.  */
+  if (cpu_ghz > 0.0)
+    {
+      cycles_per_byte = nsecs_per_byte * cpu_ghz;
+      double_to_str (cpbyte_buf, sizeof (cpbyte_buf), cycles_per_byte);
+    }
+
+  mbytes_per_sec =
+    (1000.0 * 1000.0 * 1000.0) / (nsecs_per_byte * 1024 * 1024);
+  double_to_str (mbpsec_buf, sizeof (mbpsec_buf), mbytes_per_sec);
+
+  strncat (nsecpbyte_buf, " ns/B", sizeof (nsecpbyte_buf) - 1);
+  strncat (mbpsec_buf, " MiB/s", sizeof (mbpsec_buf) - 1);
+  strncat (cpbyte_buf, " c/B", sizeof (cpbyte_buf) - 1);
+
+  printf ("%14s %15s %13s\n", nsecpbyte_buf, mbpsec_buf, cpbyte_buf);
+}
+
+static void
+bench_print_header (const char *algo_name)
+{
+  printf (" %-14s | ", algo_name);
+  printf ("%14s %15s %13s\n", "nanosecs/byte", "mebibytes/sec",
+	  "cycles/byte");
+}
+
+static void
+bench_print_footer (void)
+{
+  printf (" %-14s =\n", "");
+}
+
+
+/********************************************************* Cipher benchmarks. */
+
+struct bench_cipher_mode
+{
+  int mode;
+  const char *name;
+  struct bench_ops *ops;
+
+  int algo;
+};
+
+
+static int
+bench_encrypt_init (struct bench_obj *obj)
+{
+  struct bench_cipher_mode *mode = obj->priv;
+  gcry_cipher_hd_t hd;
+  int err, keylen;
+
+  obj->min_bufsize = BUF_START_SIZE;
+  obj->max_bufsize = BUF_END_SIZE;
+  obj->step_size = BUF_STEP_SIZE;
+  obj->num_measure_repetitions = NUM_MEASUREMENT_REPETITIONS;
+
+  err = gcry_cipher_open (&hd, mode->algo, mode->mode, 0);
+  if (err)
+    {
+      fprintf (stderr, PGM ": error opening cipher `%s'\n",
+	       gcry_cipher_algo_name (mode->algo));
+      exit (1);
+    }
+
+  keylen = gcry_cipher_get_algo_keylen (mode->algo);
+  if (keylen)
+    {
+      char key[keylen];
+      int i;
+
+      for (i = 0; i < keylen; i++)
+	key[i] = 0x33 ^ (11 - i);
+
+      err = gcry_cipher_setkey (hd, key, keylen);
+      if (err)
+	{
+	  fprintf (stderr, PGM ": gcry_cipher_setkey failed: %s\n",
+		   gpg_strerror (err));
+	  gcry_cipher_close (hd);
+	  exit (1);
+	}
+    }
+  else
+    {
+      fprintf (stderr, PGM ": failed to get key length for algorithm `%s'\n",
+	       gcry_cipher_algo_name (mode->algo));
+      gcry_cipher_close (hd);
+      exit (1);
+    }
+
+  obj->priv = hd;
+
+  return 0;
+}
+
+static void
+bench_encrypt_free (struct bench_obj *obj)
+{
+  gcry_cipher_hd_t hd = obj->priv;
+
+  gcry_cipher_close (hd);
+}
+
+static void
+bench_encrypt_do_bench (struct bench_obj *obj, void *buf, size_t buflen)
+{
+  gcry_cipher_hd_t hd = obj->priv;
+  int err;
+
+  err = gcry_cipher_encrypt (hd, buf, buflen, buf, buflen);
+  if (err)
+    {
+      fprintf (stderr, PGM ": gcry_cipher_encrypt failed: %s\n",
+	       gpg_strerror (err));
+      gcry_cipher_close (hd);
+      exit (1);
+    }
+}
+
+static void
+bench_decrypt_do_bench (struct bench_obj *obj, void *buf, size_t buflen)
+{
+  gcry_cipher_hd_t hd = obj->priv;
+  int err;
+
+  err = gcry_cipher_decrypt (hd, buf, buflen, buf, buflen);
+  if (err)
+    {
+      fprintf (stderr, PGM ": gcry_cipher_encrypt failed: %s\n",
+	       gpg_strerror (err));
+      gcry_cipher_close (hd);
+      exit (1);
+    }
+}
+
+static struct bench_ops encrypt_ops = {
+  &bench_encrypt_init,
+  &bench_encrypt_free,
+  &bench_encrypt_do_bench
+};
+
+static struct bench_ops decrypt_ops = {
+  &bench_encrypt_init,
+  &bench_encrypt_free,
+  &bench_decrypt_do_bench
+};
+
+
+
+static void
+bench_ccm_encrypt_do_bench (struct bench_obj *obj, void *buf, size_t buflen)
+{
+  gcry_cipher_hd_t hd = obj->priv;
+  int err;
+  char tag[8];
+  char nonce[11] = { 0x80, 0x01, };
+  size_t params[3];
+
+  gcry_cipher_setiv (hd, nonce, sizeof (nonce));
+
+  /* Set CCM lengths */
+  params[0] = buflen;
+  params[1] = 0;		/*aadlen */
+  params[2] = sizeof (tag);
+  err =
+    gcry_cipher_ctl (hd, GCRYCTL_SET_CCM_LENGTHS, params, sizeof (params));
+  if (err)
+    {
+      fprintf (stderr, PGM ": gcry_cipher_ctl failed: %s\n",
+	       gpg_strerror (err));
+      gcry_cipher_close (hd);
+      exit (1);
+    }
+
+  err = gcry_cipher_encrypt (hd, buf, buflen, buf, buflen);
+  if (err)
+    {
+      fprintf (stderr, PGM ": gcry_cipher_encrypt failed: %s\n",
+	       gpg_strerror (err));
+      gcry_cipher_close (hd);
+      exit (1);
+    }
+
+  err = gcry_cipher_gettag (hd, tag, sizeof (tag));
+  if (err)
+    {
+      fprintf (stderr, PGM ": gcry_cipher_gettag failed: %s\n",
+	       gpg_strerror (err));
+      gcry_cipher_close (hd);
+      exit (1);
+    }
+}
+
+static void
+bench_ccm_decrypt_do_bench (struct bench_obj *obj, void *buf, size_t buflen)
+{
+  gcry_cipher_hd_t hd = obj->priv;
+  int err;
+  char tag[8] = { 0, };
+  char nonce[11] = { 0x80, 0x01, };
+  size_t params[3];
+
+  gcry_cipher_setiv (hd, nonce, sizeof (nonce));
+
+  /* Set CCM lengths */
+  params[0] = buflen;
+  params[1] = 0;		/*aadlen */
+  params[2] = sizeof (tag);
+  err =
+    gcry_cipher_ctl (hd, GCRYCTL_SET_CCM_LENGTHS, params, sizeof (params));
+  if (err)
+    {
+      fprintf (stderr, PGM ": gcry_cipher_ctl failed: %s\n",
+	       gpg_strerror (err));
+      gcry_cipher_close (hd);
+      exit (1);
+    }
+
+  err = gcry_cipher_decrypt (hd, buf, buflen, buf, buflen);
+  if (err)
+    {
+      fprintf (stderr, PGM ": gcry_cipher_encrypt failed: %s\n",
+	       gpg_strerror (err));
+      gcry_cipher_close (hd);
+      exit (1);
+    }
+
+  err = gcry_cipher_checktag (hd, tag, sizeof (tag));
+  if (gpg_err_code (err) == GPG_ERR_CHECKSUM)
+    err = gpg_error (GPG_ERR_NO_ERROR);
+  if (err)
+    {
+      fprintf (stderr, PGM ": gcry_cipher_gettag failed: %s\n",
+	       gpg_strerror (err));
+      gcry_cipher_close (hd);
+      exit (1);
+    }
+}
+
+static void
+bench_ccm_authenticate_do_bench (struct bench_obj *obj, void *buf,
+				 size_t buflen)
+{
+  gcry_cipher_hd_t hd = obj->priv;
+  int err;
+  char tag[8] = { 0, };
+  char nonce[11] = { 0x80, 0x01, };
+  size_t params[3];
+  char data = 0xff;
+
+  gcry_cipher_setiv (hd, nonce, sizeof (nonce));
+
+  /* Set CCM lengths */
+  params[0] = sizeof (data);	/*datalen */
+  params[1] = buflen;		/*aadlen */
+  params[2] = sizeof (tag);
+  err =
+    gcry_cipher_ctl (hd, GCRYCTL_SET_CCM_LENGTHS, params, sizeof (params));
+  if (err)
+    {
+      fprintf (stderr, PGM ": gcry_cipher_ctl failed: %s\n",
+	       gpg_strerror (err));
+      gcry_cipher_close (hd);
+      exit (1);
+    }
+
+  err = gcry_cipher_authenticate (hd, buf, buflen);
+  if (err)
+    {
+      fprintf (stderr, PGM ": gcry_cipher_authenticate failed: %s\n",
+	       gpg_strerror (err));
+      gcry_cipher_close (hd);
+      exit (1);
+    }
+
+  err = gcry_cipher_encrypt (hd, &data, sizeof (data), &data, sizeof (data));
+  if (err)
+    {
+      fprintf (stderr, PGM ": gcry_cipher_encrypt failed: %s\n",
+	       gpg_strerror (err));
+      gcry_cipher_close (hd);
+      exit (1);
+    }
+
+  err = gcry_cipher_gettag (hd, tag, sizeof (tag));
+  if (err)
+    {
+      fprintf (stderr, PGM ": gcry_cipher_gettag failed: %s\n",
+	       gpg_strerror (err));
+      gcry_cipher_close (hd);
+      exit (1);
+    }
+}
+
+static struct bench_ops ccm_encrypt_ops = {
+  &bench_encrypt_init,
+  &bench_encrypt_free,
+  &bench_ccm_encrypt_do_bench
+};
+
+static struct bench_ops ccm_decrypt_ops = {
+  &bench_encrypt_init,
+  &bench_encrypt_free,
+  &bench_ccm_decrypt_do_bench
+};
+
+static struct bench_ops ccm_authenticate_ops = {
+  &bench_encrypt_init,
+  &bench_encrypt_free,
+  &bench_ccm_authenticate_do_bench
+};
+
+
+static struct bench_cipher_mode cipher_modes[] = {
+  {GCRY_CIPHER_MODE_ECB, "ECB enc", &encrypt_ops},
+  {GCRY_CIPHER_MODE_ECB, "ECB dec", &decrypt_ops},
+  {GCRY_CIPHER_MODE_CBC, "CBC enc", &encrypt_ops},
+  {GCRY_CIPHER_MODE_CBC, "CBC dec", &decrypt_ops},
+  {GCRY_CIPHER_MODE_CFB, "CFB enc", &encrypt_ops},
+  {GCRY_CIPHER_MODE_CFB, "CFB dec", &decrypt_ops},
+  {GCRY_CIPHER_MODE_OFB, "OFB enc", &encrypt_ops},
+  {GCRY_CIPHER_MODE_OFB, "OFB dec", &decrypt_ops},
+  {GCRY_CIPHER_MODE_CTR, "CTR enc", &encrypt_ops},
+  {GCRY_CIPHER_MODE_CTR, "CTR dec", &decrypt_ops},
+  {GCRY_CIPHER_MODE_CCM, "CCM enc", &ccm_encrypt_ops},
+  {GCRY_CIPHER_MODE_CCM, "CCM dec", &ccm_decrypt_ops},
+  {GCRY_CIPHER_MODE_CCM, "CCM auth", &ccm_authenticate_ops},
+  {0},
+};
+
+
+static void
+cipher_bench_one (int algo, struct bench_cipher_mode *pmode)
+{
+  struct bench_cipher_mode mode = *pmode;
+  struct bench_obj obj = { 0 };
+  double result;
+  unsigned int blklen;
+
+  mode.algo = algo;
+
+  /* Check if this mode is ok */
+  blklen = gcry_cipher_get_algo_blklen (algo);
+  if (!blklen)
+    return;
+
+  /* Stream cipher? Only test with ECB. */
+  if (blklen == 1 && mode.mode != GCRY_CIPHER_MODE_ECB)
+    return;
+  if (blklen == 1 && mode.mode == GCRY_CIPHER_MODE_ECB)
+    {
+      mode.mode = GCRY_CIPHER_MODE_STREAM;
+      mode.name = mode.ops == &encrypt_ops ? "STREAM enc" : "STREAM dec";
+    }
+
+  /* CCM has restrictions for block-size */
+  if (mode.mode == GCRY_CIPHER_MODE_CCM && blklen != GCRY_CCM_BLOCK_LEN)
+    return;
+
+  printf (" %14s | ", mode.name);
+  fflush (stdout);
+
+  obj.ops = mode.ops;
+  obj.priv = &mode;
+
+  result = do_slope_benchmark (&obj);
+
+  bench_print_result (result);
+}
+
+
+static void
+__cipher_bench (int algo)
+{
+  const char *algoname;
+  int i;
+
+  algoname = gcry_cipher_algo_name (algo);
+
+  bench_print_header (algoname);
+
+  for (i = 0; cipher_modes[i].mode; i++)
+    cipher_bench_one (algo, &cipher_modes[i]);
+
+  bench_print_footer ();
+}
+
+
+void
+cipher_bench (char **argv, int argc)
+{
+  int i, algo;
+
+  printf ("Cipher:\n");
+
+  if (argv && argc)
+    {
+      for (i = 0; i < argc; i++)
+	{
+	  algo = gcry_cipher_map_name (argv[i]);
+	  if (algo)
+	    __cipher_bench (algo);
+	}
+    }
+  else
+    {
+      for (i = 1; i < 400; i++)
+	if (!gcry_cipher_test_algo (i))
+	  __cipher_bench (i);
+    }
+}
+
+
+/*********************************************************** Hash benchmarks. */
+
+struct bench_hash_mode
+{
+  const char *name;
+  struct bench_ops *ops;
+
+  int algo;
+};
+
+
+static int
+bench_hash_init (struct bench_obj *obj)
+{
+  struct bench_hash_mode *mode = obj->priv;
+  gcry_md_hd_t hd;
+  int err;
+
+  obj->min_bufsize = BUF_START_SIZE;
+  obj->max_bufsize = BUF_END_SIZE;
+  obj->step_size = BUF_STEP_SIZE;
+  obj->num_measure_repetitions = NUM_MEASUREMENT_REPETITIONS;
+
+  err = gcry_md_open (&hd, mode->algo, 0);
+  if (err)
+    {
+      fprintf (stderr, PGM ": error opening hash `%s'\n",
+	       gcry_md_algo_name (mode->algo));
+      exit (1);
+    }
+
+  obj->priv = hd;
+
+  return 0;
+}
+
+static void
+bench_hash_free (struct bench_obj *obj)
+{
+  gcry_md_hd_t hd = obj->priv;
+
+  gcry_md_close (hd);
+}
+
+static void
+bench_hash_do_bench (struct bench_obj *obj, void *buf, size_t buflen)
+{
+  gcry_md_hd_t hd = obj->priv;
+
+  gcry_md_write (hd, buf, buflen);
+  gcry_md_final (hd);
+}
+
+static struct bench_ops hash_ops = {
+  &bench_hash_init,
+  &bench_hash_free,
+  &bench_hash_do_bench
+};
+
+
+static struct bench_hash_mode hash_modes[] = {
+  {"", &hash_ops},
+  {0},
+};
+
+
+static void
+hash_bench_one (int algo, struct bench_hash_mode *pmode)
+{
+  struct bench_hash_mode mode = *pmode;
+  struct bench_obj obj = { 0 };
+  double result;
+
+  mode.algo = algo;
+
+  if (mode.name[0] == '\0')
+    printf (" %-14s | ", gcry_md_algo_name (algo));
+  else
+    printf (" %14s | ", mode.name);
+  fflush (stdout);
+
+  obj.ops = mode.ops;
+  obj.priv = &mode;
+
+  result = do_slope_benchmark (&obj);
+
+  bench_print_result (result);
+}
+
+static void
+__hash_bench (int algo)
+{
+  int i;
+
+  for (i = 0; hash_modes[i].name; i++)
+    hash_bench_one (algo, &hash_modes[i]);
+}
+
+void
+hash_bench (char **argv, int argc)
+{
+  int i, algo;
+
+  printf ("Hash:\n");
+
+  bench_print_header ("");
+
+  if (argv && argc)
+    {
+      for (i = 0; i < argc; i++)
+	{
+	  algo = gcry_md_map_name (argv[i]);
+	  if (algo)
+	    __hash_bench (algo);
+	}
+    }
+  else
+    {
+      for (i = 1; i < 400; i++)
+	if (!gcry_md_test_algo (i))
+	  __hash_bench (i);
+    }
+
+  bench_print_footer ();
+}
+
+
+/************************************************************** Main program. */
+
+void
+print_help (void)
+{
+  static const char *help_lines[] = {
+    "usage: bench-slope [options] [hash|cipher [algonames]]",
+    "",
+    " options:",
+    "     --cpu-mhz <mhz>           Set CPU speed for calculating cycles per bytes",
+    "                               results.",
+    "     --disable-hwf <features>  Disable hardware acceleration feature(s) for",
+    "                               benchmarking.",
+    NULL
+  };
+  const char **line;
+
+  for (line = help_lines; *line; line++)
+    fprintf (stdout, "%s\n", *line);
+}
+
+
+/* Warm up CPU.  */
+static void
+warm_up_cpu (void)
+{
+  struct nsec_time start, end;
+
+  get_nsec_time (&start);
+  do
+    {
+      get_nsec_time (&end);
+    }
+  while (get_time_nsec_diff (&start, &end) < 1000.0 * 1000.0 * 1000.0);
+}
+
+
+int
+main (int argc, char **argv)
+{
+  int last_argc = -1;
+  int debug = 0;
+
+  if (argc)
+    {
+      argc--;
+      argv++;
+    }
+
+  while (argc && last_argc != argc)
+    {
+      last_argc = argc;
+
+      if (!strcmp (*argv, "--"))
+	{
+	  argc--;
+	  argv++;
+	  break;
+	}
+      else if (!strcmp (*argv, "--help"))
+	{
+	  print_help ();
+	  exit (0);
+	}
+      else if (!strcmp (*argv, "--verbose"))
+	{
+	  verbose++;
+	  argc--;
+	  argv++;
+	}
+      else if (!strcmp (*argv, "--debug"))
+	{
+	  verbose += 2;
+	  debug++;
+	  argc--;
+	  argv++;
+	}
+      else if (!strcmp (*argv, "--disable-hwf"))
+	{
+	  argc--;
+	  argv++;
+	  if (argc)
+	    {
+	      if (gcry_control (GCRYCTL_DISABLE_HWF, *argv, NULL))
+		fprintf (stderr,
+			 PGM
+			 ": unknown hardware feature `%s' - option ignored\n",
+			 *argv);
+	      argc--;
+	      argv++;
+	    }
+	}
+      else if (!strcmp (*argv, "--cpu-mhz"))
+	{
+	  argc--;
+	  argv++;
+	  if (argc)
+	    {
+	      cpu_ghz = atof (*argv);
+	      cpu_ghz /= 1000;	/* Mhz => Ghz */
+
+	      argc--;
+	      argv++;
+	    }
+	}
+    }
+
+  gcry_control (GCRYCTL_SET_VERBOSITY, (int) verbose);
+
+  if (!gcry_check_version (GCRYPT_VERSION))
+    {
+      fprintf (stderr, PGM ": version mismatch; pgm=%s, library=%s\n",
+	       GCRYPT_VERSION, gcry_check_version (NULL));
+      exit (1);
+    }
+
+  if (debug)
+    gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1u, 0);
+
+  gcry_control (GCRYCTL_DISABLE_SECMEM, 0);
+  gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
+  gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
+
+  if (!argc)
+    {
+      warm_up_cpu ();
+      hash_bench (NULL, 0);
+      cipher_bench (NULL, 0);
+    }
+  else if (!strcmp (*argv, "hash"))
+    {
+      argc--;
+      argv++;
+
+      warm_up_cpu ();
+      hash_bench ((argc == 0) ? NULL : argv, argc);
+    }
+  else if (!strcmp (*argv, "cipher"))
+    {
+      argc--;
+      argv++;
+
+      warm_up_cpu ();
+      cipher_bench ((argc == 0) ? NULL : argv, argc);
+    }
+  else
+    {
+      fprintf (stderr, PGM ": unknown argument: %s\n", *argv);
+      print_help ();
+    }
+
+  return 0;
+}
+
+#endif /* !NO_GET_NSEC_TIME */

-----------------------------------------------------------------------

Summary of changes:
 tests/Makefile.am   |    4 +-
 tests/bench-slope.c | 1172 +++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 1174 insertions(+), 2 deletions(-)
 create mode 100644 tests/bench-slope.c


hooks/post-receive
-- 
The GNU crypto library
http://git.gnupg.org




More information about the Gnupg-commits mailing list