Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 24 Dec 2011 01:32:01 +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: r228856 - in head/sys: kern sys
Message-ID:  <201112240132.pBO1W173091277@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: lstewart
Date: Sat Dec 24 01:32:01 2011
New Revision: 228856
URL: http://svn.freebsd.org/changeset/base/228856

Log:
  Introduce the sysclock_getsnapshot() and sysclock_snap2bintime() KPIs. The
  sysclock_getsnapshot() function allows the caller to obtain a snapshot of all
  the system clock and timecounter state required to create time stamps at a later
  point. The sysclock_snap2bintime() function converts a previously obtained
  snapshot into a bintime time stamp according to the specified flags e.g. which
  system clock, uptime vs absolute time, etc.
  
  These KPIs enable useful functionality, including direct comparison of the
  feedback and feed-forward system clocks and generation of multiple time stamps
  with different formats from a single timecounter read.
  
  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/
  
  In collaboration with:	Julien Ridoux (jridoux at unimelb edu au)

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

Modified: head/sys/kern/kern_ntptime.c
==============================================================================
--- head/sys/kern/kern_ntptime.c	Sat Dec 24 00:23:27 2011	(r228855)
+++ head/sys/kern/kern_ntptime.c	Sat Dec 24 01:32:01 2011	(r228856)
@@ -148,13 +148,13 @@ typedef int64_t l_fp;
 #define SHIFT_FLL	2		/* FLL loop gain (shift) */
 
 static int time_state = TIME_OK;	/* clock state */
-static int time_status = STA_UNSYNC;	/* clock status bits */
+int time_status = STA_UNSYNC;	/* clock status bits */
 static long time_tai;			/* TAI offset (s) */
 static long time_monitor;		/* last time offset scaled (ns) */
 static long time_constant;		/* poll interval (shift) (s) */
 static long time_precision = 1;		/* clock precision (ns) */
 static long time_maxerror = MAXPHASE / 1000; /* maximum error (us) */
-static long time_esterror = MAXPHASE / 1000; /* estimated error (us) */
+long time_esterror = MAXPHASE / 1000; /* estimated error (us) */
 static long time_reftime;		/* time at last adjustment (s) */
 static l_fp time_offset;		/* time offset (ns) */
 static l_fp time_freq;			/* frequency offset (ns/s) */

Modified: head/sys/kern/kern_tc.c
==============================================================================
--- head/sys/kern/kern_tc.c	Sat Dec 24 00:23:27 2011	(r228855)
+++ head/sys/kern/kern_tc.c	Sat Dec 24 01:32:01 2011	(r228856)
@@ -28,9 +28,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/sysctl.h>
 #include <sys/syslog.h>
 #include <sys/systm.h>
-#ifdef FFCLOCK
 #include <sys/timeffc.h>
-#endif
 #include <sys/timepps.h>
 #include <sys/timetc.h>
 #include <sys/timex.h>
@@ -461,8 +459,6 @@ 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. */
@@ -956,9 +952,149 @@ getmicrotime(struct timeval *tvp)
 
 	getmicrouptime_fromclock(tvp, sysclock_active);
 }
+
 #endif /* FFCLOCK */
 
 /*
+ * System clock currently providing time to the system. Modifiable via sysctl
+ * when the FFCLOCK option is defined.
+ */
+int sysclock_active = SYSCLOCK_FBCK;
+
+/* Internal NTP status and error estimates. */
+extern int time_status;
+extern long time_esterror;
+
+/*
+ * Take a snapshot of sysclock data which can be used to compare system clocks
+ * and generate timestamps after the fact.
+ */
+void
+sysclock_getsnapshot(struct sysclock_snap *clock_snap, int fast)
+{
+	struct fbclock_info *fbi;
+	struct timehands *th;
+	struct bintime bt;
+	unsigned int delta, gen;
+#ifdef FFCLOCK
+	ffcounter ffcount;
+	struct fftimehands *ffth;
+	struct ffclock_info *ffi;
+	struct ffclock_estimate cest;
+
+	ffi = &clock_snap->ff_info;
+#endif
+
+	fbi = &clock_snap->fb_info;
+	delta = 0;
+
+	do {
+		th = timehands;
+		gen = th->th_generation;
+		fbi->th_scale = th->th_scale;
+		fbi->tick_time = th->th_offset;
+#ifdef FFCLOCK
+		ffth = fftimehands;
+		ffi->tick_time = ffth->tick_time_lerp;
+		ffi->tick_time_lerp = ffth->tick_time_lerp;
+		ffi->period = ffth->cest.period;
+		ffi->period_lerp = ffth->period_lerp;
+		clock_snap->ffcount = ffth->tick_ffcount;
+		cest = ffth->cest;
+#endif
+		if (!fast)
+			delta = tc_delta(th);
+	} while (gen == 0 || gen != th->th_generation);
+
+	clock_snap->delta = delta;
+	clock_snap->sysclock_active = sysclock_active;
+
+	/* Record feedback clock status and error. */
+	clock_snap->fb_info.status = time_status;
+	/* XXX: Very crude estimate of feedback clock error. */
+	bt.sec = time_esterror / 1000000;
+	bt.frac = ((time_esterror - bt.sec) * 1000000) *
+	    (uint64_t)18446744073709ULL;
+	clock_snap->fb_info.error = bt;
+
+#ifdef FFCLOCK
+	if (!fast)
+		clock_snap->ffcount += delta;
+
+	/* Record feed-forward clock leap second adjustment. */
+	ffi->leapsec_adjustment = cest.leapsec_total;
+	if (clock_snap->ffcount > cest.leapsec_next)
+		ffi->leapsec_adjustment -= cest.leapsec;
+
+	/* Record feed-forward clock status and error. */
+	clock_snap->ff_info.status = cest.status;
+	ffcount = clock_snap->ffcount - cest.update_ffcount;
+	ffclock_convert_delta(ffcount, cest.period, &bt);
+	/* 18446744073709 = int(2^64/1e12), err_bound_rate in [ps/s]. */
+	bintime_mul(&bt, cest.errb_rate * (uint64_t)18446744073709ULL);
+	/* 18446744073 = int(2^64 / 1e9), since err_abs in [ns]. */
+	bintime_addx(&bt, cest.errb_abs * (uint64_t)18446744073ULL);
+	clock_snap->ff_info.error = bt;
+#endif
+}
+
+/*
+ * Convert a sysclock snapshot into a struct bintime based on the specified
+ * clock source and flags.
+ */
+int
+sysclock_snap2bintime(struct sysclock_snap *cs, struct bintime *bt,
+    int whichclock, uint32_t flags)
+{
+#ifdef FFCLOCK
+	struct bintime bt2;
+	uint64_t period;
+#endif
+
+	switch (whichclock) {
+	case SYSCLOCK_FBCK:
+		*bt = cs->fb_info.tick_time;
+
+		/* If snapshot was created with !fast, delta will be >0. */
+		if (cs->delta > 0)
+			bintime_addx(bt, cs->fb_info.th_scale * cs->delta);
+
+		if ((flags & FBCLOCK_UPTIME) == 0)
+			bintime_add(bt, &boottimebin);
+		break;
+#ifdef FFCLOCK
+	case SYSCLOCK_FFWD:
+		if (flags & FFCLOCK_LERP) {
+			*bt = cs->ff_info.tick_time_lerp;
+			period = cs->ff_info.period_lerp;
+		} else {
+			*bt = cs->ff_info.tick_time;
+			period = cs->ff_info.period;
+		}
+
+		/* If snapshot was created with !fast, delta will be >0. */
+		if (cs->delta > 0) {
+			ffclock_convert_delta(cs->delta, period, &bt2);
+			bintime_add(bt, &bt2);
+		}
+
+		/* Leap second adjustment. */
+		if (flags & FFCLOCK_LEAPSEC)
+			bt->sec -= cs->ff_info.leapsec_adjustment;
+
+		/* Boot time adjustment, for uptime/monotonic clocks. */
+		if (flags & FFCLOCK_UPTIME)
+			bintime_sub(bt, &ffclock_boottime);
+#endif
+	default:
+		return (EINVAL);
+		break;
+	}
+
+	return (0);
+}
+
+/*
  * Initialize a new timecounter and possibly use it.
  */
 void

Modified: head/sys/sys/timeffc.h
==============================================================================
--- head/sys/sys/timeffc.h	Sat Dec 24 00:23:27 2011	(r228855)
+++ head/sys/sys/timeffc.h	Sat Dec 24 01:32:01 2011	(r228856)
@@ -81,19 +81,75 @@ extern int sysclock_active;
 #define	FFCLOCK_STA_WARMUP	2
 
 /*
- * Clock flags to select how the feed-forward counter is converted to absolute
- * time by ffclock_convert_abs().
- * FAST:    do not read the hardware counter, return feed-forward clock time
- *          at last tick. The time returned has the resolution of the kernel
- *          tick (1/hz [s]).
- * LERP:    linear interpolation of ffclock time to guarantee monotonic time.
- * LEAPSEC: include leap seconds.
- * UPTIME:  removes time of boot.
- */
-#define	FFCLOCK_FAST		1
-#define	FFCLOCK_LERP		2
-#define	FFCLOCK_LEAPSEC		4
-#define	FFCLOCK_UPTIME		8
+ * Flags for use by sysclock_snap2bintime() and various ffclock_ functions to
+ * control how the timecounter hardware is read and how the hardware snapshot is
+ * converted into absolute time.
+ * {FB|FF}CLOCK_FAST:	Do not read the hardware counter, instead using the
+ *			value at last tick. The time returned has a resolution
+ *			of the kernel tick timer (1/hz [s]).
+ * FFCLOCK_LERP:	Linear interpolation of ffclock time to guarantee
+ *			monotonic time.
+ * FFCLOCK_LEAPSEC:	Include leap seconds.
+ * {FB|FF}CLOCK_UPTIME:	Time stamp should be relative to system boot, not epoch.
+ */
+#define	FFCLOCK_FAST		0x00000001
+#define	FFCLOCK_LERP		0x00000002
+#define	FFCLOCK_LEAPSEC		0x00000004
+#define	FFCLOCK_UPTIME		0x00000008
+#define	FFCLOCK_MASK		0x0000ffff
+
+#define	FBCLOCK_FAST		0x00010000 /* Currently unused. */
+#define	FBCLOCK_UPTIME		0x00020000
+#define	FBCLOCK_MASK		0xffff0000
+
+/*
+ * Feedback clock specific info structure. The feedback clock's estimation of
+ * clock error is an absolute figure determined by the NTP algorithm. The status
+ * is determined by the userland daemon.
+ */
+struct fbclock_info {
+	struct bintime		error;
+	struct bintime		tick_time;
+	uint64_t		th_scale;
+	int			status;
+};
+
+/*
+ * Feed-forward clock specific info structure. The feed-forward clock's
+ * estimation of clock error is an upper bound, which although potentially
+ * looser than the feedback clock equivalent, is much more reliable. The status
+ * is determined by the userland daemon.
+ */
+struct ffclock_info {
+	struct bintime		error;
+	struct bintime		tick_time;
+	struct bintime		tick_time_lerp;
+	uint64_t		period;
+	uint64_t		period_lerp;
+	int			leapsec_adjustment;
+	int			status;
+};
+
+/*
+ * Snapshot of system clocks and related information. Holds time read from each
+ * clock based on a single read of the active hardware timecounter, as well as
+ * respective clock information such as error estimates and the ffcounter value
+ * at the time of the read.
+ */
+struct sysclock_snap {
+	struct fbclock_info	fb_info;
+	struct ffclock_info	ff_info;
+	ffcounter		ffcount;
+	unsigned int		delta;
+	int			sysclock_active;
+};
+
+/* Take a snapshot of the system clocks and related information. */
+void sysclock_getsnapshot(struct sysclock_snap *clock_snap, int fast);
+
+/* Convert a timestamp from the selected system clock into bintime. */
+int sysclock_snap2bintime(struct sysclock_snap *cs, struct bintime *bt,
+    int whichclock, uint32_t flags);
 
 /* Resets feed-forward clock from RTC */
 void ffclock_reset_clock(struct timespec *ts);



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