Commit | Line | Data |
---|---|---|
7642fe3b MW |
1 | #include <errno.h> |
2 | #include <stdlib.h> | |
3 | #include <time.h> | |
4 | ||
5 | #if defined(__GNUC__) && (defined(__i386__) || defined (__x86_64__)) | |
6 | ||
7 | struct cycle_counter { | |
8 | char dummy; | |
9 | }; | |
10 | ||
11 | static int init_counter(struct cycle_counter *cy) { return (0); } | |
12 | static void teardown_counter(struct cycle_counter *cy) { ; } | |
13 | ||
14 | int cycles(struct cycle_counter *cy, unsigned long long *t_out) | |
15 | { | |
16 | unsigned lo, hi; | |
17 | ||
18 | __asm__("rdtsc" : "=a"(lo), "=d"(hi)); | |
19 | *t_out = lo | ((unsigned long long)hi << 32); | |
20 | return (0); | |
21 | } | |
22 | ||
23 | #elif defined(__linux__) | |
24 | ||
25 | #include <unistd.h> | |
26 | #include <linux/perf_event.h> | |
27 | #include <asm/unistd.h> | |
28 | ||
29 | struct cycle_counter { | |
30 | int fd; | |
31 | }; | |
32 | ||
33 | static int init_counter(struct cycle_counter *cy) | |
34 | { | |
35 | struct perf_event_attr attr = { 0 }; | |
36 | ||
37 | attr.type = PERF_TYPE_HARDWARE; | |
38 | attr.size = sizeof(attr); | |
39 | attr.config = PERF_COUNT_HW_CPU_CYCLES; | |
40 | attr.disabled = 0; | |
41 | attr.exclude_kernel = 1; | |
42 | attr.exclude_hv = 1; | |
43 | ||
44 | cy->fd = syscall(__NR_perf_event_open, &attr, 0, -1, -1, 0); | |
45 | if (cy->fd < 0) return (-1); | |
46 | return (0); | |
47 | } | |
48 | ||
49 | static void teardown_counter(struct cycle_counter *cy) | |
50 | { if (cy->fd >= 0) close(cy->fd); } | |
51 | ||
52 | int cycles(struct cycle_counter *cy, unsigned long long *t_out) | |
53 | { | |
54 | ssize_t n; | |
55 | ||
56 | if (cy->fd < 0) { errno = EBADF; return (-1); } | |
57 | n = read(cy->fd, t_out, sizeof(*t_out)); | |
58 | if (n < sizeof(*t_out)) { | |
59 | if (n >= 0) errno = ENODATA; | |
60 | close(cy->fd); cy->fd = -1; | |
61 | return (-1); | |
62 | } | |
63 | return (0); | |
64 | } | |
65 | ||
66 | #else | |
67 | ||
68 | struct cycle_counter { | |
69 | char dummy; | |
70 | }; | |
71 | ||
72 | static int init_counter(struct cycle_counter *cy) | |
73 | { errno = ENOSYS; return (-1); } | |
74 | static void teardown_counter(struct cycle_counter *cy) { ; } | |
75 | int cycles(struct cycle_counter *cy, unsigned long long *t_out) | |
76 | { return (-1); } | |
77 | ||
78 | #endif | |
79 | ||
80 | struct cycle_counter *open_cycle_counter(void) | |
81 | { | |
82 | struct cycle_counter *cy = 0, *cy_ret = 0; | |
83 | ||
84 | cy = malloc(sizeof(*cy)); if (!cy) goto end; | |
85 | if (init_counter(cy)) goto end; | |
86 | cy_ret = cy; cy = 0; | |
87 | end: | |
88 | free(cy); | |
89 | return (cy_ret); | |
90 | } | |
91 | ||
92 | void close_cycle_counter(struct cycle_counter *cy) | |
93 | { teardown_counter(cy); free(cy); } | |
94 | ||
95 | struct clock { | |
96 | long long sec; | |
97 | unsigned nsec; | |
98 | }; | |
99 | ||
100 | int thread_clock(struct clock *clk_out) | |
101 | { | |
102 | struct timespec tv; | |
103 | ||
104 | if (clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tv)) return (-1); | |
105 | clk_out->sec = tv.tv_sec; clk_out->nsec = tv.tv_nsec; | |
106 | return (0); | |
107 | } | |
108 | ||
109 | int get_errno(void) { return (errno); } |