tod.c 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  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);
  74. tod.umultiplier = mk64fract(MicroFREQ, f);
  75. tod.udivider = mk64fract(f, MicroFREQ);
  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. // we don't want time to pass twixt the measuring of fastticks
  120. // and grabbing tod.last. Also none of the vlongs are atomic so
  121. // we have to look at them inside the lock.
  122. ilock(&tod);
  123. tod.cnt++;
  124. ticks = fastticks(nil);
  125. // add in correction
  126. if(tod.sstart != tod.send){
  127. t = MACHP(0)->ticks;
  128. if(t >= tod.send)
  129. t = tod.send;
  130. tod.off = tod.off + tod.delta*(t - tod.sstart);
  131. tod.sstart = t;
  132. }
  133. // convert to epoch
  134. diff = ticks - tod.last;
  135. if(diff < 0)
  136. diff = 0;
  137. mul64fract(&x, diff, tod.multiplier);
  138. x += tod.off;
  139. // time can't go backwards
  140. if(x < tod.lasttime)
  141. x = tod.lasttime;
  142. else
  143. tod.lasttime = x;
  144. iunlock(&tod);
  145. if(ticksp != nil)
  146. *ticksp = ticks;
  147. return x;
  148. }
  149. /*
  150. * convert time of day to ticks
  151. */
  152. uvlong
  153. tod2fastticks(vlong ns)
  154. {
  155. uvlong x;
  156. ilock(&tod);
  157. mul64fract(&x, ns-tod.off, tod.divider);
  158. x += tod.last;
  159. iunlock(&tod);
  160. return x;
  161. }
  162. /*
  163. * called regularly to avoid calculation overflows
  164. */
  165. static void
  166. todfix(void)
  167. {
  168. vlong ticks, diff;
  169. uvlong x;
  170. ticks = fastticks(nil);
  171. diff = ticks - tod.last;
  172. if(diff > tod.hz){
  173. ilock(&tod);
  174. // convert to epoch
  175. mul64fract(&x, diff, tod.multiplier);
  176. if(x > 30000000000ULL) print("todfix %llud\n", x);
  177. x += tod.off;
  178. // protect against overflows
  179. tod.last = ticks;
  180. tod.off = x;
  181. iunlock(&tod);
  182. }
  183. }
  184. long
  185. seconds(void)
  186. {
  187. vlong x;
  188. int i;
  189. x = todget(nil);
  190. x = x/TODFREQ;
  191. i = x;
  192. return i;
  193. }
  194. uvlong
  195. fastticks2us(uvlong ticks)
  196. {
  197. uvlong res;
  198. if(!tod.init)
  199. todinit();
  200. mul64fract(&res, ticks, tod.umultiplier);
  201. return res;
  202. }
  203. uvlong
  204. us2fastticks(uvlong us)
  205. {
  206. uvlong res;
  207. if(!tod.init)
  208. todinit();
  209. mul64fract(&res, us, tod.udivider);
  210. return res;
  211. }
  212. /*
  213. * convert milliseconds to fast ticks
  214. */
  215. uvlong
  216. ms2fastticks(ulong ms)
  217. {
  218. if(!tod.init)
  219. todinit();
  220. return (tod.hz*ms)/1000ULL;
  221. }
  222. /*
  223. * convert nanoseconds to fast ticks
  224. */
  225. uvlong
  226. ns2fastticks(uvlong ns)
  227. {
  228. uvlong res;
  229. if(!tod.init)
  230. todinit();
  231. mul64fract(&res, ns, tod.divider);
  232. return res;
  233. }
  234. /*
  235. * convert fast ticks to ns
  236. */
  237. uvlong
  238. fastticks2ns(uvlong ticks)
  239. {
  240. uvlong res;
  241. if(!tod.init)
  242. todinit();
  243. mul64fract(&res, ticks, tod.multiplier);
  244. return res;
  245. }
  246. /*
  247. * Make a 64 bit fixed point number that has a decimal point
  248. * to the left of the low order 32 bits. This is used with
  249. * mul64fract for converting twixt nanoseconds and fastticks.
  250. *
  251. * multiplier = (to<<32)/from
  252. */
  253. uvlong
  254. mk64fract(uvlong to, uvlong from)
  255. {
  256. /*
  257. int shift;
  258. if(to == 0ULL)
  259. return 0ULL;
  260. shift = 0;
  261. while(shift < 32 && to < (1ULL<<(32+24))){
  262. to <<= 8;
  263. shift += 8;
  264. }
  265. while(shift < 32 && to < (1ULL<<(32+31))){
  266. to <<= 1;
  267. shift += 1;
  268. }
  269. return (to/from)<<(32-shift);
  270. */
  271. return (to<<32)/from;
  272. }