Minor touchup for tsc-compat
[akaros.git] / user / parlib / include / tsc-compat.h
1 /* Basic TSC compatability helpers, callable from Akaros or Linux. Supports:
2  *              uint64_t read_tsc()
3  *              uint64_t read_tsc_serialized()
4  *              uint64_t get_tsc_freq()
5  *              uint64_t get_tsc_overhead()
6  *
7  * Note this relies on specifics of procinfo, which isn't stable.  If procinfo
8  * changes, this will need to change as well.  You'll know when this doesn't
9  * compile (say, if timing_overhead moves).  */
10
11 #ifndef _TSC_COMPAT_H
12 #define _TSC_COMPAT_H
13
14 #if defined(__i386__) || defined(__x86_64__)
15 #else
16 #error "Platform not supported for read_tsc()"
17 #endif
18
19 #ifdef __cplusplus
20         extern "C" {
21 #endif
22
23 #ifdef __ros__
24
25 #include <arch/arch.h>
26 #include <ros/procinfo.h>
27
28 static inline uint64_t get_tsc_freq(void)
29 {
30         return __procinfo.tsc_freq;
31 }
32
33 static inline uint64_t get_tsc_overhead(void)
34 {
35         return __procinfo.timing_overhead;
36 }
37
38 #else /* ! _ros_ (linux) */
39
40 #include <sys/time.h>
41 #include <stdint.h>
42 #include <stdbool.h>
43
44 /* Akaros has this helper in ros/common.h. (it returns a bool btw)
45  *
46  * We wraparound if UINT_MAX < a * b, which is also UINT_MAX / a < b. */
47 static inline int mult_will_overflow_u64(uint64_t a, uint64_t b)
48 {
49         if (!a)
50                 return false;
51         return (uint64_t)(-1) / a < b;
52 }
53
54 # ifdef __i386__
55
56 static inline uint64_t read_tsc(void)
57 {
58         uint64_t tsc;
59         asm volatile("rdtsc" : "=A" (tsc));
60         return tsc;
61 }
62
63 static inline uint64_t read_tsc_serialized(void)
64 {
65         uint64_t tsc;
66         asm volatile("lfence; rdtsc" : "=A" (tsc));
67         return tsc;
68 }
69
70 # elif __x86_64__
71
72 static inline uint64_t read_tsc(void)
73 {
74         uint32_t lo, hi;
75         /* We cannot use "=A", since this would use %rax on x86_64 */
76         asm volatile("rdtsc" : "=a" (lo), "=d" (hi));
77         return (uint64_t)hi << 32 | lo;
78 }
79
80 static inline uint64_t read_tsc_serialized(void)
81 {
82         uint32_t lo, hi;
83         asm volatile("lfence; rdtsc" : "=a" (lo), "=d" (hi));
84         return (uint64_t)hi << 32 | lo;
85 }
86
87 # else
88 #  error "Which arch is this?"
89 # endif /* __i386__ | __x86_64__ */
90
91 static inline uint64_t get_tsc_freq(void)
92 {
93         struct timeval prev;
94         struct timeval curr;
95         uint64_t beg = read_tsc_serialized();
96         gettimeofday(&prev, 0);
97         while (1) {
98                 gettimeofday(&curr, 0);
99                 if (curr.tv_sec > (prev.tv_sec + 1) ||
100                         (curr.tv_sec > prev.tv_sec && curr.tv_usec > prev.tv_usec))
101                         break;
102         }
103         uint64_t end = read_tsc_serialized();
104         return end - beg;
105 }
106
107 /* Don't have a good way to get the overhead on Linux in userspace. */
108 static inline uint64_t get_tsc_overhead(void)
109 {
110         return 0;
111 }
112
113 #endif /* ! _ros_ */
114
115 #ifdef __cplusplus
116         }
117 #endif
118
119 #endif /* _TSC_COMPAT_H */