File srhd.c changed (mode: 100644) (index 716ee13..4af0777) |
9 |
9 |
#include <sched.h> |
#include <sched.h> |
10 |
10 |
#include <linux/perf_event.h> |
#include <linux/perf_event.h> |
11 |
11 |
#include <asm/unistd.h> |
#include <asm/unistd.h> |
|
12 |
|
#include <sys/epoll.h> |
|
13 |
|
#include <signal.h> |
12 |
14 |
|
|
13 |
15 |
#define barrier() asm volatile ("" ::: "memory") |
#define barrier() asm volatile ("" ::: "memory") |
14 |
16 |
|
|
15 |
|
#define MMAP_BUF_SIZE 16 /* in pages */ |
|
|
17 |
|
#define MMAP_BUF_SIZE 8 /* in pages */ |
16 |
18 |
|
|
17 |
19 |
static unsigned long page_size; |
static unsigned long page_size; |
18 |
20 |
|
|
|
... |
... |
static long perf_event_open(struct perf_event_attr *hw_event, pid_t pid, |
27 |
29 |
/* |
/* |
28 |
30 |
* Registers a counter |
* Registers a counter |
29 |
31 |
*/ |
*/ |
30 |
|
static int register_event(const __u32 type, __u64 config, void **m) |
|
|
32 |
|
static int register_event(const unsigned int cpu, const __u32 type, |
|
33 |
|
__u64 config, void **m) |
31 |
34 |
{ |
{ |
32 |
35 |
int fd; |
int fd; |
33 |
36 |
struct perf_event_attr attr; |
struct perf_event_attr attr; |
|
... |
... |
static int register_event(const __u32 type, __u64 config, void **m) |
37 |
40 |
attr.sample_type = PERF_SAMPLE_IP |
attr.sample_type = PERF_SAMPLE_IP |
38 |
41 |
| PERF_SAMPLE_TID |
| PERF_SAMPLE_TID |
39 |
42 |
| PERF_SAMPLE_ADDR |
| PERF_SAMPLE_ADDR |
40 |
|
| PERF_SAMPLE_PERIOD; |
|
41 |
|
attr.sample_period = 1000 * 1000; |
|
42 |
|
attr.enable_on_exec = 1; |
|
43 |
|
attr.disabled = 1; |
|
|
43 |
|
| PERF_SAMPLE_PERIOD |
|
44 |
|
| PERF_SAMPLE_CPU; |
|
45 |
|
attr.sample_period = 1000; |
|
46 |
|
//attr.enable_on_exec = 1; |
|
47 |
|
attr.disabled = 0; |
44 |
48 |
attr.exclude_kernel = 1; |
attr.exclude_kernel = 1; |
45 |
49 |
//attr.exclude_hv = 1; |
//attr.exclude_hv = 1; |
46 |
|
|
|
|
50 |
|
//attr.mmap = 1; |
|
51 |
|
//attr.mmap2 = 1; |
|
52 |
|
//attr.comm = 1; |
|
53 |
|
attr.wakeup_events = 1; |
47 |
54 |
attr.type = type; |
attr.type = type; |
48 |
55 |
attr.config = config; |
attr.config = config; |
49 |
56 |
|
|
50 |
|
fd = perf_event_open(&attr, -1 /* pid */, 0 /* cpu */, |
|
|
57 |
|
fd = perf_event_open(&attr, -1 /* pid */, cpu, |
51 |
58 |
-1 /* group_fd */, PERF_FLAG_FD_CLOEXEC); |
-1 /* group_fd */, PERF_FLAG_FD_CLOEXEC); |
52 |
59 |
if (fd == -1) { |
if (fd == -1) { |
53 |
60 |
fprintf(stderr, "Cannot call perf_event_open, config %llx\n", |
fprintf(stderr, "Cannot call perf_event_open, config %llx\n", |
|
... |
... |
static int register_event(const __u32 type, __u64 config, void **m) |
55 |
62 |
exit(1); |
exit(1); |
56 |
63 |
} |
} |
57 |
64 |
|
|
58 |
|
*m = mmap(NULL, 1 + MMAP_BUF_SIZE * page_size, |
|
|
65 |
|
*m = mmap(NULL, (1 + MMAP_BUF_SIZE) * page_size, |
59 |
66 |
PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); |
PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); |
60 |
|
if (!*m) { |
|
|
67 |
|
fprintf(stderr, "cpu=%d fd=%d *m=%p\n", cpu, fd, *m); |
|
68 |
|
if (*m == MAP_FAILED) { |
61 |
69 |
fprintf(stderr, "Cannot mmap (%s)!\n", strerror(errno)); |
fprintf(stderr, "Cannot mmap (%s)!\n", strerror(errno)); |
62 |
70 |
exit(1); |
exit(1); |
63 |
71 |
} |
} |
|
... |
... |
static int check(void *m) |
73 |
81 |
{ |
{ |
74 |
82 |
struct perf_event_mmap_page *mp; |
struct perf_event_mmap_page *mp; |
75 |
83 |
struct perf_event_header *h; |
struct perf_event_header *h; |
76 |
|
void *p; |
|
77 |
|
unsigned long long *p_ip, *p_addr, *p_period; |
|
78 |
|
unsigned int *p_pid, *p_tid; |
|
|
84 |
|
void *p, *q; |
|
85 |
|
unsigned long long *p_ip, *p_addr, *p_period, *p_len, *p_pgoff; |
|
86 |
|
unsigned long long *p_time; |
|
87 |
|
unsigned int *p_pid, *p_ppid, *p_tid, *p_ptid, *p_cpu; |
79 |
88 |
unsigned int version, seq, index; |
unsigned int version, seq, index; |
80 |
89 |
unsigned long long count, head, tail, rest; |
unsigned long long count, head, tail, rest; |
|
90 |
|
char *filename, *comm; |
81 |
91 |
|
|
82 |
92 |
mp = m; |
mp = m; |
83 |
93 |
do { |
do { |
|
... |
... |
static int check(void *m) |
102 |
112 |
p = m + page_size + tail; |
p = m + page_size + tail; |
103 |
113 |
rest = head - tail; |
rest = head - tail; |
104 |
114 |
while (rest > 0) { |
while (rest > 0) { |
105 |
|
h = p; |
|
|
115 |
|
q = p; |
|
116 |
|
h = q; |
106 |
117 |
fprintf(stderr, "\th: type=%u misc=%hu size=%hu rest=%llu\n", |
fprintf(stderr, "\th: type=%u misc=%hu size=%hu rest=%llu\n", |
107 |
118 |
h->type, h->misc, h->size, rest); |
h->type, h->misc, h->size, rest); |
108 |
|
p += sizeof(struct perf_event_header); |
|
|
119 |
|
q += sizeof(struct perf_event_header); |
109 |
120 |
|
|
110 |
121 |
switch (h->type) { |
switch (h->type) { |
|
122 |
|
case PERF_RECORD_MMAP: |
|
123 |
|
p_pid = q; q += 4; |
|
124 |
|
p_tid = q; q += 4; |
|
125 |
|
p_addr = q; q += 8; |
|
126 |
|
p_len = q; q += 8; |
|
127 |
|
p_pgoff = q; q += 8; |
|
128 |
|
filename = q; |
|
129 |
|
fprintf(stderr, "\tmmap pid=%u tid=%u addr=%llx" |
|
130 |
|
" len=%llu pgoff=%llx filename=%s.\n", |
|
131 |
|
*p_pid, *p_tid, *p_addr, |
|
132 |
|
*p_len, *p_pgoff, filename); |
|
133 |
|
break; |
|
134 |
|
|
111 |
135 |
case PERF_RECORD_SAMPLE: |
case PERF_RECORD_SAMPLE: |
112 |
|
p_ip = p; p += 8; |
|
113 |
|
p_pid = p; p += 4; |
|
114 |
|
p_tid = p; p += 4; |
|
115 |
|
p_addr = p; p += 8; |
|
116 |
|
p_period = p; p += 8; |
|
117 |
|
fprintf(stderr, "\tsample! ip=0x%llx pid=%u" |
|
118 |
|
" tid=%u addr=%llx period=%llu\n", |
|
119 |
|
*p_ip, *p_pid, *p_tid, *p_addr, *p_period); |
|
|
136 |
|
p_ip = q; q += 8; |
|
137 |
|
p_pid = q; q += 4; |
|
138 |
|
p_tid = q; q += 4; |
|
139 |
|
p_addr = q; q += 8; |
|
140 |
|
p_cpu = q; q += 8; |
|
141 |
|
p_period = q; q += 8; |
|
142 |
|
fprintf(stderr, "\tsample ip=0x%llx pid=%u" |
|
143 |
|
" tid=%u addr=%llx period=%llu cpu=%u\n", |
|
144 |
|
*p_ip, *p_pid, *p_tid, *p_addr, *p_period, *p_cpu); |
|
145 |
|
break; |
|
146 |
|
|
|
147 |
|
case PERF_RECORD_EXIT: |
|
148 |
|
p_pid = q; q += 4; |
|
149 |
|
p_ppid = q; q += 4; |
|
150 |
|
p_tid = q; q += 4; |
|
151 |
|
p_ptid = q; q += 4; |
|
152 |
|
p_time = q; q += 8; |
|
153 |
|
fprintf(stderr, "\texit pid=%u ppid=%u tid=%u" |
|
154 |
|
" ptid=%u time=%llu\n", |
|
155 |
|
*p_pid, *p_ppid, *p_tid, *p_ptid, |
|
156 |
|
*p_time); |
|
157 |
|
break; |
|
158 |
|
|
|
159 |
|
case PERF_RECORD_COMM: |
|
160 |
|
p_pid = q; q += 4; |
|
161 |
|
p_tid = q; q += 4; |
|
162 |
|
comm = q; |
|
163 |
|
fprintf(stderr, "\tcomm pid=%u tid=%u comm=%s\n", |
|
164 |
|
*p_pid, *p_tid, comm); |
|
165 |
|
break; |
|
166 |
|
|
|
167 |
|
case PERF_RECORD_MMAP2: |
|
168 |
|
p_pid = q; q += 4; |
|
169 |
|
p_tid = q; q += 4; |
|
170 |
|
p_addr = q; q += 8; |
|
171 |
|
p_len = q; q += 8; |
|
172 |
|
p_pgoff = q; q += 8; |
|
173 |
|
q += 4; /* maj */ |
|
174 |
|
q += 4; /* min */ |
|
175 |
|
q += 8; /* ino */ |
|
176 |
|
q += 8; /* ino_generation */ |
|
177 |
|
q += 4; /* prot */ |
|
178 |
|
q += 4; /* flags */ |
|
179 |
|
filename = p; |
|
180 |
|
fprintf(stderr, "\tmmap pid=%u tid=%u addr=%llx" |
|
181 |
|
" len=%llu pgoff=%llx filename=%s.\n", |
|
182 |
|
*p_pid, *p_tid, *p_addr, |
|
183 |
|
*p_len, *p_pgoff, filename); |
|
184 |
|
break; |
|
185 |
|
|
|
186 |
|
case PERF_RECORD_FORK: |
|
187 |
|
p_pid = q; q += 4; |
|
188 |
|
p_ppid = q; q += 4; |
|
189 |
|
p_tid = q; q += 4; |
|
190 |
|
p_ptid = q; q += 4; |
|
191 |
|
p_time = q; q += 8; |
|
192 |
|
fprintf(stderr, "\tfork pid=%u ppid=%u tid=%u" |
|
193 |
|
" ptid=%u time=%llu\n", |
|
194 |
|
*p_pid, *p_ppid, *p_tid, *p_ptid, |
|
195 |
|
*p_time); |
120 |
196 |
break; |
break; |
121 |
197 |
|
|
122 |
198 |
default: |
default: |
123 |
|
fprintf(stderr, "Unknown type %u\n", h->type); |
|
|
199 |
|
fprintf(stderr, "\tUnknown type %u\n", h->type); |
|
200 |
|
break; |
124 |
201 |
} |
} |
|
202 |
|
p += h->size; |
125 |
203 |
rest -= h->size; |
rest -= h->size; |
126 |
204 |
} |
} |
127 |
205 |
mp->data_tail = head; |
mp->data_tail = head; |
|
... |
... |
static int check(void *m) |
132 |
210 |
int main(void) |
int main(void) |
133 |
211 |
{ |
{ |
134 |
212 |
struct sched_param param; |
struct sched_param param; |
135 |
|
int fd1, fd2, nr_cpus; |
|
136 |
|
void *m1, *m2; |
|
|
213 |
|
int fd1, fd2[2], nr_cpus, r, efd, i, fd; |
|
214 |
|
void *m1, *m2[2]; |
|
215 |
|
struct epoll_event ee; |
137 |
216 |
|
|
138 |
217 |
nr_cpus = sysconf(_SC_NPROCESSORS_ONLN); |
nr_cpus = sysconf(_SC_NPROCESSORS_ONLN); |
139 |
218 |
fprintf(stderr, "%d cpu(s) online.\n", nr_cpus); |
fprintf(stderr, "%d cpu(s) online.\n", nr_cpus); |
|
... |
... |
int main(void) |
148 |
227 |
return 1; |
return 1; |
149 |
228 |
} |
} |
150 |
229 |
|
|
151 |
|
fd1 = register_event(PERF_TYPE_HW_CACHE, PERF_COUNT_HW_CACHE_LL |
|
|
230 |
|
efd = epoll_create1(EPOLL_CLOEXEC); |
|
231 |
|
if (efd == -1) { |
|
232 |
|
fprintf(stderr, "Cannot create epoll fd (%s)!\n", |
|
233 |
|
strerror(errno)); |
|
234 |
|
return 1; |
|
235 |
|
} |
|
236 |
|
|
|
237 |
|
/* |
|
238 |
|
fd1 = register_event(0, PERF_TYPE_HW_CACHE, PERF_COUNT_HW_CACHE_LL |
152 |
239 |
| (PERF_COUNT_HW_CACHE_OP_READ << 8) |
| (PERF_COUNT_HW_CACHE_OP_READ << 8) |
153 |
240 |
| (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16), &m1); |
| (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16), &m1); |
154 |
|
fd2 = register_event(PERF_TYPE_HW_CACHE, PERF_COUNT_HW_CACHE_LL |
|
155 |
|
| (PERF_COUNT_HW_CACHE_OP_READ << 8) |
|
156 |
|
| (PERF_COUNT_HW_CACHE_RESULT_MISS << 16), &m2); |
|
|
241 |
|
*/ |
|
242 |
|
|
|
243 |
|
for (i = 0; i < 2; i++) { |
|
244 |
|
fd2[i] = register_event(i, PERF_TYPE_HW_CACHE, PERF_COUNT_HW_CACHE_LL |
|
245 |
|
| (PERF_COUNT_HW_CACHE_OP_READ << 8) |
|
246 |
|
| (PERF_COUNT_HW_CACHE_RESULT_MISS << 16), &m2[i]); |
|
247 |
|
fprintf(stderr, "fd2[%d]=%d m2[%d]=%p\n", |
|
248 |
|
i, fd2[i], i, m2[i]); |
|
249 |
|
|
|
250 |
|
memset(&ee, 0, sizeof(struct epoll_event)); |
|
251 |
|
ee.events = EPOLLIN; |
|
252 |
|
ee.data.fd = fd2[i]; |
|
253 |
|
r = epoll_ctl(efd, EPOLL_CTL_ADD, fd2[i], &ee); |
|
254 |
|
if (r != 0) { |
|
255 |
|
fprintf(stderr, "Canot add fd to epoll (%s)!\n", |
|
256 |
|
strerror(errno)); |
|
257 |
|
return 1; |
|
258 |
|
} |
|
259 |
|
} |
157 |
260 |
|
|
158 |
261 |
//ioctl(fd1, PERF_EVENT_IOC_RESET, 0); |
//ioctl(fd1, PERF_EVENT_IOC_RESET, 0); |
159 |
|
ioctl(fd2, PERF_EVENT_IOC_RESET, 0); |
|
|
262 |
|
//ioctl(fd2, PERF_EVENT_IOC_RESET, 0); |
160 |
263 |
//ioctl(fd1, PERF_EVENT_IOC_ENABLE, 0); |
//ioctl(fd1, PERF_EVENT_IOC_ENABLE, 0); |
161 |
|
ioctl(fd2, PERF_EVENT_IOC_ENABLE, 0); |
|
|
264 |
|
//ioctl(fd2, PERF_EVENT_IOC_ENABLE, 0); |
162 |
265 |
|
|
163 |
266 |
while (1) { |
while (1) { |
164 |
|
fprintf(stderr, "Checking...\n"); |
|
165 |
|
check(m2); |
|
166 |
|
usleep(1000 * 1000); |
|
|
267 |
|
r = epoll_wait(efd, &ee, 1, 1000); |
|
268 |
|
if (r == -1) { |
|
269 |
|
if (errno == EINTR) |
|
270 |
|
continue; |
|
271 |
|
|
|
272 |
|
fprintf(stderr, "Cannot wait (%s)!\n", strerror(errno)); |
|
273 |
|
return 1; |
|
274 |
|
} |
|
275 |
|
|
|
276 |
|
if (r == 0) |
|
277 |
|
continue; |
|
278 |
|
|
|
279 |
|
fd = ee.data.fd; |
|
280 |
|
for (i = 0; i < 2; i++) { |
|
281 |
|
if (fd == fd2[i]) |
|
282 |
|
break; |
|
283 |
|
} |
|
284 |
|
//fprintf(stderr, "Got an event fd=%d i=%d\n", fd, i); |
|
285 |
|
check(m2[i]); |
167 |
286 |
} |
} |
168 |
|
ioctl(fd1, PERF_EVENT_IOC_DISABLE, 0); |
|
169 |
|
ioctl(fd2, PERF_EVENT_IOC_DISABLE, 0); |
|
|
287 |
|
//ioctl(fd1, PERF_EVENT_IOC_DISABLE, 0); |
|
288 |
|
//ioctl(fd2, PERF_EVENT_IOC_DISABLE, 0); |
170 |
289 |
|
|
171 |
290 |
munmap(m1, 0); /* TODO: 0 is correct? */ |
munmap(m1, 0); /* TODO: 0 is correct? */ |
172 |
291 |
munmap(m2, 0); |
munmap(m2, 0); |
173 |
292 |
|
|
174 |
293 |
close(fd1); |
close(fd1); |
175 |
|
close(fd2); |
|
|
294 |
|
for (i = 0; i < 2; i++) |
|
295 |
|
close(fd2[i]); |
|
296 |
|
|
|
297 |
|
close(efd); |
176 |
298 |
|
|
177 |
299 |
return 0; |
return 0; |
178 |
300 |
} |
} |