From: Matthew Dillon Date: Sat, 27 Oct 2018 01:08:35 +0000 (-0700) Subject: libc - Add kpmap shortcut for gettimeofday() X-Git-Tag: v5.5.0~80 X-Git-Url: https://gitweb.dragonflybsd.org/dragonfly.git/commitdiff_plain/b227f3f50d5dc0f5fdecd8f9df23e96e8521baaf libc - Add kpmap shortcut for gettimeofday() * 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. --- diff --git a/lib/libc/upmap/Makefile.inc b/lib/libc/upmap/Makefile.inc index 01b9196da3..412e155a5a 100644 --- a/lib/libc/upmap/Makefile.inc +++ b/lib/libc/upmap/Makefile.inc @@ -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 index 0000000000..847823f77c --- /dev/null +++ b/lib/libc/upmap/ukp_gettimeofday.c @@ -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 + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +/*#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); diff --git a/share/man/man4/upmap.4 b/share/man/man4/upmap.4 index 63d86549e1..b5d7e1569b 100644 --- a/share/man/man4/upmap.4 +++ b/share/man/man4/upmap.4 @@ -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 diff --git a/share/man/man7/tuning.7 b/share/man/man7/tuning.7 index 17305cc5ab..1c5b43c382 100644 --- a/share/man/man7/tuning.7 +++ b/share/man/man7/tuning.7 @@ -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 diff --git a/sys/kern/init_main.c b/sys/kern/init_main.c index 7cc8614f93..a68192c9e9 100644 --- a/sys/kern/init_main.c +++ b/sys/kern/init_main.c @@ -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); diff --git a/sys/kern/kern_time.c b/sys/kern/kern_time.c index 887d41bf10..c2e9f77666 100644 --- a/sys/kern/kern_time.c +++ b/sys/kern/kern_time.c @@ -45,6 +45,7 @@ #include #include #include +#include #include #include @@ -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, >od, 0, req); + if (error || req->newptr == NULL) + return error; + gettimeofday_quick = gtod; + if (kpmap) + kpmap->fast_gtod = gtod; + return 0; +} diff --git a/sys/sys/upmap.h b/sys/sys/upmap.h index 2b6387049f..da1697e26c 100644 --- a/sys/sys/upmap.h +++ b/sys/sys/upmap.h @@ -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