Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 20 Nov 2011 05:32:12 +0000 (UTC)
From:      Lawrence Stewart <lstewart@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r227747 - in head/sys: kern sys
Message-ID:  <201111200532.pAK5WC4o077159@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: lstewart
Date: Sun Nov 20 05:32:12 2011
New Revision: 227747
URL: http://svn.freebsd.org/changeset/base/227747

Log:
  - Provide a sysctl interface to change the active system clock at runtime.
  
  - Wrap [get]{bin,nano,micro}[up]time() functions of sys/time.h to allow
    requesting time from either the feedback or the feed-forward clock. If a
    feedback (e.g. ntpd) and feed-forward (e.g. radclock) daemon are both running
    on the system, both kernel clocks are updated but only one serves time.
  
  - Add similar wrappers for the feed-forward difference clock.
  
  Committed on behalf of Julien Ridoux and Darryl Veitch from the University of
  Melbourne, Australia, as part of the FreeBSD Foundation funded "Feed-Forward
  Clock Synchronization Algorithms" project.
  
  For more information, see http://www.synclab.org/radclock/
  
  Submitted by:	Julien Ridoux (jridoux at unimelb edu au)

Modified:
  head/sys/kern/kern_ffclock.c
  head/sys/kern/kern_tc.c
  head/sys/sys/timeffc.h

Modified: head/sys/kern/kern_ffclock.c
==============================================================================
--- head/sys/kern/kern_ffclock.c	Sun Nov 20 01:48:22 2011	(r227746)
+++ head/sys/kern/kern_ffclock.c	Sun Nov 20 05:32:12 2011	(r227747)
@@ -31,6 +31,8 @@
 __FBSDID("$FreeBSD$");
 
 #include <sys/param.h>
+#include <sys/sbuf.h>
+#include <sys/sysctl.h>
 #include <sys/systm.h>
 #include <sys/timeffc.h>
 
@@ -127,3 +129,215 @@ ffclock_difftime(ffcounter ffdelta, stru
 		bintime_mul(error_bound, err_rate * (uint64_t)18446744073709LL);
 	}
 }
+
+/*
+ * Sysctl for the Feed-Forward Clock.
+ */
+
+static int ffclock_version = 2;
+SYSCTL_NODE(_kern, OID_AUTO, ffclock, CTLFLAG_RW, 0,
+    "Feed-Forward Clock Support");
+SYSCTL_INT(_kern_ffclock, OID_AUTO, version, CTLFLAG_RD, &ffclock_version, 0,
+    "Version of Feed-Forward Clock Support");
+
+/*
+ * Sysctl to select which clock is read when calling any of the
+ * [get]{bin,nano,micro}[up]time() functions.
+ */
+char *sysclocks[] = {"feedback", "feed-forward"};
+
+#define	NUM_SYSCLOCKS (sizeof(sysclocks) / sizeof(*sysclocks))
+
+/* Report or change the active timecounter hardware. */
+static int
+sysctl_kern_ffclock_choice(SYSCTL_HANDLER_ARGS)
+{
+	struct sbuf *s;
+	int clk, error;
+
+	s = sbuf_new_for_sysctl(NULL, NULL, 16 * NUM_SYSCLOCKS, req);
+	if (s == NULL)
+		return (ENOMEM);
+
+	for (clk = 0; clk < NUM_SYSCLOCKS; clk++) {
+		sbuf_cat(s, sysclocks[clk]);
+		if (clk + 1 < NUM_SYSCLOCKS)
+			sbuf_cat(s, " ");
+	}
+	error = sbuf_finish(s);
+	sbuf_delete(s);
+
+	return (error);
+}
+
+SYSCTL_PROC(_kern_ffclock, OID_AUTO, choice, CTLTYPE_STRING | CTLFLAG_RD,
+    0, 0, sysctl_kern_ffclock_choice, "A", "Clock paradigms available");
+
+extern int sysclock_active;
+
+static int
+sysctl_kern_ffclock_active(SYSCTL_HANDLER_ARGS)
+{
+	char newclock[32];
+	int error;
+
+	switch (sysclock_active) {
+	case SYSCLOCK_FBCK:
+		strlcpy(newclock, sysclocks[SYSCLOCK_FBCK], sizeof(newclock));
+		break;
+	case SYSCLOCK_FFWD:
+		strlcpy(newclock, sysclocks[SYSCLOCK_FFWD], sizeof(newclock));
+		break;
+	}
+
+	error = sysctl_handle_string(oidp, &newclock[0], sizeof(newclock), req);
+	if (error != 0 || req->newptr == NULL)
+		return (error);
+	if (strncmp(newclock, sysclocks[SYSCLOCK_FBCK],
+	    sizeof(sysclocks[SYSCLOCK_FBCK])) == 0)
+		sysclock_active = SYSCLOCK_FBCK;
+	else if (strncmp(newclock, sysclocks[SYSCLOCK_FFWD],
+	    sizeof(sysclocks[SYSCLOCK_FFWD])) == 0)
+		sysclock_active = SYSCLOCK_FFWD;
+	else
+		return (EINVAL);
+
+	return (error);
+}
+
+SYSCTL_PROC(_kern_ffclock, OID_AUTO, active, CTLTYPE_STRING | CTLFLAG_RW,
+    0, 0, sysctl_kern_ffclock_active, "A", "Kernel clock selected");
+
+/*
+ * High level functions to access the Feed-Forward Clock.
+ */
+void
+ffclock_bintime(struct bintime *bt)
+{
+
+	ffclock_abstime(NULL, bt, NULL, FFCLOCK_LERP | FFCLOCK_LEAPSEC);
+}
+
+void
+ffclock_nanotime(struct timespec *tsp)
+{
+	struct bintime bt;
+
+	ffclock_abstime(NULL, &bt, NULL, FFCLOCK_LERP | FFCLOCK_LEAPSEC);
+	bintime2timespec(&bt, tsp);
+}
+
+void
+ffclock_microtime(struct timeval *tvp)
+{
+	struct bintime bt;
+
+	ffclock_abstime(NULL, &bt, NULL, FFCLOCK_LERP | FFCLOCK_LEAPSEC);
+	bintime2timeval(&bt, tvp);
+}
+
+void
+ffclock_getbintime(struct bintime *bt)
+{
+
+	ffclock_abstime(NULL, bt, NULL,
+	    FFCLOCK_LERP | FFCLOCK_LEAPSEC | FFCLOCK_FAST);
+}
+
+void
+ffclock_getnanotime(struct timespec *tsp)
+{
+	struct bintime bt;
+
+	ffclock_abstime(NULL, &bt, NULL,
+	    FFCLOCK_LERP | FFCLOCK_LEAPSEC | FFCLOCK_FAST);
+	bintime2timespec(&bt, tsp);
+}
+
+void
+ffclock_getmicrotime(struct timeval *tvp)
+{
+	struct bintime bt;
+
+	ffclock_abstime(NULL, &bt, NULL,
+	    FFCLOCK_LERP | FFCLOCK_LEAPSEC | FFCLOCK_FAST);
+	bintime2timeval(&bt, tvp);
+}
+
+void
+ffclock_binuptime(struct bintime *bt)
+{
+
+	ffclock_abstime(NULL, bt, NULL, FFCLOCK_LERP | FFCLOCK_UPTIME);
+}
+
+void
+ffclock_nanouptime(struct timespec *tsp)
+{
+	struct bintime bt;
+
+	ffclock_abstime(NULL, &bt, NULL, FFCLOCK_LERP | FFCLOCK_UPTIME);
+	bintime2timespec(&bt, tsp);
+}
+
+void
+ffclock_microuptime(struct timeval *tvp)
+{
+	struct bintime bt;
+
+	ffclock_abstime(NULL, &bt, NULL, FFCLOCK_LERP | FFCLOCK_UPTIME);
+	bintime2timeval(&bt, tvp);
+}
+
+void
+ffclock_getbinuptime(struct bintime *bt)
+{
+
+	ffclock_abstime(NULL, bt, NULL,
+	    FFCLOCK_LERP | FFCLOCK_UPTIME | FFCLOCK_FAST);
+}
+
+void
+ffclock_getnanouptime(struct timespec *tsp)
+{
+	struct bintime bt;
+
+	ffclock_abstime(NULL, &bt, NULL,
+	    FFCLOCK_LERP | FFCLOCK_UPTIME | FFCLOCK_FAST);
+	bintime2timespec(&bt, tsp);
+}
+
+void
+ffclock_getmicrouptime(struct timeval *tvp)
+{
+	struct bintime bt;
+
+	ffclock_abstime(NULL, &bt, NULL,
+	    FFCLOCK_LERP | FFCLOCK_UPTIME | FFCLOCK_FAST);
+	bintime2timeval(&bt, tvp);
+}
+
+void
+ffclock_bindifftime(ffcounter ffdelta, struct bintime *bt)
+{
+
+	ffclock_difftime(ffdelta, bt, NULL);
+}
+
+void
+ffclock_nanodifftime(ffcounter ffdelta, struct timespec *tsp)
+{
+	struct bintime bt;
+
+	ffclock_difftime(ffdelta, &bt, NULL);
+	bintime2timespec(&bt, tsp);
+}
+
+void
+ffclock_microdifftime(ffcounter ffdelta, struct timeval *tvp)
+{
+	struct bintime bt;
+
+	ffclock_difftime(ffdelta, &bt, NULL);
+	bintime2timeval(&bt, tvp);
+}

Modified: head/sys/kern/kern_tc.c
==============================================================================
--- head/sys/kern/kern_tc.c	Sun Nov 20 01:48:22 2011	(r227746)
+++ head/sys/kern/kern_tc.c	Sun Nov 20 05:32:12 2011	(r227747)
@@ -177,6 +177,144 @@ tc_delta(struct timehands *th)
  * the comment in <sys/time.h> for a description of these 12 functions.
  */
 
+#ifdef FFCLOCK
+static void
+fbclock_binuptime(struct bintime *bt)
+{
+	struct timehands *th;
+	unsigned int gen;
+
+	do {
+		th = timehands;
+		gen = th->th_generation;
+		*bt = th->th_offset;
+		bintime_addx(bt, th->th_scale * tc_delta(th));
+	} while (gen == 0 || gen != th->th_generation);
+}
+
+static void
+fbclock_nanouptime(struct timespec *tsp)
+{
+	struct bintime bt;
+
+	binuptime(&bt);
+	bintime2timespec(&bt, tsp);
+}
+
+static void
+fbclock_microuptime(struct timeval *tvp)
+{
+	struct bintime bt;
+
+	binuptime(&bt);
+	bintime2timeval(&bt, tvp);
+}
+
+static void
+fbclock_bintime(struct bintime *bt)
+{
+
+	binuptime(bt);
+	bintime_add(bt, &boottimebin);
+}
+
+static void
+fbclock_nanotime(struct timespec *tsp)
+{
+	struct bintime bt;
+
+	bintime(&bt);
+	bintime2timespec(&bt, tsp);
+}
+
+static void
+fbclock_microtime(struct timeval *tvp)
+{
+	struct bintime bt;
+
+	bintime(&bt);
+	bintime2timeval(&bt, tvp);
+}
+
+static void
+fbclock_getbinuptime(struct bintime *bt)
+{
+	struct timehands *th;
+	unsigned int gen;
+
+	do {
+		th = timehands;
+		gen = th->th_generation;
+		*bt = th->th_offset;
+	} while (gen == 0 || gen != th->th_generation);
+}
+
+static void
+fbclock_getnanouptime(struct timespec *tsp)
+{
+	struct timehands *th;
+	unsigned int gen;
+
+	do {
+		th = timehands;
+		gen = th->th_generation;
+		bintime2timespec(&th->th_offset, tsp);
+	} while (gen == 0 || gen != th->th_generation);
+}
+
+static void
+fbclock_getmicrouptime(struct timeval *tvp)
+{
+	struct timehands *th;
+	unsigned int gen;
+
+	do {
+		th = timehands;
+		gen = th->th_generation;
+		bintime2timeval(&th->th_offset, tvp);
+	} while (gen == 0 || gen != th->th_generation);
+}
+
+static void
+fbclock_getbintime(struct bintime *bt)
+{
+	struct timehands *th;
+	unsigned int gen;
+
+	do {
+		th = timehands;
+		gen = th->th_generation;
+		*bt = th->th_offset;
+	} while (gen == 0 || gen != th->th_generation);
+	bintime_add(bt, &boottimebin);
+}
+
+static void
+fbclock_getnanotime(struct timespec *tsp)
+{
+	struct timehands *th;
+	unsigned int gen;
+
+	do {
+		th = timehands;
+		gen = th->th_generation;
+		*tsp = th->th_nanotime;
+	} while (gen == 0 || gen != th->th_generation);
+}
+
+static void
+fbclock_getmicrotime(struct timeval *tvp)
+{
+	struct timehands *th;
+	unsigned int gen;
+
+	do {
+		th = timehands;
+		gen = th->th_generation;
+		*tvp = th->th_microtime;
+	} while (gen == 0 || gen != th->th_generation);
+}
+#else /* !FFCLOCK */
 void
 binuptime(struct bintime *bt)
 {
@@ -313,6 +451,7 @@ getmicrotime(struct timeval *tvp)
 		*tvp = th->th_microtime;
 	} while (gen == 0 || gen != th->th_generation);
 }
+#endif /* FFCLOCK */
 
 #ifdef FFCLOCK
 /*
@@ -322,6 +461,8 @@ getmicrotime(struct timeval *tvp)
  * necessary.
  */
 
+int sysclock_active = SYSCLOCK_FBCK;
+
 /* Feed-forward clock estimates kept updated by the synchronization daemon. */
 struct ffclock_estimate ffclock_estimate;
 struct bintime ffclock_boottime;	/* Feed-forward boot time estimate. */
@@ -329,6 +470,38 @@ uint32_t ffclock_status;		/* Feed-forwar
 int8_t ffclock_updated;			/* New estimates are available. */
 struct mtx ffclock_mtx;			/* Mutex on ffclock_estimate. */
 
+struct sysclock_ops {
+	int active;
+	void (*binuptime) (struct bintime *bt);
+	void (*nanouptime) (struct timespec *tsp);
+	void (*microuptime) (struct timeval *tvp);
+	void (*bintime) (struct bintime *bt);
+	void (*nanotime) (struct timespec *tsp);
+	void (*microtime) (struct timeval *tvp);
+	void (*getbinuptime) (struct bintime *bt);
+	void (*getnanouptime) (struct timespec *tsp);
+	void (*getmicrouptime) (struct timeval *tvp);
+	void (*getbintime) (struct bintime *bt);
+	void (*getnanotime) (struct timespec *tsp);
+	void (*getmicrotime) (struct timeval *tvp);
+};
+
+static struct sysclock_ops sysclock = {
+	.active = SYSCLOCK_FBCK,
+	.binuptime = fbclock_binuptime,
+	.nanouptime = fbclock_nanouptime,
+	.microuptime = fbclock_microuptime,
+	.bintime = fbclock_bintime,
+	.nanotime = fbclock_nanotime,
+	.microtime = fbclock_microtime,
+	.getbinuptime = fbclock_getbinuptime,
+	.getnanouptime = fbclock_getnanouptime,
+	.getmicrouptime = fbclock_getmicrouptime,
+	.getbintime = fbclock_getbintime,
+	.getnanotime = fbclock_getnanotime,
+	.getmicrotime = fbclock_getmicrotime
+};
+
 struct fftimehands {
 	struct ffclock_estimate	cest;
 	struct bintime		tick_time;
@@ -621,6 +794,46 @@ ffclock_change_tc(struct timehands *th)
 	fftimehands = ffth;
 }
 
+static void
+change_sysclock(int new_sysclock)
+{
+
+	sysclock.active = new_sysclock;
+
+	switch (sysclock.active) {
+	case SYSCLOCK_FBCK:
+		sysclock.binuptime = fbclock_binuptime;
+		sysclock.nanouptime = fbclock_nanouptime;
+		sysclock.microuptime = fbclock_microuptime;
+		sysclock.bintime = fbclock_bintime;
+		sysclock.nanotime = fbclock_nanotime;
+		sysclock.microtime = fbclock_microtime;
+		sysclock.getbinuptime = fbclock_getbinuptime;
+		sysclock.getnanouptime = fbclock_getnanouptime;
+		sysclock.getmicrouptime = fbclock_getmicrouptime;
+		sysclock.getbintime = fbclock_getbintime;
+		sysclock.getnanotime = fbclock_getnanotime;
+		sysclock.getmicrotime = fbclock_getmicrotime;
+		break;
+	case SYSCLOCK_FFWD:
+		sysclock.binuptime = ffclock_binuptime;
+		sysclock.nanouptime = ffclock_nanouptime;
+		sysclock.microuptime = ffclock_microuptime;
+		sysclock.bintime = ffclock_bintime;
+		sysclock.nanotime = ffclock_nanotime;
+		sysclock.microtime = ffclock_microtime;
+		sysclock.getbinuptime = ffclock_getbinuptime;
+		sysclock.getnanouptime = ffclock_getnanouptime;
+		sysclock.getmicrouptime = ffclock_getmicrouptime;
+		sysclock.getbintime = ffclock_getbintime;
+		sysclock.getnanotime = ffclock_getnanotime;
+		sysclock.getmicrotime = ffclock_getmicrotime;
+		break;
+	default:
+		break;
+	}
+}
+
 /*
  * Retrieve feed-forward counter and time of last kernel tick.
  */
@@ -731,6 +944,90 @@ ffclock_read_counter(ffcounter *ffcount)
 
 	*ffcount += delta;
 }
+
+void
+binuptime(struct bintime *bt)
+{
+
+	sysclock.binuptime(bt);
+}
+
+void
+nanouptime(struct timespec *tsp)
+{
+
+	sysclock.nanouptime(tsp);
+}
+
+void
+microuptime(struct timeval *tvp)
+{
+
+	sysclock.microuptime(tvp);
+}
+
+void
+bintime(struct bintime *bt)
+{
+
+	sysclock.bintime(bt);
+}
+
+void
+nanotime(struct timespec *tsp)
+{
+
+	sysclock.nanotime(tsp);
+}
+
+void
+microtime(struct timeval *tvp)
+{
+
+	sysclock.microtime(tvp);
+}
+
+void
+getbinuptime(struct bintime *bt)
+{
+
+	sysclock.getbinuptime(bt);
+}
+
+void
+getnanouptime(struct timespec *tsp)
+{
+
+	sysclock.getnanouptime(tsp);
+}
+
+void
+getmicrouptime(struct timeval *tvp)
+{
+
+	sysclock.getmicrouptime(tvp);
+}
+
+void
+getbintime(struct bintime *bt)
+{
+
+	sysclock.getbintime(bt);
+}
+
+void
+getnanotime(struct timespec *tsp)
+{
+
+	sysclock.getnanotime(tsp);
+}
+
+void
+getmicrotime(struct timeval *tvp)
+{
+
+	sysclock.getmicrouptime(tvp);
+}
 #endif /* FFCLOCK */
 
 /*
@@ -971,6 +1268,11 @@ tc_windup(void)
 	scale /= th->th_counter->tc_frequency;
 	th->th_scale = scale * 2;
 
+#ifdef FFCLOCK
+	if (sysclock_active != sysclock.active)
+		change_sysclock(sysclock_active);
+#endif
+
 	/*
 	 * Now that the struct timehands is again consistent, set the new
 	 * generation number, making sure to not make it zero.
@@ -980,8 +1282,21 @@ tc_windup(void)
 	th->th_generation = ogen;
 
 	/* Go live with the new struct timehands. */
-	time_second = th->th_microtime.tv_sec;
-	time_uptime = th->th_offset.sec;
+#ifdef FFCLOCK
+	switch (sysclock_active) {
+	case SYSCLOCK_FBCK:
+#endif
+		time_second = th->th_microtime.tv_sec;
+		time_uptime = th->th_offset.sec;
+#ifdef FFCLOCK
+		break;
+	case SYSCLOCK_FFWD:
+		time_second = fftimehands->tick_time_lerp.sec;
+		time_uptime = fftimehands->tick_time_lerp.sec - ffclock_boottime.sec;
+		break;
+	}
+#endif
+
 	timehands = th;
 }
 
@@ -1261,6 +1576,7 @@ inittimecounter(void *dummy)
 
 #ifdef FFCLOCK
 	ffclock_init();
+	change_sysclock(sysclock_active);
 #endif
 	/* warm up new timecounter (again) and get rolling. */
 	(void)timecounter->tc_get_timecount(timecounter);

Modified: head/sys/sys/timeffc.h
==============================================================================
--- head/sys/sys/timeffc.h	Sun Nov 20 01:48:22 2011	(r227746)
+++ head/sys/sys/timeffc.h	Sun Nov 20 05:32:12 2011	(r227747)
@@ -56,6 +56,13 @@ struct ffclock_estimate {
 #ifdef _KERNEL
 
 /*
+ * Index into the sysclocks array for obtaining the ASCII name of a particular
+ * sysclock.
+ */
+#define	SYSCLOCK_FBCK	0
+#define	SYSCLOCK_FFWD	1
+
+/*
  * Parameters of counter characterisation required by feed-forward algorithms.
  */
 #define	FFCLOCK_SKM_SCALE	1024
@@ -128,6 +135,35 @@ void ffclock_abstime(ffcounter *ffcount,
 void ffclock_difftime(ffcounter ffdelta, struct bintime *bt,
     struct bintime *error_bound);
 
+/*
+ * Wrapper routines to return current absolute time using the feed-forward
+ * clock. These functions are named after those defined in <sys/time.h>, which
+ * contains a description of the original ones.
+ */
+void ffclock_bintime(struct bintime *bt);
+void ffclock_nanotime(struct timespec *tsp);
+void ffclock_microtime(struct timeval *tvp);
+
+void ffclock_getbintime(struct bintime *bt);
+void ffclock_getnanotime(struct timespec *tsp);
+void ffclock_getmicrotime(struct timeval *tvp);
+
+void ffclock_binuptime(struct bintime *bt);
+void ffclock_nanouptime(struct timespec *tsp);
+void ffclock_microuptime(struct timeval *tvp);
+
+void ffclock_getbinuptime(struct bintime *bt);
+void ffclock_getnanouptime(struct timespec *tsp);
+void ffclock_getmicrouptime(struct timeval *tvp);
+
+/*
+ * Wrapper routines to convert a time interval specified in ffcounter units into
+ * seconds using the current feed-forward clock estimates.
+ */
+void ffclock_bindifftime(ffcounter ffdelta, struct bintime *bt);
+void ffclock_nanodifftime(ffcounter ffdelta, struct timespec *tsp);
+void ffclock_microdifftime(ffcounter ffdelta, struct timeval *tvp);
+
 #endif /* _KERNEL */
 #endif /* __BSD_VISIBLE */
 #endif /* _SYS_TIMEFF_H_ */



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