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