diff options
Diffstat (limited to 'tools/perf/builtin-record.c')
-rw-r--r-- | tools/perf/builtin-record.c | 197 |
1 files changed, 124 insertions, 73 deletions
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 319712a4e02b..515510ecc76a 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c | |||
@@ -32,6 +32,8 @@ | |||
32 | #include "util/parse-branch-options.h" | 32 | #include "util/parse-branch-options.h" |
33 | #include "util/parse-regs-options.h" | 33 | #include "util/parse-regs-options.h" |
34 | #include "util/llvm-utils.h" | 34 | #include "util/llvm-utils.h" |
35 | #include "util/bpf-loader.h" | ||
36 | #include "asm/bug.h" | ||
35 | 37 | ||
36 | #include <unistd.h> | 38 | #include <unistd.h> |
37 | #include <sched.h> | 39 | #include <sched.h> |
@@ -49,7 +51,9 @@ struct record { | |||
49 | const char *progname; | 51 | const char *progname; |
50 | int realtime_prio; | 52 | int realtime_prio; |
51 | bool no_buildid; | 53 | bool no_buildid; |
54 | bool no_buildid_set; | ||
52 | bool no_buildid_cache; | 55 | bool no_buildid_cache; |
56 | bool no_buildid_cache_set; | ||
53 | bool buildid_all; | 57 | bool buildid_all; |
54 | unsigned long long samples; | 58 | unsigned long long samples; |
55 | }; | 59 | }; |
@@ -320,7 +324,10 @@ try_again: | |||
320 | } else { | 324 | } else { |
321 | pr_err("failed to mmap with %d (%s)\n", errno, | 325 | pr_err("failed to mmap with %d (%s)\n", errno, |
322 | strerror_r(errno, msg, sizeof(msg))); | 326 | strerror_r(errno, msg, sizeof(msg))); |
323 | rc = -errno; | 327 | if (errno) |
328 | rc = -errno; | ||
329 | else | ||
330 | rc = -EINVAL; | ||
324 | } | 331 | } |
325 | goto out; | 332 | goto out; |
326 | } | 333 | } |
@@ -464,6 +471,29 @@ static void record__init_features(struct record *rec) | |||
464 | perf_header__clear_feat(&session->header, HEADER_STAT); | 471 | perf_header__clear_feat(&session->header, HEADER_STAT); |
465 | } | 472 | } |
466 | 473 | ||
474 | static void | ||
475 | record__finish_output(struct record *rec) | ||
476 | { | ||
477 | struct perf_data_file *file = &rec->file; | ||
478 | int fd = perf_data_file__fd(file); | ||
479 | |||
480 | if (file->is_pipe) | ||
481 | return; | ||
482 | |||
483 | rec->session->header.data_size += rec->bytes_written; | ||
484 | file->size = lseek(perf_data_file__fd(file), 0, SEEK_CUR); | ||
485 | |||
486 | if (!rec->no_buildid) { | ||
487 | process_buildids(rec); | ||
488 | |||
489 | if (rec->buildid_all) | ||
490 | dsos__hit_all(rec->session); | ||
491 | } | ||
492 | perf_session__write_header(rec->session, rec->evlist, fd, true); | ||
493 | |||
494 | return; | ||
495 | } | ||
496 | |||
467 | static volatile int workload_exec_errno; | 497 | static volatile int workload_exec_errno; |
468 | 498 | ||
469 | /* | 499 | /* |
@@ -482,6 +512,74 @@ static void workload_exec_failed_signal(int signo __maybe_unused, | |||
482 | 512 | ||
483 | static void snapshot_sig_handler(int sig); | 513 | static void snapshot_sig_handler(int sig); |
484 | 514 | ||
515 | static int record__synthesize(struct record *rec) | ||
516 | { | ||
517 | struct perf_session *session = rec->session; | ||
518 | struct machine *machine = &session->machines.host; | ||
519 | struct perf_data_file *file = &rec->file; | ||
520 | struct record_opts *opts = &rec->opts; | ||
521 | struct perf_tool *tool = &rec->tool; | ||
522 | int fd = perf_data_file__fd(file); | ||
523 | int err = 0; | ||
524 | |||
525 | if (file->is_pipe) { | ||
526 | err = perf_event__synthesize_attrs(tool, session, | ||
527 | process_synthesized_event); | ||
528 | if (err < 0) { | ||
529 | pr_err("Couldn't synthesize attrs.\n"); | ||
530 | goto out; | ||
531 | } | ||
532 | |||
533 | if (have_tracepoints(&rec->evlist->entries)) { | ||
534 | /* | ||
535 | * FIXME err <= 0 here actually means that | ||
536 | * there were no tracepoints so its not really | ||
537 | * an error, just that we don't need to | ||
538 | * synthesize anything. We really have to | ||
539 | * return this more properly and also | ||
540 | * propagate errors that now are calling die() | ||
541 | */ | ||
542 | err = perf_event__synthesize_tracing_data(tool, fd, rec->evlist, | ||
543 | process_synthesized_event); | ||
544 | if (err <= 0) { | ||
545 | pr_err("Couldn't record tracing data.\n"); | ||
546 | goto out; | ||
547 | } | ||
548 | rec->bytes_written += err; | ||
549 | } | ||
550 | } | ||
551 | |||
552 | if (rec->opts.full_auxtrace) { | ||
553 | err = perf_event__synthesize_auxtrace_info(rec->itr, tool, | ||
554 | session, process_synthesized_event); | ||
555 | if (err) | ||
556 | goto out; | ||
557 | } | ||
558 | |||
559 | err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event, | ||
560 | machine); | ||
561 | WARN_ONCE(err < 0, "Couldn't record kernel reference relocation symbol\n" | ||
562 | "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n" | ||
563 | "Check /proc/kallsyms permission or run as root.\n"); | ||
564 | |||
565 | err = perf_event__synthesize_modules(tool, process_synthesized_event, | ||
566 | machine); | ||
567 | WARN_ONCE(err < 0, "Couldn't record kernel module information.\n" | ||
568 | "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n" | ||
569 | "Check /proc/modules permission or run as root.\n"); | ||
570 | |||
571 | if (perf_guest) { | ||
572 | machines__process_guests(&session->machines, | ||
573 | perf_event__synthesize_guest_os, tool); | ||
574 | } | ||
575 | |||
576 | err = __machine__synthesize_threads(machine, tool, &opts->target, rec->evlist->threads, | ||
577 | process_synthesized_event, opts->sample_address, | ||
578 | opts->proc_map_timeout); | ||
579 | out: | ||
580 | return err; | ||
581 | } | ||
582 | |||
485 | static int __cmd_record(struct record *rec, int argc, const char **argv) | 583 | static int __cmd_record(struct record *rec, int argc, const char **argv) |
486 | { | 584 | { |
487 | int err; | 585 | int err; |
@@ -534,6 +632,16 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) | |||
534 | goto out_child; | 632 | goto out_child; |
535 | } | 633 | } |
536 | 634 | ||
635 | err = bpf__apply_obj_config(); | ||
636 | if (err) { | ||
637 | char errbuf[BUFSIZ]; | ||
638 | |||
639 | bpf__strerror_apply_obj_config(err, errbuf, sizeof(errbuf)); | ||
640 | pr_err("ERROR: Apply config to BPF failed: %s\n", | ||
641 | errbuf); | ||
642 | goto out_child; | ||
643 | } | ||
644 | |||
537 | /* | 645 | /* |
538 | * Normally perf_session__new would do this, but it doesn't have the | 646 | * Normally perf_session__new would do this, but it doesn't have the |
539 | * evlist. | 647 | * evlist. |
@@ -566,63 +674,8 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) | |||
566 | 674 | ||
567 | machine = &session->machines.host; | 675 | machine = &session->machines.host; |
568 | 676 | ||
569 | if (file->is_pipe) { | 677 | err = record__synthesize(rec); |
570 | err = perf_event__synthesize_attrs(tool, session, | ||
571 | process_synthesized_event); | ||
572 | if (err < 0) { | ||
573 | pr_err("Couldn't synthesize attrs.\n"); | ||
574 | goto out_child; | ||
575 | } | ||
576 | |||
577 | if (have_tracepoints(&rec->evlist->entries)) { | ||
578 | /* | ||
579 | * FIXME err <= 0 here actually means that | ||
580 | * there were no tracepoints so its not really | ||
581 | * an error, just that we don't need to | ||
582 | * synthesize anything. We really have to | ||
583 | * return this more properly and also | ||
584 | * propagate errors that now are calling die() | ||
585 | */ | ||
586 | err = perf_event__synthesize_tracing_data(tool, fd, rec->evlist, | ||
587 | process_synthesized_event); | ||
588 | if (err <= 0) { | ||
589 | pr_err("Couldn't record tracing data.\n"); | ||
590 | goto out_child; | ||
591 | } | ||
592 | rec->bytes_written += err; | ||
593 | } | ||
594 | } | ||
595 | |||
596 | if (rec->opts.full_auxtrace) { | ||
597 | err = perf_event__synthesize_auxtrace_info(rec->itr, tool, | ||
598 | session, process_synthesized_event); | ||
599 | if (err) | ||
600 | goto out_delete_session; | ||
601 | } | ||
602 | |||
603 | err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event, | ||
604 | machine); | ||
605 | if (err < 0) | ||
606 | pr_err("Couldn't record kernel reference relocation symbol\n" | ||
607 | "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n" | ||
608 | "Check /proc/kallsyms permission or run as root.\n"); | ||
609 | |||
610 | err = perf_event__synthesize_modules(tool, process_synthesized_event, | ||
611 | machine); | ||
612 | if (err < 0) | 678 | if (err < 0) |
613 | pr_err("Couldn't record kernel module information.\n" | ||
614 | "Symbol resolution may be skewed if relocation was used (e.g. kexec).\n" | ||
615 | "Check /proc/modules permission or run as root.\n"); | ||
616 | |||
617 | if (perf_guest) { | ||
618 | machines__process_guests(&session->machines, | ||
619 | perf_event__synthesize_guest_os, tool); | ||
620 | } | ||
621 | |||
622 | err = __machine__synthesize_threads(machine, tool, &opts->target, rec->evlist->threads, | ||
623 | process_synthesized_event, opts->sample_address, | ||
624 | opts->proc_map_timeout); | ||
625 | if (err != 0) | ||
626 | goto out_child; | 679 | goto out_child; |
627 | 680 | ||
628 | if (rec->realtime_prio) { | 681 | if (rec->realtime_prio) { |
@@ -758,18 +811,8 @@ out_child: | |||
758 | /* this will be recalculated during process_buildids() */ | 811 | /* this will be recalculated during process_buildids() */ |
759 | rec->samples = 0; | 812 | rec->samples = 0; |
760 | 813 | ||
761 | if (!err && !file->is_pipe) { | 814 | if (!err) |
762 | rec->session->header.data_size += rec->bytes_written; | 815 | record__finish_output(rec); |
763 | file->size = lseek(perf_data_file__fd(file), 0, SEEK_CUR); | ||
764 | |||
765 | if (!rec->no_buildid) { | ||
766 | process_buildids(rec); | ||
767 | |||
768 | if (rec->buildid_all) | ||
769 | dsos__hit_all(rec->session); | ||
770 | } | ||
771 | perf_session__write_header(rec->session, rec->evlist, fd, true); | ||
772 | } | ||
773 | 816 | ||
774 | if (!err && !quiet) { | 817 | if (!err && !quiet) { |
775 | char samples[128]; | 818 | char samples[128]; |
@@ -1097,10 +1140,12 @@ struct option __record_options[] = { | |||
1097 | OPT_BOOLEAN('P', "period", &record.opts.period, "Record the sample period"), | 1140 | OPT_BOOLEAN('P', "period", &record.opts.period, "Record the sample period"), |
1098 | OPT_BOOLEAN('n', "no-samples", &record.opts.no_samples, | 1141 | OPT_BOOLEAN('n', "no-samples", &record.opts.no_samples, |
1099 | "don't sample"), | 1142 | "don't sample"), |
1100 | OPT_BOOLEAN('N', "no-buildid-cache", &record.no_buildid_cache, | 1143 | OPT_BOOLEAN_SET('N', "no-buildid-cache", &record.no_buildid_cache, |
1101 | "do not update the buildid cache"), | 1144 | &record.no_buildid_cache_set, |
1102 | OPT_BOOLEAN('B', "no-buildid", &record.no_buildid, | 1145 | "do not update the buildid cache"), |
1103 | "do not collect buildids in perf.data"), | 1146 | OPT_BOOLEAN_SET('B', "no-buildid", &record.no_buildid, |
1147 | &record.no_buildid_set, | ||
1148 | "do not collect buildids in perf.data"), | ||
1104 | OPT_CALLBACK('G', "cgroup", &record.evlist, "name", | 1149 | OPT_CALLBACK('G', "cgroup", &record.evlist, "name", |
1105 | "monitor event in cgroup name only", | 1150 | "monitor event in cgroup name only", |
1106 | parse_cgroups), | 1151 | parse_cgroups), |
@@ -1136,6 +1181,12 @@ struct option __record_options[] = { | |||
1136 | "per thread proc mmap processing timeout in ms"), | 1181 | "per thread proc mmap processing timeout in ms"), |
1137 | OPT_BOOLEAN(0, "switch-events", &record.opts.record_switch_events, | 1182 | OPT_BOOLEAN(0, "switch-events", &record.opts.record_switch_events, |
1138 | "Record context switch events"), | 1183 | "Record context switch events"), |
1184 | OPT_BOOLEAN_FLAG(0, "all-kernel", &record.opts.all_kernel, | ||
1185 | "Configure all used events to run in kernel space.", | ||
1186 | PARSE_OPT_EXCLUSIVE), | ||
1187 | OPT_BOOLEAN_FLAG(0, "all-user", &record.opts.all_user, | ||
1188 | "Configure all used events to run in user space.", | ||
1189 | PARSE_OPT_EXCLUSIVE), | ||
1139 | OPT_STRING(0, "clang-path", &llvm_param.clang_path, "clang path", | 1190 | OPT_STRING(0, "clang-path", &llvm_param.clang_path, "clang path", |
1140 | "clang binary to use for compiling BPF scriptlets"), | 1191 | "clang binary to use for compiling BPF scriptlets"), |
1141 | OPT_STRING(0, "clang-opt", &llvm_param.clang_opt, "clang options", | 1192 | OPT_STRING(0, "clang-opt", &llvm_param.clang_opt, "clang options", |