libc - Add kpmap shortcut for gettimeofday()
authorMatthew Dillon <dillon@apollo.backplane.com>
Sat, 27 Oct 2018 01:08:35 +0000 (18:08 -0700)
committerMatthew Dillon <dillon@apollo.backplane.com>
Sat, 27 Oct 2018 01:40:27 +0000 (18:40 -0700)
* If the kern.gettimeofday_quick sysctl is set to 1, libc's
  gettimeofday() will use the tick-granular realtime in
  the kpmap instead of making a system call.  The sysctl
  defaults to 0 (off).

* Useful in situations where gettimeofday() interferes with
  benchmarks, but otherwise not recommended.

* Running programs react instantly to changes in this sysctl.

lib/libc/upmap/Makefile.inc
lib/libc/upmap/ukp_gettimeofday.c [new file with mode: 0644]
share/man/man4/upmap.4
share/man/man7/tuning.7
sys/kern/init_main.c
sys/kern/kern_time.c
sys/sys/upmap.h

index 01b9196..412e155 100644 (file)
@@ -7,4 +7,4 @@ CFLAGS+=-I${.CURDIR}/../libc/sysvipc
 
 CMAPS+=        ${.CURDIR}/upmap/Symbol.map
 
-SRCS+= upmap.c ukp_clock.c ukp_getpid.c ukp_setproctitle.c
+SRCS+= upmap.c ukp_clock.c ukp_getpid.c ukp_setproctitle.c ukp_gettimeofday.c
diff --git a/lib/libc/upmap/ukp_gettimeofday.c b/lib/libc/upmap/ukp_gettimeofday.c
new file mode 100644 (file)
index 0000000..847823f
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2018 The DragonFly Project.  All rights reserved.
+ *
+ * This code is derived from software contributed to The DragonFly Project
+ * by Matthew Dillon <dillon@backplane.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ * 3. Neither the name of The DragonFly Project nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific, prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * UKP-Optimized gettimeofday().  Use the kpmap after the 10th call.
+ */
+#include <sys/cdefs.h>
+#include <sys/types.h>
+#include <sys/syscall.h>
+#include <sys/upmap.h>
+#include <sys/time.h>
+#include <machine/cpufunc.h>
+#include <errno.h>
+#include <time.h>
+#include <stdio.h>
+#include <unistd.h>
+/*#include "un-namespace.h"*/
+#include "libc_private.h"
+#include "upmap.h"
+
+extern int __sys_gettimeofday(struct timeval *, struct timezone *);
+int __gettimeofday(struct timeval *, struct timezone *);
+
+static int fast_clock;
+static int fast_count;
+static int *fast_gtod;
+static int *upticksp;
+static struct timespec *ts_realtime;
+
+#ifdef KPTYPE_FAST_GTOD
+int
+__gettimeofday(struct timeval *tv, struct timezone *tz)
+{
+       struct timespec ts;
+       int res;
+       int w;
+
+       if (fast_clock == 0 && fast_count++ >= 10) {
+                __kpmap_map(&upticksp, &fast_clock, KPTYPE_UPTICKS);
+               __kpmap_map(&ts_realtime, &fast_clock, KPTYPE_TS_REALTIME);
+               __kpmap_map(&fast_gtod, &fast_clock, KPTYPE_FAST_GTOD);
+               __kpmap_map(NULL, &fast_clock, 0);
+       }
+       if (fast_clock > 0 && *fast_gtod && tz == NULL) {
+               do {
+                       w = *upticksp;
+                       cpu_lfence();
+                       ts = ts_realtime[w & 1];
+                       cpu_lfence();
+                       w = *upticksp - w;
+               } while (w > 1);
+               res = 0;
+               if (tv) {
+                       tv->tv_sec = ts.tv_sec;
+                       tv->tv_usec = ts.tv_nsec / 1000;
+               }
+       } else {
+               res = __sys_gettimeofday(tv, tz);
+       }
+       return res;
+}
+
+#else
+
+int
+__gettimeofday(struct timeval *tv, struct timezone *tz)
+{
+       int res;
+
+       res = __sys_gettimeofday(tv, tz);
+       return res;
+}
+
+#endif
+
+__weak_reference(__gettimeofday, gettimeofday);
index 63d8654..b5d7e15 100644 (file)
@@ -144,6 +144,12 @@ The tick resolution of
 and
 .Fa ts_realtime
 and approximate tick resolution for the scheduler, typically 100.
+.It Va fast_gtod
+This integer reflects the state of the "kern.gettimeofday_quick"
+sysctl.  When set to 1, gettimeofday(&tv, NULL) calls will access
+the tick-resolution ts_realtime[] fields instead of executing the
+system call.  Changes in the sysctl are immediately reflected in
+programs that are already running.
 .El
 .Sh NOTES
 With
index 17305cc..1c5b43c 100644 (file)
@@ -177,6 +177,13 @@ In this document we will only cover the ones that have the greatest effect
 on the system.
 .Pp
 The
+.Va kern.gettimeofday_quick
+sysctl defaults to 0 (off).  Setting this sysctl to 1 causes gettimeofday()
+calls in libc to use a tick-granular time from the kpmap instead of making
+a system call.  Setting this feature can be useful when running benchmarks
+which make large numbers of gettimeofday() calls, such as postgres.
+.Pp
+The
 .Va kern.ipc.shm_use_phys
 sysctl defaults to 1 (on) and may be set to 0 (off) or 1 (on).
 Setting
index 7cc8614..a68192c 100644 (file)
@@ -738,6 +738,8 @@ kpmap_init(const void *udata __unused)
        kpmap->header[4].offset = offsetof(struct sys_kpmap, tsc_freq);
        kpmap->header[5].type = KPTYPE_TICK_FREQ;
        kpmap->header[5].offset = offsetof(struct sys_kpmap, tick_freq);
+       kpmap->header[5].type = KPTYPE_FAST_GTOD;
+       kpmap->header[5].offset = offsetof(struct sys_kpmap, fast_gtod);
        kpmap->version = KPMAP_VERSION;
 }
 SYSINIT(kpmapinit, SI_BOOT1_POST, SI_ORDER_FIRST, kpmap_init, NULL);
index 887d41b..c2e9f77 100644 (file)
@@ -45,6 +45,7 @@
 #include <sys/vnode.h>
 #include <sys/sysctl.h>
 #include <sys/kern_syscall.h>
+#include <sys/upmap.h>
 #include <vm/vm.h>
 #include <vm/vm_extern.h>
 
@@ -76,6 +77,9 @@ static int    settime(struct timeval *);
 static void    timevalfix(struct timeval *);
 static void    realitexpire(void *arg);
 
+static int sysctl_gettimeofday_quick(SYSCTL_HANDLER_ARGS);
+
+
 /*
  * Nanosleep tries very hard to sleep for a precisely requested time
  * interval, down to 1uS.  The administrator can impose a minimum delay
@@ -92,8 +96,8 @@ SYSCTL_INT(_kern, OID_AUTO, nanosleep_min_us, CTLFLAG_RW,
           &nanosleep_min_us, 0, "");
 SYSCTL_INT(_kern, OID_AUTO, nanosleep_hard_us, CTLFLAG_RW,
           &nanosleep_hard_us, 0, "");
-SYSCTL_INT(_kern, OID_AUTO, gettimeofday_quick, CTLFLAG_RW,
-          &gettimeofday_quick, 0, "");
+SYSCTL_PROC(_kern, OID_AUTO, gettimeofday_quick, CTLTYPE_INT | CTLFLAG_RW,
+          0, 0, sysctl_gettimeofday_quick, "I", "Quick mode gettimeofday");
 
 static struct lock masterclock_lock = LOCK_INITIALIZER("mstrclk", 0, 0);
 
@@ -1130,3 +1134,19 @@ ppsratecheck(struct timeval *lasttime, int *curpps, int maxpps)
                return (maxpps < 0 || *curpps < maxpps);
        }
 }
+
+static int
+sysctl_gettimeofday_quick(SYSCTL_HANDLER_ARGS)
+{
+       int error;
+       int gtod;
+
+       gtod = gettimeofday_quick;
+       error = sysctl_handle_int(oidp, &gtod, 0, req);
+       if (error || req->newptr == NULL)
+               return error;
+       gettimeofday_quick = gtod;
+       if (kpmap)
+               kpmap->fast_gtod = gtod;
+       return 0;
+}
index 2b63870..da1697e 100644 (file)
@@ -86,6 +86,7 @@ typedef struct ukpheader {
 #define KPTYPE_TS_REALTIME     (0x8002 | UKPLEN_TS)
 #define KPTYPE_TSC_FREQ                (0x8003 | UKPLEN_8)
 #define KPTYPE_TICK_FREQ       (0x8004 | UKPLEN_8)
+#define KPTYPE_FAST_GTOD       (0x8005 | UKPLEN_4)
 
 #if defined(_KERNEL) || defined(_KERNEL_STRUCTURES)
 
@@ -137,6 +138,7 @@ struct sys_kpmap {
        struct timespec ts_realtime[2]; /* realtime @ticks resolution */
        int64_t         tsc_freq;       /* (if supported by cpu) */
        int32_t         tick_freq;      /* scheduler tick frequency */
+       int32_t         fast_gtod;      /* fast gettimeofday() */
 };
 
 #endif