diff options
Diffstat (limited to 'tools')
-rw-r--r-- | tools/perf/builtin-record.c | 158 |
1 files changed, 109 insertions, 49 deletions
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 479ff2a038fc..7b8b891d4d56 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c | |||
@@ -71,19 +71,23 @@ static void advance_output(struct perf_record *rec, size_t size) | |||
71 | rec->bytes_written += size; | 71 | rec->bytes_written += size; |
72 | } | 72 | } |
73 | 73 | ||
74 | static void write_output(struct perf_record *rec, void *buf, size_t size) | 74 | static int write_output(struct perf_record *rec, void *buf, size_t size) |
75 | { | 75 | { |
76 | while (size) { | 76 | while (size) { |
77 | int ret = write(rec->output, buf, size); | 77 | int ret = write(rec->output, buf, size); |
78 | 78 | ||
79 | if (ret < 0) | 79 | if (ret < 0) { |
80 | die("failed to write"); | 80 | pr_err("failed to write\n"); |
81 | return -1; | ||
82 | } | ||
81 | 83 | ||
82 | size -= ret; | 84 | size -= ret; |
83 | buf += ret; | 85 | buf += ret; |
84 | 86 | ||
85 | rec->bytes_written += ret; | 87 | rec->bytes_written += ret; |
86 | } | 88 | } |
89 | |||
90 | return 0; | ||
87 | } | 91 | } |
88 | 92 | ||
89 | static int process_synthesized_event(struct perf_tool *tool, | 93 | static int process_synthesized_event(struct perf_tool *tool, |
@@ -92,11 +96,13 @@ static int process_synthesized_event(struct perf_tool *tool, | |||
92 | struct machine *machine __used) | 96 | struct machine *machine __used) |
93 | { | 97 | { |
94 | struct perf_record *rec = container_of(tool, struct perf_record, tool); | 98 | struct perf_record *rec = container_of(tool, struct perf_record, tool); |
95 | write_output(rec, event, event->header.size); | 99 | if (write_output(rec, event, event->header.size) < 0) |
100 | return -1; | ||
101 | |||
96 | return 0; | 102 | return 0; |
97 | } | 103 | } |
98 | 104 | ||
99 | static void perf_record__mmap_read(struct perf_record *rec, | 105 | static int perf_record__mmap_read(struct perf_record *rec, |
100 | struct perf_mmap *md) | 106 | struct perf_mmap *md) |
101 | { | 107 | { |
102 | unsigned int head = perf_mmap__read_head(md); | 108 | unsigned int head = perf_mmap__read_head(md); |
@@ -104,9 +110,10 @@ static void perf_record__mmap_read(struct perf_record *rec, | |||
104 | unsigned char *data = md->base + rec->page_size; | 110 | unsigned char *data = md->base + rec->page_size; |
105 | unsigned long size; | 111 | unsigned long size; |
106 | void *buf; | 112 | void *buf; |
113 | int rc = 0; | ||
107 | 114 | ||
108 | if (old == head) | 115 | if (old == head) |
109 | return; | 116 | return 0; |
110 | 117 | ||
111 | rec->samples++; | 118 | rec->samples++; |
112 | 119 | ||
@@ -117,17 +124,26 @@ static void perf_record__mmap_read(struct perf_record *rec, | |||
117 | size = md->mask + 1 - (old & md->mask); | 124 | size = md->mask + 1 - (old & md->mask); |
118 | old += size; | 125 | old += size; |
119 | 126 | ||
120 | write_output(rec, buf, size); | 127 | if (write_output(rec, buf, size) < 0) { |
128 | rc = -1; | ||
129 | goto out; | ||
130 | } | ||
121 | } | 131 | } |
122 | 132 | ||
123 | buf = &data[old & md->mask]; | 133 | buf = &data[old & md->mask]; |
124 | size = head - old; | 134 | size = head - old; |
125 | old += size; | 135 | old += size; |
126 | 136 | ||
127 | write_output(rec, buf, size); | 137 | if (write_output(rec, buf, size) < 0) { |
138 | rc = -1; | ||
139 | goto out; | ||
140 | } | ||
128 | 141 | ||
129 | md->prev = old; | 142 | md->prev = old; |
130 | perf_mmap__write_tail(md, old); | 143 | perf_mmap__write_tail(md, old); |
144 | |||
145 | out: | ||
146 | return rc; | ||
131 | } | 147 | } |
132 | 148 | ||
133 | static volatile int done = 0; | 149 | static volatile int done = 0; |
@@ -183,12 +199,13 @@ static bool perf_evlist__equal(struct perf_evlist *evlist, | |||
183 | return true; | 199 | return true; |
184 | } | 200 | } |
185 | 201 | ||
186 | static void perf_record__open(struct perf_record *rec) | 202 | static int perf_record__open(struct perf_record *rec) |
187 | { | 203 | { |
188 | struct perf_evsel *pos; | 204 | struct perf_evsel *pos; |
189 | struct perf_evlist *evlist = rec->evlist; | 205 | struct perf_evlist *evlist = rec->evlist; |
190 | struct perf_session *session = rec->session; | 206 | struct perf_session *session = rec->session; |
191 | struct perf_record_opts *opts = &rec->opts; | 207 | struct perf_record_opts *opts = &rec->opts; |
208 | int rc = 0; | ||
192 | 209 | ||
193 | perf_evlist__config_attrs(evlist, opts); | 210 | perf_evlist__config_attrs(evlist, opts); |
194 | 211 | ||
@@ -222,10 +239,13 @@ try_again: | |||
222 | 239 | ||
223 | if (err == EPERM || err == EACCES) { | 240 | if (err == EPERM || err == EACCES) { |
224 | ui__error_paranoid(); | 241 | ui__error_paranoid(); |
225 | exit(EXIT_FAILURE); | 242 | rc = -err; |
243 | goto out; | ||
226 | } else if (err == ENODEV && opts->target.cpu_list) { | 244 | } else if (err == ENODEV && opts->target.cpu_list) { |
227 | die("No such device - did you specify" | 245 | pr_err("No such device - did you specify" |
228 | " an out-of-range profile CPU?\n"); | 246 | " an out-of-range profile CPU?\n"); |
247 | rc = -err; | ||
248 | goto out; | ||
229 | } else if (err == EINVAL) { | 249 | } else if (err == EINVAL) { |
230 | if (!opts->exclude_guest_missing && | 250 | if (!opts->exclude_guest_missing && |
231 | (attr->exclude_guest || attr->exclude_host)) { | 251 | (attr->exclude_guest || attr->exclude_host)) { |
@@ -272,7 +292,8 @@ try_again: | |||
272 | if (err == ENOENT) { | 292 | if (err == ENOENT) { |
273 | ui__error("The %s event is not supported.\n", | 293 | ui__error("The %s event is not supported.\n", |
274 | perf_evsel__name(pos)); | 294 | perf_evsel__name(pos)); |
275 | exit(EXIT_FAILURE); | 295 | rc = -err; |
296 | goto out; | ||
276 | } | 297 | } |
277 | 298 | ||
278 | printf("\n"); | 299 | printf("\n"); |
@@ -280,34 +301,46 @@ try_again: | |||
280 | err, strerror(err)); | 301 | err, strerror(err)); |
281 | 302 | ||
282 | #if defined(__i386__) || defined(__x86_64__) | 303 | #if defined(__i386__) || defined(__x86_64__) |
283 | if (attr->type == PERF_TYPE_HARDWARE && err == EOPNOTSUPP) | 304 | if (attr->type == PERF_TYPE_HARDWARE && |
284 | die("No hardware sampling interrupt available." | 305 | err == EOPNOTSUPP) { |
285 | " No APIC? If so then you can boot the kernel" | 306 | pr_err("No hardware sampling interrupt available." |
286 | " with the \"lapic\" boot parameter to" | 307 | " No APIC? If so then you can boot the kernel" |
287 | " force-enable it.\n"); | 308 | " with the \"lapic\" boot parameter to" |
309 | " force-enable it.\n"); | ||
310 | rc = -err; | ||
311 | goto out; | ||
312 | } | ||
288 | #endif | 313 | #endif |
289 | 314 | ||
290 | die("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); | 315 | pr_err("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); |
316 | rc = -err; | ||
317 | goto out; | ||
291 | } | 318 | } |
292 | } | 319 | } |
293 | 320 | ||
294 | if (perf_evlist__set_filters(evlist)) { | 321 | if (perf_evlist__set_filters(evlist)) { |
295 | error("failed to set filter with %d (%s)\n", errno, | 322 | error("failed to set filter with %d (%s)\n", errno, |
296 | strerror(errno)); | 323 | strerror(errno)); |
297 | exit(-1); | 324 | rc = -1; |
325 | goto out; | ||
298 | } | 326 | } |
299 | 327 | ||
300 | if (perf_evlist__mmap(evlist, opts->mmap_pages, false) < 0) { | 328 | if (perf_evlist__mmap(evlist, opts->mmap_pages, false) < 0) { |
301 | if (errno == EPERM) | 329 | if (errno == EPERM) { |
302 | die("Permission error mapping pages.\n" | 330 | pr_err("Permission error mapping pages.\n" |
303 | "Consider increasing " | 331 | "Consider increasing " |
304 | "/proc/sys/kernel/perf_event_mlock_kb,\n" | 332 | "/proc/sys/kernel/perf_event_mlock_kb,\n" |
305 | "or try again with a smaller value of -m/--mmap_pages.\n" | 333 | "or try again with a smaller value of -m/--mmap_pages.\n" |
306 | "(current value: %d)\n", opts->mmap_pages); | 334 | "(current value: %d)\n", opts->mmap_pages); |
307 | else if (!is_power_of_2(opts->mmap_pages)) | 335 | rc = -errno; |
308 | die("--mmap_pages/-m value must be a power of two."); | 336 | } else if (!is_power_of_2(opts->mmap_pages)) { |
309 | 337 | pr_err("--mmap_pages/-m value must be a power of two."); | |
310 | die("failed to mmap with %d (%s)\n", errno, strerror(errno)); | 338 | rc = -EINVAL; |
339 | } else { | ||
340 | pr_err("failed to mmap with %d (%s)\n", errno, strerror(errno)); | ||
341 | rc = -errno; | ||
342 | } | ||
343 | goto out; | ||
311 | } | 344 | } |
312 | 345 | ||
313 | if (rec->file_new) | 346 | if (rec->file_new) |
@@ -315,11 +348,14 @@ try_again: | |||
315 | else { | 348 | else { |
316 | if (!perf_evlist__equal(session->evlist, evlist)) { | 349 | if (!perf_evlist__equal(session->evlist, evlist)) { |
317 | fprintf(stderr, "incompatible append\n"); | 350 | fprintf(stderr, "incompatible append\n"); |
318 | exit(-1); | 351 | rc = -1; |
352 | goto out; | ||
319 | } | 353 | } |
320 | } | 354 | } |
321 | 355 | ||
322 | perf_session__set_id_hdr_size(session); | 356 | perf_session__set_id_hdr_size(session); |
357 | out: | ||
358 | return rc; | ||
323 | } | 359 | } |
324 | 360 | ||
325 | static int process_buildids(struct perf_record *rec) | 361 | static int process_buildids(struct perf_record *rec) |
@@ -335,10 +371,13 @@ static int process_buildids(struct perf_record *rec) | |||
335 | size, &build_id__mark_dso_hit_ops); | 371 | size, &build_id__mark_dso_hit_ops); |
336 | } | 372 | } |
337 | 373 | ||
338 | static void perf_record__exit(int status __used, void *arg) | 374 | static void perf_record__exit(int status, void *arg) |
339 | { | 375 | { |
340 | struct perf_record *rec = arg; | 376 | struct perf_record *rec = arg; |
341 | 377 | ||
378 | if (status != 0) | ||
379 | return; | ||
380 | |||
342 | if (!rec->opts.pipe_output) { | 381 | if (!rec->opts.pipe_output) { |
343 | rec->session->header.data_size += rec->bytes_written; | 382 | rec->session->header.data_size += rec->bytes_written; |
344 | 383 | ||
@@ -393,17 +432,26 @@ static struct perf_event_header finished_round_event = { | |||
393 | .type = PERF_RECORD_FINISHED_ROUND, | 432 | .type = PERF_RECORD_FINISHED_ROUND, |
394 | }; | 433 | }; |
395 | 434 | ||
396 | static void perf_record__mmap_read_all(struct perf_record *rec) | 435 | static int perf_record__mmap_read_all(struct perf_record *rec) |
397 | { | 436 | { |
398 | int i; | 437 | int i; |
438 | int rc = 0; | ||
399 | 439 | ||
400 | for (i = 0; i < rec->evlist->nr_mmaps; i++) { | 440 | for (i = 0; i < rec->evlist->nr_mmaps; i++) { |
401 | if (rec->evlist->mmap[i].base) | 441 | if (rec->evlist->mmap[i].base) { |
402 | perf_record__mmap_read(rec, &rec->evlist->mmap[i]); | 442 | if (perf_record__mmap_read(rec, &rec->evlist->mmap[i]) != 0) { |
443 | rc = -1; | ||
444 | goto out; | ||
445 | } | ||
446 | } | ||
403 | } | 447 | } |
404 | 448 | ||
405 | if (perf_header__has_feat(&rec->session->header, HEADER_TRACING_DATA)) | 449 | if (perf_header__has_feat(&rec->session->header, HEADER_TRACING_DATA)) |
406 | write_output(rec, &finished_round_event, sizeof(finished_round_event)); | 450 | rc = write_output(rec, &finished_round_event, |
451 | sizeof(finished_round_event)); | ||
452 | |||
453 | out: | ||
454 | return rc; | ||
407 | } | 455 | } |
408 | 456 | ||
409 | static int __cmd_record(struct perf_record *rec, int argc, const char **argv) | 457 | static int __cmd_record(struct perf_record *rec, int argc, const char **argv) |
@@ -463,7 +511,7 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv) | |||
463 | output = open(output_name, flags, S_IRUSR | S_IWUSR); | 511 | output = open(output_name, flags, S_IRUSR | S_IWUSR); |
464 | if (output < 0) { | 512 | if (output < 0) { |
465 | perror("failed to create output file"); | 513 | perror("failed to create output file"); |
466 | exit(-1); | 514 | return -1; |
467 | } | 515 | } |
468 | 516 | ||
469 | rec->output = output; | 517 | rec->output = output; |
@@ -503,7 +551,10 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv) | |||
503 | } | 551 | } |
504 | } | 552 | } |
505 | 553 | ||
506 | perf_record__open(rec); | 554 | if (perf_record__open(rec) != 0) { |
555 | err = -1; | ||
556 | goto out_delete_session; | ||
557 | } | ||
507 | 558 | ||
508 | /* | 559 | /* |
509 | * perf_session__delete(session) will be called at perf_record__exit() | 560 | * perf_session__delete(session) will be called at perf_record__exit() |
@@ -513,19 +564,20 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv) | |||
513 | if (opts->pipe_output) { | 564 | if (opts->pipe_output) { |
514 | err = perf_header__write_pipe(output); | 565 | err = perf_header__write_pipe(output); |
515 | if (err < 0) | 566 | if (err < 0) |
516 | return err; | 567 | goto out_delete_session; |
517 | } else if (rec->file_new) { | 568 | } else if (rec->file_new) { |
518 | err = perf_session__write_header(session, evsel_list, | 569 | err = perf_session__write_header(session, evsel_list, |
519 | output, false); | 570 | output, false); |
520 | if (err < 0) | 571 | if (err < 0) |
521 | return err; | 572 | goto out_delete_session; |
522 | } | 573 | } |
523 | 574 | ||
524 | if (!rec->no_buildid | 575 | if (!rec->no_buildid |
525 | && !perf_header__has_feat(&session->header, HEADER_BUILD_ID)) { | 576 | && !perf_header__has_feat(&session->header, HEADER_BUILD_ID)) { |
526 | pr_err("Couldn't generate buildids. " | 577 | pr_err("Couldn't generate buildids. " |
527 | "Use --no-buildid to profile anyway.\n"); | 578 | "Use --no-buildid to profile anyway.\n"); |
528 | return -1; | 579 | err = -1; |
580 | goto out_delete_session; | ||
529 | } | 581 | } |
530 | 582 | ||
531 | rec->post_processing_offset = lseek(output, 0, SEEK_CUR); | 583 | rec->post_processing_offset = lseek(output, 0, SEEK_CUR); |
@@ -533,7 +585,8 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv) | |||
533 | machine = perf_session__find_host_machine(session); | 585 | machine = perf_session__find_host_machine(session); |
534 | if (!machine) { | 586 | if (!machine) { |
535 | pr_err("Couldn't find native kernel information.\n"); | 587 | pr_err("Couldn't find native kernel information.\n"); |
536 | return -1; | 588 | err = -1; |
589 | goto out_delete_session; | ||
537 | } | 590 | } |
538 | 591 | ||
539 | if (opts->pipe_output) { | 592 | if (opts->pipe_output) { |
@@ -541,14 +594,14 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv) | |||
541 | process_synthesized_event); | 594 | process_synthesized_event); |
542 | if (err < 0) { | 595 | if (err < 0) { |
543 | pr_err("Couldn't synthesize attrs.\n"); | 596 | pr_err("Couldn't synthesize attrs.\n"); |
544 | return err; | 597 | goto out_delete_session; |
545 | } | 598 | } |
546 | 599 | ||
547 | err = perf_event__synthesize_event_types(tool, process_synthesized_event, | 600 | err = perf_event__synthesize_event_types(tool, process_synthesized_event, |
548 | machine); | 601 | machine); |
549 | if (err < 0) { | 602 | if (err < 0) { |
550 | pr_err("Couldn't synthesize event_types.\n"); | 603 | pr_err("Couldn't synthesize event_types.\n"); |
551 | return err; | 604 | goto out_delete_session; |
552 | } | 605 | } |
553 | 606 | ||
554 | if (have_tracepoints(&evsel_list->entries)) { | 607 | if (have_tracepoints(&evsel_list->entries)) { |
@@ -564,7 +617,7 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv) | |||
564 | process_synthesized_event); | 617 | process_synthesized_event); |
565 | if (err <= 0) { | 618 | if (err <= 0) { |
566 | pr_err("Couldn't record tracing data.\n"); | 619 | pr_err("Couldn't record tracing data.\n"); |
567 | return err; | 620 | goto out_delete_session; |
568 | } | 621 | } |
569 | advance_output(rec, err); | 622 | advance_output(rec, err); |
570 | } | 623 | } |
@@ -592,20 +645,24 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv) | |||
592 | perf_event__synthesize_guest_os); | 645 | perf_event__synthesize_guest_os); |
593 | 646 | ||
594 | if (!opts->target.system_wide) | 647 | if (!opts->target.system_wide) |
595 | perf_event__synthesize_thread_map(tool, evsel_list->threads, | 648 | err = perf_event__synthesize_thread_map(tool, evsel_list->threads, |
596 | process_synthesized_event, | 649 | process_synthesized_event, |
597 | machine); | 650 | machine); |
598 | else | 651 | else |
599 | perf_event__synthesize_threads(tool, process_synthesized_event, | 652 | err = perf_event__synthesize_threads(tool, process_synthesized_event, |
600 | machine); | 653 | machine); |
601 | 654 | ||
655 | if (err != 0) | ||
656 | goto out_delete_session; | ||
657 | |||
602 | if (rec->realtime_prio) { | 658 | if (rec->realtime_prio) { |
603 | struct sched_param param; | 659 | struct sched_param param; |
604 | 660 | ||
605 | param.sched_priority = rec->realtime_prio; | 661 | param.sched_priority = rec->realtime_prio; |
606 | if (sched_setscheduler(0, SCHED_FIFO, ¶m)) { | 662 | if (sched_setscheduler(0, SCHED_FIFO, ¶m)) { |
607 | pr_err("Could not set realtime priority.\n"); | 663 | pr_err("Could not set realtime priority.\n"); |
608 | exit(-1); | 664 | err = -1; |
665 | goto out_delete_session; | ||
609 | } | 666 | } |
610 | } | 667 | } |
611 | 668 | ||
@@ -620,7 +677,10 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv) | |||
620 | for (;;) { | 677 | for (;;) { |
621 | int hits = rec->samples; | 678 | int hits = rec->samples; |
622 | 679 | ||
623 | perf_record__mmap_read_all(rec); | 680 | if (perf_record__mmap_read_all(rec) < 0) { |
681 | err = -1; | ||
682 | goto out_delete_session; | ||
683 | } | ||
624 | 684 | ||
625 | if (hits == rec->samples) { | 685 | if (hits == rec->samples) { |
626 | if (done) | 686 | if (done) |