Library for measurement statistics
[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
43 /* Akaros has this helper in ros/common.h. (it returns a bool btw)
44  *
45  * We wraparound if UINT_MAX < a * b, which is also UINT_MAX / a < b. */
46 static inline int mult_will_overflow_u64(uint64_t a, uint64_t b)
47 {
48         if (!a)
49                 return FALSE;
50         return (uint64_t)(-1) / a < b;
51 }
52
53 # ifdef __i386__
54
55 static inline uint64_t read_tsc(void)
56 {
57         uint64_t tsc;
58         asm volatile("rdtsc" : "=A" (tsc));
59         return tsc;
60 }
61
62 static inline uint64_t read_tsc_serialized(void)
63 {
64         uint64_t tsc;
65         asm volatile("lfence; rdtsc" : "=A" (tsc));
66         return tsc;
67 }
68
69 # elif __x86_64__
70
71 static inline uint64_t read_tsc(void)
72 {
73         uint32_t lo, hi;
74         /* We cannot use "=A", since this would use %rax on x86_64 */
75         asm volatile("rdtsc" : "=a" (lo), "=d" (hi));
76         return (uint64_t)hi << 32 | lo;
77 }
78
79 static inline uint64_t read_tsc_serialized(void)
80 {
81         uint32_t lo, hi;
82         asm volatile("lfence; rdtsc" : "=a" (lo), "=d" (hi));
83         return (uint64_t)hi << 32 | lo;
84 }
85
86 # else
87 #  error "Which arch is this?"
88 # endif /* __i386__ | __x86_64__ */
89
90 static inline uint64_t get_tsc_freq(void)
91 {
92         struct timeval prev;
93         struct timeval curr;
94         uint64_t beg = read_tsc_serialized();
95         gettimeofday(&prev, 0);
96         while (1) {
97                 gettimeofday(&curr, 0);
98                 if (curr.tv_sec > (prev.tv_sec + 1) ||
99                         (curr.tv_sec > prev.tv_sec && curr.tv_usec > prev.tv_usec))
100                         break;
101         }
102         uint64_t end = read_tsc_serialized();
103         return end - beg;
104 }
105
106 /* Don't have a good way to get the overhead on Linux in userspace. */
107 static inline uint64_t get_tsc_overhead(void)
108 {
109         return 0;
110 }
111
112 #endif /* ! _ros_ */
113
114 #ifdef __cplusplus
115         }
116 #endif
117
118 #endif /* _TSC_COMPAT_H */