tod.c 5.3 KB

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