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