diff options
| -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) |
