/*
* Compute nanosecond epoch time from the fastest ticking clock
* on the system. Converting the time to nanoseconds requires
* the following formula
*
* t = (((1000000000<<31)/f)*ticks)>>31
*
* where
*
* 'f' is the clock frequency
* 'ticks' are clock ticks
*
* to avoid too much calculation in todget(), we calculate
*
* mult = (1000000000<<32)/f
*
* each time f is set. f is normally set by a user level
* program writing to /dev/fastclock. mul64fract will then
* take that fractional multiplier and a 64 bit integer and
* return the resulting integer product.
*
* We assume that the cpu's of a multiprocessor are synchronized.
* This assumption needs to be questioned with each new architecture.
*/
/* frequency of the tod clock */
#define TODFREQ 1000000000ULL
#define MicroFREQ 1000000ULL
struct {
int init; /* true if initialized */
ulong cnt;
Lock;
uvlong multiplier; /* ns = off + (multiplier*ticks)>>31 */
uvlong divider; /* ticks = (divider*(ns-off))>>31 */
uvlong umultiplier; /* µs = (µmultiplier*ticks)>>31 */
uvlong udivider; /* ticks = (µdivider*µs)>>31 */
vlong hz; /* frequency of fast clock */
vlong last; /* last reading of fast clock */
vlong off; /* offset from epoch to last */
vlong lasttime; /* last return value from todget */
vlong delta; /* add 'delta' each slow clock tick from sstart to send */
ulong sstart; /* ... */
ulong send; /* ... */
} tod;
/*
* get time of day
*/
vlong
todget(vlong *ticksp)
{
uvlong x;
vlong ticks, diff;
ulong t;
if(!tod.init)
todinit();
/*
* we don't want time to pass twixt the measuring of fastticks
* and grabbing tod.last. Also none of the vlongs are atomic so
* we have to look at them inside the lock.
*/
ilock(&tod);
tod.cnt++;
ticks = fastticks(nil);
/* add in correction */
if(tod.sstart != tod.send){
t = MACHP(0)->ticks;
if(t >= tod.send)
t = tod.send;
tod.off = tod.off + tod.delta*(t - tod.sstart);
tod.sstart = t;
}
/*
* Make a 64 bit fixed point number that has a decimal point
* to the left of the low order 32 bits. This is used with
* mul64fract for converting twixt nanoseconds and fastticks.
*
* multiplier = (to<<32)/from
*/
uvlong
mk64fract(uvlong to, uvlong from)
{
/*
int shift;
if(to == 0ULL)
return 0ULL;
shift = 0;
while(shift < 32 && to < (1ULL<<(32+24))){
to <<= 8;
shift += 8;
}
while(shift < 32 && to < (1ULL<<(32+31))){
to <<= 1;
shift += 1;
}