## diffname port/tod.c 1999/0219 ## diff -e /dev/null /n/emeliedump/1999/0219/sys/src/brazil/port/tod.c 0a #include "u.h" #include "../port/lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "../port/error.h" // frequency of the tod clock #define TODFREQ 1000000000LL enum { Log2mult= 22, // multiplier should have 22 bits Log2todfreq= 30, // number of significant bits of TODFREQ }; static vlong logtab[40]; struct { Lock; int shift; // time = (ticks*multiplier)>>shift vlong multiplier; // ... 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 gettod vlong delta; // amount to add to bias each slow clock tick int n; // number of times to add in delta int i; // number of times we've added in delta } tod; int log2(vlong x) { int i; for(i = 0; i < nelem(logtab); i++){ if(x < logtab[i]) break; } return i+8; } void todinit(void) { vlong v; int i; v = 1LL<<8; for(i = 0; i < nelem(logtab); i++){ logtab[i] = v; v <<= 1; } fastticks((uvlong*)&tod.hz); todsetfreq(tod.hz); addclock0link(todfix); } // // This routine makes sure that the multiplier has // at least Log2mult bits to guarantee that precision. // void todsetfreq(vlong f) { // this ensures that the multiplier has 22 bits ilock(&tod); tod.hz = f; tod.shift = Log2mult - Log2todfreq + log2(f); tod.multiplier = (TODFREQ<= 0){ tod.off = t; tod.last = fastticks(nil); tod.lasttime = 0; } else { tod.delta = delta; tod.n = n; } iunlock(&tod); } // // get time of day // vlong todget(void) { vlong ticks, x, diff; ilock(&tod); if(tod.hz == 0) ticks = fastticks((uvlong*)&tod.hz); else ticks = fastticks(nil); diff = ticks - tod.last; // convert to epoch x = (diff*tod.multiplier)>>tod.shift; x += tod.off; // protect against overflows if(diff > (1LL<<(63-Log2mult))){ tod.last = ticks; tod.off = x; } /* time can't go backwards */ if(x < tod.lasttime) x = tod.lasttime; tod.lasttime = x; iunlock(&tod); return x; } // // called every clock tick // void todfix(void) { if((MACHP(0)->ticks % HZ) != 0) return; ilock(&tod); if(tod.n > tod.i++) tod.off += tod.delta; iunlock(&tod); } long seconds(void) { vlong x; int i; x = todget(); x /= TODFREQ; i = x; return i; } . ## diffname port/tod.c 1999/0225 ## diff -e /n/emeliedump/1999/0219/sys/src/brazil/port/tod.c /n/emeliedump/1999/0225/sys/src/brazil/port/tod.c 141a // once a minute, make sure we don't overflow if((MACHP(0)->ticks % (60*HZ)) == 0) todget(); . 137a // once a second apply correction . 116c if(diff > tod.maxdiff){ . 112c x = ((diff>>tod.s2)*tod.multiplier)>>(tod.s1-tod.s2); . 73a //print("hz %lld mult %lld s1 %d s2 %d maxdiff %lld\n", tod.hz, tod.multiplier, tod.s1, tod.s2, tod.maxdiff); . 71,72c lf = log2(f); tod.s2 = lf - 25; if(tod.s2 < 0) tod.s2 = 0; tod.s1 = 2*lf - tod.s2 - 30; if(tod.s1 < 0) tod.s1 = 0; if(tod.s1 > 33) tod.s1 = 33; tod.multiplier = (TODFREQ<>s2)*multiplier)>>(s1-s2) . 12,17d 7a // compute nanosecond epoch time from the fastest ticking clock // on the system. converting the time to nanoseconds requires // the following formula // // t = (((1000000000<>s2))>>(s1-s2) // // where // // 'f' is the clock frequency // 'ticks' are clock ticks // 's1' and 's2' are shift ammounts to avoid 64 bit // overflows in the calculations // // to avoid too much calculation in gettod(), we calculate // // mult = (1000000000<>s2)) <= 63 // or log2(mult) + 12 + log2(f) - s2 <= 63 // or log2(mult) + log2(f) - 51 <= s2 // // by definition // // 3) log2(mult) = log2(1000000000) + s1 - log2(f) // or log2(mult) = 30 + s1 - log2(f) // // To balance the accuracy of the multiplier and the sampled // ticks we set // // 4) log2(mult) = log2(f>>s2) // or log2(mult) = log2(f) - s2 // // Combining 2) and 4) we get // // 5) log2(f) - s2 + log2(f) - 51 <= s2 // or 2*log2(f) - 51 <= 2*s2 // or log2(f) - 25 <= s2 // // Combining 3) and 4) // // 6) 30 + s1 - log2(f) = log2(f) - s2 // or s1 = 2*log2(f) - s2 - 30 // // Since shifting ticks left doesn't increase accuracy, and // shifting 1000000000 right loses accuracy // // 7) s2 >= 0 // 8) s1 >= 0 // // As an example, that gives us the following // // for f = 100, log2(f) = 7 // // s2 = 0 // s1 = 0 // // for f = 267000000, log2(f) = 28 // // s2 = 3 // s1 = 23 // // for f = 2000000000, log2(f) = 31 // // s2 = 6 // s1 = 26 // // for f = 8000000000, log2(f) = 33 // // s2 = 8 // s1 = 28 . ## diffname port/tod.c 1999/0227 ## diff -e /n/emeliedump/1999/0225/sys/src/brazil/port/tod.c /n/emeliedump/1999/0227/sys/src/brazil/port/tod.c 225,233d 199a // add in correction if(tod.sstart < tod.send){ t = MACHP(0)->ticks; if(t >= tod.send) t = tod.send; tod.off += tod.delta*(t - tod.sstart); tod.sstart = t; } . 190a ulong t; . 179d 177a if(n <= 0) n = 1; n *= HZ; if(delta < 0 && n > -delta) n = -delta; if(delta > 0 && n > delta) n = delta; delta /= n; tod.sstart = MACHP(0)->ticks; tod.send = tod.sstart + n; . 172c tod.sstart = tod.send = 0; . 162d 105,107c vlong delta; // add 'delta' each slow clock tick from sstart to send ulong sstart; // ... ulong send; // ... . ## diffname port/tod.c 1999/0421 ## diff -e /n/emeliedump/1999/0227/sys/src/brazil/port/tod.c /n/emeliedump/1999/0421/sys/src/brazil/port/tod.c 222,226c // protect against overflows (gettod is called at least once a second) tod.last = ticks; tod.off = x; . 160d 157,158c if(tod.s1 > 32) tod.s1 = 32; . 151c tod.s2 = lf - 28; . 100d 87,88c // s2 = 5 // s1 = 31 . 82,83c // s2 = 3 // s1 = 29 . 77,78c // s2 = 0 // s1 = 26 . 53,55c // 5) log2(f) - s2 + log2(f) - 57 <= s2 // or 2*log2(f) - 57 <= 2*s2 // or log2(f) - 28 <= s2 . 34,38c // or s1 <= 32 // 2) accomodate 1 minute of ticks without overflow // or log2(((1000000000<>s2)) <= 63 // or log2(mult) + 6 + log2(f) - s2 <= 63 // or log2(mult) + log2(f) - 57 <= s2 . ## diffname port/tod.c 1999/0508 ## diff -e /n/emeliedump/1999/0421/sys/src/brazil/port/tod.c /n/emeliedump/1999/0508/sys/src/brazil/port/tod.c 239,240c // once a second, make sure we don't overflow if((MACHP(0)->ticks % HZ) == 0) . 224c // time can't go backwards . 216,217c // convert to epoch, make sure calculation is unsigned x = (((uvlong)diff) * ((uvlong)tod.multiplier)) >> 31; . 196c uvlong x; vlong ticks, diff; . 149,158c tod.multiplier = (TODFREQ<<31)/f; . 146c // the shift is an attempt to maintain precision // during the caculations. the number of bits in // the multiplier should be log(TODFREQ) + 31 - log(f). // // Freq bits // 167 MHZ 34 // 267 MHZ 33 // 500 MHZ 32 // // in all cases, we need to call todget() at least once // a second to keep the subsequent calculations from // overflowing. . 138,139c // calculate multiplier . 124,131d 109,120d 93,94d 89a . 27,88d 23c // mult = (1000000000<<31)/f . 18,19d 12c // t = (((1000000000<<31)/f)*ticks)>>31 . ## diffname port/tod.c 1999/0509 ## diff -e /n/emeliedump/1999/0508/sys/src/brazil/port/tod.c /n/emeliedump/1999/0509/sys/src/brazil/port/tod.c 58,59d ## diffname port/tod.c 1999/0517 ## diff -e /n/emeliedump/1999/0509/sys/src/brazil/port/tod.c /n/emeliedump/1999/0517/sys/src/brazil/port/tod.c 157a } . 156c if(MACHP(0)->ticks - last >= HZ){ last = MACHP(0)->ticks; . 154a static ulong last; . 136,138c // protect against overflows if(diff > tod.hz){ tod.last = ticks; tod.off = x; } . 132,133c // convert to epoch x = (diff * tod.multiplier) >> 31; . 124c if(tod.sstart != tod.send){ . 88a tod.delta = 0; tod.sstart = tod.send; . 84d 58,70d 32,34c vlong multiplier; // t = off + (multiplier*ticks)>>31 . ## diffname port/tod.c 1999/0531 ## diff -e /n/emeliedump/1999/0517/sys/src/brazil/port/tod.c /n/emeliedump/1999/0531/sys/src/brazil/port/tod.c 158c x = todget(nil); . 148c todget(nil); . 132a if(ticksp != nil) *ticksp = ticks; . 95c todget(vlong *ticksp) . ## diffname port/tod.c 1999/0806 ## diff -e /n/emeliedump/1999/0531/sys/src/brazil/port/tod.c /n/emeliedump/1999/0806/sys/src/brazil/port/tod.c 162c x = x/TODFREQ; . 120c x = x + tod.off; . 114c tod.off = tod.off + tod.delta*(t - tod.sstart); . 83c delta = delta/n; . ## diffname port/tod.c 1999/0810 ## diff -e /n/emeliedump/1999/0806/sys/src/brazil/port/tod.c /n/emeliedump/1999/0810/sys/src/brazil/port/tod.c 136d 131c else tod.lasttime = x; . 122,125c if(m->machno == 0){ ilock(&tod); // 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; } // protect against overflows if(diff > tod.hz){ tod.last = ticks; tod.off = x; } iunlock(&tod); . 109,117d 101,102d ## diffname port/tod.c 2000/0621 ## diff -e /n/emeliedump/1999/0810/sys/src/brazil/port/tod.c /n/emeliedump/2000/0621/sys/src/9/port/tod.c 155d 151,153c ticks = fastticks(nil); diff = ticks - tod.last; if(diff > tod.hz) . 149c vlong ticks, diff; . 144c // called every clock tick to avoid calculation overflows . ## diffname port/tod.c 2000/0625 ## diff -e /n/emeliedump/2000/0621/sys/src/9/port/tod.c /n/emeliedump/2000/0625/sys/src/9/port/tod.c 135a iunlock(&tod); . 128d 112d 104a /* since 64 bit ops are not atomix, we have to lock around them */ ilock(&tod); . ## diffname port/tod.c 2000/0626 ## diff -e /n/emeliedump/2000/0625/sys/src/9/port/tod.c /n/emeliedump/2000/0626/sys/src/9/port/tod.c 156,157c if(diff > tod.hz){ ilock(&tod); // convert to epoch diff = ticks - tod.last; x = (diff * tod.multiplier) >> 31; x = x + tod.off; // protect against overflows tod.last = ticks; tod.off = x; iunlock(&tod); } . 151a uvlong x; . 136a . 114,131d 110a diff = ticks - tod.last; . 109a // 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; } . 108c tod.cnt++; . 106c // since 64 bit loads are not atomic, we have to lock around them . 30a ulong cnt; . 24a // // We assume that the cpu's of a multiprocessor are synchronized. // This assumption needs to be questioned with each new architecture. . ## diffname port/tod.c 2000/1215 ## diff -e /n/emeliedump/2000/0626/sys/src/9/port/tod.c /n/emeliedump/2000/1215/sys/src/9/port/tod.c 158,159c x = diff * tod.multiplier; x = x >> 31; . 49c ilock(&tod); tod.last = fastticks((uvlong*)&tod.hz); iunlock(&tod); . 40c vlong lasttime; // last return value from todget . 19c // to avoid too much calculation in todget(), we calculate . ## diffname port/tod.c 2002/0410 ## diff -e /n/emeliedump/2000/1215/sys/src/9/port/tod.c /n/emeliedump/2002/0410/sys/src/9/port/tod.c 181a } // convert milliseconds to fast ticks // uvlong ms2fastticks(ulong ms) { if(tod.hz == 0) fastticks((uvlong*)&tod.hz); return (tod.hz*ms)/1000ULL; . 64a . 63a /* calculate multiplier for time conversion */ . 31c #define TODFREQ 1000000000ULL . ## diffname port/tod.c 2002/0411 ## diff -e /n/emeliedump/2002/0410/sys/src/9/port/tod.c /n/emeliedump/2002/0411/sys/src/9/port/tod.c 41,43c vlong delta; // add 'delta' each slow clock tick from sstart to send ulong sstart; // ... ulong send; // ... . ## diffname port/tod.c 2002/0928 ## diff -e /n/emeliedump/2002/0411/sys/src/9/port/tod.c /n/emeliedump/2002/0928/sys/src/9/port/tod.c 148c // called regularly to avoid calculation overflows . 53c addclock0link(todfix, 100); .