[master] 32e518aae gethrtime() is now slower than clock_gettime() on modern Solarisen

Nils Goroll nils.goroll at uplex.de
Fri Oct 5 10:31:07 UTC 2018


commit 32e518aae2b63db4cccfd3861b2256ca6049959d
Author: Nils Goroll <nils.goroll at uplex.de>
Date:   Fri Oct 5 12:25:42 2018 +0200

    gethrtime() is now slower than clock_gettime() on modern Solarisen
    
    Throw out the conventional wisdom and base the decision on a micro
    benchmark.
    
    clock_gettime() is now preferred if it is consistently at least
    double as fast as gethrtime(), which is the case on varnishdev-il,
    the SmartOS vtest machine.
    
    config.log gives details on the performance check, sample output
    below:
    
    configure:22703: ./conftest
    hrtime              45989530 check 16748699083977959327
    clock_gettime        4119385 check 16748701613138517215
    ...
    hrtime              48113108 check 16748749015170035860
    clock_gettime        4020802 check 16748751585081458308
    clock_gettime wins 10/10

diff --git a/configure.ac b/configure.ac
index 1f9a2f8b2..85f377dc9 100644
--- a/configure.ac
+++ b/configure.ac
@@ -355,6 +355,63 @@ AC_CHECK_FUNCS([clock_gettime])
 AC_CHECK_FUNCS([gethrtime])
 LIBS="${save_LIBS}"
 
+if test "x$ac_cv_func_gethrtime" = xyes && \
+   test "x$ac_cv_func_clock_gettime" = xyes ; then
+  AC_MSG_CHECKING(if clock_gettime is faster than gethrtime)
+  AC_RUN_IFELSE(
+    [AC_LANG_PROGRAM([[
+#include <sys/time.h>
+#include <time.h>
+#include <stdio.h>
+
+static hrtime_t cl()
+{
+	struct timespec ts;
+
+	(void) clock_gettime(CLOCK_MONOTONIC, &ts);
+	return (ts.tv_sec * 1e9 + ts.tv_nsec);
+}
+    ]],[[
+	hrtime_t s, c, e, t_hr, t_cl;
+	int i, r, wins;
+
+	wins = 0;
+	for (r = 0; r < 10; r++) {
+		c = 0;
+		s = gethrtime();
+		for (i=0; i<100000; i++)
+			c += gethrtime();
+		e = gethrtime();
+		t_hr = e - s;
+		fprintf(stderr, "hrtime\t\t%12lu check %lu\n",
+		    (unsigned long)t_hr, (unsigned long)c);
+
+		c = 0;
+		s = gethrtime();
+		for (i=0; i<100000; i++)
+			c += cl();
+		e = gethrtime();
+		t_cl = e - s;
+		fprintf(stderr, "clock_gettime\t%12lu check %lu\n",
+		    (unsigned long)t_cl, (unsigned long)c);
+
+		if (t_cl * 2 < t_hr)
+			wins++;
+	}
+	fprintf(stderr, "clock_gettime wins %d/%d\n", wins, r);
+	if (2 * wins >= r)
+		return (0);
+	return (1);
+    ]])],
+    [AC_MSG_RESULT(yes)
+     AC_DEFINE([USE_GETHRTIME], [0], [whether to use gethrtime])
+    ],
+    [AC_MSG_RESULT(no)
+     AC_DEFINE([USE_GETHRTIME], [1], [whether to use gethrtime])
+    ]
+  )
+fi
+
 # --enable-kqueue
 AC_ARG_ENABLE(kqueue,
     AS_HELP_STRING([--enable-kqueue],
diff --git a/lib/libvarnish/vtim.c b/lib/libvarnish/vtim.c
index f9de6244e..39d5ca342 100644
--- a/lib/libvarnish/vtim.c
+++ b/lib/libvarnish/vtim.c
@@ -118,15 +118,16 @@ init(void)
 #endif
 
 /*
- * Note on Solaris: for some reason, clock_gettime(CLOCK_MONOTONIC, &ts) is not
- * implemented in assembly, but falls into a syscall, while gethrtime() doesn't,
- * so we save a syscall by using gethrtime() if it is defined.
+ * On older Solaris-incarnations, gethrtime() was faster than
+ * clock_gettime(CLOCK_MONOTONIC). Our configure script prefers
+ * clock_gettime if it is consistently at least twice as fast as
+ * gethrtime(), which is the case on modern Solaris descendents.
  */
 
 double
 VTIM_mono(void)
 {
-#ifdef HAVE_GETHRTIME
+#if defined(HAVE_GETHRTIME) && USE_GETHRTIME
 	return (gethrtime() * 1e-9);
 #elif  HAVE_CLOCK_GETTIME
 	struct timespec ts;


More information about the varnish-commit mailing list