aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/builtin-record.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/builtin-record.c')
-rw-r--r--tools/perf/builtin-record.c345
1 files changed, 129 insertions, 216 deletions
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index a4be453fc8a9..0e519c667e3a 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -17,55 +17,52 @@
17#include "util/header.h" 17#include "util/header.h"
18#include "util/event.h" 18#include "util/event.h"
19#include "util/debug.h" 19#include "util/debug.h"
20#include "util/trace-event.h" 20#include "util/symbol.h"
21 21
22#include <unistd.h> 22#include <unistd.h>
23#include <sched.h> 23#include <sched.h>
24 24
25#define ALIGN(x, a) __ALIGN_MASK(x, (typeof(x))(a)-1)
26#define __ALIGN_MASK(x, mask) (((x)+(mask))&~(mask))
27
28static int fd[MAX_NR_CPUS][MAX_COUNTERS]; 25static int fd[MAX_NR_CPUS][MAX_COUNTERS];
29 26
30static long default_interval = 100000; 27static long default_interval = 0;
31 28
32static int nr_cpus = 0; 29static int nr_cpus = 0;
33static unsigned int page_size; 30static unsigned int page_size;
34static unsigned int mmap_pages = 128; 31static unsigned int mmap_pages = 128;
35static int freq = 0; 32static int freq = 1000;
36static int output; 33static int output;
37static const char *output_name = "perf.data"; 34static const char *output_name = "perf.data";
38static int group = 0; 35static int group = 0;
39static unsigned int realtime_prio = 0; 36static unsigned int realtime_prio = 0;
40static int raw_samples = 0; 37static int raw_samples = 0;
41static int system_wide = 0; 38static int system_wide = 0;
42static int profile_cpu = -1; 39static int profile_cpu = -1;
43static pid_t target_pid = -1; 40static pid_t target_pid = -1;
44static pid_t child_pid = -1; 41static pid_t child_pid = -1;
45static int inherit = 1; 42static int inherit = 1;
46static int force = 0; 43static int force = 0;
47static int append_file = 0; 44static int append_file = 0;
48static int call_graph = 0; 45static int call_graph = 0;
49static int inherit_stat = 0; 46static int inherit_stat = 0;
50static int no_samples = 0; 47static int no_samples = 0;
51static int sample_address = 0; 48static int sample_address = 0;
52static int multiplex = 0; 49static int multiplex = 0;
53static int multiplex_fd = -1; 50static int multiplex_fd = -1;
54 51
55static long samples; 52static long samples = 0;
56static struct timeval last_read; 53static struct timeval last_read;
57static struct timeval this_read; 54static struct timeval this_read;
58 55
59static u64 bytes_written; 56static u64 bytes_written = 0;
60 57
61static struct pollfd event_array[MAX_NR_CPUS * MAX_COUNTERS]; 58static struct pollfd event_array[MAX_NR_CPUS * MAX_COUNTERS];
62 59
63static int nr_poll; 60static int nr_poll = 0;
64static int nr_cpu; 61static int nr_cpu = 0;
65 62
66static int file_new = 1; 63static int file_new = 1;
67 64
68struct perf_header *header; 65struct perf_header *header = NULL;
69 66
70struct mmap_data { 67struct mmap_data {
71 int counter; 68 int counter;
@@ -113,6 +110,24 @@ static void write_output(void *buf, size_t size)
113 } 110 }
114} 111}
115 112
113static void write_event(event_t *buf, size_t size)
114{
115 /*
116 * Add it to the list of DSOs, so that when we finish this
117 * record session we can pick the available build-ids.
118 */
119 if (buf->header.type == PERF_RECORD_MMAP)
120 dsos__findnew(buf->mmap.filename);
121
122 write_output(buf, size);
123}
124
125static int process_synthesized_event(event_t *event)
126{
127 write_event(event, event->header.size);
128 return 0;
129}
130
116static void mmap_read(struct mmap_data *md) 131static void mmap_read(struct mmap_data *md)
117{ 132{
118 unsigned int head = mmap_read_head(md); 133 unsigned int head = mmap_read_head(md);
@@ -161,14 +176,14 @@ static void mmap_read(struct mmap_data *md)
161 size = md->mask + 1 - (old & md->mask); 176 size = md->mask + 1 - (old & md->mask);
162 old += size; 177 old += size;
163 178
164 write_output(buf, size); 179 write_event(buf, size);
165 } 180 }
166 181
167 buf = &data[old & md->mask]; 182 buf = &data[old & md->mask];
168 size = head - old; 183 size = head - old;
169 old += size; 184 old += size;
170 185
171 write_output(buf, size); 186 write_event(buf, size);
172 187
173 md->prev = old; 188 md->prev = old;
174 mmap_write_tail(md, old); 189 mmap_write_tail(md, old);
@@ -195,168 +210,6 @@ static void sig_atexit(void)
195 kill(getpid(), signr); 210 kill(getpid(), signr);
196} 211}
197 212
198static pid_t pid_synthesize_comm_event(pid_t pid, int full)
199{
200 struct comm_event comm_ev;
201 char filename[PATH_MAX];
202 char bf[BUFSIZ];
203 FILE *fp;
204 size_t size = 0;
205 DIR *tasks;
206 struct dirent dirent, *next;
207 pid_t tgid = 0;
208
209 snprintf(filename, sizeof(filename), "/proc/%d/status", pid);
210
211 fp = fopen(filename, "r");
212 if (fp == NULL) {
213 /*
214 * We raced with a task exiting - just return:
215 */
216 if (verbose)
217 fprintf(stderr, "couldn't open %s\n", filename);
218 return 0;
219 }
220
221 memset(&comm_ev, 0, sizeof(comm_ev));
222 while (!comm_ev.comm[0] || !comm_ev.pid) {
223 if (fgets(bf, sizeof(bf), fp) == NULL)
224 goto out_failure;
225
226 if (memcmp(bf, "Name:", 5) == 0) {
227 char *name = bf + 5;
228 while (*name && isspace(*name))
229 ++name;
230 size = strlen(name) - 1;
231 memcpy(comm_ev.comm, name, size++);
232 } else if (memcmp(bf, "Tgid:", 5) == 0) {
233 char *tgids = bf + 5;
234 while (*tgids && isspace(*tgids))
235 ++tgids;
236 tgid = comm_ev.pid = atoi(tgids);
237 }
238 }
239
240 comm_ev.header.type = PERF_RECORD_COMM;
241 size = ALIGN(size, sizeof(u64));
242 comm_ev.header.size = sizeof(comm_ev) - (sizeof(comm_ev.comm) - size);
243
244 if (!full) {
245 comm_ev.tid = pid;
246
247 write_output(&comm_ev, comm_ev.header.size);
248 goto out_fclose;
249 }
250
251 snprintf(filename, sizeof(filename), "/proc/%d/task", pid);
252
253 tasks = opendir(filename);
254 while (!readdir_r(tasks, &dirent, &next) && next) {
255 char *end;
256 pid = strtol(dirent.d_name, &end, 10);
257 if (*end)
258 continue;
259
260 comm_ev.tid = pid;
261
262 write_output(&comm_ev, comm_ev.header.size);
263 }
264 closedir(tasks);
265
266out_fclose:
267 fclose(fp);
268 return tgid;
269
270out_failure:
271 fprintf(stderr, "couldn't get COMM and pgid, malformed %s\n",
272 filename);
273 exit(EXIT_FAILURE);
274}
275
276static void pid_synthesize_mmap_samples(pid_t pid, pid_t tgid)
277{
278 char filename[PATH_MAX];
279 FILE *fp;
280
281 snprintf(filename, sizeof(filename), "/proc/%d/maps", pid);
282
283 fp = fopen(filename, "r");
284 if (fp == NULL) {
285 /*
286 * We raced with a task exiting - just return:
287 */
288 if (verbose)
289 fprintf(stderr, "couldn't open %s\n", filename);
290 return;
291 }
292 while (1) {
293 char bf[BUFSIZ], *pbf = bf;
294 struct mmap_event mmap_ev = {
295 .header = { .type = PERF_RECORD_MMAP },
296 };
297 int n;
298 size_t size;
299 if (fgets(bf, sizeof(bf), fp) == NULL)
300 break;
301
302 /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */
303 n = hex2u64(pbf, &mmap_ev.start);
304 if (n < 0)
305 continue;
306 pbf += n + 1;
307 n = hex2u64(pbf, &mmap_ev.len);
308 if (n < 0)
309 continue;
310 pbf += n + 3;
311 if (*pbf == 'x') { /* vm_exec */
312 char *execname = strchr(bf, '/');
313
314 /* Catch VDSO */
315 if (execname == NULL)
316 execname = strstr(bf, "[vdso]");
317
318 if (execname == NULL)
319 continue;
320
321 size = strlen(execname);
322 execname[size - 1] = '\0'; /* Remove \n */
323 memcpy(mmap_ev.filename, execname, size);
324 size = ALIGN(size, sizeof(u64));
325 mmap_ev.len -= mmap_ev.start;
326 mmap_ev.header.size = (sizeof(mmap_ev) -
327 (sizeof(mmap_ev.filename) - size));
328 mmap_ev.pid = tgid;
329 mmap_ev.tid = pid;
330
331 write_output(&mmap_ev, mmap_ev.header.size);
332 }
333 }
334
335 fclose(fp);
336}
337
338static void synthesize_all(void)
339{
340 DIR *proc;
341 struct dirent dirent, *next;
342
343 proc = opendir("/proc");
344
345 while (!readdir_r(proc, &dirent, &next) && next) {
346 char *end;
347 pid_t pid, tgid;
348
349 pid = strtol(dirent.d_name, &end, 10);
350 if (*end) /* only interested in proper numerical dirents */
351 continue;
352
353 tgid = pid_synthesize_comm_event(pid, 1);
354 pid_synthesize_mmap_samples(pid, tgid);
355 }
356
357 closedir(proc);
358}
359
360static int group_fd; 213static int group_fd;
361 214
362static struct perf_header_attr *get_header_attr(struct perf_event_attr *a, int nr) 215static struct perf_header_attr *get_header_attr(struct perf_event_attr *a, int nr)
@@ -367,7 +220,11 @@ static struct perf_header_attr *get_header_attr(struct perf_event_attr *a, int n
367 h_attr = header->attr[nr]; 220 h_attr = header->attr[nr];
368 } else { 221 } else {
369 h_attr = perf_header_attr__new(a); 222 h_attr = perf_header_attr__new(a);
370 perf_header__add_attr(header, h_attr); 223 if (h_attr != NULL)
224 if (perf_header__add_attr(header, h_attr) < 0) {
225 perf_header_attr__delete(h_attr);
226 h_attr = NULL;
227 }
371 } 228 }
372 229
373 return h_attr; 230 return h_attr;
@@ -375,9 +232,11 @@ static struct perf_header_attr *get_header_attr(struct perf_event_attr *a, int n
375 232
376static void create_counter(int counter, int cpu, pid_t pid) 233static void create_counter(int counter, int cpu, pid_t pid)
377{ 234{
235 char *filter = filters[counter];
378 struct perf_event_attr *attr = attrs + counter; 236 struct perf_event_attr *attr = attrs + counter;
379 struct perf_header_attr *h_attr; 237 struct perf_header_attr *h_attr;
380 int track = !counter; /* only the first counter needs these */ 238 int track = !counter; /* only the first counter needs these */
239 int ret;
381 struct { 240 struct {
382 u64 count; 241 u64 count;
383 u64 time_enabled; 242 u64 time_enabled;
@@ -448,11 +307,19 @@ try_again:
448 printf("\n"); 307 printf("\n");
449 error("perfcounter syscall returned with %d (%s)\n", 308 error("perfcounter syscall returned with %d (%s)\n",
450 fd[nr_cpu][counter], strerror(err)); 309 fd[nr_cpu][counter], strerror(err));
310
311#if defined(__i386__) || defined(__x86_64__)
312 if (attr->type == PERF_TYPE_HARDWARE && err == EOPNOTSUPP)
313 die("No hardware sampling interrupt available. No APIC? If so then you can boot the kernel with the \"lapic\" boot parameter to force-enable it.\n");
314#endif
315
451 die("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); 316 die("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
452 exit(-1); 317 exit(-1);
453 } 318 }
454 319
455 h_attr = get_header_attr(attr, counter); 320 h_attr = get_header_attr(attr, counter);
321 if (h_attr == NULL)
322 die("nomem\n");
456 323
457 if (!file_new) { 324 if (!file_new) {
458 if (memcmp(&h_attr->attr, attr, sizeof(*attr))) { 325 if (memcmp(&h_attr->attr, attr, sizeof(*attr))) {
@@ -466,7 +333,10 @@ try_again:
466 exit(-1); 333 exit(-1);
467 } 334 }
468 335
469 perf_header_attr__add_id(h_attr, read_data.id); 336 if (perf_header_attr__add_id(h_attr, read_data.id) < 0) {
337 pr_warning("Not enough memory to add id\n");
338 exit(-1);
339 }
470 340
471 assert(fd[nr_cpu][counter] >= 0); 341 assert(fd[nr_cpu][counter] >= 0);
472 fcntl(fd[nr_cpu][counter], F_SETFL, O_NONBLOCK); 342 fcntl(fd[nr_cpu][counter], F_SETFL, O_NONBLOCK);
@@ -480,7 +350,6 @@ try_again:
480 multiplex_fd = fd[nr_cpu][counter]; 350 multiplex_fd = fd[nr_cpu][counter];
481 351
482 if (multiplex && fd[nr_cpu][counter] != multiplex_fd) { 352 if (multiplex && fd[nr_cpu][counter] != multiplex_fd) {
483 int ret;
484 353
485 ret = ioctl(fd[nr_cpu][counter], PERF_EVENT_IOC_SET_OUTPUT, multiplex_fd); 354 ret = ioctl(fd[nr_cpu][counter], PERF_EVENT_IOC_SET_OUTPUT, multiplex_fd);
486 assert(ret != -1); 355 assert(ret != -1);
@@ -500,6 +369,16 @@ try_again:
500 } 369 }
501 } 370 }
502 371
372 if (filter != NULL) {
373 ret = ioctl(fd[nr_cpu][counter],
374 PERF_EVENT_IOC_SET_FILTER, filter);
375 if (ret) {
376 error("failed to set filter with %d (%s)\n", errno,
377 strerror(errno));
378 exit(-1);
379 }
380 }
381
503 ioctl(fd[nr_cpu][counter], PERF_EVENT_IOC_ENABLE); 382 ioctl(fd[nr_cpu][counter], PERF_EVENT_IOC_ENABLE);
504} 383}
505 384
@@ -518,7 +397,7 @@ static void atexit_header(void)
518{ 397{
519 header->data_size += bytes_written; 398 header->data_size += bytes_written;
520 399
521 perf_header__write(header, output); 400 perf_header__write(header, output, true);
522} 401}
523 402
524static int __cmd_record(int argc, const char **argv) 403static int __cmd_record(int argc, const char **argv)
@@ -527,7 +406,7 @@ static int __cmd_record(int argc, const char **argv)
527 struct stat st; 406 struct stat st;
528 pid_t pid = 0; 407 pid_t pid = 0;
529 int flags; 408 int flags;
530 int ret; 409 int err;
531 unsigned long waking = 0; 410 unsigned long waking = 0;
532 411
533 page_size = sysconf(_SC_PAGE_SIZE); 412 page_size = sysconf(_SC_PAGE_SIZE);
@@ -561,22 +440,29 @@ static int __cmd_record(int argc, const char **argv)
561 exit(-1); 440 exit(-1);
562 } 441 }
563 442
564 if (!file_new) 443 header = perf_header__new();
565 header = perf_header__read(output); 444 if (header == NULL) {
566 else 445 pr_err("Not enough memory for reading perf file header\n");
567 header = perf_header__new(); 446 return -1;
447 }
568 448
449 if (!file_new) {
450 err = perf_header__read(header, output);
451 if (err < 0)
452 return err;
453 }
569 454
570 if (raw_samples) { 455 if (raw_samples) {
571 read_tracing_data(attrs, nr_counters); 456 perf_header__set_feat(header, HEADER_TRACE_INFO);
572 } else { 457 } else {
573 for (i = 0; i < nr_counters; i++) { 458 for (i = 0; i < nr_counters; i++) {
574 if (attrs[i].sample_type & PERF_SAMPLE_RAW) { 459 if (attrs[i].sample_type & PERF_SAMPLE_RAW) {
575 read_tracing_data(attrs, nr_counters); 460 perf_header__set_feat(header, HEADER_TRACE_INFO);
576 break; 461 break;
577 } 462 }
578 } 463 }
579 } 464 }
465
580 atexit(atexit_header); 466 atexit(atexit_header);
581 467
582 if (!system_wide) { 468 if (!system_wide) {
@@ -594,25 +480,36 @@ static int __cmd_record(int argc, const char **argv)
594 } 480 }
595 } 481 }
596 482
597 if (file_new) 483 if (file_new) {
598 perf_header__write(header, output); 484 err = perf_header__write(header, output, false);
485 if (err < 0)
486 return err;
487 }
599 488
600 if (!system_wide) { 489 if (!system_wide)
601 pid_t tgid = pid_synthesize_comm_event(pid, 0); 490 event__synthesize_thread(pid, process_synthesized_event);
602 pid_synthesize_mmap_samples(pid, tgid); 491 else
603 } else 492 event__synthesize_threads(process_synthesized_event);
604 synthesize_all();
605 493
606 if (target_pid == -1 && argc) { 494 if (target_pid == -1 && argc) {
607 pid = fork(); 495 pid = fork();
608 if (pid < 0) 496 if (pid < 0)
609 perror("failed to fork"); 497 die("failed to fork");
610 498
611 if (!pid) { 499 if (!pid) {
612 if (execvp(argv[0], (char **)argv)) { 500 if (execvp(argv[0], (char **)argv)) {
613 perror(argv[0]); 501 perror(argv[0]);
614 exit(-1); 502 exit(-1);
615 } 503 }
504 } else {
505 /*
506 * Wait a bit for the execv'ed child to appear
507 * and be updated in /proc
508 * FIXME: Do you know a less heuristical solution?
509 */
510 usleep(1000);
511 event__synthesize_thread(pid,
512 process_synthesized_event);
616 } 513 }
617 514
618 child_pid = pid; 515 child_pid = pid;
@@ -623,7 +520,7 @@ static int __cmd_record(int argc, const char **argv)
623 520
624 param.sched_priority = realtime_prio; 521 param.sched_priority = realtime_prio;
625 if (sched_setscheduler(0, SCHED_FIFO, &param)) { 522 if (sched_setscheduler(0, SCHED_FIFO, &param)) {
626 printf("Could not set realtime priority.\n"); 523 pr_err("Could not set realtime priority.\n");
627 exit(-1); 524 exit(-1);
628 } 525 }
629 } 526 }
@@ -641,7 +538,7 @@ static int __cmd_record(int argc, const char **argv)
641 if (hits == samples) { 538 if (hits == samples) {
642 if (done) 539 if (done)
643 break; 540 break;
644 ret = poll(event_array, nr_poll, -1); 541 err = poll(event_array, nr_poll, -1);
645 waking++; 542 waking++;
646 } 543 }
647 544
@@ -677,6 +574,8 @@ static const struct option options[] = {
677 OPT_CALLBACK('e', "event", NULL, "event", 574 OPT_CALLBACK('e', "event", NULL, "event",
678 "event selector. use 'perf list' to list available events", 575 "event selector. use 'perf list' to list available events",
679 parse_events), 576 parse_events),
577 OPT_CALLBACK(0, "filter", NULL, "filter",
578 "event filter", parse_filter),
680 OPT_INTEGER('p', "pid", &target_pid, 579 OPT_INTEGER('p', "pid", &target_pid,
681 "record events on existing pid"), 580 "record events on existing pid"),
682 OPT_INTEGER('r', "realtime", &realtime_prio, 581 OPT_INTEGER('r', "realtime", &realtime_prio,
@@ -720,6 +619,8 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
720{ 619{
721 int counter; 620 int counter;
722 621
622 symbol__init(0);
623
723 argc = parse_options(argc, argv, options, record_usage, 624 argc = parse_options(argc, argv, options, record_usage,
724 PARSE_OPT_STOP_AT_NON_OPTION); 625 PARSE_OPT_STOP_AT_NON_OPTION);
725 if (!argc && target_pid == -1 && !system_wide) 626 if (!argc && target_pid == -1 && !system_wide)
@@ -731,6 +632,18 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
731 attrs[0].config = PERF_COUNT_HW_CPU_CYCLES; 632 attrs[0].config = PERF_COUNT_HW_CPU_CYCLES;
732 } 633 }
733 634
635 /*
636 * User specified count overrides default frequency.
637 */
638 if (default_interval)
639 freq = 0;
640 else if (freq) {
641 default_interval = freq;
642 } else {
643 fprintf(stderr, "frequency and count are zero, aborting\n");
644 exit(EXIT_FAILURE);
645 }
646
734 for (counter = 0; counter < nr_counters; counter++) { 647 for (counter = 0; counter < nr_counters; counter++) {
735 if (attrs[counter].sample_period) 648 if (attrs[counter].sample_period)
736 continue; 649 continue;