summaryrefslogtreecommitdiffstats
path: root/sys/kern/kern_tc.c
diff options
context:
space:
mode:
authorphk <phk@FreeBSD.org>2002-02-07 21:21:55 +0000
committerphk <phk@FreeBSD.org>2002-02-07 21:21:55 +0000
commita028cfa65dbfebcb696a855c911b657a10f019f3 (patch)
tree22a0fc3aaa4649b1470ece4721a94e7ce63da317 /sys/kern/kern_tc.c
parentb5eb64d6f0fccb72419da5552deee22cb6117fac (diff)
downloadFreeBSD-src-a028cfa65dbfebcb696a855c911b657a10f019f3.zip
FreeBSD-src-a028cfa65dbfebcb696a855c911b657a10f019f3.tar.gz
Revise timercounters to use binary fixed point format internally.
The binary format "bintime" is a 32.64 format, it will go to 64.64 when time_t does. The bintime format is available to consumers of time in the kernel, and is preferable where timeintervals needs to be accumulated. This change simplifies much of the magic math inside the timecounters and improves the frequency and time precision by a couple of bits. I have not been able to measure a performance difference which was not a tiny fraction of the standard deviation on the measurements.
Diffstat (limited to 'sys/kern/kern_tc.c')
-rw-r--r--sys/kern/kern_tc.c168
1 files changed, 60 insertions, 108 deletions
diff --git a/sys/kern/kern_tc.c b/sys/kern/kern_tc.c
index fa1832a..71b9e5a 100644
--- a/sys/kern/kern_tc.c
+++ b/sys/kern/kern_tc.c
@@ -35,6 +35,7 @@ static __inline unsigned tco_delta __P((struct timecounter *tc));
time_t time_second;
+struct bintime boottimebin;
struct timeval boottime;
SYSCTL_STRUCT(_kern, KERN_BOOTTIME, boottime, CTLFLAG_RD,
&boottime, timeval, "System boottime");
@@ -102,6 +103,24 @@ tco_delta(struct timecounter *tc)
*/
void
+binuptime(struct bintime *bt)
+{
+ struct timecounter *tc;
+
+ tc = timecounter;
+ *bt = tc->tc_offset;
+ bintime_addx(bt, tc->tc_scale * tco_delta(tc));
+}
+
+void
+bintime(struct bintime *bt)
+{
+
+ binuptime(bt);
+ bintime_add(bt, &boottimebin);
+}
+
+void
getmicrotime(struct timeval *tvp)
{
struct timecounter *tc;
@@ -124,43 +143,21 @@ getnanotime(struct timespec *tsp)
void
microtime(struct timeval *tv)
{
- struct timecounter *tc;
+ struct bintime bt;
nmicrotime++;
- tc = timecounter;
- tv->tv_sec = tc->tc_offset_sec;
- tv->tv_usec = tc->tc_offset_micro;
- tv->tv_usec += ((u_int64_t)tco_delta(tc) * tc->tc_scale_micro) >> 32;
- tv->tv_usec += boottime.tv_usec;
- tv->tv_sec += boottime.tv_sec;
- while (tv->tv_usec >= 1000000) {
- tv->tv_usec -= 1000000;
- tv->tv_sec++;
- }
+ bintime(&bt);
+ bintime2timeval(&bt, tv);
}
void
nanotime(struct timespec *ts)
{
- unsigned count;
- u_int64_t delta;
- struct timecounter *tc;
+ struct bintime bt;
nnanotime++;
- tc = timecounter;
- ts->tv_sec = tc->tc_offset_sec;
- count = tco_delta(tc);
- delta = tc->tc_offset_nano;
- delta += ((u_int64_t)count * tc->tc_scale_nano_f);
- delta >>= 32;
- delta += ((u_int64_t)count * tc->tc_scale_nano_i);
- delta += boottime.tv_usec * 1000;
- ts->tv_sec += boottime.tv_sec;
- while (delta >= 1000000000) {
- delta -= 1000000000;
- ts->tv_sec++;
- }
- ts->tv_nsec = delta;
+ bintime(&bt);
+ bintime2timespec(&bt, ts);
}
void
@@ -170,8 +167,7 @@ getmicrouptime(struct timeval *tvp)
ngetmicrouptime++;
tc = timecounter;
- tvp->tv_sec = tc->tc_offset_sec;
- tvp->tv_usec = tc->tc_offset_micro;
+ bintime2timeval(&tc->tc_offset, tvp);
}
void
@@ -181,46 +177,27 @@ getnanouptime(struct timespec *tsp)
ngetnanouptime++;
tc = timecounter;
- tsp->tv_sec = tc->tc_offset_sec;
- tsp->tv_nsec = tc->tc_offset_nano >> 32;
+ bintime2timespec(&tc->tc_offset, tsp);
}
void
microuptime(struct timeval *tv)
{
- struct timecounter *tc;
+ struct bintime bt;
nmicrouptime++;
- tc = timecounter;
- tv->tv_sec = tc->tc_offset_sec;
- tv->tv_usec = tc->tc_offset_micro;
- tv->tv_usec += ((u_int64_t)tco_delta(tc) * tc->tc_scale_micro) >> 32;
- while (tv->tv_usec >= 1000000) {
- tv->tv_usec -= 1000000;
- tv->tv_sec++;
- }
+ binuptime(&bt);
+ bintime2timeval(&bt, tv);
}
void
nanouptime(struct timespec *ts)
{
- unsigned count;
- u_int64_t delta;
- struct timecounter *tc;
+ struct bintime bt;
nnanouptime++;
- tc = timecounter;
- ts->tv_sec = tc->tc_offset_sec;
- count = tco_delta(tc);
- delta = tc->tc_offset_nano;
- delta += ((u_int64_t)count * tc->tc_scale_nano_f);
- delta >>= 32;
- delta += ((u_int64_t)count * tc->tc_scale_nano_i);
- while (delta >= 1000000000) {
- delta -= 1000000000;
- ts->tv_sec++;
- }
- ts->tv_nsec = delta;
+ binuptime(&bt);
+ bintime2timespec(&bt, ts);
}
static void
@@ -228,12 +205,11 @@ tco_setscales(struct timecounter *tc)
{
u_int64_t scale;
- scale = 1000000000LL << 32;
- scale += tc->tc_adjustment;
+ /* Sacrifice the lower bit to the deity for code clarity */
+ scale = 1ULL << 63;
+ scale += (tc->tc_adjustment * 4295LL) / 1000LL;
scale /= tc->tc_tweak->tc_frequency;
- tc->tc_scale_micro = scale / 1000;
- tc->tc_scale_nano_f = scale & 0xffffffff;
- tc->tc_scale_nano_i = scale >> 32;
+ tc->tc_scale = scale * 2;
}
void
@@ -245,7 +221,6 @@ tc_update(struct timecounter *tc)
void
tc_init(struct timecounter *tc)
{
- struct timespec ts1;
struct timecounter *t1, *t2, *t3;
int i;
@@ -279,10 +254,7 @@ tc_init(struct timecounter *tc)
/* XXX: For now always start using the counter. */
tc->tc_offset_count = tc->tc_get_timecount(tc);
- nanouptime(&ts1);
- tc->tc_offset_nano = (u_int64_t)ts1.tv_nsec << 32;
- tc->tc_offset_micro = ts1.tv_nsec / 1000;
- tc->tc_offset_sec = ts1.tv_sec;
+ binuptime(&tc->tc_offset);
timecounter = tc;
}
@@ -298,6 +270,7 @@ tc_setclock(struct timespec *ts)
boottime.tv_usec += 1000000;
boottime.tv_sec--;
}
+ timeval2bintime(&boottime, &boottimebin);
/* fiddle all the little crinkly bits around the fiords... */
tc_windup();
}
@@ -307,7 +280,6 @@ switch_timecounter(struct timecounter *newtc)
{
int s;
struct timecounter *tc;
- struct timespec ts;
s = splclock();
tc = timecounter;
@@ -316,10 +288,7 @@ switch_timecounter(struct timecounter *newtc)
return;
}
newtc = newtc->tc_tweak->tc_other;
- nanouptime(&ts);
- newtc->tc_offset_sec = ts.tv_sec;
- newtc->tc_offset_nano = (u_int64_t)ts.tv_nsec << 32;
- newtc->tc_offset_micro = ts.tv_nsec / 1000;
+ binuptime(&newtc->tc_offset);
newtc->tc_offset_count = newtc->tc_get_timecount(newtc);
tco_setscales(newtc);
timecounter = newtc;
@@ -340,8 +309,7 @@ sync_other_counter(void)
delta = tco_delta(tc);
tc->tc_offset_count += delta;
tc->tc_offset_count &= tc->tc_counter_mask;
- tc->tc_offset_nano += (u_int64_t)delta * tc->tc_scale_nano_f;
- tc->tc_offset_nano += (u_int64_t)delta * tc->tc_scale_nano_i << 32;
+ bintime_addx(&tc->tc_offset, tc->tc_scale * delta);
return (tc);
}
@@ -349,7 +317,9 @@ void
tc_windup(void)
{
struct timecounter *tc, *tco;
+ struct bintime bt;
struct timeval tvt;
+ int i;
tco = timecounter;
tc = sync_other_counter();
@@ -375,30 +345,19 @@ tc_windup(void)
tvt.tv_usec += 1000000;
}
boottime = tvt;
+ timeval2bintime(&boottime, &boottimebin);
timedelta -= tickdelta;
}
-
- while (tc->tc_offset_nano >= 1000000000ULL << 32) {
- tc->tc_offset_nano -= 1000000000ULL << 32;
- tc->tc_offset_sec++;
+ for (i = tc->tc_offset.sec - tco->tc_offset.sec; i > 0; i--) {
ntp_update_second(tc); /* XXX only needed if xntpd runs */
tco_setscales(tc);
}
- tc->tc_offset_micro = (tc->tc_offset_nano / 1000) >> 32;
-
- /* Figure out the wall-clock time */
- tc->tc_nanotime.tv_sec = tc->tc_offset_sec + boottime.tv_sec;
- tc->tc_nanotime.tv_nsec =
- (tc->tc_offset_nano >> 32) + boottime.tv_usec * 1000;
- tc->tc_microtime.tv_usec = tc->tc_offset_micro + boottime.tv_usec;
- if (tc->tc_nanotime.tv_nsec >= 1000000000) {
- tc->tc_nanotime.tv_nsec -= 1000000000;
- tc->tc_microtime.tv_usec -= 1000000;
- tc->tc_nanotime.tv_sec++;
- }
- time_second = tc->tc_microtime.tv_sec = tc->tc_nanotime.tv_sec;
-
+ bt = tc->tc_offset;
+ bintime_add(&bt, &boottimebin);
+ bintime2timeval(&bt, &tc->tc_microtime);
+ bintime2timespec(&bt, &tc->tc_nanotime);
+ time_second = tc->tc_microtime.tv_sec;
timecounter = tc;
}
@@ -504,8 +463,8 @@ void
pps_event(struct pps_state *pps, struct timecounter *tc, unsigned count, int event)
{
struct timespec ts, *tsp, *osp;
- u_int64_t delta;
unsigned tcount, *pcount;
+ struct bintime bt;
int foff, fhard;
pps_seq_t *pseq;
@@ -542,20 +501,11 @@ pps_event(struct pps_state *pps, struct timecounter *tc, unsigned count, int eve
*pcount = count;
/* Convert the count to timespec */
- ts.tv_sec = tc->tc_offset_sec;
tcount = count - tc->tc_offset_count;
tcount &= tc->tc_counter_mask;
- delta = tc->tc_offset_nano;
- delta += ((u_int64_t)tcount * tc->tc_scale_nano_f);
- delta >>= 32;
- delta += ((u_int64_t)tcount * tc->tc_scale_nano_i);
- delta += boottime.tv_usec * 1000;
- ts.tv_sec += boottime.tv_sec;
- while (delta >= 1000000000) {
- delta -= 1000000000;
- ts.tv_sec++;
- }
- ts.tv_nsec = delta;
+ bt = tc->tc_offset;
+ bintime_addx(&bt, tc->tc_scale * tcount);
+ bintime2timespec(&bt, &ts);
(*pseq)++;
*tsp = ts;
@@ -569,14 +519,16 @@ pps_event(struct pps_state *pps, struct timecounter *tc, unsigned count, int eve
}
#ifdef PPS_SYNC
if (fhard) {
+ u_int64_t delta;
/* magic, at its best... */
tcount = count - pps->ppscount[2];
pps->ppscount[2] = count;
tcount &= tc->tc_counter_mask;
- delta = ((u_int64_t)tcount * tc->tc_tweak->tc_scale_nano_f);
- delta >>= 32;
- delta += ((u_int64_t)tcount * tc->tc_tweak->tc_scale_nano_i);
- hardpps(tsp, delta);
+ bt.sec = 0;
+ bt.frac = 0;
+ bintime_addx(&bt, tc->tc_scale * tcount);
+ bintime2timespec(&bt, &ts);
+ hardpps(tsp, ts.tv_nsec + 1000000000 * ts.tv_sec);
}
#endif
}
OpenPOWER on IntegriCloud