[PATCH 3/3] tests/bench-slope: avoid divide by zero

Jussi Kivilinna jussi.kivilinna at iki.fi
Mon Oct 25 20:02:14 CEST 2021


* tests/bench-slope.c (safe_div): New.
(get_slope): Make static; Skip if number of points is too small; Use
safe_div.
(do_slope_benchmark): Retry benchmark if result does not make sense;
Limit retries to 4 for non-auto-ghz and 1000 for auto-ghz.
(get_auto_ghz, do_slope_benchmark, bench_print_result_csv)
(bench_print_result_std): Use safe_div.
--

Signed-off-by: Jussi Kivilinna <jussi.kivilinna at iki.fi>
---
 tests/bench-slope.c | 64 ++++++++++++++++++++++++++++++++++-----------
 1 file changed, 49 insertions(+), 15 deletions(-)

diff --git a/tests/bench-slope.c b/tests/bench-slope.c
index 1723899c..7a17cf10 100644
--- a/tests/bench-slope.c
+++ b/tests/bench-slope.c
@@ -23,7 +23,9 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdarg.h>
+#include <string.h>
 #include <assert.h>
+#include <float.h>
 #include <time.h>
 #ifdef _WIN32
 #include <windows.h>
@@ -253,7 +255,28 @@ struct bench_ops
 };
 
 
-double
+static double
+safe_div (double x, double y)
+{
+  union
+  {
+    double d;
+    char buf[sizeof(double)];
+  } u_neg_zero, u_y;
+
+  if (y != 0)
+    return x / y;
+
+  u_neg_zero.d = -0.0;
+  u_y.d = y;
+  if (memcmp(u_neg_zero.buf, u_y.buf, sizeof(double)) == 0)
+    return -DBL_MAX;
+
+  return DBL_MAX;
+}
+
+
+static double
 get_slope (double (*const get_x) (unsigned int idx, void *priv),
 	   void *get_x_priv, double y_points[], unsigned int npoints,
 	   double *overhead)
@@ -264,12 +287,18 @@ get_slope (double (*const get_x) (unsigned int idx, void *priv),
 
   sumx = sumy = sumx2 = sumy2 = sumxy = 0;
 
+  if (npoints <= 1)
+    {
+      /* No slope with zero or one point. */
+      return 0;
+    }
+
   for (i = 0; i < npoints; i++)
     {
       double x, y;
 
       x = get_x (i, get_x_priv);	/* bytes */
-      y = y_points[i];		/* nsecs */
+      y = y_points[i];			/* nsecs */
 
       sumx += x;
       sumy += y;
@@ -278,11 +307,13 @@ get_slope (double (*const get_x) (unsigned int idx, void *priv),
       sumxy += x * y;
     }
 
-  b = (npoints * sumxy - sumx * sumy) / (npoints * sumx2 - sumx * sumx);
-  a = (sumy - b * sumx) / npoints;
+  b = safe_div(npoints * sumxy - sumx * sumy, npoints * sumx2 - sumx * sumx);
 
   if (overhead)
-    *overhead = a;		/* nsecs */
+    {
+      a = safe_div(sumy - b * sumx, npoints);
+      *overhead = a;		/* nsecs */
+    }
 
   return b;			/* nsecs per byte */
 }
@@ -590,20 +621,25 @@ get_auto_ghz (void)
 
   /* Adjust CPU Ghz so that cycles per iteration would give '1024.0'. */
 
-  return cpu_ghz * 1024 / cycles_per_iteration;
+  return safe_div(cpu_ghz * 1024, cycles_per_iteration);
 }
 
 
 double
 do_slope_benchmark (struct bench_obj *obj)
 {
+  unsigned int try_count = 0;
   double ret;
 
   if (!auto_ghz)
     {
       /* Perform measurement without autodetection of CPU frequency. */
 
-      ret = slope_benchmark (obj);
+      do
+        {
+	  ret = slope_benchmark (obj);
+        }
+      while (ret <= 0 && try_count++ <= 4);
 
       bench_ghz = cpu_ghz;
       bench_ghz_diff = 0;
@@ -615,7 +651,6 @@ do_slope_benchmark (struct bench_obj *obj)
       double cpu_auto_ghz_after;
       double nsecs_per_iteration;
       double diff;
-      unsigned int try_count = 0;
 
       /* Perform measurement with CPU frequency autodetection. */
 
@@ -623,12 +658,10 @@ do_slope_benchmark (struct bench_obj *obj)
         {
           /* Repeat measurement until CPU turbo frequency has stabilized. */
 
-	  if (try_count++ > 4)
+	  if ((++try_count % 4) == 0)
 	    {
 	      /* Too much frequency instability on the system, relax target
 	       * accuracy. */
-
-	      try_count = 0;
 	      target_diff *= 2;
 	    }
 
@@ -638,10 +671,11 @@ do_slope_benchmark (struct bench_obj *obj)
 
           cpu_auto_ghz_after = get_auto_ghz ();
 
-          diff = 1.0 - (cpu_auto_ghz_before / cpu_auto_ghz_after);
+          diff = 1.0 - safe_div(cpu_auto_ghz_before, cpu_auto_ghz_after);
           diff = diff < 0 ? -diff : diff;
         }
-      while (diff > target_diff);
+      while ((nsecs_per_iteration <= 0 || diff > target_diff)
+	     && try_count < 1000);
 
       ret = nsecs_per_iteration;
 
@@ -702,7 +736,7 @@ bench_print_result_csv (double nsecs_per_byte)
     }
 
   mbytes_per_sec =
-    (1000.0 * 1000.0 * 1000.0) / (nsecs_per_byte * 1024 * 1024);
+      safe_div(1000.0 * 1000.0 * 1000.0, nsecs_per_byte * 1024 * 1024);
   double_to_str (mbpsec_buf, sizeof (mbpsec_buf), mbytes_per_sec);
 
   /* We print two empty fields to allow for future enhancements.  */
@@ -763,7 +797,7 @@ bench_print_result_std (double nsecs_per_byte)
     }
 
   mbytes_per_sec =
-    (1000.0 * 1000.0 * 1000.0) / (nsecs_per_byte * 1024 * 1024);
+      safe_div(1000.0 * 1000.0 * 1000.0, nsecs_per_byte * 1024 * 1024);
   double_to_str (mbpsec_buf, sizeof (mbpsec_buf), mbytes_per_sec);
 
   if (auto_ghz)
-- 
2.32.0




More information about the Gcrypt-devel mailing list