summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorlstewart <lstewart@FreeBSD.org>2011-12-24 01:32:01 +0000
committerlstewart <lstewart@FreeBSD.org>2011-12-24 01:32:01 +0000
commit1c0bb02c84b89eb2f680e27b37e58dd05abc23c1 (patch)
treef6c0eaf45fcae96aeeac68d7acbad79ae3dd9c58 /sys
parent2425a92fa5a7e0049961b21fb111a4dabe00d257 (diff)
downloadFreeBSD-src-1c0bb02c84b89eb2f680e27b37e58dd05abc23c1.zip
FreeBSD-src-1c0bb02c84b89eb2f680e27b37e58dd05abc23c1.tar.gz
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)
Diffstat (limited to 'sys')
-rw-r--r--sys/kern/kern_ntptime.c4
-rw-r--r--sys/kern/kern_tc.c144
-rw-r--r--sys/sys/timeffc.h80
3 files changed, 210 insertions, 18 deletions
diff --git a/sys/kern/kern_ntptime.c b/sys/kern/kern_ntptime.c
index 2669a54..7da7de2 100644
--- a/sys/kern/kern_ntptime.c
+++ b/sys/kern/kern_ntptime.c
@@ -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) */
diff --git a/sys/kern/kern_tc.c b/sys/kern/kern_tc.c
index e2ba80d..d8d53a2 100644
--- a/sys/kern/kern_tc.c
+++ b/sys/kern/kern_tc.c
@@ -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
diff --git a/sys/sys/timeffc.h b/sys/sys/timeffc.h
index 6a5bcc0..3bda5d4 100644
--- a/sys/sys/timeffc.h
+++ b/sys/sys/timeffc.h
@@ -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.
+ * 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 1
-#define FFCLOCK_LERP 2
-#define FFCLOCK_LEAPSEC 4
-#define FFCLOCK_UPTIME 8
+#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);
OpenPOWER on IntegriCloud