2 #include "../port/lib.h"
6 #include "../port/error.h"
9 * Compute nanosecond epoch time from the fastest ticking clock
10 * on the system. Converting the time to nanoseconds requires
11 * the following formula
13 * t = (((1000000000<<31)/f)*ticks)>>31
17 * 'f' is the clock frequency
18 * 'ticks' are clock ticks
20 * to avoid too much calculation in todget(), we calculate
22 * mult = (1000000000<<32)/f
24 * each time f is set. f is normally set by a user level
25 * program writing to /dev/fastclock. mul64fract will then
26 * take that fractional multiplier and a 64 bit integer and
27 * return the resulting integer product.
29 * We assume that the cpu's of a multiprocessor are synchronized.
30 * This assumption needs to be questioned with each new architecture.
33 /* frequency of the tod clock */
34 #define TODFREQ 1000000000ULL
35 #define MicroFREQ 1000000ULL
38 int init; /* true if initialized */
41 uvlong multiplier; /* ns = off + (multiplier*ticks)>>31 */
42 uvlong divider; /* ticks = (divider*(ns-off))>>31 */
43 uvlong umultiplier; /* µs = (µmultiplier*ticks)>>31 */
44 uvlong udivider; /* ticks = (µdivider*µs)>>31 */
45 vlong hz; /* frequency of fast clock */
46 vlong last; /* last reading of fast clock */
47 vlong off; /* offset from epoch to last */
48 vlong lasttime; /* last return value from todget */
49 vlong delta; /* add 'delta' each slow clock tick from sstart to send */
50 ulong sstart; /* ... */
54 static void todfix(void);
62 tod.init = 1; /* prevent reentry via fastticks */
63 tod.last = fastticks((uvlong *)&tod.hz);
66 addclock0link(todfix, 100);
70 * calculate multiplier
76 panic("todsetfreq: freq %lld <= 0", f);
80 /* calculate multiplier for time conversion */
81 tod.multiplier = mk64fract(TODFREQ, f);
82 tod.divider = mk64fract(f, TODFREQ) + 1;
83 tod.umultiplier = mk64fract(MicroFREQ, f);
84 tod.udivider = mk64fract(f, MicroFREQ) + 1;
89 * Set the time of day struct
92 todset(vlong t, vlong delta, int n)
100 tod.last = fastticks(nil);
103 tod.sstart = tod.send;
108 if(delta < 0 && n > -delta)
110 if(delta > 0 && n > delta)
113 iprint("todset: n == 0, delta == %lld\n", delta);
117 tod.sstart = MACHP(0)->ticks;
118 tod.send = tod.sstart + n;
128 todget(vlong *ticksp)
138 * we don't want time to pass twixt the measuring of fastticks
139 * and grabbing tod.last. Also none of the vlongs are atomic so
140 * we have to look at them inside the lock.
144 ticks = fastticks(nil);
146 /* add in correction */
147 if(tod.sstart != tod.send){
151 tod.off = tod.off + tod.delta*(t - tod.sstart);
155 /* convert to epoch */
156 diff = ticks - tod.last;
159 mul64fract(&x, diff, tod.multiplier);
162 /* time can't go backwards */
177 * convert time of day to ticks
180 tod2fastticks(vlong ns)
185 mul64fract(&x, ns-tod.off, tod.divider);
192 * called regularly to avoid calculation overflows
200 ticks = fastticks(nil);
201 diff = ticks - tod.last;
206 diff = ticks - tod.last;
208 /* convert to epoch */
209 mul64fract(&x, diff, tod.multiplier);
212 /* protect against overflows */
222 return (vlong)todget(nil) / TODFREQ;
226 fastticks2us(uvlong ticks)
232 mul64fract(&res, ticks, tod.umultiplier);
237 us2fastticks(uvlong us)
243 mul64fract(&res, us, tod.udivider);
248 * convert milliseconds to fast ticks
251 ms2fastticks(ulong ms)
255 return (tod.hz*ms)/1000ULL;
259 * convert nanoseconds to fast ticks
262 ns2fastticks(uvlong ns)
268 mul64fract(&res, ns, tod.divider);
273 * convert fast ticks to ns
276 fastticks2ns(uvlong ticks)
282 mul64fract(&res, ticks, tod.multiplier);
287 * Make a 64 bit fixed point number that has a decimal point
288 * to the left of the low order 32 bits. This is used with
289 * mul64fract for converting twixt nanoseconds and fastticks.
291 * multiplier = (to<<32)/from
294 mk64fract(uvlong to, uvlong from)
303 while(shift < 32 && to < (1ULL<<(32+24))){
307 while(shift < 32 && to < (1ULL<<(32+31))){
312 return (to/from)<<(32-shift);
314 return (to<<32) / from;