summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorcheloha <cheloha@openbsd.org>2019-06-14 19:23:53 +0000
committercheloha <cheloha@openbsd.org>2019-06-14 19:23:53 +0000
commit345f6e5566bb5c781592f1052b39774dc2847b8d (patch)
treecb9c99c5a2116a54b6134f26d2b7d4d697fc2127
parentAdd TSC_ADJUST CPUID flag. (diff)
downloadwireguard-openbsd-345f6e5566bb5c781592f1052b39774dc2847b8d.tar.xz
wireguard-openbsd-345f6e5566bb5c781592f1052b39774dc2847b8d.zip
new regress: clock_gettime(2); test if CLOCK_MONOTONIC is really monotonic
suggested by kettenis@, tweaked by anton@. ok mpi@ jca@
-rw-r--r--regress/sys/kern/Makefile4
-rw-r--r--regress/sys/kern/clock_gettime/Makefile15
-rw-r--r--regress/sys/kern/clock_gettime/monotonicrelapse.c101
3 files changed, 118 insertions, 2 deletions
diff --git a/regress/sys/kern/Makefile b/regress/sys/kern/Makefile
index 0ad0f7b0552..a2960ece924 100644
--- a/regress/sys/kern/Makefile
+++ b/regress/sys/kern/Makefile
@@ -1,6 +1,6 @@
-# $OpenBSD: Makefile,v 1.81 2019/05/17 20:08:38 beck Exp $
+# $OpenBSD: Makefile,v 1.82 2019/06/14 19:23:53 cheloha Exp $
-SUBDIR+= __syscall access accept cmsgsize
+SUBDIR+= __syscall access accept cmsgsize clock_gettime
SUBDIR+= dup2 dup2_accept dup2_self descrip
SUBDIR+= exec_self execve exit extent
SUBDIR+= fchdir
diff --git a/regress/sys/kern/clock_gettime/Makefile b/regress/sys/kern/clock_gettime/Makefile
new file mode 100644
index 00000000000..b8a73d7fd05
--- /dev/null
+++ b/regress/sys/kern/clock_gettime/Makefile
@@ -0,0 +1,15 @@
+# $OpenBSD: Makefile,v 1.1 2019/06/14 19:23:53 cheloha Exp $
+
+PROG= monotonicrelapse
+LDADD+= -lpthread
+DPADD+= ${LIBPTHREAD}
+WARNINGS= yes
+
+NCPUONLINE!= sysctl -n hw.ncpuonline
+
+REGRESS_TARGETS+= run-regress-monotonicrelapse
+
+run-regress-monotonicrelapse: ${PROG}
+ ${PROG} ${NCPUONLINE}
+
+.include <bsd.regress.mk>
diff --git a/regress/sys/kern/clock_gettime/monotonicrelapse.c b/regress/sys/kern/clock_gettime/monotonicrelapse.c
new file mode 100644
index 00000000000..a2239429a06
--- /dev/null
+++ b/regress/sys/kern/clock_gettime/monotonicrelapse.c
@@ -0,0 +1,101 @@
+/* $OpenBSD: monotonicrelapse.c,v 1.1 2019/06/14 19:23:53 cheloha Exp $ */
+/*
+ * Scott Cheloha <scottcheloha@gmail.com>, 2019. Public Domain.
+ */
+
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#include <sys/time.h>
+
+#include <err.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <unistd.h>
+
+void report_relapse(int, struct timespec *, struct timespec *);
+void *thread_func(void *);
+void thread_spawn(pthread_t **, int, void *(*)(void *));
+
+/*
+ * Is the active timecounter monotonic?
+ *
+ * Spawn the given number of threads and measure the monotonic clock
+ * across nanosleep(2) calls.
+ *
+ * Threads have a tendency to wake up on new CPUs. If the active
+ * timecounter is not synchronized across CPUs this will be detected
+ * relatively quickly and the test will fail.
+ */
+
+int
+main(int argc, char *argv[])
+{
+ const char *errstr;
+ pthread_t *thread;
+ int error, i, nthreads;
+
+ if (argc != 2) {
+ fprintf(stderr, "usage: %s nthreads\n", getprogname());
+ return 1;
+ }
+ nthreads = strtonum(argv[1], 1, INT_MAX, &errstr);
+ if (errstr != NULL)
+ errx(1, "nthreads is %s: %s", errstr, argv[1]);
+
+ thread = calloc(nthreads, sizeof(*thread));
+ if (thread == NULL)
+ err(1, NULL);
+
+ for (i = 0; i < nthreads; i++) {
+ error = pthread_create(&thread[i], NULL, thread_func,
+ (void *)(i + 1));
+ if (error)
+ errc(1, error, "pthread_create");
+ }
+
+ sleep(10);
+
+ return 0;
+}
+
+void
+report_relapse(int num, struct timespec *before, struct timespec *after)
+{
+ static pthread_mutex_t report_mutex = PTHREAD_MUTEX_INITIALIZER;
+ struct timespec relapsed;
+ int error;
+
+ error = pthread_mutex_lock(&report_mutex);
+ if (error)
+ errc(1, error, "T%d: pthread_mutex_lock", num);
+
+ timespecsub(before, after, &relapsed);
+ errx(1, "T%d: monotonic clock relapsed %.9f seconds: %.9f -> %.9f",
+ num, relapsed.tv_sec + relapsed.tv_nsec / 1000000000.0,
+ before->tv_sec + before->tv_nsec / 1000000000.0,
+ after->tv_sec + after->tv_nsec / 1000000000.0);
+}
+
+void *
+thread_func(void *arg)
+{
+ struct timespec after, before, timeout;
+ int num;
+
+ timeout.tv_sec = 0;
+ timeout.tv_nsec = 1;
+ num = (int)arg;
+
+ for (;;) {
+ clock_gettime(CLOCK_MONOTONIC, &before);
+ if (nanosleep(&timeout, NULL) == -1)
+ err(1, "T%d: nanosleep", num);
+ clock_gettime(CLOCK_MONOTONIC, &after);
+ if (timespeccmp(&after, &before, <))
+ report_relapse(num, &before, &after);
+ }
+
+ return NULL;
+}