tod.c 5.8 KB

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