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