tod.c 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  1. #include "u.h"
  2. #include "../port/lib.h"
  3. #include "mem.h"
  4. #include "dat.h"
  5. #include "fns.h"
  6. #include "../port/error.h"
  7. /* compute nanosecond epoch time from the fastest ticking clock
  8. * on the system. converting the time to nanoseconds requires
  9. * the following formula
  10. *
  11. * t = (((1000000000<<31)/f)*ticks)>>31
  12. *
  13. * where
  14. *
  15. * 'f' is the clock frequency
  16. * 'ticks' are clock ticks
  17. *
  18. * to avoid too much calculation in todget(), we calculate
  19. *
  20. * mult = (1000000000<<32)/f
  21. *
  22. * each time f is set. f is normally set by a user level
  23. * program writing to /dev/fastclock. mul64fract will then
  24. * take that fractional multiplier and a 64 bit integer and
  25. * return the resulting integer product.
  26. *
  27. * We assume that the cpu's of a multiprocessor are synchronized.
  28. * This assumption needs to be questioned with each new architecture.
  29. */
  30. /* frequency of the tod clock */
  31. #define TODFREQ 1000000000ULL
  32. #define MicroFREQ 1000000ULL
  33. struct {
  34. int init; // true if initialized
  35. ulong cnt;
  36. Lock;
  37. uvlong multiplier; // ns = off + (multiplier*ticks)>>31
  38. uvlong divider; // ticks = (divider*(ns-off))>>31
  39. uvlong umultiplier; // µs = (µmultiplier*ticks)>>31
  40. uvlong udivider; // ticks = (µdivider*µs)>>31
  41. vlong hz; // frequency of fast clock
  42. vlong last; // last reading of fast clock
  43. vlong off; // offset from epoch to last
  44. vlong lasttime; // last return value from todget
  45. vlong delta; // add 'delta' each slow clock tick from sstart to send
  46. ulong sstart; // ...
  47. ulong send; // ...
  48. } tod;
  49. void
  50. todinit(void)
  51. {
  52. if(tod.init)
  53. return;
  54. ilock(&tod);
  55. tod.last = fastticks((uvlong*)&tod.hz);
  56. iunlock(&tod);
  57. todsetfreq(tod.hz);
  58. tod.init = 1;
  59. addclock0link(todfix, 100);
  60. }
  61. /*
  62. * calculate multiplier
  63. */
  64. void
  65. todsetfreq(vlong f)
  66. {
  67. ilock(&tod);
  68. tod.hz = f;
  69. /* calculate multiplier for time conversion */
  70. tod.multiplier = mk64fract(TODFREQ, f);
  71. tod.divider = mk64fract(f, TODFREQ);
  72. tod.umultiplier = mk64fract(MicroFREQ, f);
  73. tod.udivider = mk64fract(f, MicroFREQ);
  74. iunlock(&tod);
  75. }
  76. /*
  77. * Set the time of day struct
  78. */
  79. void
  80. todset(vlong t, vlong delta, int n)
  81. {
  82. if(!tod.init)
  83. todinit();
  84. ilock(&tod);
  85. if(t >= 0){
  86. tod.off = t;
  87. tod.last = fastticks(nil);
  88. tod.lasttime = 0;
  89. tod.delta = 0;
  90. tod.sstart = tod.send;
  91. } else {
  92. if(n <= 0)
  93. n = 1;
  94. n *= HZ;
  95. if(delta < 0 && n > -delta)
  96. n = -delta;
  97. if(delta > 0 && n > delta)
  98. n = delta;
  99. delta = delta/n;
  100. tod.sstart = MACHP(0)->ticks;
  101. tod.send = tod.sstart + n;
  102. tod.delta = delta;
  103. }
  104. iunlock(&tod);
  105. }
  106. /*
  107. * get time of day
  108. */
  109. vlong
  110. todget(vlong *ticksp)
  111. {
  112. uvlong x;
  113. vlong ticks, diff;
  114. ulong t;
  115. if(!tod.init)
  116. todinit();
  117. // we don't want time to pass twixt the measuring of fastticks
  118. // and grabbing tod.last. Also none of the vlongs are atomic so
  119. // we have to look at them inside the lock.
  120. ilock(&tod);
  121. tod.cnt++;
  122. ticks = fastticks(nil);
  123. // add in correction
  124. if(tod.sstart != tod.send){
  125. t = MACHP(0)->ticks;
  126. if(t >= tod.send)
  127. t = tod.send;
  128. tod.off = tod.off + tod.delta*(t - tod.sstart);
  129. tod.sstart = t;
  130. }
  131. // convert to epoch
  132. diff = ticks - tod.last;
  133. if(diff < 0)
  134. diff = 0;
  135. mul64fract(&x, diff, tod.multiplier);
  136. x += tod.off;
  137. // time can't go backwards
  138. if(x < tod.lasttime)
  139. x = tod.lasttime;
  140. else
  141. tod.lasttime = x;
  142. iunlock(&tod);
  143. if(ticksp != nil)
  144. *ticksp = ticks;
  145. return x;
  146. }
  147. /*
  148. * convert time of day to ticks
  149. */
  150. uvlong
  151. tod2fastticks(vlong ns)
  152. {
  153. uvlong x;
  154. ilock(&tod);
  155. mul64fract(&x, ns-tod.off, tod.divider);
  156. x += tod.last;
  157. iunlock(&tod);
  158. return x;
  159. }
  160. /*
  161. * called regularly to avoid calculation overflows
  162. */
  163. void
  164. todfix(void)
  165. {
  166. vlong ticks, diff;
  167. uvlong x;
  168. ticks = fastticks(nil);
  169. diff = ticks - tod.last;
  170. if(diff > tod.hz){
  171. ilock(&tod);
  172. // convert to epoch
  173. mul64fract(&x, diff, tod.multiplier);
  174. if(x > 30000000000ULL) print("todfix %llud\n", x);
  175. x += tod.off;
  176. // protect against overflows
  177. tod.last = ticks;
  178. tod.off = x;
  179. iunlock(&tod);
  180. }
  181. }
  182. long
  183. seconds(void)
  184. {
  185. vlong x;
  186. int i;
  187. x = todget(nil);
  188. x = x/TODFREQ;
  189. i = x;
  190. return i;
  191. }
  192. uvlong
  193. fastticks2us(uvlong ticks)
  194. {
  195. uvlong res;
  196. if(!tod.init)
  197. todinit();
  198. mul64fract(&res, ticks, tod.umultiplier);
  199. return res;
  200. }
  201. uvlong
  202. us2fastticks(uvlong us)
  203. {
  204. uvlong res;
  205. if(!tod.init)
  206. todinit();
  207. mul64fract(&res, us, tod.udivider);
  208. return res;
  209. }
  210. // convert milliseconds to fast ticks
  211. //
  212. uvlong
  213. ms2fastticks(ulong ms)
  214. {
  215. if(!tod.init)
  216. todinit();
  217. return (tod.hz*ms)/1000ULL;
  218. }
  219. /*
  220. * convert nanoseconds to fast ticks
  221. */
  222. uvlong
  223. ns2fastticks(uvlong ns)
  224. {
  225. uvlong res;
  226. if(!tod.init)
  227. todinit();
  228. mul64fract(&res, ns, tod.divider);
  229. return res;
  230. }
  231. /*
  232. * convert fast ticks to ns
  233. */
  234. uvlong
  235. fastticks2ns(uvlong ticks)
  236. {
  237. uvlong res;
  238. if(!tod.init)
  239. todinit();
  240. mul64fract(&res, ticks, tod.multiplier);
  241. return res;
  242. }
  243. /*
  244. * Make a 64 bit fixed point number that has a decimal point
  245. * to the left of the low order 32 bits. This is used with
  246. * mul64fract for converting twixt nanoseconds and fastticks.
  247. *
  248. * multiplier = (to<<32)/from
  249. */
  250. uvlong
  251. mk64fract(uvlong to, uvlong from)
  252. {
  253. /*
  254. int shift;
  255. if(to == 0ULL)
  256. return 0ULL;
  257. shift = 0;
  258. while(shift < 32 && to < (1ULL<<(32+24))){
  259. to <<= 8;
  260. shift += 8;
  261. }
  262. while(shift < 32 && to < (1ULL<<(32+31))){
  263. to <<= 1;
  264. shift += 1;
  265. }
  266. return (to/from)<<(32-shift);
  267. */
  268. return (to<<32)/from;
  269. }