vmm: refactor userspace's emsr_fakewrite()
[akaros.git] / user / parlib / timing.c
1 #include <parlib/arch/arch.h>
2 #include <parlib/common.h>
3 #include <parlib/timing.h>
4 #include <ros/procinfo.h>
5 #include <parlib/stdio.h>
6
7 uint64_t udelay(uint64_t usec)
8 {
9         uint64_t start, end, now;
10
11         start = read_tsc();
12         end = start + (get_tsc_freq() * usec) / 1000000;
13         do {
14                 cpu_relax();
15                 now = read_tsc();
16         } while (now < end || (now > start && end < start));
17         return tsc2usec(now);
18 }
19
20 /* Not super accurate, due to overheads of reading tsc and looping */
21 uint64_t ndelay(uint64_t nsec)
22 {
23         uint64_t start, end, now;
24
25         start = read_tsc();
26         end = start + (get_tsc_freq() * nsec) / 1000000000;
27         do {
28                 cpu_relax();
29                 now = read_tsc();
30         } while (now < end || (now > start && end < start));
31         return tsc2nsec(now);
32 }
33
34 /* Difference between the ticks in microseconds */
35 uint64_t udiff(uint64_t begin, uint64_t end)
36 {
37         return (end - begin) * 1000000 / __procinfo.tsc_freq;
38 }
39
40 /* Difference between the ticks in nanoseconds */
41 uint64_t ndiff(uint64_t begin, uint64_t end)
42 {
43         return (end - begin) * 1000000000 / __procinfo.tsc_freq;
44 }
45
46 /* Conversion btw tsc ticks and time units.  From Akaros's kern/src/time.c */
47
48 /* We can overflow/wraparound when we multiply up, but we have to divide last,
49  * or else we lose precision.  If we're too big and will overflow, we'll
50  * sacrifice precision for correctness, and degrade to the next lower level
51  * (losing 3 digits worth).  The recursive case shouldn't overflow, since it
52  * called something that scaled down the tsc_time by more than 1000. */
53 uint64_t tsc2sec(uint64_t tsc_time)
54 {
55         return tsc_time / get_tsc_freq();
56 }
57
58 uint64_t tsc2msec(uint64_t tsc_time)
59 {
60         if (mult_will_overflow_u64(tsc_time, 1000))
61                 return tsc2sec(tsc_time) * 1000;
62         else
63                 return (tsc_time * 1000) / get_tsc_freq();
64 }
65
66 uint64_t tsc2usec(uint64_t tsc_time)
67 {
68         if (mult_will_overflow_u64(tsc_time, 1000000))
69                 return tsc2msec(tsc_time) * 1000;
70         else
71                 return (tsc_time * 1000000) / get_tsc_freq();
72 }
73
74 uint64_t tsc2nsec(uint64_t tsc_time)
75 {
76         if (mult_will_overflow_u64(tsc_time, 1000000000))
77                 return tsc2usec(tsc_time) * 1000;
78         else
79                 return (tsc_time * 1000000000) / get_tsc_freq();
80 }
81
82 uint64_t sec2tsc(uint64_t sec)
83 {
84         if (mult_will_overflow_u64(sec, get_tsc_freq()))
85                 return (uint64_t)(-1);
86         else
87                 return sec * get_tsc_freq();
88 }
89
90 uint64_t msec2tsc(uint64_t msec)
91 {
92         if (mult_will_overflow_u64(msec, get_tsc_freq()))
93                 return sec2tsc(msec / 1000);
94         else
95                 return (msec * get_tsc_freq()) / 1000;
96 }
97
98 uint64_t usec2tsc(uint64_t usec)
99 {
100         if (mult_will_overflow_u64(usec, get_tsc_freq()))
101                 return msec2tsc(usec / 1000);
102         else
103                 return (usec * get_tsc_freq()) / 1000000;
104 }
105
106 uint64_t nsec2tsc(uint64_t nsec)
107 {
108         if (mult_will_overflow_u64(nsec, get_tsc_freq()))
109                 return usec2tsc(nsec / 1000);
110         else
111                 return (nsec * get_tsc_freq()) / 1000000000;
112 }
113
114 uint64_t nsec(void)
115 {
116         return tsc2nsec(read_tsc());
117 }