Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 19 Dec 2016 07:40:46 +0000 (UTC)
From:      Sepherosa Ziehau <sephe@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r310239 - in head: lib/libc/x86/sys sys/dev/hyperv/vmbus/amd64 sys/sys sys/x86/include
Message-ID:  <201612190740.uBJ7ekkY034652@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: sephe
Date: Mon Dec 19 07:40:45 2016
New Revision: 310239
URL: https://svnweb.freebsd.org/changeset/base/310239

Log:
  hyperv: Implement userspace gettimeofday(2) with Hyper-V reference TSC
  
  This 6 times gettimeofday performance, as measured by
  tools/tools/syscall_timing
  
  Reviewed by:	kib
  MFC after:	1 week
  Sponsored by:	Microsoft
  Differential Revision:	https://reviews.freebsd.org/D8789

Modified:
  head/lib/libc/x86/sys/__vdso_gettc.c
  head/sys/dev/hyperv/vmbus/amd64/hyperv_machdep.c
  head/sys/sys/vdso.h
  head/sys/x86/include/vdso.h

Modified: head/lib/libc/x86/sys/__vdso_gettc.c
==============================================================================
--- head/lib/libc/x86/sys/__vdso_gettc.c	Mon Dec 19 00:28:04 2016	(r310238)
+++ head/lib/libc/x86/sys/__vdso_gettc.c	Mon Dec 19 07:40:45 2016	(r310239)
@@ -45,6 +45,10 @@ __FBSDID("$FreeBSD$");
 #include <machine/cpufunc.h>
 #include <machine/specialreg.h>
 #include <dev/acpica/acpi_hpet.h>
+#ifdef __amd64__
+#include <machine/atomic.h>
+#include <dev/hyperv/hyperv.h>
+#endif
 #include "libc_private.h"
 
 static void
@@ -144,6 +148,67 @@ __vdso_init_hpet(uint32_t u)
 	_close(fd);
 }
 
+#ifdef __amd64__
+
+#define HYPERV_REFTSC_DEVPATH	"/dev/" HYPERV_REFTSC_DEVNAME
+
+/*
+ * NOTE:
+ * We use 'NULL' for this variable to indicate that initialization
+ * is required.  And if this variable is 'MAP_FAILED', then Hyper-V
+ * reference TSC can not be used, e.g. in misconfigured jail.
+ */
+static struct hyperv_reftsc *hyperv_ref_tsc;
+
+static void
+__vdso_init_hyperv_tsc(void)
+{
+	int fd;
+
+	fd = _open(HYPERV_REFTSC_DEVPATH, O_RDONLY);
+	if (fd < 0) {
+		/* Prevent the caller from re-entering. */
+		hyperv_ref_tsc = MAP_FAILED;
+		return;
+	}
+	hyperv_ref_tsc = mmap(NULL, sizeof(*hyperv_ref_tsc), PROT_READ,
+	    MAP_SHARED, fd, 0);
+	_close(fd);
+}
+
+static int
+__vdso_hyperv_tsc(struct hyperv_reftsc *tsc_ref, u_int *tc)
+{
+	uint64_t disc, ret, tsc, scale;
+	uint32_t seq;
+	int64_t ofs;
+
+	while ((seq = atomic_load_acq_int(&tsc_ref->tsc_seq)) != 0) {
+		scale = tsc_ref->tsc_scale;
+		ofs = tsc_ref->tsc_ofs;
+
+		lfence_mb();
+		tsc = rdtsc();
+
+		/* ret = ((tsc * scale) >> 64) + ofs */
+		__asm__ __volatile__ ("mulq %3" :
+		    "=d" (ret), "=a" (disc) :
+		    "a" (tsc), "r" (scale));
+		ret += ofs;
+
+		atomic_thread_fence_acq();
+		if (tsc_ref->tsc_seq == seq) {
+			*tc = ret;
+			return (0);
+		}
+
+		/* Sequence changed; re-sync. */
+	}
+	return (ENOSYS);
+}
+
+#endif	/* __amd64__ */
+
 #pragma weak __vdso_gettc
 int
 __vdso_gettc(const struct vdso_timehands *th, u_int *tc)
@@ -165,6 +230,14 @@ __vdso_gettc(const struct vdso_timehands
 			return (ENOSYS);
 		*tc = *(volatile uint32_t *)(hpet_dev_map + HPET_MAIN_COUNTER);
 		return (0);
+#ifdef __amd64__
+	case VDSO_TH_ALGO_X86_HVTSC:
+		if (hyperv_ref_tsc == NULL)
+			__vdso_init_hyperv_tsc();
+		if (hyperv_ref_tsc == MAP_FAILED)
+			return (ENOSYS);
+		return (__vdso_hyperv_tsc(hyperv_ref_tsc, tc));
+#endif
 	default:
 		return (ENOSYS);
 	}

Modified: head/sys/dev/hyperv/vmbus/amd64/hyperv_machdep.c
==============================================================================
--- head/sys/dev/hyperv/vmbus/amd64/hyperv_machdep.c	Mon Dec 19 00:28:04 2016	(r310238)
+++ head/sys/dev/hyperv/vmbus/amd64/hyperv_machdep.c	Mon Dec 19 07:40:45 2016	(r310239)
@@ -33,6 +33,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/kernel.h>
 #include <sys/systm.h>
 #include <sys/timetc.h>
+#include <sys/vdso.h>
 
 #include <machine/cpufunc.h>
 #include <machine/cputypes.h>
@@ -52,18 +53,20 @@ struct hyperv_reftsc_ctx {
 	struct hyperv_dma	tsc_ref_dma;
 };
 
+static uint32_t			hyperv_tsc_vdso_timehands(
+				    struct vdso_timehands *,
+				    struct timecounter *);
+
 static d_open_t			hyperv_tsc_open;
 static d_mmap_t			hyperv_tsc_mmap;
 
 static struct timecounter	hyperv_tsc_timecounter = {
 	.tc_get_timecount	= NULL,	/* based on CPU vendor. */
-	.tc_poll_pps		= NULL,
 	.tc_counter_mask	= 0xffffffff,
 	.tc_frequency		= HYPERV_TIMER_FREQ,
 	.tc_name		= "Hyper-V-TSC",
 	.tc_quality		= 3000,
-	.tc_flags		= 0,
-	.tc_priv		= NULL
+	.tc_fill_vdso_timehands = hyperv_tsc_vdso_timehands,
 };
 
 static struct cdevsw		hyperv_tsc_cdevsw = {
@@ -117,6 +120,18 @@ hyperv_tsc_mmap(struct cdev *dev __unuse
 	return (0);
 }
 
+static uint32_t
+hyperv_tsc_vdso_timehands(struct vdso_timehands *vdso_th,
+    struct timecounter *tc __unused)
+{
+
+	vdso_th->th_algo = VDSO_TH_ALGO_X86_HVTSC;
+	vdso_th->th_x86_shift = 0;
+	vdso_th->th_x86_hpet_idx = 0;
+	bzero(vdso_th->th_res, sizeof(vdso_th->th_res));
+	return (1);
+}
+
 #define HYPERV_TSC_TIMECOUNT(fence)					\
 static u_int								\
 hyperv_tsc_timecount_##fence(struct timecounter *tc)			\

Modified: head/sys/sys/vdso.h
==============================================================================
--- head/sys/sys/vdso.h	Mon Dec 19 00:28:04 2016	(r310238)
+++ head/sys/sys/vdso.h	Mon Dec 19 07:40:45 2016	(r310239)
@@ -54,6 +54,8 @@ struct vdso_timekeep {
 #define	VDSO_TK_VER_CURR	VDSO_TK_VER_1
 #define	VDSO_TH_ALGO_1		0x1
 #define	VDSO_TH_ALGO_2		0x2
+#define	VDSO_TH_ALGO_3		0x3
+#define	VDSO_TH_ALGO_4		0x4
 
 #ifndef _KERNEL
 

Modified: head/sys/x86/include/vdso.h
==============================================================================
--- head/sys/x86/include/vdso.h	Mon Dec 19 00:28:04 2016	(r310238)
+++ head/sys/x86/include/vdso.h	Mon Dec 19 07:40:45 2016	(r310239)
@@ -39,6 +39,7 @@
 
 #define	VDSO_TH_ALGO_X86_TSC	VDSO_TH_ALGO_1
 #define	VDSO_TH_ALGO_X86_HPET	VDSO_TH_ALGO_2
+#define	VDSO_TH_ALGO_X86_HVTSC	VDSO_TH_ALGO_3	/* Hyper-V ref. TSC */
 
 #ifdef _KERNEL
 #ifdef COMPAT_FREEBSD32



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201612190740.uBJ7ekkY034652>