Blame view
tools/perf/builtin-record.c
16.4 KB
abaff32a0 perf record: Add ... |
1 |
/* |
bf9e18763 perf_counter tool... |
2 3 4 5 6 |
* builtin-record.c * * Builtin record command: Record the profile of a workload * (or a CPU, or a PID) into the perf.data output file - for * later analysis via perf report. |
abaff32a0 perf record: Add ... |
7 |
*/ |
16f762a2a perf_counter tool... |
8 |
#include "builtin.h" |
bf9e18763 perf_counter tool... |
9 10 |
#include "perf.h" |
6eda5838b perfcounter tools... |
11 |
#include "util/util.h" |
0e9b20b8a perf record: Conv... |
12 |
#include "util/parse-options.h" |
8ad8db378 perf_counter tool... |
13 |
#include "util/parse-events.h" |
a0055ae2a perf_counter tool... |
14 |
#include "util/string.h" |
6eda5838b perfcounter tools... |
15 |
|
7c6a1c65b perf_counter tool... |
16 |
#include "util/header.h" |
66e274f3b perf tools: Facto... |
17 |
#include "util/event.h" |
8f28827a1 perf tools: Libra... |
18 |
#include "util/debug.h" |
5f9c39dca perf tools: Add p... |
19 |
#include "util/trace-event.h" |
7c6a1c65b perf_counter tool... |
20 |
|
97124d5e2 perf_counter: too... |
21 |
#include <unistd.h> |
de9ac07bb perf_counter: som... |
22 |
#include <sched.h> |
de9ac07bb perf_counter: som... |
23 |
|
0e9b20b8a perf record: Conv... |
24 25 |
#define ALIGN(x, a) __ALIGN_MASK(x, (typeof(x))(a)-1) #define __ALIGN_MASK(x, mask) (((x)+(mask))&~(mask)) |
1a853e368 perf record: Allo... |
26 |
|
de9ac07bb perf_counter: som... |
27 |
static int fd[MAX_NR_CPUS][MAX_COUNTERS]; |
a21ca2cac perf_counter: Sep... |
28 29 |
static long default_interval = 100000; |
3cf165fc2 perf record: Incr... |
30 |
static int nr_cpus = 0; |
de9ac07bb perf_counter: som... |
31 |
static unsigned int page_size; |
3cf165fc2 perf record: Incr... |
32 |
static unsigned int mmap_pages = 128; |
cf1f45744 perf record, top:... |
33 |
static int freq = 0; |
de9ac07bb perf_counter: som... |
34 |
static int output; |
23ac9cbed perf_counter tool... |
35 |
static const char *output_name = "perf.data"; |
de9ac07bb perf_counter: som... |
36 |
static int group = 0; |
16c8a1093 perf_counter: too... |
37 |
static unsigned int realtime_prio = 0; |
daac07b2e perf tools: Add a... |
38 |
static int raw_samples = 0; |
16c8a1093 perf_counter: too... |
39 |
static int system_wide = 0; |
0a5ac8465 perf record: Add ... |
40 |
static int profile_cpu = -1; |
1a853e368 perf record: Allo... |
41 |
static pid_t target_pid = -1; |
933da83aa perf: Propagate t... |
42 |
static pid_t child_pid = -1; |
16c8a1093 perf_counter: too... |
43 |
static int inherit = 1; |
97124d5e2 perf_counter: too... |
44 |
static int force = 0; |
abaff32a0 perf record: Add ... |
45 |
static int append_file = 0; |
3efa1cc99 perf record/repor... |
46 |
static int call_graph = 0; |
649c48a9e perf-report: Add ... |
47 48 |
static int inherit_stat = 0; static int no_samples = 0; |
4bba828dd perf_counter: Add... |
49 |
static int sample_address = 0; |
d13025222 perf tools: Add a... |
50 |
static int multiplex = 0; |
ea57c4f52 perf tools: Imple... |
51 |
static int multiplex_fd = -1; |
de9ac07bb perf_counter: som... |
52 |
|
a21ca2cac perf_counter: Sep... |
53 54 55 |
static long samples; static struct timeval last_read; static struct timeval this_read; |
9cffa8d53 perf_counter tool... |
56 |
static u64 bytes_written; |
a21ca2cac perf_counter: Sep... |
57 58 59 60 61 |
static struct pollfd event_array[MAX_NR_CPUS * MAX_COUNTERS]; static int nr_poll; static int nr_cpu; |
f5970550d perf_counter tool... |
62 |
static int file_new = 1; |
7c6a1c65b perf_counter tool... |
63 64 |
struct perf_header *header; |
f5970550d perf_counter tool... |
65 |
|
de9ac07bb perf_counter: som... |
66 |
struct mmap_data { |
a21ca2cac perf_counter: Sep... |
67 68 69 70 |
int counter; void *base; unsigned int mask; unsigned int prev; |
de9ac07bb perf_counter: som... |
71 |
}; |
a21ca2cac perf_counter: Sep... |
72 |
static struct mmap_data mmap_array[MAX_NR_CPUS][MAX_COUNTERS]; |
9d91a6f7a perf_counter tool... |
73 |
static unsigned long mmap_read_head(struct mmap_data *md) |
de9ac07bb perf_counter: som... |
74 |
{ |
cdd6c482c perf: Do the big ... |
75 |
struct perf_event_mmap_page *pc = md->base; |
9d91a6f7a perf_counter tool... |
76 |
long head; |
de9ac07bb perf_counter: som... |
77 78 79 80 81 82 |
head = pc->data_head; rmb(); return head; } |
9d91a6f7a perf_counter tool... |
83 84 |
static void mmap_write_tail(struct mmap_data *md, unsigned long tail) { |
cdd6c482c perf: Do the big ... |
85 |
struct perf_event_mmap_page *pc = md->base; |
9d91a6f7a perf_counter tool... |
86 87 88 89 90 91 92 |
/* * ensure all reads are done before we write the tail out. */ /* mb(); */ pc->data_tail = tail; } |
f5970550d perf_counter tool... |
93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
static void write_output(void *buf, size_t size) { while (size) { int ret = write(output, buf, size); if (ret < 0) die("failed to write"); size -= ret; buf += ret; bytes_written += ret; } } |
de9ac07bb perf_counter: som... |
107 108 109 110 111 112 113 114 115 116 117 118 119 |
static void mmap_read(struct mmap_data *md) { unsigned int head = mmap_read_head(md); unsigned int old = md->prev; unsigned char *data = md->base + page_size; unsigned long size; void *buf; int diff; gettimeofday(&this_read, NULL); /* * If we're further behind than half the buffer, there's a chance |
2debbc836 perf_counter tool... |
120 |
* the writer will bite our tail and mess up the samples under us. |
de9ac07bb perf_counter: som... |
121 122 123 124 125 126 |
* * If we somehow ended up ahead of the head, we got messed up. * * In either case, truncate and restart at head. */ diff = head - old; |
9d91a6f7a perf_counter tool... |
127 |
if (diff < 0) { |
de9ac07bb perf_counter: som... |
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 |
struct timeval iv; unsigned long msecs; timersub(&this_read, &last_read, &iv); msecs = iv.tv_sec*1000 + iv.tv_usec/1000; fprintf(stderr, "WARNING: failed to keep up with mmap data." " Last read %lu msecs ago. ", msecs); /* * head points to a known good entry, start there. */ old = head; } last_read = this_read; if (old != head) |
2debbc836 perf_counter tool... |
147 |
samples++; |
de9ac07bb perf_counter: som... |
148 149 150 151 152 153 154 |
size = head - old; if ((old & md->mask) + size != (head & md->mask)) { buf = &data[old & md->mask]; size = md->mask + 1 - (old & md->mask); old += size; |
021e9f476 perf record: Refi... |
155 |
|
f5970550d perf_counter tool... |
156 |
write_output(buf, size); |
de9ac07bb perf_counter: som... |
157 158 159 160 161 |
} buf = &data[old & md->mask]; size = head - old; old += size; |
021e9f476 perf record: Refi... |
162 |
|
f5970550d perf_counter tool... |
163 |
write_output(buf, size); |
de9ac07bb perf_counter: som... |
164 165 |
md->prev = old; |
9d91a6f7a perf_counter tool... |
166 |
mmap_write_tail(md, old); |
de9ac07bb perf_counter: som... |
167 168 169 |
} static volatile int done = 0; |
f7b7c26e0 perf_counter tool... |
170 |
static volatile int signr = -1; |
de9ac07bb perf_counter: som... |
171 |
|
16c8a1093 perf_counter: too... |
172 |
static void sig_handler(int sig) |
de9ac07bb perf_counter: som... |
173 |
{ |
16c8a1093 perf_counter: too... |
174 |
done = 1; |
f7b7c26e0 perf_counter tool... |
175 176 177 178 179 |
signr = sig; } static void sig_atexit(void) { |
933da83aa perf: Propagate t... |
180 181 |
if (child_pid != -1) kill(child_pid, SIGTERM); |
f7b7c26e0 perf_counter tool... |
182 183 184 185 186 |
if (signr == -1) return; signal(signr, SIG_DFL); kill(getpid(), signr); |
de9ac07bb perf_counter: som... |
187 |
} |
2a8083f06 perf record: Fix ... |
188 |
static pid_t pid_synthesize_comm_event(pid_t pid, int full) |
1a853e368 perf record: Allo... |
189 |
{ |
16f762a2a perf_counter tool... |
190 |
struct comm_event comm_ev; |
1a853e368 perf record: Allo... |
191 192 |
char filename[PATH_MAX]; char bf[BUFSIZ]; |
2a8083f06 perf record: Fix ... |
193 194 |
FILE *fp; size_t size = 0; |
f70e87d7a perf_counter: too... |
195 196 |
DIR *tasks; struct dirent dirent, *next; |
2a8083f06 perf record: Fix ... |
197 |
pid_t tgid = 0; |
1a853e368 perf record: Allo... |
198 |
|
2a8083f06 perf record: Fix ... |
199 |
snprintf(filename, sizeof(filename), "/proc/%d/status", pid); |
1a853e368 perf record: Allo... |
200 |
|
2a8083f06 perf record: Fix ... |
201 |
fp = fopen(filename, "r"); |
39e6dd735 perf record: Fix ... |
202 |
if (fp == NULL) { |
613d86022 perf record: Fix ... |
203 204 205 206 207 208 |
/* * We raced with a task exiting - just return: */ if (verbose) fprintf(stderr, "couldn't open %s ", filename); |
2a8083f06 perf record: Fix ... |
209 |
return 0; |
1a853e368 perf record: Allo... |
210 |
} |
1a853e368 perf record: Allo... |
211 |
|
1a853e368 perf record: Allo... |
212 |
memset(&comm_ev, 0, sizeof(comm_ev)); |
2a8083f06 perf record: Fix ... |
213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 |
while (!comm_ev.comm[0] || !comm_ev.pid) { if (fgets(bf, sizeof(bf), fp) == NULL) goto out_failure; if (memcmp(bf, "Name:", 5) == 0) { char *name = bf + 5; while (*name && isspace(*name)) ++name; size = strlen(name) - 1; memcpy(comm_ev.comm, name, size++); } else if (memcmp(bf, "Tgid:", 5) == 0) { char *tgids = bf + 5; while (*tgids && isspace(*tgids)) ++tgids; tgid = comm_ev.pid = atoi(tgids); } } |
cdd6c482c perf: Do the big ... |
230 |
comm_ev.header.type = PERF_RECORD_COMM; |
9cffa8d53 perf_counter tool... |
231 |
size = ALIGN(size, sizeof(u64)); |
1a853e368 perf record: Allo... |
232 |
comm_ev.header.size = sizeof(comm_ev) - (sizeof(comm_ev.comm) - size); |
16f762a2a perf_counter tool... |
233 |
|
f70e87d7a perf_counter: too... |
234 235 |
if (!full) { comm_ev.tid = pid; |
f5970550d perf_counter tool... |
236 |
write_output(&comm_ev, comm_ev.header.size); |
2a8083f06 perf record: Fix ... |
237 |
goto out_fclose; |
f70e87d7a perf_counter: too... |
238 239 240 241 242 243 244 245 246 247 248 249 |
} snprintf(filename, sizeof(filename), "/proc/%d/task", pid); tasks = opendir(filename); while (!readdir_r(tasks, &dirent, &next) && next) { char *end; pid = strtol(dirent.d_name, &end, 10); if (*end) continue; comm_ev.tid = pid; |
f5970550d perf_counter tool... |
250 |
write_output(&comm_ev, comm_ev.header.size); |
1a853e368 perf record: Allo... |
251 |
} |
f70e87d7a perf_counter: too... |
252 |
closedir(tasks); |
2a8083f06 perf record: Fix ... |
253 254 255 256 |
out_fclose: fclose(fp); return tgid; |
f70e87d7a perf_counter: too... |
257 |
|
a0055ae2a perf_counter tool... |
258 259 260 261 262 |
out_failure: fprintf(stderr, "couldn't get COMM and pgid, malformed %s ", filename); exit(EXIT_FAILURE); |
1a853e368 perf record: Allo... |
263 |
} |
2a8083f06 perf record: Fix ... |
264 |
static void pid_synthesize_mmap_samples(pid_t pid, pid_t tgid) |
1a853e368 perf record: Allo... |
265 266 267 268 269 270 271 272 |
{ char filename[PATH_MAX]; FILE *fp; snprintf(filename, sizeof(filename), "/proc/%d/maps", pid); fp = fopen(filename, "r"); if (fp == NULL) { |
613d86022 perf record: Fix ... |
273 274 275 276 277 278 279 |
/* * We raced with a task exiting - just return: */ if (verbose) fprintf(stderr, "couldn't open %s ", filename); return; |
1a853e368 perf record: Allo... |
280 281 |
} while (1) { |
a0055ae2a perf_counter tool... |
282 |
char bf[BUFSIZ], *pbf = bf; |
1a853e368 perf record: Allo... |
283 |
struct mmap_event mmap_ev = { |
cdd6c482c perf: Do the big ... |
284 |
.header = { .type = PERF_RECORD_MMAP }, |
1a853e368 perf record: Allo... |
285 |
}; |
a0055ae2a perf_counter tool... |
286 |
int n; |
1a853e368 perf record: Allo... |
287 288 289 290 291 |
size_t size; if (fgets(bf, sizeof(bf), fp) == NULL) break; /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */ |
a0055ae2a perf_counter tool... |
292 293 294 295 296 297 298 299 300 |
n = hex2u64(pbf, &mmap_ev.start); if (n < 0) continue; pbf += n + 1; n = hex2u64(pbf, &mmap_ev.len); if (n < 0) continue; pbf += n + 3; if (*pbf == 'x') { /* vm_exec */ |
76c64c5e4 perf record: Fix ... |
301 |
char *execname = strchr(bf, '/'); |
1a853e368 perf record: Allo... |
302 |
|
11b5f81e1 perf_counter: Syn... |
303 304 305 |
/* Catch VDSO */ if (execname == NULL) execname = strstr(bf, "[vdso]"); |
76c64c5e4 perf record: Fix ... |
306 |
if (execname == NULL) |
1a853e368 perf record: Allo... |
307 |
continue; |
1a853e368 perf record: Allo... |
308 309 310 311 |
size = strlen(execname); execname[size - 1] = '\0'; /* Remove */ memcpy(mmap_ev.filename, execname, size); |
9cffa8d53 perf_counter tool... |
312 |
size = ALIGN(size, sizeof(u64)); |
1a853e368 perf record: Allo... |
313 314 315 |
mmap_ev.len -= mmap_ev.start; mmap_ev.header.size = (sizeof(mmap_ev) - (sizeof(mmap_ev.filename) - size)); |
2a8083f06 perf record: Fix ... |
316 |
mmap_ev.pid = tgid; |
1a853e368 perf record: Allo... |
317 |
mmap_ev.tid = pid; |
f5970550d perf_counter tool... |
318 |
write_output(&mmap_ev, mmap_ev.header.size); |
1a853e368 perf record: Allo... |
319 320 321 322 323 |
} } fclose(fp); } |
7c6a1c65b perf_counter tool... |
324 |
static void synthesize_all(void) |
f70e87d7a perf_counter: too... |
325 326 327 328 329 330 331 332 |
{ DIR *proc; struct dirent dirent, *next; proc = opendir("/proc"); while (!readdir_r(proc, &dirent, &next) && next) { char *end; |
2a8083f06 perf record: Fix ... |
333 |
pid_t pid, tgid; |
f70e87d7a perf_counter: too... |
334 335 336 337 |
pid = strtol(dirent.d_name, &end, 10); if (*end) /* only interested in proper numerical dirents */ continue; |
2a8083f06 perf record: Fix ... |
338 339 |
tgid = pid_synthesize_comm_event(pid, 1); pid_synthesize_mmap_samples(pid, tgid); |
f70e87d7a perf_counter: too... |
340 341 342 343 |
} closedir(proc); } |
f250c030a perf record: Spli... |
344 |
static int group_fd; |
cdd6c482c perf: Do the big ... |
345 |
static struct perf_header_attr *get_header_attr(struct perf_event_attr *a, int nr) |
7c6a1c65b perf_counter tool... |
346 347 348 349 350 351 352 353 354 355 356 357 |
{ struct perf_header_attr *h_attr; if (nr < header->attrs) { h_attr = header->attr[nr]; } else { h_attr = perf_header_attr__new(a); perf_header__add_attr(header, h_attr); } return h_attr; } |
f250c030a perf record: Spli... |
358 |
static void create_counter(int counter, int cpu, pid_t pid) |
de9ac07bb perf_counter: som... |
359 |
{ |
cdd6c482c perf: Do the big ... |
360 |
struct perf_event_attr *attr = attrs + counter; |
7c6a1c65b perf_counter tool... |
361 362 363 364 365 366 367 368 369 370 371 372 |
struct perf_header_attr *h_attr; int track = !counter; /* only the first counter needs these */ struct { u64 count; u64 time_enabled; u64 time_running; u64 id; } read_data; attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | PERF_FORMAT_TOTAL_TIME_RUNNING | PERF_FORMAT_ID; |
16c8a1093 perf_counter: too... |
373 |
|
3a9f131fb perf tools: Add a... |
374 |
attr->sample_type |= PERF_SAMPLE_IP | PERF_SAMPLE_TID; |
3efa1cc99 perf record/repor... |
375 |
|
1dba15e74 perf record: Set ... |
376 |
if (freq) { |
ea1900e57 perf_counter tool... |
377 |
attr->sample_type |= PERF_SAMPLE_PERIOD; |
a21ca2cac perf_counter: Sep... |
378 379 |
attr->freq = 1; attr->sample_freq = freq; |
1dba15e74 perf record: Set ... |
380 |
} |
3efa1cc99 perf record/repor... |
381 |
|
649c48a9e perf-report: Add ... |
382 383 384 385 386 |
if (no_samples) attr->sample_freq = 0; if (inherit_stat) attr->inherit_stat = 1; |
4bba828dd perf_counter: Add... |
387 388 |
if (sample_address) attr->sample_type |= PERF_SAMPLE_ADDR; |
3efa1cc99 perf record/repor... |
389 390 |
if (call_graph) attr->sample_type |= PERF_SAMPLE_CALLCHAIN; |
cd6feeeaf perf trace: Sampl... |
391 |
if (raw_samples) { |
6ddf259da perf trace: Sampl... |
392 |
attr->sample_type |= PERF_SAMPLE_TIME; |
daac07b2e perf tools: Add a... |
393 |
attr->sample_type |= PERF_SAMPLE_RAW; |
cd6feeeaf perf trace: Sampl... |
394 395 |
attr->sample_type |= PERF_SAMPLE_CPU; } |
f413cdb80 perf_counter: Fix... |
396 |
|
a21ca2cac perf_counter: Sep... |
397 398 399 |
attr->mmap = track; attr->comm = track; attr->inherit = (cpu < 0) && inherit; |
4502d77c1 perf_counter tool... |
400 |
attr->disabled = 1; |
16c8a1093 perf_counter: too... |
401 |
|
3da297a60 perf record: Fall... |
402 |
try_again: |
cdd6c482c perf: Do the big ... |
403 |
fd[nr_cpu][counter] = sys_perf_event_open(attr, pid, cpu, group_fd, 0); |
16c8a1093 perf_counter: too... |
404 |
|
f250c030a perf record: Spli... |
405 406 |
if (fd[nr_cpu][counter] < 0) { int err = errno; |
16c8a1093 perf_counter: too... |
407 |
|
c10edee2e perf tools: Fix p... |
408 |
if (err == EPERM || err == EACCES) |
3da297a60 perf record: Fall... |
409 410 |
die("Permission error - are you root? "); |
0a5ac8465 perf record: Add ... |
411 412 413 |
else if (err == ENODEV && profile_cpu != -1) die("No such device - did you specify an out-of-range profile CPU? "); |
3da297a60 perf record: Fall... |
414 415 416 417 418 419 420 |
/* * If it's cycles then fall back to hrtimer * based cpu-clock-tick sw counter, which * is always available even if no PMU support: */ if (attr->type == PERF_TYPE_HARDWARE |
f4dbfa8f3 perf_counter: Sta... |
421 |
&& attr->config == PERF_COUNT_HW_CPU_CYCLES) { |
3da297a60 perf record: Fall... |
422 423 424 425 426 |
if (verbose) warning(" ... trying to fall back to cpu-clock-ticks "); attr->type = PERF_TYPE_SOFTWARE; |
f4dbfa8f3 perf_counter: Sta... |
427 |
attr->config = PERF_COUNT_SW_CPU_CLOCK; |
3da297a60 perf record: Fall... |
428 429 |
goto try_again; } |
30c806a09 perf_counter tool... |
430 431 432 433 434 |
printf(" "); error("perfcounter syscall returned with %d (%s) ", fd[nr_cpu][counter], strerror(err)); |
cdd6c482c perf: Do the big ... |
435 436 |
die("No CONFIG_PERF_EVENTS=y kernel support configured? "); |
f250c030a perf record: Spli... |
437 438 |
exit(-1); } |
3da297a60 perf record: Fall... |
439 |
|
7c6a1c65b perf_counter tool... |
440 441 442 443 444 445 446 447 448 |
h_attr = get_header_attr(attr, counter); if (!file_new) { if (memcmp(&h_attr->attr, attr, sizeof(*attr))) { fprintf(stderr, "incompatible append "); exit(-1); } } |
3928ddbe9 perf record: Fix ... |
449 450 451 452 453 |
if (read(fd[nr_cpu][counter], &read_data, sizeof(read_data)) == -1) { perror("Unable to read perf file descriptor "); exit(-1); } |
7c6a1c65b perf_counter tool... |
454 455 |
perf_header_attr__add_id(h_attr, read_data.id); |
f250c030a perf record: Spli... |
456 457 |
assert(fd[nr_cpu][counter] >= 0); fcntl(fd[nr_cpu][counter], F_SETFL, O_NONBLOCK); |
16c8a1093 perf_counter: too... |
458 |
|
f250c030a perf record: Spli... |
459 460 461 462 463 |
/* * First counter acts as the group leader: */ if (group && group_fd == -1) group_fd = fd[nr_cpu][counter]; |
ea57c4f52 perf tools: Imple... |
464 465 |
if (multiplex && multiplex_fd == -1) multiplex_fd = fd[nr_cpu][counter]; |
f250c030a perf record: Spli... |
466 |
|
ea57c4f52 perf tools: Imple... |
467 468 |
if (multiplex && fd[nr_cpu][counter] != multiplex_fd) { int ret; |
4502d77c1 perf_counter tool... |
469 |
|
cdd6c482c perf: Do the big ... |
470 |
ret = ioctl(fd[nr_cpu][counter], PERF_EVENT_IOC_SET_OUTPUT, multiplex_fd); |
ea57c4f52 perf tools: Imple... |
471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 |
assert(ret != -1); } else { event_array[nr_poll].fd = fd[nr_cpu][counter]; event_array[nr_poll].events = POLLIN; nr_poll++; mmap_array[nr_cpu][counter].counter = counter; mmap_array[nr_cpu][counter].prev = 0; mmap_array[nr_cpu][counter].mask = mmap_pages*page_size - 1; mmap_array[nr_cpu][counter].base = mmap(NULL, (mmap_pages+1)*page_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd[nr_cpu][counter], 0); if (mmap_array[nr_cpu][counter].base == MAP_FAILED) { error("failed to mmap with %d (%s) ", errno, strerror(errno)); exit(-1); } } |
d13025222 perf tools: Add a... |
488 |
|
cdd6c482c perf: Do the big ... |
489 |
ioctl(fd[nr_cpu][counter], PERF_EVENT_IOC_ENABLE); |
f250c030a perf record: Spli... |
490 |
} |
f2521b6e4 perf_counter tool... |
491 |
|
f250c030a perf record: Spli... |
492 493 494 |
static void open_counters(int cpu, pid_t pid) { int counter; |
16c8a1093 perf_counter: too... |
495 |
|
f250c030a perf record: Spli... |
496 497 498 |
group_fd = -1; for (counter = 0; counter < nr_counters; counter++) create_counter(counter, cpu, pid); |
16c8a1093 perf_counter: too... |
499 500 |
nr_cpu++; } |
f5970550d perf_counter tool... |
501 502 |
static void atexit_header(void) { |
7c6a1c65b perf_counter tool... |
503 |
header->data_size += bytes_written; |
f5970550d perf_counter tool... |
504 |
|
7c6a1c65b perf_counter tool... |
505 |
perf_header__write(header, output); |
f5970550d perf_counter tool... |
506 |
} |
0e9b20b8a perf record: Conv... |
507 |
static int __cmd_record(int argc, const char **argv) |
16c8a1093 perf_counter: too... |
508 509 |
{ int i, counter; |
abaff32a0 perf record: Add ... |
510 |
struct stat st; |
7c6a1c65b perf_counter tool... |
511 |
pid_t pid = 0; |
abaff32a0 perf record: Add ... |
512 |
int flags; |
de9ac07bb perf_counter: som... |
513 |
int ret; |
8b412664d perf record: Disa... |
514 |
unsigned long waking = 0; |
de9ac07bb perf_counter: som... |
515 516 |
page_size = sysconf(_SC_PAGE_SIZE); |
de9ac07bb perf_counter: som... |
517 518 519 |
nr_cpus = sysconf(_SC_NPROCESSORS_ONLN); assert(nr_cpus <= MAX_NR_CPUS); assert(nr_cpus >= 0); |
f5970550d perf_counter tool... |
520 521 522 |
atexit(sig_atexit); signal(SIGCHLD, sig_handler); signal(SIGINT, sig_handler); |
266e0e219 perf record: Fix ... |
523 524 525 526 527 528 529 530 531 |
if (!stat(output_name, &st) && st.st_size) { if (!force && !append_file) { fprintf(stderr, "Error, output file %s exists, use -A to append or -f to overwrite. ", output_name); exit(-1); } } else { append_file = 0; |
97124d5e2 perf_counter: too... |
532 |
} |
abaff32a0 perf record: Add ... |
533 534 |
flags = O_CREAT|O_RDWR; if (append_file) |
f5970550d perf_counter tool... |
535 |
file_new = 0; |
abaff32a0 perf record: Add ... |
536 537 538 539 |
else flags |= O_TRUNC; output = open(output_name, flags, S_IRUSR|S_IWUSR); |
de9ac07bb perf_counter: som... |
540 541 542 543 |
if (output < 0) { perror("failed to create output file"); exit(-1); } |
7c6a1c65b perf_counter tool... |
544 545 546 547 |
if (!file_new) header = perf_header__read(output); else header = perf_header__new(); |
f5970550d perf_counter tool... |
548 |
|
9df37ddd8 perf tools: Recor... |
549 550 |
if (raw_samples) { |
1ef2ed106 perf tools: Only ... |
551 |
read_tracing_data(attrs, nr_counters); |
9df37ddd8 perf tools: Recor... |
552 553 554 |
} else { for (i = 0; i < nr_counters; i++) { if (attrs[i].sample_type & PERF_SAMPLE_RAW) { |
1ef2ed106 perf tools: Only ... |
555 |
read_tracing_data(attrs, nr_counters); |
9df37ddd8 perf tools: Recor... |
556 557 558 559 |
break; } } } |
f5970550d perf_counter tool... |
560 |
atexit(atexit_header); |
1a853e368 perf record: Allo... |
561 |
if (!system_wide) { |
7c6a1c65b perf_counter tool... |
562 563 564 |
pid = target_pid; if (pid == -1) pid = getpid(); |
0a5ac8465 perf record: Add ... |
565 566 567 568 569 570 571 572 573 |
open_counters(profile_cpu, pid); } else { if (profile_cpu != -1) { open_counters(profile_cpu, target_pid); } else { for (i = 0; i < nr_cpus; i++) open_counters(i, target_pid); } } |
de9ac07bb perf_counter: som... |
574 |
|
7c6a1c65b perf_counter tool... |
575 576 577 578 |
if (file_new) perf_header__write(header, output); if (!system_wide) { |
2a8083f06 perf record: Fix ... |
579 580 |
pid_t tgid = pid_synthesize_comm_event(pid, 0); pid_synthesize_mmap_samples(pid, tgid); |
7c6a1c65b perf_counter tool... |
581 582 |
} else synthesize_all(); |
ef65b2a0b perf record: Fix ... |
583 |
if (target_pid == -1 && argc) { |
1a853e368 perf record: Allo... |
584 585 586 |
pid = fork(); if (pid < 0) perror("failed to fork"); |
de9ac07bb perf_counter: som... |
587 |
|
1a853e368 perf record: Allo... |
588 |
if (!pid) { |
0e9b20b8a perf record: Conv... |
589 |
if (execvp(argv[0], (char **)argv)) { |
1a853e368 perf record: Allo... |
590 591 592 |
perror(argv[0]); exit(-1); } |
de9ac07bb perf_counter: som... |
593 |
} |
933da83aa perf: Propagate t... |
594 595 |
child_pid = pid; |
de9ac07bb perf_counter: som... |
596 597 598 599 600 601 602 603 604 605 606 607 |
} if (realtime_prio) { struct sched_param param; param.sched_priority = realtime_prio; if (sched_setscheduler(0, SCHED_FIFO, ¶m)) { printf("Could not set realtime priority. "); exit(-1); } } |
649c48a9e perf-report: Add ... |
608 |
for (;;) { |
2debbc836 perf_counter tool... |
609 |
int hits = samples; |
de9ac07bb perf_counter: som... |
610 |
|
16c8a1093 perf_counter: too... |
611 |
for (i = 0; i < nr_cpu; i++) { |
ea57c4f52 perf tools: Imple... |
612 613 614 615 |
for (counter = 0; counter < nr_counters; counter++) { if (mmap_array[i][counter].base) mmap_read(&mmap_array[i][counter]); } |
de9ac07bb perf_counter: som... |
616 |
} |
649c48a9e perf-report: Add ... |
617 618 619 |
if (hits == samples) { if (done) break; |
8b412664d perf record: Disa... |
620 621 622 623 624 625 626 |
ret = poll(event_array, nr_poll, -1); waking++; } if (done) { for (i = 0; i < nr_cpu; i++) { for (counter = 0; counter < nr_counters; counter++) |
cdd6c482c perf: Do the big ... |
627 |
ioctl(fd[i][counter], PERF_EVENT_IOC_DISABLE); |
8b412664d perf record: Disa... |
628 |
} |
649c48a9e perf-report: Add ... |
629 |
} |
de9ac07bb perf_counter: som... |
630 |
} |
8b412664d perf record: Disa... |
631 632 |
fprintf(stderr, "[ perf record: Woken up %ld times to write data ] ", waking); |
021e9f476 perf record: Refi... |
633 634 635 636 |
/* * Approximate RIP event size: 24 bytes. */ fprintf(stderr, |
2debbc836 perf_counter tool... |
637 638 |
"[ perf record: Captured and wrote %.3f MB %s (~%lld samples) ] ", |
021e9f476 perf record: Refi... |
639 640 641 |
(double)bytes_written / 1024.0 / 1024.0, output_name, bytes_written / 24); |
addc2785c perf record: Prin... |
642 |
|
de9ac07bb perf_counter: som... |
643 644 |
return 0; } |
0e9b20b8a perf record: Conv... |
645 |
|
0e9b20b8a perf record: Conv... |
646 |
static const char * const record_usage[] = { |
9e0967536 perf_counter tool... |
647 648 |
"perf record [<options>] [<command>]", "perf record [<options>] -- <command> [<options>]", |
0e9b20b8a perf record: Conv... |
649 650 |
NULL }; |
5242519b0 perf stat: Conver... |
651 |
static const struct option options[] = { |
0e9b20b8a perf record: Conv... |
652 |
OPT_CALLBACK('e', "event", NULL, "event", |
86847b62f perf_counter tool... |
653 654 |
"event selector. use 'perf list' to list available events", parse_events), |
0e9b20b8a perf record: Conv... |
655 656 657 658 |
OPT_INTEGER('p', "pid", &target_pid, "record events on existing pid"), OPT_INTEGER('r', "realtime", &realtime_prio, "collect data with this RT SCHED_FIFO priority"), |
daac07b2e perf tools: Add a... |
659 660 |
OPT_BOOLEAN('R', "raw-samples", &raw_samples, "collect raw sample records from all opened counters"), |
0e9b20b8a perf record: Conv... |
661 662 |
OPT_BOOLEAN('a', "all-cpus", &system_wide, "system-wide collection from all CPUs"), |
abaff32a0 perf record: Add ... |
663 664 |
OPT_BOOLEAN('A', "append", &append_file, "append to the output file to do incremental profiling"), |
0a5ac8465 perf record: Add ... |
665 666 |
OPT_INTEGER('C', "profile_cpu", &profile_cpu, "CPU to profile on"), |
97124d5e2 perf_counter: too... |
667 668 |
OPT_BOOLEAN('f', "force", &force, "overwrite existing data file"), |
e61078a0c perf record: Use ... |
669 |
OPT_LONG('c', "count", &default_interval, |
abaff32a0 perf record: Add ... |
670 671 672 673 674 |
"event period to sample"), OPT_STRING('o', "output", &output_name, "file", "output file name"), OPT_BOOLEAN('i', "inherit", &inherit, "child tasks inherit counters"), |
cf1f45744 perf record, top:... |
675 676 |
OPT_INTEGER('F', "freq", &freq, "profile at this frequency"), |
abaff32a0 perf record: Add ... |
677 678 |
OPT_INTEGER('m', "mmap-pages", &mmap_pages, "number of mmap data pages"), |
3efa1cc99 perf record/repor... |
679 680 |
OPT_BOOLEAN('g', "call-graph", &call_graph, "do call-graph (stack chain/backtrace) recording"), |
3da297a60 perf record: Fall... |
681 682 |
OPT_BOOLEAN('v', "verbose", &verbose, "be more verbose (show counter open errors, etc)"), |
649c48a9e perf-report: Add ... |
683 684 |
OPT_BOOLEAN('s', "stat", &inherit_stat, "per thread counts"), |
4bba828dd perf_counter: Add... |
685 686 |
OPT_BOOLEAN('d', "data", &sample_address, "Sample addresses"), |
649c48a9e perf-report: Add ... |
687 688 |
OPT_BOOLEAN('n', "no-samples", &no_samples, "don't sample"), |
d13025222 perf tools: Add a... |
689 690 |
OPT_BOOLEAN('M', "multiplex", &multiplex, "multiplex counter output in a single channel"), |
0e9b20b8a perf record: Conv... |
691 692 |
OPT_END() }; |
f37a291c5 perf_counter tool... |
693 |
int cmd_record(int argc, const char **argv, const char *prefix __used) |
0e9b20b8a perf record: Conv... |
694 695 |
{ int counter; |
a0541234f perf_counter: Imp... |
696 697 |
argc = parse_options(argc, argv, options, record_usage, PARSE_OPT_STOP_AT_NON_OPTION); |
ef65b2a0b perf record: Fix ... |
698 |
if (!argc && target_pid == -1 && !system_wide) |
0e9b20b8a perf record: Conv... |
699 |
usage_with_options(record_usage, options); |
bbd36e5e6 perf record: Expl... |
700 701 702 703 704 |
if (!nr_counters) { nr_counters = 1; attrs[0].type = PERF_TYPE_HARDWARE; attrs[0].config = PERF_COUNT_HW_CPU_CYCLES; } |
0e9b20b8a perf record: Conv... |
705 706 |
for (counter = 0; counter < nr_counters; counter++) { |
a21ca2cac perf_counter: Sep... |
707 |
if (attrs[counter].sample_period) |
0e9b20b8a perf record: Conv... |
708 |
continue; |
a21ca2cac perf_counter: Sep... |
709 |
attrs[counter].sample_period = default_interval; |
0e9b20b8a perf record: Conv... |
710 711 712 713 |
} return __cmd_record(argc, argv); } |