tests: Add benchmarking option to tests/random.
authorWerner Koch <wk@gnupg.org>
Wed, 2 Aug 2017 16:44:14 +0000 (18:44 +0200)
committerWerner Koch <wk@gnupg.org>
Wed, 2 Aug 2017 16:46:55 +0000 (18:46 +0200)
* tests/random.c: Always include unistd.h.
(prepend_srcdir): New.
(run_benchmark): New.
(main): Add options --benchmark and --with-seed-file.  Print whetehr
JENT has been used.
* tests/t-common.h (split_fields_colon): New. Taken from GnuPG.
License of that code changed to LGPLv2.1.

--

Running these tests on a KVM hosted Windows Vista using a statically
compiled tests/random and modifying the extra random added in
read_seed_file gave these results:

  | Seed | Jent | Bytes | Bits | Time (ms)  |
  |------+------+-------+------+------------|
  | yes  | yes  |    32 |  256 |  46 ..  62 |
  | yes  | yes  |    64 |  512 |  62 ..  78 |
  | yes  | yes  |   128 | 1024 |  78 ..  93 |
  | yes  | yes  |   256 | 2048 | 124 .. 156 |
  | yes  | yes  |   384 | 3072 | 171 .. 202 |
  | yes  | yes  |   512 | 4096 | 234 .. 249 |
  | yes  | no   |    32 |  256 |  15 ..  31 |
  | yes  | no   |    64 |  512 |  15 ..  31 |
  | yes  | no   |   128 | 1024 |  15        |
  | no   | yes  |     - |    - |  78 .. 93  |
  | no   | no   |     - |    - |  15        |

 Seed: Whether a seed file is used.
 Jent: Whether JENT was working.
Bytes: The number bytes mixed into the pool after reading
       the seed file.
 Bits: 8 * Bytes
 Time: Measured time including the time to read the seed file.
       Mimimun and maximum values are given.  Granularity of
       the used timer is quite large.

Signed-off-by: Werner Koch <wk@gnupg.org>
tests/random.c
tests/t-common.h

index 8a85429..2f48323 100644 (file)
 #include <string.h>
 #include <stdlib.h>
 #include <errno.h>
+#include <unistd.h>
 #ifndef HAVE_W32_SYSTEM
 # include <signal.h>
-# include <unistd.h>
 # include <sys/wait.h>
 #endif
 
+#include "stopwatch.h"
+
+
 #define PGM "random"
+#define NEED_EXTRA_TEST_SUPPORT 1
 #include "t-common.h"
 
 static int with_progress;
 
 
+/* Prepend FNAME with the srcdir environment variable's value and
+ * return an allocated filename.  */
+static char *
+prepend_srcdir (const char *fname)
+{
+  static const char *srcdir;
+  char *result;
+
+  if (!srcdir && !(srcdir = getenv ("srcdir")))
+    srcdir = ".";
+
+  result = xmalloc (strlen (srcdir) + 1 + strlen (fname) + 1);
+  strcpy (result, srcdir);
+  strcat (result, "/");
+  strcat (result, fname);
+  return result;
+}
+
+
 static void
 print_hex (const char *text, const void *buf, size_t n)
 {
@@ -537,12 +560,43 @@ run_all_rng_tests (const char *program)
   free (cmdline);
 }
 
+
+static void
+run_benchmark (void)
+{
+  char rndbuf[32];
+  int i, j;
+
+  if (verbose)
+    info ("benchmarking GCRY_STRONG_RANDOM (/dev/urandom)\n");
+
+  start_timer ();
+  gcry_randomize (rndbuf, sizeof rndbuf, GCRY_STRONG_RANDOM);
+  stop_timer ();
+
+  info ("getting first 256 bits: %s", elapsed_time (1));
+
+  for (j=0; j < 5; j++)
+    {
+      start_timer ();
+      for (i=0; i < 100; i++)
+        gcry_randomize (rndbuf, sizeof rndbuf, GCRY_STRONG_RANDOM);
+      stop_timer ();
+
+      info ("100 calls of 256 bits each: %s", elapsed_time (100));
+    }
+
+}
+
+
 int
 main (int argc, char **argv)
 {
   int last_argc = -1;
   int early_rng = 0;
   int in_recursion = 0;
+  int benchmark = 0;
+  int with_seed_file = 0;
   const char *program = NULL;
 
   if (argc)
@@ -586,16 +640,27 @@ main (int argc, char **argv)
           in_recursion = 1;
           argc--; argv++;
         }
+      else if (!strcmp (*argv, "--benchmark"))
+        {
+          benchmark = 1;
+          argc--; argv++;
+        }
       else if (!strcmp (*argv, "--early-rng-check"))
         {
           early_rng = 1;
           argc--; argv++;
         }
+      else if (!strcmp (*argv, "--with-seed-file"))
+        {
+          with_seed_file = 1;
+          argc--; argv++;
+        }
       else if (!strcmp (*argv, "--prefer-standard-rng"))
         {
           /* This is anyway the default, but we may want to use it for
              debugging. */
-          xgcry_control (GCRYCTL_SET_PREFERRED_RNG_TYPE, GCRY_RNG_TYPE_STANDARD);
+          xgcry_control (GCRYCTL_SET_PREFERRED_RNG_TYPE,
+                         GCRY_RNG_TYPE_STANDARD);
           argc--; argv++;
         }
       else if (!strcmp (*argv, "--prefer-fips-rng"))
@@ -608,12 +673,27 @@ main (int argc, char **argv)
           xgcry_control (GCRYCTL_SET_PREFERRED_RNG_TYPE, GCRY_RNG_TYPE_SYSTEM);
           argc--; argv++;
         }
+      else if (!strcmp (*argv, "--disable-hwf"))
+        {
+          argc--;
+          argv++;
+          if (argc)
+            {
+              if (gcry_control (GCRYCTL_DISABLE_HWF, *argv, NULL))
+                die ("unknown hardware feature `%s'\n", *argv);
+              argc--;
+              argv++;
+            }
+        }
     }
 
 #ifndef HAVE_W32_SYSTEM
   signal (SIGPIPE, SIG_IGN);
 #endif
 
+  if (benchmark && !verbose)
+    verbose = 1;
+
   if (early_rng)
     {
       /* Don't switch RNG in fips mode. */
@@ -628,11 +708,25 @@ main (int argc, char **argv)
   if (with_progress)
     gcry_set_progress_handler (progress_cb, NULL);
 
+  if (with_seed_file)
+    {
+      char *fname = prepend_srcdir ("random.seed");
+
+      if (access (fname, F_OK))
+        info ("random seed file '%s' not found\n", fname);
+      gcry_control (GCRYCTL_SET_RANDOM_SEED_FILE, fname);
+      xfree (fname);
+    }
+
   xgcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
   if (debug)
     xgcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1u, 0);
 
-  if (!in_recursion)
+  if (benchmark)
+    {
+      run_benchmark ();
+    }
+  else if (!in_recursion)
     {
       check_forking ();
       check_nonce_forking ();
@@ -640,16 +734,31 @@ main (int argc, char **argv)
     }
   /* For now we do not run the drgb_reinit check from "make check" due
      to its high requirement for entropy.  */
-  if (!getenv ("GCRYPT_IN_REGRESSION_TEST"))
+  if (!benchmark && !getenv ("GCRYPT_IN_REGRESSION_TEST"))
     check_drbg_reinit ();
 
   /* Don't switch RNG in fips mode.  */
-  if (!gcry_fips_mode_active())
+  if (!benchmark && !gcry_fips_mode_active())
     check_rng_type_switching ();
 
-  if (!in_recursion)
+  if (!in_recursion && !benchmark)
     run_all_rng_tests (program);
 
+  /* Print this info last so that it does not influence the
+   * initialization and thus the benchmarking.  */
+  if (!in_recursion && verbose)
+    {
+      char *buf;
+      char *fields[5];
+
+      buf = gcry_get_config (0, "rng-type");
+      if (buf
+          && split_fields_colon (buf, fields, DIM (fields)) >= 5
+          && atoi (fields[4]) > 0)
+        info ("The JENT RNG was active\n");
+      gcry_free (buf);
+    }
+
   if (debug)
     xgcry_control (GCRYCTL_DUMP_RANDOM_STATS);
 
index 8466ac1..2040f09 100644 (file)
@@ -158,3 +158,41 @@ info (const char *format, ...)
       die ("line %d: gcry_control (%s) failed: %s",             \
            __LINE__, #cmd, gcry_strerror (err__));              \
   } while (0)
+
+
+/* Split a string into colon delimited fields A pointer to each field
+ * is stored in ARRAY.  Stop splitting at ARRAYSIZE fields.  The
+ * function modifies STRING.  The number of parsed fields is returned.
+ * Note that leading and trailing spaces are not removed from the fields.
+ * Example:
+ *
+ *   char *fields[2];
+ *   if (split_fields (string, fields, DIM (fields)) < 2)
+ *     return  // Not enough args.
+ *   foo (fields[0]);
+ *   foo (fields[1]);
+ */
+#ifdef NEED_EXTRA_TEST_SUPPORT
+static int
+split_fields_colon (char *string, char **array, int arraysize)
+{
+  int n = 0;
+  char *p, *pend;
+
+  p = string;
+  do
+    {
+      if (n == arraysize)
+        break;
+      array[n++] = p;
+      pend = strchr (p, ':');
+      if (!pend)
+        break;
+      *pend++ = 0;
+      p = pend;
+    }
+  while (*p);
+
+  return n;
+}
+#endif /*NEED_EXTRA_TEST_SUPPORT*/