diff options
Diffstat (limited to 'tools/perf')
110 files changed, 999 insertions, 4107 deletions
diff --git a/tools/perf/Documentation/perf-annotate.txt b/tools/perf/Documentation/perf-annotate.txt index e8c972f89357..1b5042f134a8 100644 --- a/tools/perf/Documentation/perf-annotate.txt +++ b/tools/perf/Documentation/perf-annotate.txt @@ -112,6 +112,12 @@ OPTIONS --objdump=<path>:: Path to objdump binary. +--prefix=PREFIX:: +--prefix-strip=N:: + Remove first N entries from source file path names in executables + and add PREFIX. This allows to display source code compiled on systems + with different file system layout. + --skip-missing:: Skip symbols that cannot be annotated. diff --git a/tools/perf/Documentation/perf-kvm.txt b/tools/perf/Documentation/perf-kvm.txt index 6a5bb2b17039..cf95baef7b61 100644 --- a/tools/perf/Documentation/perf-kvm.txt +++ b/tools/perf/Documentation/perf-kvm.txt @@ -68,10 +68,11 @@ OPTIONS ------- -i:: --input=<path>:: - Input file name. + Input file name, for the 'report', 'diff' and 'buildid-list' subcommands. -o:: --output=<path>:: - Output file name. + Output file name, for the 'record' subcommand. Doesn't work with 'report', + just redirect the output to a file when using 'report'. --host:: Collect host side performance profile. --guest:: diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt index 8dbe2119686a..db61f16ffa56 100644 --- a/tools/perf/Documentation/perf-report.txt +++ b/tools/perf/Documentation/perf-report.txt @@ -367,6 +367,12 @@ OPTIONS --objdump=<path>:: Path to objdump binary. +--prefix=PREFIX:: +--prefix-strip=N:: + Remove first N entries from source file path names in executables + and add PREFIX. This allows to display source code compiled on systems + with different file system layout. + --group:: Show event group information together. It forces group output also if there are no groups defined in data file. diff --git a/tools/perf/Documentation/perf-sched.txt b/tools/perf/Documentation/perf-sched.txt index 63f938b887dd..5fbe42bd599b 100644 --- a/tools/perf/Documentation/perf-sched.txt +++ b/tools/perf/Documentation/perf-sched.txt @@ -110,6 +110,10 @@ OPTIONS for 'perf sched timehist' --max-stack:: Maximum number of functions to display in backtrace, default 5. +-C=:: +--cpu=:: + Only show events for the given CPU(s) (comma separated list). + -p=:: --pid=:: Only show events for given process ID (comma separated list). diff --git a/tools/perf/Documentation/perf-top.txt b/tools/perf/Documentation/perf-top.txt index 5596129a71cf..324b6b53c86b 100644 --- a/tools/perf/Documentation/perf-top.txt +++ b/tools/perf/Documentation/perf-top.txt @@ -158,6 +158,12 @@ Default is to monitor all CPUS. -M:: --disassembler-style=:: Set disassembler style for objdump. +--prefix=PREFIX:: +--prefix-strip=N:: + Remove first N entries from source file path names in executables + and add PREFIX. This allows to display source code compiled on systems + with different file system layout. + --source:: Interleave source code with assembly code. Enabled by default, disable with --no-source. diff --git a/tools/perf/MANIFEST b/tools/perf/MANIFEST index 4934edb5adfd..5d7b947320fb 100644 --- a/tools/perf/MANIFEST +++ b/tools/perf/MANIFEST @@ -7,6 +7,7 @@ tools/lib/traceevent tools/lib/api tools/lib/bpf tools/lib/subcmd +tools/lib/perf tools/lib/argv_split.c tools/lib/ctype.c tools/lib/hweight.c diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config index c90f4146e5a2..80e55e796be9 100644 --- a/tools/perf/Makefile.config +++ b/tools/perf/Makefile.config @@ -286,7 +286,7 @@ ifeq ($(DEBUG),0) endif endif -INC_FLAGS += -I$(src-perf)/lib/include +INC_FLAGS += -I$(srctree)/tools/lib/perf/include INC_FLAGS += -I$(src-perf)/util/include INC_FLAGS += -I$(src-perf)/arch/$(SRCARCH)/include INC_FLAGS += -I$(srctree)/tools/include/ diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index eae5d5e95952..3eda9d4b88e7 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf @@ -230,7 +230,7 @@ LIB_DIR = $(srctree)/tools/lib/api/ TRACE_EVENT_DIR = $(srctree)/tools/lib/traceevent/ BPF_DIR = $(srctree)/tools/lib/bpf/ SUBCMD_DIR = $(srctree)/tools/lib/subcmd/ -LIBPERF_DIR = $(srctree)/tools/perf/lib/ +LIBPERF_DIR = $(srctree)/tools/lib/perf/ # Set FEATURE_TESTS to 'all' so all possible feature checkers are executed. # Without this setting the output feature dump file misses some features, for diff --git a/tools/perf/arch/arm/tests/regs_load.S b/tools/perf/arch/arm/tests/regs_load.S index 6e2495cc4517..4284307d7822 100644 --- a/tools/perf/arch/arm/tests/regs_load.S +++ b/tools/perf/arch/arm/tests/regs_load.S @@ -37,7 +37,7 @@ .text .type perf_regs_load,%function -ENTRY(perf_regs_load) +SYM_FUNC_START(perf_regs_load) str r0, [r0, #R0] str r1, [r0, #R1] str r2, [r0, #R2] @@ -56,4 +56,4 @@ ENTRY(perf_regs_load) str lr, [r0, #PC] // store pc as lr in order to skip the call // to this function mov pc, lr -ENDPROC(perf_regs_load) +SYM_FUNC_END(perf_regs_load) diff --git a/tools/perf/arch/arm64/tests/regs_load.S b/tools/perf/arch/arm64/tests/regs_load.S index 07042511dca9..d49de40b6818 100644 --- a/tools/perf/arch/arm64/tests/regs_load.S +++ b/tools/perf/arch/arm64/tests/regs_load.S @@ -7,7 +7,7 @@ #define LDR_REG(r) ldr x##r, [x0, 8 * r] #define SP (8 * 31) #define PC (8 * 32) -ENTRY(perf_regs_load) +SYM_FUNC_START(perf_regs_load) STR_REG(0) STR_REG(1) STR_REG(2) @@ -44,4 +44,4 @@ ENTRY(perf_regs_load) str x30, [x0, #PC] LDR_REG(1) ret -ENDPROC(perf_regs_load) +SYM_FUNC_END(perf_regs_load) diff --git a/tools/perf/arch/x86/tests/regs_load.S b/tools/perf/arch/x86/tests/regs_load.S index bbe5a0d16e51..80f14f52e3f6 100644 --- a/tools/perf/arch/x86/tests/regs_load.S +++ b/tools/perf/arch/x86/tests/regs_load.S @@ -28,7 +28,7 @@ .text #ifdef HAVE_ARCH_X86_64_SUPPORT -ENTRY(perf_regs_load) +SYM_FUNC_START(perf_regs_load) movq %rax, AX(%rdi) movq %rbx, BX(%rdi) movq %rcx, CX(%rdi) @@ -60,9 +60,9 @@ ENTRY(perf_regs_load) movq %r14, R14(%rdi) movq %r15, R15(%rdi) ret -ENDPROC(perf_regs_load) +SYM_FUNC_END(perf_regs_load) #else -ENTRY(perf_regs_load) +SYM_FUNC_START(perf_regs_load) push %edi movl 8(%esp), %edi movl %eax, AX(%edi) @@ -88,7 +88,7 @@ ENTRY(perf_regs_load) movl $0, FS(%edi) movl $0, GS(%edi) ret -ENDPROC(perf_regs_load) +SYM_FUNC_END(perf_regs_load) #endif /* diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 5898662bc8fb..ff61795a4d13 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -535,6 +535,10 @@ int cmd_annotate(int argc, const char **argv) "Display raw encoding of assembly instructions (default)"), OPT_STRING('M', "disassembler-style", &annotate.opts.disassembler_style, "disassembler style", "Specify disassembler style (e.g. -M intel for intel syntax)"), + OPT_STRING(0, "prefix", &annotate.opts.prefix, "prefix", + "Add prefix to source file path names in programs (with --prefix-strip)"), + OPT_STRING(0, "prefix-strip", &annotate.opts.prefix_strip, "N", + "Strip first N entries of source file path name in programs (with --prefix)"), OPT_STRING(0, "objdump", &annotate.opts.objdump_path, "path", "objdump binary to use for disassembly and annotations"), OPT_BOOLEAN(0, "group", &symbol_conf.event_group, @@ -574,6 +578,9 @@ int cmd_annotate(int argc, const char **argv) annotate.sym_hist_filter = argv[0]; } + if (annotate_check_args(&annotate.opts) < 0) + return -EINVAL; + if (symbol_conf.show_nr_samples && annotate.use_gtk) { pr_err("--show-nr-samples is not available in --gtk mode at this time\n"); return ret; diff --git a/tools/perf/builtin-c2c.c b/tools/perf/builtin-c2c.c index e69f44941aad..246ac0b4d54f 100644 --- a/tools/perf/builtin-c2c.c +++ b/tools/perf/builtin-c2c.c @@ -595,8 +595,8 @@ tot_hitm_cmp(struct perf_hpp_fmt *fmt __maybe_unused, { struct c2c_hist_entry *c2c_left; struct c2c_hist_entry *c2c_right; - unsigned int tot_hitm_left; - unsigned int tot_hitm_right; + uint64_t tot_hitm_left; + uint64_t tot_hitm_right; c2c_left = container_of(left, struct c2c_hist_entry, he); c2c_right = container_of(right, struct c2c_hist_entry, he); @@ -629,7 +629,8 @@ __f ## _cmp(struct perf_hpp_fmt *fmt __maybe_unused, \ \ c2c_left = container_of(left, struct c2c_hist_entry, he); \ c2c_right = container_of(right, struct c2c_hist_entry, he); \ - return c2c_left->stats.__f - c2c_right->stats.__f; \ + return (uint64_t) c2c_left->stats.__f - \ + (uint64_t) c2c_right->stats.__f; \ } #define STAT_FN(__f) \ @@ -682,7 +683,8 @@ ld_llcmiss_cmp(struct perf_hpp_fmt *fmt __maybe_unused, c2c_left = container_of(left, struct c2c_hist_entry, he); c2c_right = container_of(right, struct c2c_hist_entry, he); - return llc_miss(&c2c_left->stats) - llc_miss(&c2c_right->stats); + return (uint64_t) llc_miss(&c2c_left->stats) - + (uint64_t) llc_miss(&c2c_right->stats); } static uint64_t total_records(struct c2c_stats *stats) @@ -2384,7 +2386,7 @@ static int perf_c2c__browse_cacheline(struct hist_entry *he) c2c_browser__update_nr_entries(browser); while (1) { - key = hist_browser__run(browser, "? - help", true); + key = hist_browser__run(browser, "? - help", true, 0); switch (key) { case 's': @@ -2453,7 +2455,7 @@ static int perf_c2c__hists_browse(struct hists *hists) c2c_browser__update_nr_entries(browser); while (1) { - key = hist_browser__run(browser, "? - help", true); + key = hist_browser__run(browser, "? - help", true, 0); switch (key) { case 'q': diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c index 9664a72a089d..7e124a7b8bfd 100644 --- a/tools/perf/builtin-inject.c +++ b/tools/perf/builtin-inject.c @@ -403,17 +403,6 @@ static int perf_event__repipe_tracing_data(struct perf_session *session, return err; } -static int perf_event__repipe_id_index(struct perf_session *session, - union perf_event *event) -{ - int err; - - perf_event__repipe_synth(session->tool, event); - err = perf_event__process_id_index(session, event); - - return err; -} - static int dso__read_build_id(struct dso *dso) { if (dso->has_build_id) @@ -651,7 +640,7 @@ static int __cmd_inject(struct perf_inject *inject) inject->tool.comm = perf_event__repipe_comm; inject->tool.namespaces = perf_event__repipe_namespaces; inject->tool.exit = perf_event__repipe_exit; - inject->tool.id_index = perf_event__repipe_id_index; + inject->tool.id_index = perf_event__process_id_index; inject->tool.auxtrace_info = perf_event__process_auxtrace_info; inject->tool.auxtrace = perf_event__process_auxtrace; inject->tool.aux = perf_event__drop_aux; diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index b5063d3b6fd0..4c301466101b 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -62,6 +62,7 @@ #include <linux/string.h> #include <linux/time64.h> #include <linux/zalloc.h> +#include <linux/bitmap.h> struct switch_output { bool enabled; @@ -93,7 +94,7 @@ struct record { bool timestamp_boundary; struct switch_output switch_output; unsigned long long samples; - cpu_set_t affinity_mask; + struct mmap_cpu_mask affinity_mask; unsigned long output_max_size; /* = 0: unlimited */ }; @@ -832,7 +833,7 @@ try_again: if ((errno == EINVAL || errno == EBADF) && pos->leader != pos && pos->weak_group) { - pos = perf_evlist__reset_weak_group(evlist, pos); + pos = perf_evlist__reset_weak_group(evlist, pos, true); goto try_again; } rc = -errno; @@ -961,10 +962,15 @@ static struct perf_event_header finished_round_event = { static void record__adjust_affinity(struct record *rec, struct mmap *map) { if (rec->opts.affinity != PERF_AFFINITY_SYS && - !CPU_EQUAL(&rec->affinity_mask, &map->affinity_mask)) { - CPU_ZERO(&rec->affinity_mask); - CPU_OR(&rec->affinity_mask, &rec->affinity_mask, &map->affinity_mask); - sched_setaffinity(0, sizeof(rec->affinity_mask), &rec->affinity_mask); + !bitmap_equal(rec->affinity_mask.bits, map->affinity_mask.bits, + rec->affinity_mask.nbits)) { + bitmap_zero(rec->affinity_mask.bits, rec->affinity_mask.nbits); + bitmap_or(rec->affinity_mask.bits, rec->affinity_mask.bits, + map->affinity_mask.bits, rec->affinity_mask.nbits); + sched_setaffinity(0, MMAP_CPU_MASK_BYTES(&rec->affinity_mask), + (cpu_set_t *)rec->affinity_mask.bits); + if (verbose == 2) + mmap_cpu_mask__scnprintf(&rec->affinity_mask, "thread"); } } @@ -2433,7 +2439,6 @@ int cmd_record(int argc, const char **argv) # undef REASON #endif - CPU_ZERO(&rec->affinity_mask); rec->opts.affinity = PERF_AFFINITY_SYS; rec->evlist = evlist__new(); @@ -2499,6 +2504,16 @@ int cmd_record(int argc, const char **argv) symbol__init(NULL); + if (rec->opts.affinity != PERF_AFFINITY_SYS) { + rec->affinity_mask.nbits = cpu__max_cpu(); + rec->affinity_mask.bits = bitmap_alloc(rec->affinity_mask.nbits); + if (!rec->affinity_mask.bits) { + pr_err("Failed to allocate thread mask for %zd cpus\n", rec->affinity_mask.nbits); + return -ENOMEM; + } + pr_debug2("thread mask[%zd]: empty\n", rec->affinity_mask.nbits); + } + err = record__auxtrace_init(rec); if (err) goto out; @@ -2613,6 +2628,7 @@ int cmd_record(int argc, const char **argv) err = __cmd_record(&record, argc, argv); out: + bitmap_free(rec->affinity_mask.bits); evlist__delete(rec->evlist); symbol__exit(); auxtrace_record__free(rec->itr); diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 830d563de889..9483b3f0cae3 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -388,6 +388,14 @@ static int report__setup_sample_type(struct report *rep) } } + if (sort__mode == SORT_MODE__MEMORY) { + if (!is_pipe && !(sample_type & PERF_SAMPLE_DATA_SRC)) { + ui__error("Selected --mem-mode but no mem data. " + "Did you call perf record without -d?\n"); + return -1; + } + } + if (symbol_conf.use_callchain || symbol_conf.cumulate_callchain) { if ((sample_type & PERF_SAMPLE_REGS_USER) && (sample_type & PERF_SAMPLE_STACK_USER)) { @@ -404,10 +412,10 @@ static int report__setup_sample_type(struct report *rep) PERF_SAMPLE_BRANCH_ANY)) rep->nonany_branch_mode = true; -#ifndef HAVE_LIBUNWIND_SUPPORT +#if !defined(HAVE_LIBUNWIND_SUPPORT) && !defined(HAVE_DWARF_SUPPORT) if (dwarf_callchain_users) { - ui__warning("Please install libunwind development packages " - "during the perf build.\n"); + ui__warning("Please install libunwind or libdw " + "development packages during the perf build.\n"); } #endif @@ -1068,6 +1076,7 @@ int cmd_report(int argc, const char **argv) struct stat st; bool has_br_stack = false; int branch_mode = -1; + int last_key = 0; bool branch_call_mode = false; #define CALLCHAIN_DEFAULT_OPT "graph,0.5,caller,function,percent" static const char report_callchain_help[] = "Display call graph (stack chain/backtrace):\n\n" @@ -1155,7 +1164,8 @@ int cmd_report(int argc, const char **argv) report_callchain_help, &report_parse_callchain_opt, callchain_default_opt), OPT_BOOLEAN(0, "children", &symbol_conf.cumulate_callchain, - "Accumulate callchains of children and show total overhead as well"), + "Accumulate callchains of children and show total overhead as well. " + "Enabled by default, use --no-children to disable."), OPT_INTEGER(0, "max-stack", &report.max_stack, "Set the maximum stack depth when parsing the callchain, " "anything beyond the specified depth will be ignored. " @@ -1198,6 +1208,10 @@ int cmd_report(int argc, const char **argv) "Display raw encoding of assembly instructions (default)"), OPT_STRING('M', "disassembler-style", &report.annotation_opts.disassembler_style, "disassembler style", "Specify disassembler style (e.g. -M intel for intel syntax)"), + OPT_STRING(0, "prefix", &report.annotation_opts.prefix, "prefix", + "Add prefix to source file path names in programs (with --prefix-strip)"), + OPT_STRING(0, "prefix-strip", &report.annotation_opts.prefix_strip, "N", + "Strip first N entries of source file path name in programs (with --prefix)"), OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period, "Show a column with the sum of periods"), OPT_BOOLEAN_SET(0, "group", &symbol_conf.event_group, &report.group_set, @@ -1277,6 +1291,9 @@ int cmd_report(int argc, const char **argv) report.symbol_filter_str = argv[0]; } + if (annotate_check_args(&report.annotation_opts) < 0) + return -EINVAL; + if (report.mmaps_mode) report.tasks_mode = true; @@ -1442,7 +1459,8 @@ repeat: sort_order = sort_tmp; } - if (setup_sorting(session->evlist) < 0) { + if ((last_key != K_SWITCH_INPUT_DATA) && + (setup_sorting(session->evlist) < 0)) { if (sort_order) parse_options_usage(report_usage, options, "s", 1); if (field_order) @@ -1522,6 +1540,7 @@ repeat: ret = __cmd_report(&report); if (ret == K_SWITCH_INPUT_DATA) { perf_session__delete(session); + last_key = K_SWITCH_INPUT_DATA; goto repeat; } else ret = 0; diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index 8a12d71364c3..82fcc2c15fe4 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c @@ -51,6 +51,9 @@ #define SYM_LEN 129 #define MAX_PID 1024000 +static const char *cpu_list; +static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); + struct sched_atom; struct task_desc { @@ -2008,6 +2011,9 @@ static void timehist_print_sample(struct perf_sched *sched, char nstr[30]; u64 wait_time; + if (cpu_list && !test_bit(sample->cpu, cpu_bitmap)) + return; + timestamp__scnprintf_usec(t, tstr, sizeof(tstr)); printf("%15s [%04d] ", tstr, sample->cpu); @@ -2994,6 +3000,12 @@ static int perf_sched__timehist(struct perf_sched *sched) if (IS_ERR(session)) return PTR_ERR(session); + if (cpu_list) { + err = perf_session__cpu_bitmap(session, cpu_list, cpu_bitmap); + if (err < 0) + goto out; + } + evlist = session->evlist; symbol__init(&session->header.env); @@ -3429,6 +3441,7 @@ int cmd_sched(int argc, const char **argv) "analyze events only for given process id(s)"), OPT_STRING('t', "tid", &symbol_conf.tid_list_str, "tid[,tid...]", "analyze events only for given thread id(s)"), + OPT_STRING('C', "cpu", &cpu_list, "cpu", "list of cpus to profile"), OPT_PARENT(sched_options) }; diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 0a15253b438c..a098c2ebf4ea 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -65,6 +65,7 @@ #include "util/target.h" #include "util/time-utils.h" #include "util/top.h" +#include "util/affinity.h" #include "asm/bug.h" #include <linux/time64.h> @@ -265,15 +266,10 @@ static int read_single_counter(struct evsel *counter, int cpu, * Read out the results of a single counter: * do not aggregate counts across CPUs in system-wide mode */ -static int read_counter(struct evsel *counter, struct timespec *rs) +static int read_counter_cpu(struct evsel *counter, struct timespec *rs, int cpu) { int nthreads = perf_thread_map__nr(evsel_list->core.threads); - int ncpus, cpu, thread; - - if (target__has_cpu(&target) && !target__has_per_thread(&target)) - ncpus = perf_evsel__nr_cpus(counter); - else - ncpus = 1; + int thread; if (!counter->supported) return -ENOENT; @@ -282,40 +278,38 @@ static int read_counter(struct evsel *counter, struct timespec *rs) nthreads = 1; for (thread = 0; thread < nthreads; thread++) { - for (cpu = 0; cpu < ncpus; cpu++) { - struct perf_counts_values *count; - - count = perf_counts(counter->counts, cpu, thread); - - /* - * The leader's group read loads data into its group members - * (via perf_evsel__read_counter) and sets threir count->loaded. - */ - if (!perf_counts__is_loaded(counter->counts, cpu, thread) && - read_single_counter(counter, cpu, thread, rs)) { - counter->counts->scaled = -1; - perf_counts(counter->counts, cpu, thread)->ena = 0; - perf_counts(counter->counts, cpu, thread)->run = 0; - return -1; - } + struct perf_counts_values *count; - perf_counts__set_loaded(counter->counts, cpu, thread, false); + count = perf_counts(counter->counts, cpu, thread); - if (STAT_RECORD) { - if (perf_evsel__write_stat_event(counter, cpu, thread, count)) { - pr_err("failed to write stat event\n"); - return -1; - } - } + /* + * The leader's group read loads data into its group members + * (via perf_evsel__read_counter()) and sets their count->loaded. + */ + if (!perf_counts__is_loaded(counter->counts, cpu, thread) && + read_single_counter(counter, cpu, thread, rs)) { + counter->counts->scaled = -1; + perf_counts(counter->counts, cpu, thread)->ena = 0; + perf_counts(counter->counts, cpu, thread)->run = 0; + return -1; + } + + perf_counts__set_loaded(counter->counts, cpu, thread, false); - if (verbose > 1) { - fprintf(stat_config.output, - "%s: %d: %" PRIu64 " %" PRIu64 " %" PRIu64 "\n", - perf_evsel__name(counter), - cpu, - count->val, count->ena, count->run); + if (STAT_RECORD) { + if (perf_evsel__write_stat_event(counter, cpu, thread, count)) { + pr_err("failed to write stat event\n"); + return -1; } } + + if (verbose > 1) { + fprintf(stat_config.output, + "%s: %d: %" PRIu64 " %" PRIu64 " %" PRIu64 "\n", + perf_evsel__name(counter), + cpu, + count->val, count->ena, count->run); + } } return 0; @@ -324,15 +318,37 @@ static int read_counter(struct evsel *counter, struct timespec *rs) static void read_counters(struct timespec *rs) { struct evsel *counter; - int ret; + struct affinity affinity; + int i, ncpus, cpu; + + if (affinity__setup(&affinity) < 0) + return; + + ncpus = perf_cpu_map__nr(evsel_list->core.all_cpus); + if (!target__has_cpu(&target) || target__has_per_thread(&target)) + ncpus = 1; + evlist__for_each_cpu(evsel_list, i, cpu) { + if (i >= ncpus) + break; + affinity__set(&affinity, cpu); + + evlist__for_each_entry(evsel_list, counter) { + if (evsel__cpu_iter_skip(counter, cpu)) + continue; + if (!counter->err) { + counter->err = read_counter_cpu(counter, rs, + counter->cpu_iter - 1); + } + } + } + affinity__cleanup(&affinity); evlist__for_each_entry(evsel_list, counter) { - ret = read_counter(counter, rs); - if (ret) + if (counter->err) pr_debug("failed to read counter %s\n", counter->name); - - if (ret == 0 && perf_stat_process_counter(&stat_config, counter)) + if (counter->err == 0 && perf_stat_process_counter(&stat_config, counter)) pr_warning("failed to process counter %s\n", counter->name); + counter->err = 0; } } @@ -420,6 +436,62 @@ static bool is_target_alive(struct target *_target, return false; } +enum counter_recovery { + COUNTER_SKIP, + COUNTER_RETRY, + COUNTER_FATAL, +}; + +static enum counter_recovery stat_handle_error(struct evsel *counter) +{ + char msg[BUFSIZ]; + /* + * PPC returns ENXIO for HW counters until 2.6.37 + * (behavior changed with commit b0a873e). + */ + if (errno == EINVAL || errno == ENOSYS || + errno == ENOENT || errno == EOPNOTSUPP || + errno == ENXIO) { + if (verbose > 0) + ui__warning("%s event is not supported by the kernel.\n", + perf_evsel__name(counter)); + counter->supported = false; + /* + * errored is a sticky flag that means one of the counter's + * cpu event had a problem and needs to be reexamined. + */ + counter->errored = true; + + if ((counter->leader != counter) || + !(counter->leader->core.nr_members > 1)) + return COUNTER_SKIP; + } else if (perf_evsel__fallback(counter, errno, msg, sizeof(msg))) { + if (verbose > 0) + ui__warning("%s\n", msg); + return COUNTER_RETRY; + } else if (target__has_per_thread(&target) && + evsel_list->core.threads && + evsel_list->core.threads->err_thread != -1) { + /* + * For global --per-thread case, skip current + * error thread. + */ + if (!thread_map__remove(evsel_list->core.threads, + evsel_list->core.threads->err_thread)) { + evsel_list->core.threads->err_thread = -1; + return COUNTER_RETRY; + } + } + + perf_evsel__open_strerror(counter, &target, + errno, msg, sizeof(msg)); + ui__error("%s\n", msg); + + if (child_pid != -1) + kill(child_pid, SIGTERM); + return COUNTER_FATAL; +} + static int __run_perf_stat(int argc, const char **argv, int run_idx) { int interval = stat_config.interval; @@ -433,6 +505,9 @@ static int __run_perf_stat(int argc, const char **argv, int run_idx) int status = 0; const bool forks = (argc > 0); bool is_pipe = STAT_RECORD ? perf_stat.data.is_pipe : false; + struct affinity affinity; + int i, cpu; + bool second_pass = false; if (interval) { ts.tv_sec = interval / USEC_PER_MSEC; @@ -457,61 +532,104 @@ static int __run_perf_stat(int argc, const char **argv, int run_idx) if (group) perf_evlist__set_leader(evsel_list); - evlist__for_each_entry(evsel_list, counter) { + if (affinity__setup(&affinity) < 0) + return -1; + + evlist__for_each_cpu (evsel_list, i, cpu) { + affinity__set(&affinity, cpu); + + evlist__for_each_entry(evsel_list, counter) { + if (evsel__cpu_iter_skip(counter, cpu)) + continue; + if (counter->reset_group || counter->errored) + continue; try_again: - if (create_perf_stat_counter(counter, &stat_config, &target) < 0) { - - /* Weak group failed. Reset the group. */ - if ((errno == EINVAL || errno == EBADF) && - counter->leader != counter && - counter->weak_group) { - counter = perf_evlist__reset_weak_group(evsel_list, counter); - goto try_again; - } + if (create_perf_stat_counter(counter, &stat_config, &target, + counter->cpu_iter - 1) < 0) { - /* - * PPC returns ENXIO for HW counters until 2.6.37 - * (behavior changed with commit b0a873e). - */ - if (errno == EINVAL || errno == ENOSYS || - errno == ENOENT || errno == EOPNOTSUPP || - errno == ENXIO) { - if (verbose > 0) - ui__warning("%s event is not supported by the kernel.\n", - perf_evsel__name(counter)); - counter->supported = false; - - if ((counter->leader != counter) || - !(counter->leader->core.nr_members > 1)) - continue; - } else if (perf_evsel__fallback(counter, errno, msg, sizeof(msg))) { - if (verbose > 0) - ui__warning("%s\n", msg); - goto try_again; - } else if (target__has_per_thread(&target) && - evsel_list->core.threads && - evsel_list->core.threads->err_thread != -1) { /* - * For global --per-thread case, skip current - * error thread. + * Weak group failed. We cannot just undo this here + * because earlier CPUs might be in group mode, and the kernel + * doesn't support mixing group and non group reads. Defer + * it to later. + * Don't close here because we're in the wrong affinity. */ - if (!thread_map__remove(evsel_list->core.threads, - evsel_list->core.threads->err_thread)) { - evsel_list->core.threads->err_thread = -1; + if ((errno == EINVAL || errno == EBADF) && + counter->leader != counter && + counter->weak_group) { + perf_evlist__reset_weak_group(evsel_list, counter, false); + assert(counter->reset_group); + second_pass = true; + continue; + } + + switch (stat_handle_error(counter)) { + case COUNTER_FATAL: + return -1; + case COUNTER_RETRY: goto try_again; + case COUNTER_SKIP: + continue; + default: + break; } + } + counter->supported = true; + } + } - perf_evsel__open_strerror(counter, &target, - errno, msg, sizeof(msg)); - ui__error("%s\n", msg); + if (second_pass) { + /* + * Now redo all the weak group after closing them, + * and also close errored counters. + */ - if (child_pid != -1) - kill(child_pid, SIGTERM); + evlist__for_each_cpu(evsel_list, i, cpu) { + affinity__set(&affinity, cpu); + /* First close errored or weak retry */ + evlist__for_each_entry(evsel_list, counter) { + if (!counter->reset_group && !counter->errored) + continue; + if (evsel__cpu_iter_skip_no_inc(counter, cpu)) + continue; + perf_evsel__close_cpu(&counter->core, counter->cpu_iter); + } + /* Now reopen weak */ + evlist__for_each_entry(evsel_list, counter) { + if (!counter->reset_group && !counter->errored) + continue; + if (evsel__cpu_iter_skip(counter, cpu)) + continue; + if (!counter->reset_group) + continue; +try_again_reset: + pr_debug2("reopening weak %s\n", perf_evsel__name(counter)); + if (create_perf_stat_counter(counter, &stat_config, &target, + counter->cpu_iter - 1) < 0) { + + switch (stat_handle_error(counter)) { + case COUNTER_FATAL: + return -1; + case COUNTER_RETRY: + goto try_again_reset; + case COUNTER_SKIP: + continue; + default: + break; + } + } + counter->supported = true; + } + } + } + affinity__cleanup(&affinity); - return -1; + evlist__for_each_entry(evsel_list, counter) { + if (!counter->supported) { + perf_evsel__free_fd(&counter->core); + continue; } - counter->supported = true; l = strlen(counter->unit); if (l > stat_config.unit_width) diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index dc80044bc46f..8affcab75604 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -1512,6 +1512,10 @@ int cmd_top(int argc, const char **argv) "objdump binary to use for disassembly and annotations"), OPT_STRING('M', "disassembler-style", &top.annotation_opts.disassembler_style, "disassembler style", "Specify disassembler style (e.g. -M intel for intel syntax)"), + OPT_STRING(0, "prefix", &top.annotation_opts.prefix, "prefix", + "Add prefix to source file path names in programs (with --prefix-strip)"), + OPT_STRING(0, "prefix-strip", &top.annotation_opts.prefix_strip, "N", + "Strip first N entries of source file path name in programs (with --prefix)"), OPT_STRING('u', "uid", &target->uid_str, "user", "user to profile"), OPT_CALLBACK(0, "percent-limit", &top, "percent", "Don't show entries under that percent", parse_percent_limit), @@ -1568,9 +1572,13 @@ int cmd_top(int argc, const char **argv) */ status = perf_env__read_cpuid(&perf_env); if (status) { - pr_err("Couldn't read the cpuid for this machine: %s\n", - str_error_r(errno, errbuf, sizeof(errbuf))); - goto out_delete_evlist; + /* + * Some arches do not provide a get_cpuid(), so just use pr_debug, otherwise + * warn the user explicitely. + */ + eprintf(status == ENOSYS ? 1 : 0, verbose, + "Couldn't read the cpuid for this machine: %s\n", + str_error_r(errno, errbuf, sizeof(errbuf))); } top.evlist->env = &perf_env; @@ -1578,6 +1586,9 @@ int cmd_top(int argc, const char **argv) if (argc) usage_with_options(top_usage, options); + if (annotate_check_args(&top.annotation_opts) < 0) + goto out_delete_evlist; + if (!top.evlist->core.nr_entries && perf_evlist__add_default(top.evlist) < 0) { pr_err("Not enough memory for event selector list\n"); diff --git a/tools/perf/check-headers.sh b/tools/perf/check-headers.sh index a1dc16724352..68039a96c1dc 100755 --- a/tools/perf/check-headers.sh +++ b/tools/perf/check-headers.sh @@ -110,8 +110,8 @@ for i in $FILES; do done # diff with extra ignore lines -check arch/x86/lib/memcpy_64.S '-I "^EXPORT_SYMBOL" -I "^#include <asm/export.h>"' -check arch/x86/lib/memset_64.S '-I "^EXPORT_SYMBOL" -I "^#include <asm/export.h>"' +check arch/x86/lib/memcpy_64.S '-I "^EXPORT_SYMBOL" -I "^#include <asm/export.h>" -I"^SYM_FUNC_START\(_LOCAL\)*(memcpy_\(erms\|orig\))"' +check arch/x86/lib/memset_64.S '-I "^EXPORT_SYMBOL" -I "^#include <asm/export.h>" -I"^SYM_FUNC_START\(_LOCAL\)*(memset_\(erms\|orig\))"' check include/uapi/asm-generic/mman.h '-I "^#include <\(uapi/\)*asm-generic/mman-common\(-tools\)*.h>"' check include/uapi/linux/mman.h '-I "^#include <\(uapi/\)*asm/mman.h>"' check include/linux/ctype.h '-I "isdigit("' diff --git a/tools/perf/examples/bpf/5sec.c b/tools/perf/examples/bpf/5sec.c index b9c203219691..e6b6181c6dc6 100644 --- a/tools/perf/examples/bpf/5sec.c +++ b/tools/perf/examples/bpf/5sec.c @@ -41,9 +41,11 @@ #include <bpf.h> -int probe(hrtimer_nanosleep, rqtp->tv_sec)(void *ctx, int err, long sec) +#define NSEC_PER_SEC 1000000000L + +int probe(hrtimer_nanosleep, rqtp)(void *ctx, int err, long long sec) { - return sec == 5; + return sec / NSEC_PER_SEC == 5ULL; } license(GPL); diff --git a/tools/perf/lib/Build b/tools/perf/lib/Build deleted file mode 100644 index 2ef9a4ec6d99..000000000000 --- a/tools/perf/lib/Build +++ /dev/null @@ -1,13 +0,0 @@ -libperf-y += core.o -libperf-y += cpumap.o -libperf-y += threadmap.o -libperf-y += evsel.o -libperf-y += evlist.o -libperf-y += mmap.o -libperf-y += zalloc.o -libperf-y += xyarray.o -libperf-y += lib.o - -$(OUTPUT)zalloc.o: ../../lib/zalloc.c FORCE - $(call rule_mkdir) - $(call if_changed_dep,cc_o_c) diff --git a/tools/perf/lib/Documentation/Makefile b/tools/perf/lib/Documentation/Makefile deleted file mode 100644 index 586425a88795..000000000000 --- a/tools/perf/lib/Documentation/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -all: - rst2man man/libperf.rst > man/libperf.7 - rst2pdf tutorial/tutorial.rst - -clean: - rm -f man/libperf.7 - rm -f tutorial/tutorial.pdf diff --git a/tools/perf/lib/Documentation/man/libperf.rst b/tools/perf/lib/Documentation/man/libperf.rst deleted file mode 100644 index 09a270fccb9c..000000000000 --- a/tools/perf/lib/Documentation/man/libperf.rst +++ /dev/null @@ -1,100 +0,0 @@ -.. SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) - -libperf - -The libperf library provides an API to access the linux kernel perf -events subsystem. It provides the following high level objects: - - - struct perf_cpu_map - - struct perf_thread_map - - struct perf_evlist - - struct perf_evsel - -reference -========= -Function reference by header files: - -perf/core.h ------------ -.. code-block:: c - - typedef int (\*libperf_print_fn_t)(enum libperf_print_level level, - const char \*, va_list ap); - - void libperf_set_print(libperf_print_fn_t fn); - -perf/cpumap.h -------------- -.. code-block:: c - - struct perf_cpu_map \*perf_cpu_map__dummy_new(void); - struct perf_cpu_map \*perf_cpu_map__new(const char \*cpu_list); - struct perf_cpu_map \*perf_cpu_map__read(FILE \*file); - struct perf_cpu_map \*perf_cpu_map__get(struct perf_cpu_map \*map); - void perf_cpu_map__put(struct perf_cpu_map \*map); - int perf_cpu_map__cpu(const struct perf_cpu_map \*cpus, int idx); - int perf_cpu_map__nr(const struct perf_cpu_map \*cpus); - perf_cpu_map__for_each_cpu(cpu, idx, cpus) - -perf/threadmap.h ----------------- -.. code-block:: c - - struct perf_thread_map \*perf_thread_map__new_dummy(void); - void perf_thread_map__set_pid(struct perf_thread_map \*map, int thread, pid_t pid); - char \*perf_thread_map__comm(struct perf_thread_map \*map, int thread); - struct perf_thread_map \*perf_thread_map__get(struct perf_thread_map \*map); - void perf_thread_map__put(struct perf_thread_map \*map); - -perf/evlist.h -------------- -.. code-block:: - - void perf_evlist__init(struct perf_evlist \*evlist); - void perf_evlist__add(struct perf_evlist \*evlist, - struct perf_evsel \*evsel); - void perf_evlist__remove(struct perf_evlist \*evlist, - struct perf_evsel \*evsel); - struct perf_evlist \*perf_evlist__new(void); - void perf_evlist__delete(struct perf_evlist \*evlist); - struct perf_evsel\* perf_evlist__next(struct perf_evlist \*evlist, - struct perf_evsel \*evsel); - int perf_evlist__open(struct perf_evlist \*evlist); - void perf_evlist__close(struct perf_evlist \*evlist); - void perf_evlist__enable(struct perf_evlist \*evlist); - void perf_evlist__disable(struct perf_evlist \*evlist); - perf_evlist__for_each_evsel(evlist, pos) - void perf_evlist__set_maps(struct perf_evlist \*evlist, - struct perf_cpu_map \*cpus, - struct perf_thread_map \*threads); - -perf/evsel.h ------------- -.. code-block:: c - - struct perf_counts_values { - union { - struct { - uint64_t val; - uint64_t ena; - uint64_t run; - }; - uint64_t values[3]; - }; - }; - - void perf_evsel__init(struct perf_evsel \*evsel, - struct perf_event_attr \*attr); - struct perf_evsel \*perf_evsel__new(struct perf_event_attr \*attr); - void perf_evsel__delete(struct perf_evsel \*evsel); - int perf_evsel__open(struct perf_evsel \*evsel, struct perf_cpu_map \*cpus, - struct perf_thread_map \*threads); - void perf_evsel__close(struct perf_evsel \*evsel); - int perf_evsel__read(struct perf_evsel \*evsel, int cpu, int thread, - struct perf_counts_values \*count); - int perf_evsel__enable(struct perf_evsel \*evsel); - int perf_evsel__disable(struct perf_evsel \*evsel); - int perf_evsel__apply_filter(struct perf_evsel \*evsel, const char \*filter); - struct perf_cpu_map \*perf_evsel__cpus(struct perf_evsel \*evsel); - struct perf_thread_map \*perf_evsel__threads(struct perf_evsel \*evsel); - struct perf_event_attr \*perf_evsel__attr(struct perf_evsel \*evsel); diff --git a/tools/perf/lib/Documentation/tutorial/tutorial.rst b/tools/perf/lib/Documentation/tutorial/tutorial.rst deleted file mode 100644 index 7be7bc27b385..000000000000 --- a/tools/perf/lib/Documentation/tutorial/tutorial.rst +++ /dev/null @@ -1,123 +0,0 @@ -.. SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) - -libperf tutorial -================ - -Compile and install libperf from kernel sources -=============================================== -.. code-block:: bash - - git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git - cd linux/tools/perf/lib - make - sudo make install prefix=/usr - -Libperf object -============== -The libperf library provides several high level objects: - -struct perf_cpu_map - Provides a cpu list abstraction. - -struct perf_thread_map - Provides a thread list abstraction. - -struct perf_evsel - Provides an abstraction for single a perf event. - -struct perf_evlist - Gathers several struct perf_evsel object and performs functions on all of them. - -The exported API binds these objects together, -for full reference see the libperf.7 man page. - -Examples -======== -Examples aim to explain libperf functionality on simple use cases. -They are based in on a checked out linux kernel git tree: - -.. code-block:: bash - - $ cd tools/perf/lib/Documentation/tutorial/ - $ ls -d ex-* - ex-1-compile ex-2-evsel-stat ex-3-evlist-stat - -ex-1-compile example -==================== -This example shows the basic usage of *struct perf_cpu_map*, -how to create it and display its cpus: - -.. code-block:: bash - - $ cd ex-1-compile/ - $ make - gcc -o test test.c -lperf - $ ./test - 0 1 2 3 4 5 6 7 - - -The full code listing is here: - -.. code-block:: c - - 1 #include <perf/cpumap.h> - 2 - 3 int main(int argc, char **Argv) - 4 { - 5 struct perf_cpu_map *cpus; - 6 int cpu, tmp; - 7 - 8 cpus = perf_cpu_map__new(NULL); - 9 - 10 perf_cpu_map__for_each_cpu(cpu, tmp, cpus) - 11 fprintf(stdout, "%d ", cpu); - 12 - 13 fprintf(stdout, "\n"); - 14 - 15 perf_cpu_map__put(cpus); - 16 return 0; - 17 } - - -First you need to include the proper header to have *struct perf_cpumap* -declaration and functions: - -.. code-block:: c - - 1 #include <perf/cpumap.h> - - -The *struct perf_cpumap* object is created by *perf_cpu_map__new* call. -The *NULL* argument asks it to populate the object with the current online CPUs list: - -.. code-block:: c - - 8 cpus = perf_cpu_map__new(NULL); - -This is paired with a *perf_cpu_map__put*, that drops its reference at the end, possibly deleting it. - -.. code-block:: c - - 15 perf_cpu_map__put(cpus); - -The iteration through the *struct perf_cpumap* CPUs is done using the *perf_cpu_map__for_each_cpu* -macro which requires 3 arguments: - -- cpu - the cpu numer -- tmp - iteration helper variable -- cpus - the *struct perf_cpumap* object - -.. code-block:: c - - 10 perf_cpu_map__for_each_cpu(cpu, tmp, cpus) - 11 fprintf(stdout, "%d ", cpu); - -ex-2-evsel-stat example -======================= - -TBD - -ex-3-evlist-stat example -======================== - -TBD diff --git a/tools/perf/lib/Makefile b/tools/perf/lib/Makefile deleted file mode 100644 index 0f233638ef1f..000000000000 --- a/tools/perf/lib/Makefile +++ /dev/null @@ -1,188 +0,0 @@ -# SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) -# Most of this file is copied from tools/lib/bpf/Makefile - -LIBPERF_VERSION = 0 -LIBPERF_PATCHLEVEL = 0 -LIBPERF_EXTRAVERSION = 1 - -MAKEFLAGS += --no-print-directory - -ifeq ($(srctree),) -srctree := $(patsubst %/,%,$(dir $(CURDIR))) -srctree := $(patsubst %/,%,$(dir $(srctree))) -srctree := $(patsubst %/,%,$(dir $(srctree))) -#$(info Determined 'srctree' to be $(srctree)) -endif - -INSTALL = install - -# Use DESTDIR for installing into a different root directory. -# This is useful for building a package. The program will be -# installed in this directory as if it was the root directory. -# Then the build tool can move it later. -DESTDIR ?= -DESTDIR_SQ = '$(subst ','\'',$(DESTDIR))' - -include $(srctree)/tools/scripts/Makefile.include -include $(srctree)/tools/scripts/Makefile.arch - -ifeq ($(LP64), 1) - libdir_relative = lib64 -else - libdir_relative = lib -endif - -prefix ?= -libdir = $(prefix)/$(libdir_relative) - -# Shell quotes -libdir_SQ = $(subst ','\'',$(libdir)) -libdir_relative_SQ = $(subst ','\'',$(libdir_relative)) - -ifeq ("$(origin V)", "command line") - VERBOSE = $(V) -endif -ifndef VERBOSE - VERBOSE = 0 -endif - -ifeq ($(VERBOSE),1) - Q = -else - Q = @ -endif - -# Set compile option CFLAGS -ifdef EXTRA_CFLAGS - CFLAGS := $(EXTRA_CFLAGS) -else - CFLAGS := -g -Wall -endif - -INCLUDES = \ --I$(srctree)/tools/perf/lib/include \ --I$(srctree)/tools/lib/ \ --I$(srctree)/tools/include \ --I$(srctree)/tools/arch/$(SRCARCH)/include/ \ --I$(srctree)/tools/arch/$(SRCARCH)/include/uapi \ --I$(srctree)/tools/include/uapi - -# Append required CFLAGS -override CFLAGS += $(EXTRA_WARNINGS) -override CFLAGS += -Werror -Wall -override CFLAGS += -fPIC -override CFLAGS += $(INCLUDES) -override CFLAGS += -fvisibility=hidden - -all: - -export srctree OUTPUT CC LD CFLAGS V -export DESTDIR DESTDIR_SQ - -include $(srctree)/tools/build/Makefile.include - -VERSION_SCRIPT := libperf.map - -PATCHLEVEL = $(LIBPERF_PATCHLEVEL) -EXTRAVERSION = $(LIBPERF_EXTRAVERSION) -VERSION = $(LIBPERF_VERSION).$(LIBPERF_PATCHLEVEL).$(LIBPERF_EXTRAVERSION) - -LIBPERF_SO := $(OUTPUT)libperf.so.$(VERSION) -LIBPERF_A := $(OUTPUT)libperf.a -LIBPERF_IN := $(OUTPUT)libperf-in.o -LIBPERF_PC := $(OUTPUT)libperf.pc - -LIBPERF_ALL := $(LIBPERF_A) $(OUTPUT)libperf.so* - -LIB_DIR := $(srctree)/tools/lib/api/ - -ifneq ($(OUTPUT),) -ifneq ($(subdir),) - API_PATH=$(OUTPUT)/../lib/api/ -else - API_PATH=$(OUTPUT) -endif -else - API_PATH=$(LIB_DIR) -endif - -LIBAPI = $(API_PATH)libapi.a -export LIBAPI - -$(LIBAPI): FORCE - $(Q)$(MAKE) -C $(LIB_DIR) O=$(OUTPUT) $(OUTPUT)libapi.a - -$(LIBAPI)-clean: - $(call QUIET_CLEAN, libapi) - $(Q)$(MAKE) -C $(LIB_DIR) O=$(OUTPUT) clean >/dev/null - -$(LIBPERF_IN): FORCE - $(Q)$(MAKE) $(build)=libperf - -$(LIBPERF_A): $(LIBPERF_IN) - $(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(LIBPERF_IN) - -$(LIBPERF_SO): $(LIBPERF_IN) $(LIBAPI) - $(QUIET_LINK)$(CC) --shared -Wl,-soname,libperf.so \ - -Wl,--version-script=$(VERSION_SCRIPT) $^ -o $@ - @ln -sf $(@F) $(OUTPUT)libperf.so - @ln -sf $(@F) $(OUTPUT)libperf.so.$(LIBPERF_VERSION) - - -libs: $(LIBPERF_A) $(LIBPERF_SO) $(LIBPERF_PC) - -all: fixdep - $(Q)$(MAKE) libs - -clean: $(LIBAPI)-clean - $(call QUIET_CLEAN, libperf) $(RM) $(LIBPERF_A) \ - *.o *~ *.a *.so *.so.$(VERSION) *.so.$(LIBPERF_VERSION) .*.d .*.cmd LIBPERF-CFLAGS $(LIBPERF_PC) - $(Q)$(MAKE) -C tests clean - -tests: libs - $(Q)$(MAKE) -C tests - $(Q)$(MAKE) -C tests run - -$(LIBPERF_PC): - $(QUIET_GEN)sed -e "s|@PREFIX@|$(prefix)|" \ - -e "s|@LIBDIR@|$(libdir_SQ)|" \ - -e "s|@VERSION@|$(VERSION)|" \ - < libperf.pc.template > $@ - -define do_install_mkdir - if [ ! -d '$(DESTDIR_SQ)$1' ]; then \ - $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$1'; \ - fi -endef - -define do_install - if [ ! -d '$(DESTDIR_SQ)$2' ]; then \ - $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$2'; \ - fi; \ - $(INSTALL) $1 $(if $3,-m $3,) '$(DESTDIR_SQ)$2' -endef - -install_lib: libs - $(call QUIET_INSTALL, $(LIBPERF_ALL)) \ - $(call do_install_mkdir,$(libdir_SQ)); \ - cp -fpR $(LIBPERF_ALL) $(DESTDIR)$(libdir_SQ) - -install_headers: - $(call QUIET_INSTALL, headers) \ - $(call do_install,include/perf/core.h,$(prefix)/include/perf,644); \ - $(call do_install,include/perf/cpumap.h,$(prefix)/include/perf,644); \ - $(call do_install,include/perf/threadmap.h,$(prefix)/include/perf,644); \ - $(call do_install,include/perf/evlist.h,$(prefix)/include/perf,644); \ - $(call do_install,include/perf/evsel.h,$(prefix)/include/perf,644); \ - $(call do_install,include/perf/event.h,$(prefix)/include/perf,644); \ - $(call do_install,include/perf/mmap.h,$(prefix)/include/perf,644); - -install_pkgconfig: $(LIBPERF_PC) - $(call QUIET_INSTALL, $(LIBPERF_PC)) \ - $(call do_install,$(LIBPERF_PC),$(libdir_SQ)/pkgconfig,644) - -install: install_lib install_headers install_pkgconfig - -FORCE: - -.PHONY: all install clean tests FORCE diff --git a/tools/perf/lib/core.c b/tools/perf/lib/core.c deleted file mode 100644 index 58fc894b76c5..000000000000 --- a/tools/perf/lib/core.c +++ /dev/null @@ -1,38 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only - -#define __printf(a, b) __attribute__((format(printf, a, b))) - -#include <stdio.h> -#include <stdarg.h> -#include <unistd.h> -#include <linux/compiler.h> -#include <perf/core.h> -#include <internal/lib.h> -#include "internal.h" - -static int __base_pr(enum libperf_print_level level __maybe_unused, const char *format, - va_list args) -{ - return vfprintf(stderr, format, args); -} - -static libperf_print_fn_t __libperf_pr = __base_pr; - -__printf(2, 3) -void libperf_print(enum libperf_print_level level, const char *format, ...) -{ - va_list args; - - if (!__libperf_pr) - return; - - va_start(args, format); - __libperf_pr(level, format, args); - va_end(args); -} - -void libperf_init(libperf_print_fn_t fn) -{ - page_size = sysconf(_SC_PAGE_SIZE); - __libperf_pr = fn; -} diff --git a/tools/perf/lib/cpumap.c b/tools/perf/lib/cpumap.c deleted file mode 100644 index 2ca1fafa620d..000000000000 --- a/tools/perf/lib/cpumap.c +++ /dev/null @@ -1,274 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -#include <perf/cpumap.h> -#include <stdlib.h> -#include <linux/refcount.h> -#include <internal/cpumap.h> -#include <asm/bug.h> -#include <stdio.h> -#include <string.h> -#include <unistd.h> -#include <ctype.h> -#include <limits.h> - -struct perf_cpu_map *perf_cpu_map__dummy_new(void) -{ - struct perf_cpu_map *cpus = malloc(sizeof(*cpus) + sizeof(int)); - - if (cpus != NULL) { - cpus->nr = 1; - cpus->map[0] = -1; - refcount_set(&cpus->refcnt, 1); - } - - return cpus; -} - -static void cpu_map__delete(struct perf_cpu_map *map) -{ - if (map) { - WARN_ONCE(refcount_read(&map->refcnt) != 0, - "cpu_map refcnt unbalanced\n"); - free(map); - } -} - -struct perf_cpu_map *perf_cpu_map__get(struct perf_cpu_map *map) -{ - if (map) - refcount_inc(&map->refcnt); - return map; -} - -void perf_cpu_map__put(struct perf_cpu_map *map) -{ - if (map && refcount_dec_and_test(&map->refcnt)) - cpu_map__delete(map); -} - -static struct perf_cpu_map *cpu_map__default_new(void) -{ - struct perf_cpu_map *cpus; - int nr_cpus; - - nr_cpus = sysconf(_SC_NPROCESSORS_ONLN); - if (nr_cpus < 0) - return NULL; - - cpus = malloc(sizeof(*cpus) + nr_cpus * sizeof(int)); - if (cpus != NULL) { - int i; - - for (i = 0; i < nr_cpus; ++i) - cpus->map[i] = i; - - cpus->nr = nr_cpus; - refcount_set(&cpus->refcnt, 1); - } - - return cpus; -} - -static struct perf_cpu_map *cpu_map__trim_new(int nr_cpus, int *tmp_cpus) -{ - size_t payload_size = nr_cpus * sizeof(int); - struct perf_cpu_map *cpus = malloc(sizeof(*cpus) + payload_size); - - if (cpus != NULL) { - cpus->nr = nr_cpus; - memcpy(cpus->map, tmp_cpus, payload_size); - refcount_set(&cpus->refcnt, 1); - } - - return cpus; -} - -struct perf_cpu_map *perf_cpu_map__read(FILE *file) -{ - struct perf_cpu_map *cpus = NULL; - int nr_cpus = 0; - int *tmp_cpus = NULL, *tmp; - int max_entries = 0; - int n, cpu, prev; - char sep; - - sep = 0; - prev = -1; - for (;;) { - n = fscanf(file, "%u%c", &cpu, &sep); - if (n <= 0) - break; - if (prev >= 0) { - int new_max = nr_cpus + cpu - prev - 1; - - WARN_ONCE(new_max >= MAX_NR_CPUS, "Perf can support %d CPUs. " - "Consider raising MAX_NR_CPUS\n", MAX_NR_CPUS); - - if (new_max >= max_entries) { - max_entries = new_max + MAX_NR_CPUS / 2; - tmp = realloc(tmp_cpus, max_entries * sizeof(int)); - if (tmp == NULL) - goto out_free_tmp; - tmp_cpus = tmp; - } - - while (++prev < cpu) - tmp_cpus[nr_cpus++] = prev; - } - if (nr_cpus == max_entries) { - max_entries += MAX_NR_CPUS; - tmp = realloc(tmp_cpus, max_entries * sizeof(int)); - if (tmp == NULL) - goto out_free_tmp; - tmp_cpus = tmp; - } - - tmp_cpus[nr_cpus++] = cpu; - if (n == 2 && sep == '-') - prev = cpu; - else - prev = -1; - if (n == 1 || sep == '\n') - break; - } - - if (nr_cpus > 0) - cpus = cpu_map__trim_new(nr_cpus, tmp_cpus); - else - cpus = cpu_map__default_new(); -out_free_tmp: - free(tmp_cpus); - return cpus; -} - -static struct perf_cpu_map *cpu_map__read_all_cpu_map(void) -{ - struct perf_cpu_map *cpus = NULL; - FILE *onlnf; - - onlnf = fopen("/sys/devices/system/cpu/online", "r"); - if (!onlnf) - return cpu_map__default_new(); - - cpus = perf_cpu_map__read(onlnf); - fclose(onlnf); - return cpus; -} - -struct perf_cpu_map *perf_cpu_map__new(const char *cpu_list) -{ - struct perf_cpu_map *cpus = NULL; - unsigned long start_cpu, end_cpu = 0; - char *p = NULL; - int i, nr_cpus = 0; - int *tmp_cpus = NULL, *tmp; - int max_entries = 0; - - if (!cpu_list) - return cpu_map__read_all_cpu_map(); - - /* - * must handle the case of empty cpumap to cover - * TOPOLOGY header for NUMA nodes with no CPU - * ( e.g., because of CPU hotplug) - */ - if (!isdigit(*cpu_list) && *cpu_list != '\0') - goto out; - - while (isdigit(*cpu_list)) { - p = NULL; - start_cpu = strtoul(cpu_list, &p, 0); - if (start_cpu >= INT_MAX - || (*p != '\0' && *p != ',' && *p != '-')) - goto invalid; - - if (*p == '-') { - cpu_list = ++p; - p = NULL; - end_cpu = strtoul(cpu_list, &p, 0); - - if (end_cpu >= INT_MAX || (*p != '\0' && *p != ',')) - goto invalid; - - if (end_cpu < start_cpu) - goto invalid; - } else { - end_cpu = start_cpu; - } - - WARN_ONCE(end_cpu >= MAX_NR_CPUS, "Perf can support %d CPUs. " - "Consider raising MAX_NR_CPUS\n", MAX_NR_CPUS); - - for (; start_cpu <= end_cpu; start_cpu++) { - /* check for duplicates */ - for (i = 0; i < nr_cpus; i++) - if (tmp_cpus[i] == (int)start_cpu) - goto invalid; - - if (nr_cpus == max_entries) { - max_entries += MAX_NR_CPUS; - tmp = realloc(tmp_cpus, max_entries * sizeof(int)); - if (tmp == NULL) - goto invalid; - tmp_cpus = tmp; - } - tmp_cpus[nr_cpus++] = (int)start_cpu; - } - if (*p) - ++p; - - cpu_list = p; - } - - if (nr_cpus > 0) - cpus = cpu_map__trim_new(nr_cpus, tmp_cpus); - else if (*cpu_list != '\0') - cpus = cpu_map__default_new(); - else - cpus = perf_cpu_map__dummy_new(); -invalid: - free(tmp_cpus); -out: - return cpus; -} - -int perf_cpu_map__cpu(const struct perf_cpu_map *cpus, int idx) -{ - if (idx < cpus->nr) - return cpus->map[idx]; - - return -1; -} - -int perf_cpu_map__nr(const struct perf_cpu_map *cpus) -{ - return cpus ? cpus->nr : 1; -} - -bool perf_cpu_map__empty(const struct perf_cpu_map *map) -{ - return map ? map->map[0] == -1 : true; -} - -int perf_cpu_map__idx(struct perf_cpu_map *cpus, int cpu) -{ - int i; - - for (i = 0; i < cpus->nr; ++i) { - if (cpus->map[i] == cpu) - return i; - } - - return -1; -} - -int perf_cpu_map__max(struct perf_cpu_map *map) -{ - int i, max = -1; - - for (i = 0; i < map->nr; i++) { - if (map->map[i] > max) - max = map->map[i]; - } - - return max; -} diff --git a/tools/perf/lib/evlist.c b/tools/perf/lib/evlist.c deleted file mode 100644 index 205ddbb80bc1..000000000000 --- a/tools/perf/lib/evlist.c +++ /dev/null @@ -1,640 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include <perf/evlist.h> -#include <perf/evsel.h> -#include <linux/bitops.h> -#include <linux/list.h> -#include <linux/hash.h> -#include <sys/ioctl.h> -#include <internal/evlist.h> -#include <internal/evsel.h> -#include <internal/xyarray.h> -#include <internal/mmap.h> -#include <internal/cpumap.h> -#include <internal/threadmap.h> -#include <internal/xyarray.h> -#include <internal/lib.h> -#include <linux/zalloc.h> -#include <sys/ioctl.h> -#include <stdlib.h> -#include <errno.h> -#include <unistd.h> -#include <fcntl.h> -#include <signal.h> -#include <poll.h> -#include <sys/mman.h> -#include <perf/cpumap.h> -#include <perf/threadmap.h> -#include <api/fd/array.h> - -void perf_evlist__init(struct perf_evlist *evlist) -{ - int i; - - for (i = 0; i < PERF_EVLIST__HLIST_SIZE; ++i) - INIT_HLIST_HEAD(&evlist->heads[i]); - INIT_LIST_HEAD(&evlist->entries); - evlist->nr_entries = 0; - fdarray__init(&evlist->pollfd, 64); -} - -static void __perf_evlist__propagate_maps(struct perf_evlist *evlist, - struct perf_evsel *evsel) -{ - /* - * We already have cpus for evsel (via PMU sysfs) so - * keep it, if there's no target cpu list defined. - */ - if (!evsel->own_cpus || evlist->has_user_cpus) { - perf_cpu_map__put(evsel->cpus); - evsel->cpus = perf_cpu_map__get(evlist->cpus); - } else if (evsel->cpus != evsel->own_cpus) { - perf_cpu_map__put(evsel->cpus); - evsel->cpus = perf_cpu_map__get(evsel->own_cpus); - } - - perf_thread_map__put(evsel->threads); - evsel->threads = perf_thread_map__get(evlist->threads); -} - -static void perf_evlist__propagate_maps(struct perf_evlist *evlist) -{ - struct perf_evsel *evsel; - - perf_evlist__for_each_evsel(evlist, evsel) - __perf_evlist__propagate_maps(evlist, evsel); -} - -void perf_evlist__add(struct perf_evlist *evlist, - struct perf_evsel *evsel) -{ - list_add_tail(&evsel->node, &evlist->entries); - evlist->nr_entries += 1; - __perf_evlist__propagate_maps(evlist, evsel); -} - -void perf_evlist__remove(struct perf_evlist *evlist, - struct perf_evsel *evsel) -{ - list_del_init(&evsel->node); - evlist->nr_entries -= 1; -} - -struct perf_evlist *perf_evlist__new(void) -{ - struct perf_evlist *evlist = zalloc(sizeof(*evlist)); - - if (evlist != NULL) - perf_evlist__init(evlist); - - return evlist; -} - -struct perf_evsel * -perf_evlist__next(struct perf_evlist *evlist, struct perf_evsel *prev) -{ - struct perf_evsel *next; - - if (!prev) { - next = list_first_entry(&evlist->entries, - struct perf_evsel, - node); - } else { - next = list_next_entry(prev, node); - } - - /* Empty list is noticed here so don't need checking on entry. */ - if (&next->node == &evlist->entries) - return NULL; - - return next; -} - -static void perf_evlist__purge(struct perf_evlist *evlist) -{ - struct perf_evsel *pos, *n; - - perf_evlist__for_each_entry_safe(evlist, n, pos) { - list_del_init(&pos->node); - perf_evsel__delete(pos); - } - - evlist->nr_entries = 0; -} - -void perf_evlist__exit(struct perf_evlist *evlist) -{ - perf_cpu_map__put(evlist->cpus); - perf_thread_map__put(evlist->threads); - evlist->cpus = NULL; - evlist->threads = NULL; - fdarray__exit(&evlist->pollfd); -} - -void perf_evlist__delete(struct perf_evlist *evlist) -{ - if (evlist == NULL) - return; - - perf_evlist__munmap(evlist); - perf_evlist__close(evlist); - perf_evlist__purge(evlist); - perf_evlist__exit(evlist); - free(evlist); -} - -void perf_evlist__set_maps(struct perf_evlist *evlist, - struct perf_cpu_map *cpus, - struct perf_thread_map *threads) -{ - /* - * Allow for the possibility that one or another of the maps isn't being - * changed i.e. don't put it. Note we are assuming the maps that are - * being applied are brand new and evlist is taking ownership of the - * original reference count of 1. If that is not the case it is up to - * the caller to increase the reference count. - */ - if (cpus != evlist->cpus) { - perf_cpu_map__put(evlist->cpus); - evlist->cpus = perf_cpu_map__get(cpus); - } - - if (threads != evlist->threads) { - perf_thread_map__put(evlist->threads); - evlist->threads = perf_thread_map__get(threads); - } - - perf_evlist__propagate_maps(evlist); -} - -int perf_evlist__open(struct perf_evlist *evlist) -{ - struct perf_evsel *evsel; - int err; - - perf_evlist__for_each_entry(evlist, evsel) { - err = perf_evsel__open(evsel, evsel->cpus, evsel->threads); - if (err < 0) - goto out_err; - } - - return 0; - -out_err: - perf_evlist__close(evlist); - return err; -} - -void perf_evlist__close(struct perf_evlist *evlist) -{ - struct perf_evsel *evsel; - - perf_evlist__for_each_entry_reverse(evlist, evsel) - perf_evsel__close(evsel); -} - -void perf_evlist__enable(struct perf_evlist *evlist) -{ - struct perf_evsel *evsel; - - perf_evlist__for_each_entry(evlist, evsel) - perf_evsel__enable(evsel); -} - -void perf_evlist__disable(struct perf_evlist *evlist) -{ - struct perf_evsel *evsel; - - perf_evlist__for_each_entry(evlist, evsel) - perf_evsel__disable(evsel); -} - -u64 perf_evlist__read_format(struct perf_evlist *evlist) -{ - struct perf_evsel *first = perf_evlist__first(evlist); - - return first->attr.read_format; -} - -#define SID(e, x, y) xyarray__entry(e->sample_id, x, y) - -static void perf_evlist__id_hash(struct perf_evlist *evlist, - struct perf_evsel *evsel, - int cpu, int thread, u64 id) -{ - int hash; - struct perf_sample_id *sid = SID(evsel, cpu, thread); - - sid->id = id; - sid->evsel = evsel; - hash = hash_64(sid->id, PERF_EVLIST__HLIST_BITS); - hlist_add_head(&sid->node, &evlist->heads[hash]); -} - -void perf_evlist__id_add(struct perf_evlist *evlist, - struct perf_evsel *evsel, - int cpu, int thread, u64 id) -{ - perf_evlist__id_hash(evlist, evsel, cpu, thread, id); - evsel->id[evsel->ids++] = id; -} - -int perf_evlist__id_add_fd(struct perf_evlist *evlist, - struct perf_evsel *evsel, - int cpu, int thread, int fd) -{ - u64 read_data[4] = { 0, }; - int id_idx = 1; /* The first entry is the counter value */ - u64 id; - int ret; - - ret = ioctl(fd, PERF_EVENT_IOC_ID, &id); - if (!ret) - goto add; - - if (errno != ENOTTY) - return -1; - - /* Legacy way to get event id.. All hail to old kernels! */ - - /* - * This way does not work with group format read, so bail - * out in that case. - */ - if (perf_evlist__read_format(evlist) & PERF_FORMAT_GROUP) - return -1; - - if (!(evsel->attr.read_format & PERF_FORMAT_ID) || - read(fd, &read_data, sizeof(read_data)) == -1) - return -1; - - if (evsel->attr.read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) - ++id_idx; - if (evsel->attr.read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) - ++id_idx; - - id = read_data[id_idx]; - -add: - perf_evlist__id_add(evlist, evsel, cpu, thread, id); - return 0; -} - -int perf_evlist__alloc_pollfd(struct perf_evlist *evlist) -{ - int nr_cpus = perf_cpu_map__nr(evlist->cpus); - int nr_threads = perf_thread_map__nr(evlist->threads); - int nfds = 0; - struct perf_evsel *evsel; - - perf_evlist__for_each_entry(evlist, evsel) { - if (evsel->system_wide) - nfds += nr_cpus; - else - nfds += nr_cpus * nr_threads; - } - - if (fdarray__available_entries(&evlist->pollfd) < nfds && - fdarray__grow(&evlist->pollfd, nfds) < 0) - return -ENOMEM; - - return 0; -} - -int perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd, - void *ptr, short revent) -{ - int pos = fdarray__add(&evlist->pollfd, fd, revent | POLLERR | POLLHUP); - - if (pos >= 0) { - evlist->pollfd.priv[pos].ptr = ptr; - fcntl(fd, F_SETFL, O_NONBLOCK); - } - - return pos; -} - -static void perf_evlist__munmap_filtered(struct fdarray *fda, int fd, - void *arg __maybe_unused) -{ - struct perf_mmap *map = fda->priv[fd].ptr; - - if (map) - perf_mmap__put(map); -} - -int perf_evlist__filter_pollfd(struct perf_evlist *evlist, short revents_and_mask) -{ - return fdarray__filter(&evlist->pollfd, revents_and_mask, - perf_evlist__munmap_filtered, NULL); -} - -int perf_evlist__poll(struct perf_evlist *evlist, int timeout) -{ - return fdarray__poll(&evlist->pollfd, timeout); -} - -static struct perf_mmap* perf_evlist__alloc_mmap(struct perf_evlist *evlist, bool overwrite) -{ - int i; - struct perf_mmap *map; - - map = zalloc(evlist->nr_mmaps * sizeof(struct perf_mmap)); - if (!map) - return NULL; - - for (i = 0; i < evlist->nr_mmaps; i++) { - struct perf_mmap *prev = i ? &map[i - 1] : NULL; - - /* - * When the perf_mmap() call is made we grab one refcount, plus - * one extra to let perf_mmap__consume() get the last - * events after all real references (perf_mmap__get()) are - * dropped. - * - * Each PERF_EVENT_IOC_SET_OUTPUT points to this mmap and - * thus does perf_mmap__get() on it. - */ - perf_mmap__init(&map[i], prev, overwrite, NULL); - } - - return map; -} - -static void perf_evlist__set_sid_idx(struct perf_evlist *evlist, - struct perf_evsel *evsel, int idx, int cpu, - int thread) -{ - struct perf_sample_id *sid = SID(evsel, cpu, thread); - - sid->idx = idx; - if (evlist->cpus && cpu >= 0) - sid->cpu = evlist->cpus->map[cpu]; - else - sid->cpu = -1; - if (!evsel->system_wide && evlist->threads && thread >= 0) - sid->tid = perf_thread_map__pid(evlist->threads, thread); - else - sid->tid = -1; -} - -static struct perf_mmap* -perf_evlist__mmap_cb_get(struct perf_evlist *evlist, bool overwrite, int idx) -{ - struct perf_mmap *maps; - - maps = overwrite ? evlist->mmap_ovw : evlist->mmap; - - if (!maps) { - maps = perf_evlist__alloc_mmap(evlist, overwrite); - if (!maps) - return NULL; - - if (overwrite) - evlist->mmap_ovw = maps; - else - evlist->mmap = maps; - } - - return &maps[idx]; -} - -#define FD(e, x, y) (*(int *) xyarray__entry(e->fd, x, y)) - -static int -perf_evlist__mmap_cb_mmap(struct perf_mmap *map, struct perf_mmap_param *mp, - int output, int cpu) -{ - return perf_mmap__mmap(map, mp, output, cpu); -} - -static void perf_evlist__set_mmap_first(struct perf_evlist *evlist, struct perf_mmap *map, - bool overwrite) -{ - if (overwrite) - evlist->mmap_ovw_first = map; - else - evlist->mmap_first = map; -} - -static int -mmap_per_evsel(struct perf_evlist *evlist, struct perf_evlist_mmap_ops *ops, - int idx, struct perf_mmap_param *mp, int cpu_idx, - int thread, int *_output, int *_output_overwrite) -{ - int evlist_cpu = perf_cpu_map__cpu(evlist->cpus, cpu_idx); - struct perf_evsel *evsel; - int revent; - - perf_evlist__for_each_entry(evlist, evsel) { - bool overwrite = evsel->attr.write_backward; - struct perf_mmap *map; - int *output, fd, cpu; - - if (evsel->system_wide && thread) - continue; - - cpu = perf_cpu_map__idx(evsel->cpus, evlist_cpu); - if (cpu == -1) - continue; - - map = ops->get(evlist, overwrite, idx); - if (map == NULL) - return -ENOMEM; - - if (overwrite) { - mp->prot = PROT_READ; - output = _output_overwrite; - } else { - mp->prot = PROT_READ | PROT_WRITE; - output = _output; - } - - fd = FD(evsel, cpu, thread); - - if (*output == -1) { - *output = fd; - - /* - * The last one will be done at perf_mmap__consume(), so that we - * make sure we don't prevent tools from consuming every last event in - * the ring buffer. - * - * I.e. we can get the POLLHUP meaning that the fd doesn't exist - * anymore, but the last events for it are still in the ring buffer, - * waiting to be consumed. - * - * Tools can chose to ignore this at their own discretion, but the - * evlist layer can't just drop it when filtering events in - * perf_evlist__filter_pollfd(). - */ - refcount_set(&map->refcnt, 2); - - if (ops->mmap(map, mp, *output, evlist_cpu) < 0) - return -1; - - if (!idx) - perf_evlist__set_mmap_first(evlist, map, overwrite); - } else { - if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, *output) != 0) - return -1; - - perf_mmap__get(map); - } - - revent = !overwrite ? POLLIN : 0; - - if (!evsel->system_wide && - perf_evlist__add_pollfd(evlist, fd, map, revent) < 0) { - perf_mmap__put(map); - return -1; - } - - if (evsel->attr.read_format & PERF_FORMAT_ID) { - if (perf_evlist__id_add_fd(evlist, evsel, cpu, thread, - fd) < 0) - return -1; - perf_evlist__set_sid_idx(evlist, evsel, idx, cpu, - thread); - } - } - - return 0; -} - -static int -mmap_per_thread(struct perf_evlist *evlist, struct perf_evlist_mmap_ops *ops, - struct perf_mmap_param *mp) -{ - int thread; - int nr_threads = perf_thread_map__nr(evlist->threads); - - for (thread = 0; thread < nr_threads; thread++) { - int output = -1; - int output_overwrite = -1; - - if (ops->idx) - ops->idx(evlist, mp, thread, false); - - if (mmap_per_evsel(evlist, ops, thread, mp, 0, thread, - &output, &output_overwrite)) - goto out_unmap; - } - - return 0; - -out_unmap: - perf_evlist__munmap(evlist); - return -1; -} - -static int -mmap_per_cpu(struct perf_evlist *evlist, struct perf_evlist_mmap_ops *ops, - struct perf_mmap_param *mp) -{ - int nr_threads = perf_thread_map__nr(evlist->threads); - int nr_cpus = perf_cpu_map__nr(evlist->cpus); - int cpu, thread; - - for (cpu = 0; cpu < nr_cpus; cpu++) { - int output = -1; - int output_overwrite = -1; - - if (ops->idx) - ops->idx(evlist, mp, cpu, true); - - for (thread = 0; thread < nr_threads; thread++) { - if (mmap_per_evsel(evlist, ops, cpu, mp, cpu, - thread, &output, &output_overwrite)) - goto out_unmap; - } - } - - return 0; - -out_unmap: - perf_evlist__munmap(evlist); - return -1; -} - -static int perf_evlist__nr_mmaps(struct perf_evlist *evlist) -{ - int nr_mmaps; - - nr_mmaps = perf_cpu_map__nr(evlist->cpus); - if (perf_cpu_map__empty(evlist->cpus)) - nr_mmaps = perf_thread_map__nr(evlist->threads); - - return nr_mmaps; -} - -int perf_evlist__mmap_ops(struct perf_evlist *evlist, - struct perf_evlist_mmap_ops *ops, - struct perf_mmap_param *mp) -{ - struct perf_evsel *evsel; - const struct perf_cpu_map *cpus = evlist->cpus; - const struct perf_thread_map *threads = evlist->threads; - - if (!ops || !ops->get || !ops->mmap) - return -EINVAL; - - mp->mask = evlist->mmap_len - page_size - 1; - - evlist->nr_mmaps = perf_evlist__nr_mmaps(evlist); - - perf_evlist__for_each_entry(evlist, evsel) { - if ((evsel->attr.read_format & PERF_FORMAT_ID) && - evsel->sample_id == NULL && - perf_evsel__alloc_id(evsel, perf_cpu_map__nr(cpus), threads->nr) < 0) - return -ENOMEM; - } - - if (evlist->pollfd.entries == NULL && perf_evlist__alloc_pollfd(evlist) < 0) - return -ENOMEM; - - if (perf_cpu_map__empty(cpus)) - return mmap_per_thread(evlist, ops, mp); - - return mmap_per_cpu(evlist, ops, mp); -} - -int perf_evlist__mmap(struct perf_evlist *evlist, int pages) -{ - struct perf_mmap_param mp; - struct perf_evlist_mmap_ops ops = { - .get = perf_evlist__mmap_cb_get, - .mmap = perf_evlist__mmap_cb_mmap, - }; - - evlist->mmap_len = (pages + 1) * page_size; - - return perf_evlist__mmap_ops(evlist, &ops, &mp); -} - -void perf_evlist__munmap(struct perf_evlist *evlist) -{ - int i; - - if (evlist->mmap) { - for (i = 0; i < evlist->nr_mmaps; i++) - perf_mmap__munmap(&evlist->mmap[i]); - } - - if (evlist->mmap_ovw) { - for (i = 0; i < evlist->nr_mmaps; i++) - perf_mmap__munmap(&evlist->mmap_ovw[i]); - } - - zfree(&evlist->mmap); - zfree(&evlist->mmap_ovw); -} - -struct perf_mmap* -perf_evlist__next_mmap(struct perf_evlist *evlist, struct perf_mmap *map, - bool overwrite) -{ - if (map) - return map->next; - - return overwrite ? evlist->mmap_ovw_first : evlist->mmap_first; -} diff --git a/tools/perf/lib/evsel.c b/tools/perf/lib/evsel.c deleted file mode 100644 index 5a89857b0381..000000000000 --- a/tools/perf/lib/evsel.c +++ /dev/null @@ -1,263 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include <errno.h> -#include <unistd.h> -#include <sys/syscall.h> -#include <perf/evsel.h> -#include <perf/cpumap.h> -#include <perf/threadmap.h> -#include <linux/list.h> -#include <internal/evsel.h> -#include <linux/zalloc.h> -#include <stdlib.h> -#include <internal/xyarray.h> -#include <internal/cpumap.h> -#include <internal/threadmap.h> -#include <internal/lib.h> -#include <linux/string.h> -#include <sys/ioctl.h> - -void perf_evsel__init(struct perf_evsel *evsel, struct perf_event_attr *attr) -{ - INIT_LIST_HEAD(&evsel->node); - evsel->attr = *attr; -} - -struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr) -{ - struct perf_evsel *evsel = zalloc(sizeof(*evsel)); - - if (evsel != NULL) - perf_evsel__init(evsel, attr); - - return evsel; -} - -void perf_evsel__delete(struct perf_evsel *evsel) -{ - free(evsel); -} - -#define FD(e, x, y) (*(int *) xyarray__entry(e->fd, x, y)) - -int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads) -{ - evsel->fd = xyarray__new(ncpus, nthreads, sizeof(int)); - - if (evsel->fd) { - int cpu, thread; - for (cpu = 0; cpu < ncpus; cpu++) { - for (thread = 0; thread < nthreads; thread++) { - FD(evsel, cpu, thread) = -1; - } - } - } - - return evsel->fd != NULL ? 0 : -ENOMEM; -} - -static int -sys_perf_event_open(struct perf_event_attr *attr, - pid_t pid, int cpu, int group_fd, - unsigned long flags) -{ - return syscall(__NR_perf_event_open, attr, pid, cpu, group_fd, flags); -} - -int perf_evsel__open(struct perf_evsel *evsel, struct perf_cpu_map *cpus, - struct perf_thread_map *threads) -{ - int cpu, thread, err = 0; - - if (cpus == NULL) { - static struct perf_cpu_map *empty_cpu_map; - - if (empty_cpu_map == NULL) { - empty_cpu_map = perf_cpu_map__dummy_new(); - if (empty_cpu_map == NULL) - return -ENOMEM; - } - - cpus = empty_cpu_map; - } - - if (threads == NULL) { - static struct perf_thread_map *empty_thread_map; - - if (empty_thread_map == NULL) { - empty_thread_map = perf_thread_map__new_dummy(); - if (empty_thread_map == NULL) - return -ENOMEM; - } - - threads = empty_thread_map; - } - - if (evsel->fd == NULL && - perf_evsel__alloc_fd(evsel, cpus->nr, threads->nr) < 0) - return -ENOMEM; - - for (cpu = 0; cpu < cpus->nr; cpu++) { - for (thread = 0; thread < threads->nr; thread++) { - int fd; - - fd = sys_perf_event_open(&evsel->attr, - threads->map[thread].pid, - cpus->map[cpu], -1, 0); - - if (fd < 0) - return -errno; - - FD(evsel, cpu, thread) = fd; - } - } - - return err; -} - -void perf_evsel__close_fd(struct perf_evsel *evsel) -{ - int cpu, thread; - - for (cpu = 0; cpu < xyarray__max_x(evsel->fd); cpu++) - for (thread = 0; thread < xyarray__max_y(evsel->fd); ++thread) { - if (FD(evsel, cpu, thread) >= 0) - close(FD(evsel, cpu, thread)); - FD(evsel, cpu, thread) = -1; - } -} - -void perf_evsel__free_fd(struct perf_evsel *evsel) -{ - xyarray__delete(evsel->fd); - evsel->fd = NULL; -} - -void perf_evsel__close(struct perf_evsel *evsel) -{ - if (evsel->fd == NULL) - return; - - perf_evsel__close_fd(evsel); - perf_evsel__free_fd(evsel); -} - -int perf_evsel__read_size(struct perf_evsel *evsel) -{ - u64 read_format = evsel->attr.read_format; - int entry = sizeof(u64); /* value */ - int size = 0; - int nr = 1; - - if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) - size += sizeof(u64); - - if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) - size += sizeof(u64); - - if (read_format & PERF_FORMAT_ID) - entry += sizeof(u64); - - if (read_format & PERF_FORMAT_GROUP) { - nr = evsel->nr_members; - size += sizeof(u64); - } - - size += entry * nr; - return size; -} - -int perf_evsel__read(struct perf_evsel *evsel, int cpu, int thread, - struct perf_counts_values *count) -{ - size_t size = perf_evsel__read_size(evsel); - - memset(count, 0, sizeof(*count)); - - if (FD(evsel, cpu, thread) < 0) - return -EINVAL; - - if (readn(FD(evsel, cpu, thread), count->values, size) <= 0) - return -errno; - - return 0; -} - -static int perf_evsel__run_ioctl(struct perf_evsel *evsel, - int ioc, void *arg) -{ - int cpu, thread; - - for (cpu = 0; cpu < xyarray__max_x(evsel->fd); cpu++) { - for (thread = 0; thread < xyarray__max_y(evsel->fd); thread++) { - int fd = FD(evsel, cpu, thread), - err = ioctl(fd, ioc, arg); - - if (err) - return err; - } - } - - return 0; -} - -int perf_evsel__enable(struct perf_evsel *evsel) -{ - return perf_evsel__run_ioctl(evsel, PERF_EVENT_IOC_ENABLE, 0); -} - -int perf_evsel__disable(struct perf_evsel *evsel) -{ - return perf_evsel__run_ioctl(evsel, PERF_EVENT_IOC_DISABLE, 0); -} - -int perf_evsel__apply_filter(struct perf_evsel *evsel, const char *filter) -{ - return perf_evsel__run_ioctl(evsel, - PERF_EVENT_IOC_SET_FILTER, - (void *)filter); -} - -struct perf_cpu_map *perf_evsel__cpus(struct perf_evsel *evsel) -{ - return evsel->cpus; -} - -struct perf_thread_map *perf_evsel__threads(struct perf_evsel *evsel) -{ - return evsel->threads; -} - -struct perf_event_attr *perf_evsel__attr(struct perf_evsel *evsel) -{ - return &evsel->attr; -} - -int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads) -{ - if (ncpus == 0 || nthreads == 0) - return 0; - - if (evsel->system_wide) - nthreads = 1; - - evsel->sample_id = xyarray__new(ncpus, nthreads, sizeof(struct perf_sample_id)); - if (evsel->sample_id == NULL) - return -ENOMEM; - - evsel->id = zalloc(ncpus * nthreads * sizeof(u64)); - if (evsel->id == NULL) { - xyarray__delete(evsel->sample_id); - evsel->sample_id = NULL; - return -ENOMEM; - } - - return 0; -} - -void perf_evsel__free_id(struct perf_evsel *evsel) -{ - xyarray__delete(evsel->sample_id); - evsel->sample_id = NULL; - zfree(&evsel->id); - evsel->ids = 0; -} diff --git a/tools/perf/lib/include/internal/cpumap.h b/tools/perf/lib/include/internal/cpumap.h deleted file mode 100644 index 840d4032587b..000000000000 --- a/tools/perf/lib/include/internal/cpumap.h +++ /dev/null @@ -1,19 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef __LIBPERF_INTERNAL_CPUMAP_H -#define __LIBPERF_INTERNAL_CPUMAP_H - -#include <linux/refcount.h> - -struct perf_cpu_map { - refcount_t refcnt; - int nr; - int map[]; -}; - -#ifndef MAX_NR_CPUS -#define MAX_NR_CPUS 2048 -#endif - -int perf_cpu_map__idx(struct perf_cpu_map *cpus, int cpu); - -#endif /* __LIBPERF_INTERNAL_CPUMAP_H */ diff --git a/tools/perf/lib/include/internal/evlist.h b/tools/perf/lib/include/internal/evlist.h deleted file mode 100644 index a2fbccf1922f..000000000000 --- a/tools/perf/lib/include/internal/evlist.h +++ /dev/null @@ -1,126 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef __LIBPERF_INTERNAL_EVLIST_H -#define __LIBPERF_INTERNAL_EVLIST_H - -#include <linux/list.h> -#include <api/fd/array.h> -#include <internal/evsel.h> - -#define PERF_EVLIST__HLIST_BITS 8 -#define PERF_EVLIST__HLIST_SIZE (1 << PERF_EVLIST__HLIST_BITS) - -struct perf_cpu_map; -struct perf_thread_map; -struct perf_mmap_param; - -struct perf_evlist { - struct list_head entries; - int nr_entries; - bool has_user_cpus; - struct perf_cpu_map *cpus; - struct perf_thread_map *threads; - int nr_mmaps; - size_t mmap_len; - struct fdarray pollfd; - struct hlist_head heads[PERF_EVLIST__HLIST_SIZE]; - struct perf_mmap *mmap; - struct perf_mmap *mmap_ovw; - struct perf_mmap *mmap_first; - struct perf_mmap *mmap_ovw_first; -}; - -typedef void -(*perf_evlist_mmap__cb_idx_t)(struct perf_evlist*, struct perf_mmap_param*, int, bool); -typedef struct perf_mmap* -(*perf_evlist_mmap__cb_get_t)(struct perf_evlist*, bool, int); -typedef int -(*perf_evlist_mmap__cb_mmap_t)(struct perf_mmap*, struct perf_mmap_param*, int, int); - -struct perf_evlist_mmap_ops { - perf_evlist_mmap__cb_idx_t idx; - perf_evlist_mmap__cb_get_t get; - perf_evlist_mmap__cb_mmap_t mmap; -}; - -int perf_evlist__alloc_pollfd(struct perf_evlist *evlist); -int perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd, - void *ptr, short revent); - -int perf_evlist__mmap_ops(struct perf_evlist *evlist, - struct perf_evlist_mmap_ops *ops, - struct perf_mmap_param *mp); - -void perf_evlist__init(struct perf_evlist *evlist); -void perf_evlist__exit(struct perf_evlist *evlist); - -/** - * __perf_evlist__for_each_entry - iterate thru all the evsels - * @list: list_head instance to iterate - * @evsel: struct perf_evsel iterator - */ -#define __perf_evlist__for_each_entry(list, evsel) \ - list_for_each_entry(evsel, list, node) - -/** - * evlist__for_each_entry - iterate thru all the evsels - * @evlist: perf_evlist instance to iterate - * @evsel: struct perf_evsel iterator - */ -#define perf_evlist__for_each_entry(evlist, evsel) \ - __perf_evlist__for_each_entry(&(evlist)->entries, evsel) - -/** - * __perf_evlist__for_each_entry_reverse - iterate thru all the evsels in reverse order - * @list: list_head instance to iterate - * @evsel: struct evsel iterator - */ -#define __perf_evlist__for_each_entry_reverse(list, evsel) \ - list_for_each_entry_reverse(evsel, list, node) - -/** - * perf_evlist__for_each_entry_reverse - iterate thru all the evsels in reverse order - * @evlist: evlist instance to iterate - * @evsel: struct evsel iterator - */ -#define perf_evlist__for_each_entry_reverse(evlist, evsel) \ - __perf_evlist__for_each_entry_reverse(&(evlist)->entries, evsel) - -/** - * __perf_evlist__for_each_entry_safe - safely iterate thru all the evsels - * @list: list_head instance to iterate - * @tmp: struct evsel temp iterator - * @evsel: struct evsel iterator - */ -#define __perf_evlist__for_each_entry_safe(list, tmp, evsel) \ - list_for_each_entry_safe(evsel, tmp, list, node) - -/** - * perf_evlist__for_each_entry_safe - safely iterate thru all the evsels - * @evlist: evlist instance to iterate - * @evsel: struct evsel iterator - * @tmp: struct evsel temp iterator - */ -#define perf_evlist__for_each_entry_safe(evlist, tmp, evsel) \ - __perf_evlist__for_each_entry_safe(&(evlist)->entries, tmp, evsel) - -static inline struct perf_evsel *perf_evlist__first(struct perf_evlist *evlist) -{ - return list_entry(evlist->entries.next, struct perf_evsel, node); -} - -static inline struct perf_evsel *perf_evlist__last(struct perf_evlist *evlist) -{ - return list_entry(evlist->entries.prev, struct perf_evsel, node); -} - -u64 perf_evlist__read_format(struct perf_evlist *evlist); - -void perf_evlist__id_add(struct perf_evlist *evlist, - struct perf_evsel *evsel, - int cpu, int thread, u64 id); - -int perf_evlist__id_add_fd(struct perf_evlist *evlist, - struct perf_evsel *evsel, - int cpu, int thread, int fd); - -#endif /* __LIBPERF_INTERNAL_EVLIST_H */ diff --git a/tools/perf/lib/include/internal/evsel.h b/tools/perf/lib/include/internal/evsel.h deleted file mode 100644 index 1ffd083b235e..000000000000 --- a/tools/perf/lib/include/internal/evsel.h +++ /dev/null @@ -1,63 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef __LIBPERF_INTERNAL_EVSEL_H -#define __LIBPERF_INTERNAL_EVSEL_H - -#include <linux/types.h> -#include <linux/perf_event.h> -#include <stdbool.h> -#include <sys/types.h> - -struct perf_cpu_map; -struct perf_thread_map; -struct xyarray; - -/* - * Per fd, to map back from PERF_SAMPLE_ID to evsel, only used when there are - * more than one entry in the evlist. - */ -struct perf_sample_id { - struct hlist_node node; - u64 id; - struct perf_evsel *evsel; - /* - * 'idx' will be used for AUX area sampling. A sample will have AUX area - * data that will be queued for decoding, where there are separate - * queues for each CPU (per-cpu tracing) or task (per-thread tracing). - * The sample ID can be used to lookup 'idx' which is effectively the - * queue number. - */ - int idx; - int cpu; - pid_t tid; - - /* Holds total ID period value for PERF_SAMPLE_READ processing. */ - u64 period; -}; - -struct perf_evsel { - struct list_head node; - struct perf_event_attr attr; - struct perf_cpu_map *cpus; - struct perf_cpu_map *own_cpus; - struct perf_thread_map *threads; - struct xyarray *fd; - struct xyarray *sample_id; - u64 *id; - u32 ids; - - /* parse modifier helper */ - int nr_members; - bool system_wide; -}; - -void perf_evsel__init(struct perf_evsel *evsel, struct perf_event_attr *attr); -int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads); -void perf_evsel__close_fd(struct perf_evsel *evsel); -void perf_evsel__free_fd(struct perf_evsel *evsel); -int perf_evsel__read_size(struct perf_evsel *evsel); -int perf_evsel__apply_filter(struct perf_evsel *evsel, const char *filter); - -int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads); -void perf_evsel__free_id(struct perf_evsel *evsel); - -#endif /* __LIBPERF_INTERNAL_EVSEL_H */ diff --git a/tools/perf/lib/include/internal/lib.h b/tools/perf/lib/include/internal/lib.h deleted file mode 100644 index 5175d491b2d4..000000000000 --- a/tools/perf/lib/include/internal/lib.h +++ /dev/null @@ -1,12 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef __LIBPERF_INTERNAL_LIB_H -#define __LIBPERF_INTERNAL_LIB_H - -#include <sys/types.h> - -extern unsigned int page_size; - -ssize_t readn(int fd, void *buf, size_t n); -ssize_t writen(int fd, const void *buf, size_t n); - -#endif /* __LIBPERF_INTERNAL_CPUMAP_H */ diff --git a/tools/perf/lib/include/internal/mmap.h b/tools/perf/lib/include/internal/mmap.h deleted file mode 100644 index be7556e0a2b2..000000000000 --- a/tools/perf/lib/include/internal/mmap.h +++ /dev/null @@ -1,55 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef __LIBPERF_INTERNAL_MMAP_H -#define __LIBPERF_INTERNAL_MMAP_H - -#include <linux/compiler.h> -#include <linux/refcount.h> -#include <linux/types.h> -#include <stdbool.h> - -/* perf sample has 16 bits size limit */ -#define PERF_SAMPLE_MAX_SIZE (1 << 16) - -struct perf_mmap; - -typedef void (*libperf_unmap_cb_t)(struct perf_mmap *map); - -/** - * struct perf_mmap - perf's ring buffer mmap details - * - * @refcnt - e.g. code using PERF_EVENT_IOC_SET_OUTPUT to share this - */ -struct perf_mmap { - void *base; - int mask; - int fd; - int cpu; - refcount_t refcnt; - u64 prev; - u64 start; - u64 end; - bool overwrite; - u64 flush; - libperf_unmap_cb_t unmap_cb; - char event_copy[PERF_SAMPLE_MAX_SIZE] __aligned(8); - struct perf_mmap *next; -}; - -struct perf_mmap_param { - int prot; - int mask; -}; - -size_t perf_mmap__mmap_len(struct perf_mmap *map); - -void perf_mmap__init(struct perf_mmap *map, struct perf_mmap *prev, - bool overwrite, libperf_unmap_cb_t unmap_cb); -int perf_mmap__mmap(struct perf_mmap *map, struct perf_mmap_param *mp, - int fd, int cpu); -void perf_mmap__munmap(struct perf_mmap *map); -void perf_mmap__get(struct perf_mmap *map); -void perf_mmap__put(struct perf_mmap *map); - -u64 perf_mmap__read_head(struct perf_mmap *map); - -#endif /* __LIBPERF_INTERNAL_MMAP_H */ diff --git a/tools/perf/lib/include/internal/tests.h b/tools/perf/lib/include/internal/tests.h deleted file mode 100644 index 2093e8868a67..000000000000 --- a/tools/perf/lib/include/internal/tests.h +++ /dev/null @@ -1,33 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef __LIBPERF_INTERNAL_TESTS_H -#define __LIBPERF_INTERNAL_TESTS_H - -#include <stdio.h> - -int tests_failed; - -#define __T_START \ -do { \ - fprintf(stdout, "- running %s...", __FILE__); \ - fflush(NULL); \ - tests_failed = 0; \ -} while (0) - -#define __T_END \ -do { \ - if (tests_failed) \ - fprintf(stdout, " FAILED (%d)\n", tests_failed); \ - else \ - fprintf(stdout, "OK\n"); \ -} while (0) - -#define __T(text, cond) \ -do { \ - if (!(cond)) { \ - fprintf(stderr, "FAILED %s:%d %s\n", __FILE__, __LINE__, text); \ - tests_failed++; \ - return -1; \ - } \ -} while (0) - -#endif /* __LIBPERF_INTERNAL_TESTS_H */ diff --git a/tools/perf/lib/include/internal/threadmap.h b/tools/perf/lib/include/internal/threadmap.h deleted file mode 100644 index df748baf9eda..000000000000 --- a/tools/perf/lib/include/internal/threadmap.h +++ /dev/null @@ -1,23 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef __LIBPERF_INTERNAL_THREADMAP_H -#define __LIBPERF_INTERNAL_THREADMAP_H - -#include <linux/refcount.h> -#include <sys/types.h> -#include <unistd.h> - -struct thread_map_data { - pid_t pid; - char *comm; -}; - -struct perf_thread_map { - refcount_t refcnt; - int nr; - int err_thread; - struct thread_map_data map[]; -}; - -struct perf_thread_map *perf_thread_map__realloc(struct perf_thread_map *map, int nr); - -#endif /* __LIBPERF_INTERNAL_THREADMAP_H */ diff --git a/tools/perf/lib/include/internal/xyarray.h b/tools/perf/lib/include/internal/xyarray.h deleted file mode 100644 index 51e35d6c8ec4..000000000000 --- a/tools/perf/lib/include/internal/xyarray.h +++ /dev/null @@ -1,36 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef __LIBPERF_INTERNAL_XYARRAY_H -#define __LIBPERF_INTERNAL_XYARRAY_H - -#include <linux/compiler.h> -#include <sys/types.h> - -struct xyarray { - size_t row_size; - size_t entry_size; - size_t entries; - size_t max_x; - size_t max_y; - char contents[] __aligned(8); -}; - -struct xyarray *xyarray__new(int xlen, int ylen, size_t entry_size); -void xyarray__delete(struct xyarray *xy); -void xyarray__reset(struct xyarray *xy); - -static inline void *xyarray__entry(struct xyarray *xy, int x, int y) -{ - return &xy->contents[x * xy->row_size + y * xy->entry_size]; -} - -static inline int xyarray__max_y(struct xyarray *xy) -{ - return xy->max_y; -} - -static inline int xyarray__max_x(struct xyarray *xy) -{ - return xy->max_x; -} - -#endif /* __LIBPERF_INTERNAL_XYARRAY_H */ diff --git a/tools/perf/lib/include/perf/core.h b/tools/perf/lib/include/perf/core.h deleted file mode 100644 index a3f6d68edad7..000000000000 --- a/tools/perf/lib/include/perf/core.h +++ /dev/null @@ -1,25 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef __LIBPERF_CORE_H -#define __LIBPERF_CORE_H - -#include <stdarg.h> - -#ifndef LIBPERF_API -#define LIBPERF_API __attribute__((visibility("default"))) -#endif - -enum libperf_print_level { - LIBPERF_ERR, - LIBPERF_WARN, - LIBPERF_INFO, - LIBPERF_DEBUG, - LIBPERF_DEBUG2, - LIBPERF_DEBUG3, -}; - -typedef int (*libperf_print_fn_t)(enum libperf_print_level level, - const char *, va_list ap); - -LIBPERF_API void libperf_init(libperf_print_fn_t fn); - -#endif /* __LIBPERF_CORE_H */ diff --git a/tools/perf/lib/include/perf/cpumap.h b/tools/perf/lib/include/perf/cpumap.h deleted file mode 100644 index ac9aa497f84a..000000000000 --- a/tools/perf/lib/include/perf/cpumap.h +++ /dev/null @@ -1,26 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef __LIBPERF_CPUMAP_H -#define __LIBPERF_CPUMAP_H - -#include <perf/core.h> -#include <stdio.h> -#include <stdbool.h> - -struct perf_cpu_map; - -LIBPERF_API struct perf_cpu_map *perf_cpu_map__dummy_new(void); -LIBPERF_API struct perf_cpu_map *perf_cpu_map__new(const char *cpu_list); -LIBPERF_API struct perf_cpu_map *perf_cpu_map__read(FILE *file); -LIBPERF_API struct perf_cpu_map *perf_cpu_map__get(struct perf_cpu_map *map); -LIBPERF_API void perf_cpu_map__put(struct perf_cpu_map *map); -LIBPERF_API int perf_cpu_map__cpu(const struct perf_cpu_map *cpus, int idx); -LIBPERF_API int perf_cpu_map__nr(const struct perf_cpu_map *cpus); -LIBPERF_API bool perf_cpu_map__empty(const struct perf_cpu_map *map); -LIBPERF_API int perf_cpu_map__max(struct perf_cpu_map *map); - -#define perf_cpu_map__for_each_cpu(cpu, idx, cpus) \ - for ((idx) = 0, (cpu) = perf_cpu_map__cpu(cpus, idx); \ - (idx) < perf_cpu_map__nr(cpus); \ - (idx)++, (cpu) = perf_cpu_map__cpu(cpus, idx)) - -#endif /* __LIBPERF_CPUMAP_H */ diff --git a/tools/perf/lib/include/perf/event.h b/tools/perf/lib/include/perf/event.h deleted file mode 100644 index 18106899cb4e..000000000000 --- a/tools/perf/lib/include/perf/event.h +++ /dev/null @@ -1,385 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef __LIBPERF_EVENT_H -#define __LIBPERF_EVENT_H - -#include <linux/perf_event.h> -#include <linux/types.h> -#include <linux/limits.h> -#include <linux/bpf.h> -#include <sys/types.h> /* pid_t */ - -struct perf_record_mmap { - struct perf_event_header header; - __u32 pid, tid; - __u64 start; - __u64 len; - __u64 pgoff; - char filename[PATH_MAX]; -}; - -struct perf_record_mmap2 { - struct perf_event_header header; - __u32 pid, tid; - __u64 start; - __u64 len; - __u64 pgoff; - __u32 maj; - __u32 min; - __u64 ino; - __u64 ino_generation; - __u32 prot; - __u32 flags; - char filename[PATH_MAX]; -}; - -struct perf_record_comm { - struct perf_event_header header; - __u32 pid, tid; - char comm[16]; -}; - -struct perf_record_namespaces { - struct perf_event_header header; - __u32 pid, tid; - __u64 nr_namespaces; - struct perf_ns_link_info link_info[]; -}; - -struct perf_record_fork { - struct perf_event_header header; - __u32 pid, ppid; - __u32 tid, ptid; - __u64 time; -}; - -struct perf_record_lost { - struct perf_event_header header; - __u64 id; - __u64 lost; -}; - -struct perf_record_lost_samples { - struct perf_event_header header; - __u64 lost; -}; - -/* - * PERF_FORMAT_ENABLED | PERF_FORMAT_RUNNING | PERF_FORMAT_ID - */ -struct perf_record_read { - struct perf_event_header header; - __u32 pid, tid; - __u64 value; - __u64 time_enabled; - __u64 time_running; - __u64 id; -}; - -struct perf_record_throttle { - struct perf_event_header header; - __u64 time; - __u64 id; - __u64 stream_id; -}; - -#ifndef KSYM_NAME_LEN -#define KSYM_NAME_LEN 256 -#endif - -struct perf_record_ksymbol { - struct perf_event_header header; - __u64 addr; - __u32 len; - __u16 ksym_type; - __u16 flags; - char name[KSYM_NAME_LEN]; -}; - -struct perf_record_bpf_event { - struct perf_event_header header; - __u16 type; - __u16 flags; - __u32 id; - - /* for bpf_prog types */ - __u8 tag[BPF_TAG_SIZE]; // prog tag -}; - -struct perf_record_sample { - struct perf_event_header header; - __u64 array[]; -}; - -struct perf_record_switch { - struct perf_event_header header; - __u32 next_prev_pid; - __u32 next_prev_tid; -}; - -struct perf_record_header_attr { - struct perf_event_header header; - struct perf_event_attr attr; - __u64 id[]; -}; - -enum { - PERF_CPU_MAP__CPUS = 0, - PERF_CPU_MAP__MASK = 1, -}; - -struct cpu_map_entries { - __u16 nr; - __u16 cpu[]; -}; - -struct perf_record_record_cpu_map { - __u16 nr; - __u16 long_size; - unsigned long mask[]; -}; - -struct perf_record_cpu_map_data { - __u16 type; - char data[]; -}; - -struct perf_record_cpu_map { - struct perf_event_header header; - struct perf_record_cpu_map_data data; -}; - -enum { - PERF_EVENT_UPDATE__UNIT = 0, - PERF_EVENT_UPDATE__SCALE = 1, - PERF_EVENT_UPDATE__NAME = 2, - PERF_EVENT_UPDATE__CPUS = 3, -}; - -struct perf_record_event_update_cpus { - struct perf_record_cpu_map_data cpus; -}; - -struct perf_record_event_update_scale { - double scale; -}; - -struct perf_record_event_update { - struct perf_event_header header; - __u64 type; - __u64 id; - char data[]; -}; - -#define MAX_EVENT_NAME 64 - -struct perf_trace_event_type { - __u64 event_id; - char name[MAX_EVENT_NAME]; -}; - -struct perf_record_header_event_type { - struct perf_event_header header; - struct perf_trace_event_type event_type; -}; - -struct perf_record_header_tracing_data { - struct perf_event_header header; - __u32 size; -}; - -struct perf_record_header_build_id { - struct perf_event_header header; - pid_t pid; - __u8 build_id[24]; - char filename[]; -}; - -struct id_index_entry { - __u64 id; - __u64 idx; - __u64 cpu; - __u64 tid; -}; - -struct perf_record_id_index { - struct perf_event_header header; - __u64 nr; - struct id_index_entry entries[0]; -}; - -struct perf_record_auxtrace_info { - struct perf_event_header header; - __u32 type; - __u32 reserved__; /* For alignment */ - __u64 priv[]; -}; - -struct perf_record_auxtrace { - struct perf_event_header header; - __u64 size; - __u64 offset; - __u64 reference; - __u32 idx; - __u32 tid; - __u32 cpu; - __u32 reserved__; /* For alignment */ -}; - -#define MAX_AUXTRACE_ERROR_MSG 64 - -struct perf_record_auxtrace_error { - struct perf_event_header header; - __u32 type; - __u32 code; - __u32 cpu; - __u32 pid; - __u32 tid; - __u32 fmt; - __u64 ip; - __u64 time; - char msg[MAX_AUXTRACE_ERROR_MSG]; -}; - -struct perf_record_aux { - struct perf_event_header header; - __u64 aux_offset; - __u64 aux_size; - __u64 flags; -}; - -struct perf_record_itrace_start { - struct perf_event_header header; - __u32 pid; - __u32 tid; -}; - -struct perf_record_thread_map_entry { - __u64 pid; - char comm[16]; -}; - -struct perf_record_thread_map { - struct perf_event_header header; - __u64 nr; - struct perf_record_thread_map_entry entries[]; -}; - -enum { - PERF_STAT_CONFIG_TERM__AGGR_MODE = 0, - PERF_STAT_CONFIG_TERM__INTERVAL = 1, - PERF_STAT_CONFIG_TERM__SCALE = 2, - PERF_STAT_CONFIG_TERM__MAX = 3, -}; - -struct perf_record_stat_config_entry { - __u64 tag; - __u64 val; -}; - -struct perf_record_stat_config { - struct perf_event_header header; - __u64 nr; - struct perf_record_stat_config_entry data[]; -}; - -struct perf_record_stat { - struct perf_event_header header; - - __u64 id; - __u32 cpu; - __u32 thread; - - union { - struct { - __u64 val; - __u64 ena; - __u64 run; - }; - __u64 values[3]; - }; -}; - -struct perf_record_stat_round { - struct perf_event_header header; - __u64 type; - __u64 time; -}; - -struct perf_record_time_conv { - struct perf_event_header header; - __u64 time_shift; - __u64 time_mult; - __u64 time_zero; -}; - -struct perf_record_header_feature { - struct perf_event_header header; - __u64 feat_id; - char data[]; -}; - -struct perf_record_compressed { - struct perf_event_header header; - char data[]; -}; - -enum perf_user_event_type { /* above any possible kernel type */ - PERF_RECORD_USER_TYPE_START = 64, - PERF_RECORD_HEADER_ATTR = 64, - PERF_RECORD_HEADER_EVENT_TYPE = 65, /* deprecated */ - PERF_RECORD_HEADER_TRACING_DATA = 66, - PERF_RECORD_HEADER_BUILD_ID = 67, - PERF_RECORD_FINISHED_ROUND = 68, - PERF_RECORD_ID_INDEX = 69, - PERF_RECORD_AUXTRACE_INFO = 70, - PERF_RECORD_AUXTRACE = 71, - PERF_RECORD_AUXTRACE_ERROR = 72, - PERF_RECORD_THREAD_MAP = 73, - PERF_RECORD_CPU_MAP = 74, - PERF_RECORD_STAT_CONFIG = 75, - PERF_RECORD_STAT = 76, - PERF_RECORD_STAT_ROUND = 77, - PERF_RECORD_EVENT_UPDATE = 78, - PERF_RECORD_TIME_CONV = 79, - PERF_RECORD_HEADER_FEATURE = 80, - PERF_RECORD_COMPRESSED = 81, - PERF_RECORD_HEADER_MAX -}; - -union perf_event { - struct perf_event_header header; - struct perf_record_mmap mmap; - struct perf_record_mmap2 mmap2; - struct perf_record_comm comm; - struct perf_record_namespaces namespaces; - struct perf_record_fork fork; - struct perf_record_lost lost; - struct perf_record_lost_samples lost_samples; - struct perf_record_read read; - struct perf_record_throttle throttle; - struct perf_record_sample sample; - struct perf_record_bpf_event bpf; - struct perf_record_ksymbol ksymbol; - struct perf_record_header_attr attr; - struct perf_record_event_update event_update; - struct perf_record_header_event_type event_type; - struct perf_record_header_tracing_data tracing_data; - struct perf_record_header_build_id build_id; - struct perf_record_id_index id_index; - struct perf_record_auxtrace_info auxtrace_info; - struct perf_record_auxtrace auxtrace; - struct perf_record_auxtrace_error auxtrace_error; - struct perf_record_aux aux; - struct perf_record_itrace_start itrace_start; - struct perf_record_switch context_switch; - struct perf_record_thread_map thread_map; - struct perf_record_cpu_map cpu_map; - struct perf_record_stat_config stat_config; - struct perf_record_stat stat; - struct perf_record_stat_round stat_round; - struct perf_record_time_conv time_conv; - struct perf_record_header_feature feat; - struct perf_record_compressed pack; -}; - -#endif /* __LIBPERF_EVENT_H */ diff --git a/tools/perf/lib/include/perf/evlist.h b/tools/perf/lib/include/perf/evlist.h deleted file mode 100644 index 0a7479dc13bf..000000000000 --- a/tools/perf/lib/include/perf/evlist.h +++ /dev/null @@ -1,49 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef __LIBPERF_EVLIST_H -#define __LIBPERF_EVLIST_H - -#include <perf/core.h> -#include <stdbool.h> - -struct perf_evlist; -struct perf_evsel; -struct perf_cpu_map; -struct perf_thread_map; - -LIBPERF_API void perf_evlist__add(struct perf_evlist *evlist, - struct perf_evsel *evsel); -LIBPERF_API void perf_evlist__remove(struct perf_evlist *evlist, - struct perf_evsel *evsel); -LIBPERF_API struct perf_evlist *perf_evlist__new(void); -LIBPERF_API void perf_evlist__delete(struct perf_evlist *evlist); -LIBPERF_API struct perf_evsel* perf_evlist__next(struct perf_evlist *evlist, - struct perf_evsel *evsel); -LIBPERF_API int perf_evlist__open(struct perf_evlist *evlist); -LIBPERF_API void perf_evlist__close(struct perf_evlist *evlist); -LIBPERF_API void perf_evlist__enable(struct perf_evlist *evlist); -LIBPERF_API void perf_evlist__disable(struct perf_evlist *evlist); - -#define perf_evlist__for_each_evsel(evlist, pos) \ - for ((pos) = perf_evlist__next((evlist), NULL); \ - (pos) != NULL; \ - (pos) = perf_evlist__next((evlist), (pos))) - -LIBPERF_API void perf_evlist__set_maps(struct perf_evlist *evlist, - struct perf_cpu_map *cpus, - struct perf_thread_map *threads); -LIBPERF_API int perf_evlist__poll(struct perf_evlist *evlist, int timeout); -LIBPERF_API int perf_evlist__filter_pollfd(struct perf_evlist *evlist, - short revents_and_mask); - -LIBPERF_API int perf_evlist__mmap(struct perf_evlist *evlist, int pages); -LIBPERF_API void perf_evlist__munmap(struct perf_evlist *evlist); - -LIBPERF_API struct perf_mmap *perf_evlist__next_mmap(struct perf_evlist *evlist, - struct perf_mmap *map, - bool overwrite); -#define perf_evlist__for_each_mmap(evlist, pos, overwrite) \ - for ((pos) = perf_evlist__next_mmap((evlist), NULL, overwrite); \ - (pos) != NULL; \ - (pos) = perf_evlist__next_mmap((evlist), (pos), overwrite)) - -#endif /* __LIBPERF_EVLIST_H */ diff --git a/tools/perf/lib/include/perf/evsel.h b/tools/perf/lib/include/perf/evsel.h deleted file mode 100644 index 557f5815a9c9..000000000000 --- a/tools/perf/lib/include/perf/evsel.h +++ /dev/null @@ -1,37 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef __LIBPERF_EVSEL_H -#define __LIBPERF_EVSEL_H - -#include <stdint.h> -#include <perf/core.h> - -struct perf_evsel; -struct perf_event_attr; -struct perf_cpu_map; -struct perf_thread_map; - -struct perf_counts_values { - union { - struct { - uint64_t val; - uint64_t ena; - uint64_t run; - }; - uint64_t values[3]; - }; -}; - -LIBPERF_API struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr); -LIBPERF_API void perf_evsel__delete(struct perf_evsel *evsel); -LIBPERF_API int perf_evsel__open(struct perf_evsel *evsel, struct perf_cpu_map *cpus, - struct perf_thread_map *threads); -LIBPERF_API void perf_evsel__close(struct perf_evsel *evsel); -LIBPERF_API int perf_evsel__read(struct perf_evsel *evsel, int cpu, int thread, - struct perf_counts_values *count); -LIBPERF_API int perf_evsel__enable(struct perf_evsel *evsel); -LIBPERF_API int perf_evsel__disable(struct perf_evsel *evsel); -LIBPERF_API struct perf_cpu_map *perf_evsel__cpus(struct perf_evsel *evsel); -LIBPERF_API struct perf_thread_map *perf_evsel__threads(struct perf_evsel *evsel); -LIBPERF_API struct perf_event_attr *perf_evsel__attr(struct perf_evsel *evsel); - -#endif /* __LIBPERF_EVSEL_H */ diff --git a/tools/perf/lib/include/perf/mmap.h b/tools/perf/lib/include/perf/mmap.h deleted file mode 100644 index 9508ad90d8b9..000000000000 --- a/tools/perf/lib/include/perf/mmap.h +++ /dev/null @@ -1,15 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef __LIBPERF_MMAP_H -#define __LIBPERF_MMAP_H - -#include <perf/core.h> - -struct perf_mmap; -union perf_event; - -LIBPERF_API void perf_mmap__consume(struct perf_mmap *map); -LIBPERF_API int perf_mmap__read_init(struct perf_mmap *map); -LIBPERF_API void perf_mmap__read_done(struct perf_mmap *map); -LIBPERF_API union perf_event *perf_mmap__read_event(struct perf_mmap *map); - -#endif /* __LIBPERF_MMAP_H */ diff --git a/tools/perf/lib/include/perf/threadmap.h b/tools/perf/lib/include/perf/threadmap.h deleted file mode 100644 index a7c50de8d010..000000000000 --- a/tools/perf/lib/include/perf/threadmap.h +++ /dev/null @@ -1,20 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef __LIBPERF_THREADMAP_H -#define __LIBPERF_THREADMAP_H - -#include <perf/core.h> -#include <sys/types.h> - -struct perf_thread_map; - -LIBPERF_API struct perf_thread_map *perf_thread_map__new_dummy(void); - -LIBPERF_API void perf_thread_map__set_pid(struct perf_thread_map *map, int thread, pid_t pid); -LIBPERF_API char *perf_thread_map__comm(struct perf_thread_map *map, int thread); -LIBPERF_API int perf_thread_map__nr(struct perf_thread_map *threads); -LIBPERF_API pid_t perf_thread_map__pid(struct perf_thread_map *map, int thread); - -LIBPERF_API struct perf_thread_map *perf_thread_map__get(struct perf_thread_map *map); -LIBPERF_API void perf_thread_map__put(struct perf_thread_map *map); - -#endif /* __LIBPERF_THREADMAP_H */ diff --git a/tools/perf/lib/internal.h b/tools/perf/lib/internal.h deleted file mode 100644 index 2c27e158de6b..000000000000 --- a/tools/perf/lib/internal.h +++ /dev/null @@ -1,23 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef __LIBPERF_INTERNAL_H -#define __LIBPERF_INTERNAL_H - -#include <perf/core.h> - -void libperf_print(enum libperf_print_level level, - const char *format, ...) - __attribute__((format(printf, 2, 3))); - -#define __pr(level, fmt, ...) \ -do { \ - libperf_print(level, "libperf: " fmt, ##__VA_ARGS__); \ -} while (0) - -#define pr_err(fmt, ...) __pr(LIBPERF_ERR, fmt, ##__VA_ARGS__) -#define pr_warning(fmt, ...) __pr(LIBPERF_WARN, fmt, ##__VA_ARGS__) -#define pr_info(fmt, ...) __pr(LIBPERF_INFO, fmt, ##__VA_ARGS__) -#define pr_debug(fmt, ...) __pr(LIBPERF_DEBUG, fmt, ##__VA_ARGS__) -#define pr_debug2(fmt, ...) __pr(LIBPERF_DEBUG2, fmt, ##__VA_ARGS__) -#define pr_debug3(fmt, ...) __pr(LIBPERF_DEBUG3, fmt, ##__VA_ARGS__) - -#endif /* __LIBPERF_INTERNAL_H */ diff --git a/tools/perf/lib/lib.c b/tools/perf/lib/lib.c deleted file mode 100644 index 18658931fc71..000000000000 --- a/tools/perf/lib/lib.c +++ /dev/null @@ -1,48 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include <unistd.h> -#include <stdbool.h> -#include <errno.h> -#include <linux/kernel.h> -#include <internal/lib.h> - -unsigned int page_size; - -static ssize_t ion(bool is_read, int fd, void *buf, size_t n) -{ - void *buf_start = buf; - size_t left = n; - - while (left) { - /* buf must be treated as const if !is_read. */ - ssize_t ret = is_read ? read(fd, buf, left) : - write(fd, buf, left); - - if (ret < 0 && errno == EINTR) - continue; - if (ret <= 0) - return ret; - - left -= ret; - buf += ret; - } - - BUG_ON((size_t)(buf - buf_start) != n); - return n; -} - -/* - * Read exactly 'n' bytes or return an error. - */ -ssize_t readn(int fd, void *buf, size_t n) -{ - return ion(true, fd, buf, n); -} - -/* - * Write exactly 'n' bytes or return an error. - */ -ssize_t writen(int fd, const void *buf, size_t n) -{ - /* ion does not modify buf. */ - return ion(false, fd, (void *)buf, n); -} diff --git a/tools/perf/lib/libperf.map b/tools/perf/lib/libperf.map deleted file mode 100644 index 7be1af8a546c..000000000000 --- a/tools/perf/lib/libperf.map +++ /dev/null @@ -1,51 +0,0 @@ -LIBPERF_0.0.1 { - global: - libperf_init; - perf_cpu_map__dummy_new; - perf_cpu_map__get; - perf_cpu_map__put; - perf_cpu_map__new; - perf_cpu_map__read; - perf_cpu_map__nr; - perf_cpu_map__cpu; - perf_cpu_map__empty; - perf_cpu_map__max; - perf_thread_map__new_dummy; - perf_thread_map__set_pid; - perf_thread_map__comm; - perf_thread_map__nr; - perf_thread_map__pid; - perf_thread_map__get; - perf_thread_map__put; - perf_evsel__new; - perf_evsel__delete; - perf_evsel__enable; - perf_evsel__disable; - perf_evsel__open; - perf_evsel__close; - perf_evsel__read; - perf_evsel__cpus; - perf_evsel__threads; - perf_evsel__attr; - perf_evlist__new; - perf_evlist__delete; - perf_evlist__open; - perf_evlist__close; - perf_evlist__enable; - perf_evlist__disable; - perf_evlist__add; - perf_evlist__remove; - perf_evlist__next; - perf_evlist__set_maps; - perf_evlist__poll; - perf_evlist__mmap; - perf_evlist__munmap; - perf_evlist__filter_pollfd; - perf_evlist__next_mmap; - perf_mmap__consume; - perf_mmap__read_init; - perf_mmap__read_done; - perf_mmap__read_event; - local: - *; -}; diff --git a/tools/perf/lib/libperf.pc.template b/tools/perf/lib/libperf.pc.template deleted file mode 100644 index 117e4a237b55..000000000000 --- a/tools/perf/lib/libperf.pc.template +++ /dev/null @@ -1,11 +0,0 @@ -# SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) - -prefix=@PREFIX@ -libdir=@LIBDIR@ -includedir=${prefix}/include - -Name: libperf -Description: perf library -Version: @VERSION@ -Libs: -L${libdir} -lperf -Cflags: -I${includedir} diff --git a/tools/perf/lib/mmap.c b/tools/perf/lib/mmap.c deleted file mode 100644 index 79d5ed6c38cc..000000000000 --- a/tools/perf/lib/mmap.c +++ /dev/null @@ -1,275 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include <sys/mman.h> -#include <inttypes.h> -#include <asm/bug.h> -#include <errno.h> -#include <string.h> -#include <linux/ring_buffer.h> -#include <linux/perf_event.h> -#include <perf/mmap.h> -#include <perf/event.h> -#include <internal/mmap.h> -#include <internal/lib.h> -#include <linux/kernel.h> -#include "internal.h" - -void perf_mmap__init(struct perf_mmap *map, struct perf_mmap *prev, - bool overwrite, libperf_unmap_cb_t unmap_cb) -{ - map->fd = -1; - map->overwrite = overwrite; - map->unmap_cb = unmap_cb; - refcount_set(&map->refcnt, 0); - if (prev) - prev->next = map; -} - -size_t perf_mmap__mmap_len(struct perf_mmap *map) -{ - return map->mask + 1 + page_size; -} - -int perf_mmap__mmap(struct perf_mmap *map, struct perf_mmap_param *mp, - int fd, int cpu) -{ - map->prev = 0; - map->mask = mp->mask; - map->base = mmap(NULL, perf_mmap__mmap_len(map), mp->prot, - MAP_SHARED, fd, 0); - if (map->base == MAP_FAILED) { - map->base = NULL; - return -1; - } - - map->fd = fd; - map->cpu = cpu; - return 0; -} - -void perf_mmap__munmap(struct perf_mmap *map) -{ - if (map && map->base != NULL) { - munmap(map->base, perf_mmap__mmap_len(map)); - map->base = NULL; - map->fd = -1; - refcount_set(&map->refcnt, 0); - } - if (map && map->unmap_cb) - map->unmap_cb(map); -} - -void perf_mmap__get(struct perf_mmap *map) -{ - refcount_inc(&map->refcnt); -} - -void perf_mmap__put(struct perf_mmap *map) -{ - BUG_ON(map->base && refcount_read(&map->refcnt) == 0); - - if (refcount_dec_and_test(&map->refcnt)) - perf_mmap__munmap(map); -} - -static inline void perf_mmap__write_tail(struct perf_mmap *md, u64 tail) -{ - ring_buffer_write_tail(md->base, tail); -} - -u64 perf_mmap__read_head(struct perf_mmap *map) -{ - return ring_buffer_read_head(map->base); -} - -static bool perf_mmap__empty(struct perf_mmap *map) -{ - struct perf_event_mmap_page *pc = map->base; - - return perf_mmap__read_head(map) == map->prev && !pc->aux_size; -} - -void perf_mmap__consume(struct perf_mmap *map) -{ - if (!map->overwrite) { - u64 old = map->prev; - - perf_mmap__write_tail(map, old); - } - - if (refcount_read(&map->refcnt) == 1 && perf_mmap__empty(map)) - perf_mmap__put(map); -} - -static int overwrite_rb_find_range(void *buf, int mask, u64 *start, u64 *end) -{ - struct perf_event_header *pheader; - u64 evt_head = *start; - int size = mask + 1; - - pr_debug2("%s: buf=%p, start=%"PRIx64"\n", __func__, buf, *start); - pheader = (struct perf_event_header *)(buf + (*start & mask)); - while (true) { - if (evt_head - *start >= (unsigned int)size) { - pr_debug("Finished reading overwrite ring buffer: rewind\n"); - if (evt_head - *start > (unsigned int)size) - evt_head -= pheader->size; - *end = evt_head; - return 0; - } - - pheader = (struct perf_event_header *)(buf + (evt_head & mask)); - - if (pheader->size == 0) { - pr_debug("Finished reading overwrite ring buffer: get start\n"); - *end = evt_head; - return 0; - } - - evt_head += pheader->size; - pr_debug3("move evt_head: %"PRIx64"\n", evt_head); - } - WARN_ONCE(1, "Shouldn't get here\n"); - return -1; -} - -/* - * Report the start and end of the available data in ringbuffer - */ -static int __perf_mmap__read_init(struct perf_mmap *md) -{ - u64 head = perf_mmap__read_head(md); - u64 old = md->prev; - unsigned char *data = md->base + page_size; - unsigned long size; - - md->start = md->overwrite ? head : old; - md->end = md->overwrite ? old : head; - - if ((md->end - md->start) < md->flush) - return -EAGAIN; - - size = md->end - md->start; - if (size > (unsigned long)(md->mask) + 1) { - if (!md->overwrite) { - WARN_ONCE(1, "failed to keep up with mmap data. (warn only once)\n"); - - md->prev = head; - perf_mmap__consume(md); - return -EAGAIN; - } - - /* - * Backward ring buffer is full. We still have a chance to read - * most of data from it. - */ - if (overwrite_rb_find_range(data, md->mask, &md->start, &md->end)) - return -EINVAL; - } - - return 0; -} - -int perf_mmap__read_init(struct perf_mmap *map) -{ - /* - * Check if event was unmapped due to a POLLHUP/POLLERR. - */ - if (!refcount_read(&map->refcnt)) - return -ENOENT; - - return __perf_mmap__read_init(map); -} - -/* - * Mandatory for overwrite mode - * The direction of overwrite mode is backward. - * The last perf_mmap__read() will set tail to map->core.prev. - * Need to correct the map->core.prev to head which is the end of next read. - */ -void perf_mmap__read_done(struct perf_mmap *map) -{ - /* - * Check if event was unmapped due to a POLLHUP/POLLERR. - */ - if (!refcount_read(&map->refcnt)) - return; - - map->prev = perf_mmap__read_head(map); -} - -/* When check_messup is true, 'end' must points to a good entry */ -static union perf_event *perf_mmap__read(struct perf_mmap *map, - u64 *startp, u64 end) -{ - unsigned char *data = map->base + page_size; - union perf_event *event = NULL; - int diff = end - *startp; - - if (diff >= (int)sizeof(event->header)) { - size_t size; - - event = (union perf_event *)&data[*startp & map->mask]; - size = event->header.size; - - if (size < sizeof(event->header) || diff < (int)size) - return NULL; - - /* - * Event straddles the mmap boundary -- header should always - * be inside due to u64 alignment of output. - */ - if ((*startp & map->mask) + size != ((*startp + size) & map->mask)) { - unsigned int offset = *startp; - unsigned int len = min(sizeof(*event), size), cpy; - void *dst = map->event_copy; - - do { - cpy = min(map->mask + 1 - (offset & map->mask), len); - memcpy(dst, &data[offset & map->mask], cpy); - offset += cpy; - dst += cpy; - len -= cpy; - } while (len); - - event = (union perf_event *)map->event_copy; - } - - *startp += size; - } - - return event; -} - -/* - * Read event from ring buffer one by one. - * Return one event for each call. - * - * Usage: - * perf_mmap__read_init() - * while(event = perf_mmap__read_event()) { - * //process the event - * perf_mmap__consume() - * } - * perf_mmap__read_done() - */ -union perf_event *perf_mmap__read_event(struct perf_mmap *map) -{ - union perf_event *event; - - /* - * Check if event was unmapped due to a POLLHUP/POLLERR. - */ - if (!refcount_read(&map->refcnt)) - return NULL; - - /* non-overwirte doesn't pause the ringbuffer */ - if (!map->overwrite) - map->end = perf_mmap__read_head(map); - - event = perf_mmap__read(map, &map->start, map->end); - - if (!map->overwrite) - map->prev = map->start; - - return event; -} diff --git a/tools/perf/lib/tests/Makefile b/tools/perf/lib/tests/Makefile deleted file mode 100644 index a43cd08c5c03..000000000000 --- a/tools/perf/lib/tests/Makefile +++ /dev/null @@ -1,38 +0,0 @@ -# SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) - -TESTS = test-cpumap test-threadmap test-evlist test-evsel - -TESTS_SO := $(addsuffix -so,$(TESTS)) -TESTS_A := $(addsuffix -a,$(TESTS)) - -# Set compile option CFLAGS -ifdef EXTRA_CFLAGS - CFLAGS := $(EXTRA_CFLAGS) -else - CFLAGS := -g -Wall -endif - -all: - -include $(srctree)/tools/scripts/Makefile.include - -INCLUDE = -I$(srctree)/tools/perf/lib/include -I$(srctree)/tools/include -I$(srctree)/tools/lib - -$(TESTS_A): FORCE - $(QUIET_LINK)$(CC) $(INCLUDE) $(CFLAGS) -o $@ $(subst -a,.c,$@) ../libperf.a $(LIBAPI) - -$(TESTS_SO): FORCE - $(QUIET_LINK)$(CC) $(INCLUDE) $(CFLAGS) -L.. -o $@ $(subst -so,.c,$@) $(LIBAPI) -lperf - -all: $(TESTS_A) $(TESTS_SO) - -run: - @echo "running static:" - @for i in $(TESTS_A); do ./$$i; done - @echo "running dynamic:" - @for i in $(TESTS_SO); do LD_LIBRARY_PATH=../ ./$$i; done - -clean: - $(call QUIET_CLEAN, tests)$(RM) $(TESTS_A) $(TESTS_SO) - -.PHONY: all clean FORCE diff --git a/tools/perf/lib/tests/test-cpumap.c b/tools/perf/lib/tests/test-cpumap.c deleted file mode 100644 index c8d45091e7c2..000000000000 --- a/tools/perf/lib/tests/test-cpumap.c +++ /dev/null @@ -1,31 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include <stdarg.h> -#include <stdio.h> -#include <perf/cpumap.h> -#include <internal/tests.h> - -static int libperf_print(enum libperf_print_level level, - const char *fmt, va_list ap) -{ - return vfprintf(stderr, fmt, ap); -} - -int main(int argc, char **argv) -{ - struct perf_cpu_map *cpus; - - __T_START; - - libperf_init(libperf_print); - - cpus = perf_cpu_map__dummy_new(); - if (!cpus) - return -1; - - perf_cpu_map__get(cpus); - perf_cpu_map__put(cpus); - perf_cpu_map__put(cpus); - - __T_END; - return 0; -} diff --git a/tools/perf/lib/tests/test-evlist.c b/tools/perf/lib/tests/test-evlist.c deleted file mode 100644 index 6d8ebe0c2504..000000000000 --- a/tools/perf/lib/tests/test-evlist.c +++ /dev/null @@ -1,413 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#define _GNU_SOURCE // needed for sched.h to get sched_[gs]etaffinity and CPU_(ZERO,SET) -#include <sched.h> -#include <stdio.h> -#include <stdarg.h> -#include <unistd.h> -#include <stdlib.h> -#include <linux/perf_event.h> -#include <linux/limits.h> -#include <sys/types.h> -#include <sys/wait.h> -#include <sys/prctl.h> -#include <perf/cpumap.h> -#include <perf/threadmap.h> -#include <perf/evlist.h> -#include <perf/evsel.h> -#include <perf/mmap.h> -#include <perf/event.h> -#include <internal/tests.h> -#include <api/fs/fs.h> - -static int libperf_print(enum libperf_print_level level, - const char *fmt, va_list ap) -{ - return vfprintf(stderr, fmt, ap); -} - -static int test_stat_cpu(void) -{ - struct perf_cpu_map *cpus; - struct perf_evlist *evlist; - struct perf_evsel *evsel; - struct perf_event_attr attr1 = { - .type = PERF_TYPE_SOFTWARE, - .config = PERF_COUNT_SW_CPU_CLOCK, - }; - struct perf_event_attr attr2 = { - .type = PERF_TYPE_SOFTWARE, - .config = PERF_COUNT_SW_TASK_CLOCK, - }; - int err, cpu, tmp; - - cpus = perf_cpu_map__new(NULL); - __T("failed to create cpus", cpus); - - evlist = perf_evlist__new(); - __T("failed to create evlist", evlist); - - evsel = perf_evsel__new(&attr1); - __T("failed to create evsel1", evsel); - - perf_evlist__add(evlist, evsel); - - evsel = perf_evsel__new(&attr2); - __T("failed to create evsel2", evsel); - - perf_evlist__add(evlist, evsel); - - perf_evlist__set_maps(evlist, cpus, NULL); - - err = perf_evlist__open(evlist); - __T("failed to open evsel", err == 0); - - perf_evlist__for_each_evsel(evlist, evsel) { - cpus = perf_evsel__cpus(evsel); - - perf_cpu_map__for_each_cpu(cpu, tmp, cpus) { - struct perf_counts_values counts = { .val = 0 }; - - perf_evsel__read(evsel, cpu, 0, &counts); - __T("failed to read value for evsel", counts.val != 0); - } - } - - perf_evlist__close(evlist); - perf_evlist__delete(evlist); - - perf_cpu_map__put(cpus); - return 0; -} - -static int test_stat_thread(void) -{ - struct perf_counts_values counts = { .val = 0 }; - struct perf_thread_map *threads; - struct perf_evlist *evlist; - struct perf_evsel *evsel; - struct perf_event_attr attr1 = { - .type = PERF_TYPE_SOFTWARE, - .config = PERF_COUNT_SW_CPU_CLOCK, - }; - struct perf_event_attr attr2 = { - .type = PERF_TYPE_SOFTWARE, - .config = PERF_COUNT_SW_TASK_CLOCK, - }; - int err; - - threads = perf_thread_map__new_dummy(); - __T("failed to create threads", threads); - - perf_thread_map__set_pid(threads, 0, 0); - - evlist = perf_evlist__new(); - __T("failed to create evlist", evlist); - - evsel = perf_evsel__new(&attr1); - __T("failed to create evsel1", evsel); - - perf_evlist__add(evlist, evsel); - - evsel = perf_evsel__new(&attr2); - __T("failed to create evsel2", evsel); - - perf_evlist__add(evlist, evsel); - - perf_evlist__set_maps(evlist, NULL, threads); - - err = perf_evlist__open(evlist); - __T("failed to open evsel", err == 0); - - perf_evlist__for_each_evsel(evlist, evsel) { - perf_evsel__read(evsel, 0, 0, &counts); - __T("failed to read value for evsel", counts.val != 0); - } - - perf_evlist__close(evlist); - perf_evlist__delete(evlist); - - perf_thread_map__put(threads); - return 0; -} - -static int test_stat_thread_enable(void) -{ - struct perf_counts_values counts = { .val = 0 }; - struct perf_thread_map *threads; - struct perf_evlist *evlist; - struct perf_evsel *evsel; - struct perf_event_attr attr1 = { - .type = PERF_TYPE_SOFTWARE, - .config = PERF_COUNT_SW_CPU_CLOCK, - .disabled = 1, - }; - struct perf_event_attr attr2 = { - .type = PERF_TYPE_SOFTWARE, - .config = PERF_COUNT_SW_TASK_CLOCK, - .disabled = 1, - }; - int err; - - threads = perf_thread_map__new_dummy(); - __T("failed to create threads", threads); - - perf_thread_map__set_pid(threads, 0, 0); - - evlist = perf_evlist__new(); - __T("failed to create evlist", evlist); - - evsel = perf_evsel__new(&attr1); - __T("failed to create evsel1", evsel); - - perf_evlist__add(evlist, evsel); - - evsel = perf_evsel__new(&attr2); - __T("failed to create evsel2", evsel); - - perf_evlist__add(evlist, evsel); - - perf_evlist__set_maps(evlist, NULL, threads); - - err = perf_evlist__open(evlist); - __T("failed to open evsel", err == 0); - - perf_evlist__for_each_evsel(evlist, evsel) { - perf_evsel__read(evsel, 0, 0, &counts); - __T("failed to read value for evsel", counts.val == 0); - } - - perf_evlist__enable(evlist); - - perf_evlist__for_each_evsel(evlist, evsel) { - perf_evsel__read(evsel, 0, 0, &counts); - __T("failed to read value for evsel", counts.val != 0); - } - - perf_evlist__disable(evlist); - - perf_evlist__close(evlist); - perf_evlist__delete(evlist); - - perf_thread_map__put(threads); - return 0; -} - -static int test_mmap_thread(void) -{ - struct perf_evlist *evlist; - struct perf_evsel *evsel; - struct perf_mmap *map; - struct perf_cpu_map *cpus; - struct perf_thread_map *threads; - struct perf_event_attr attr = { - .type = PERF_TYPE_TRACEPOINT, - .sample_period = 1, - .wakeup_watermark = 1, - .disabled = 1, - }; - char path[PATH_MAX]; - int id, err, pid, go_pipe[2]; - union perf_event *event; - char bf; - int count = 0; - - snprintf(path, PATH_MAX, "%s/kernel/debug/tracing/events/syscalls/sys_enter_prctl/id", - sysfs__mountpoint()); - - if (filename__read_int(path, &id)) { - fprintf(stderr, "error: failed to get tracepoint id: %s\n", path); - return -1; - } - - attr.config = id; - - err = pipe(go_pipe); - __T("failed to create pipe", err == 0); - - fflush(NULL); - - pid = fork(); - if (!pid) { - int i; - - read(go_pipe[0], &bf, 1); - - /* Generate 100 prctl calls. */ - for (i = 0; i < 100; i++) - prctl(0, 0, 0, 0, 0); - - exit(0); - } - - threads = perf_thread_map__new_dummy(); - __T("failed to create threads", threads); - - cpus = perf_cpu_map__dummy_new(); - __T("failed to create cpus", cpus); - - perf_thread_map__set_pid(threads, 0, pid); - - evlist = perf_evlist__new(); - __T("failed to create evlist", evlist); - - evsel = perf_evsel__new(&attr); - __T("failed to create evsel1", evsel); - - perf_evlist__add(evlist, evsel); - - perf_evlist__set_maps(evlist, cpus, threads); - - err = perf_evlist__open(evlist); - __T("failed to open evlist", err == 0); - - err = perf_evlist__mmap(evlist, 4); - __T("failed to mmap evlist", err == 0); - - perf_evlist__enable(evlist); - - /* kick the child and wait for it to finish */ - write(go_pipe[1], &bf, 1); - waitpid(pid, NULL, 0); - - /* - * There's no need to call perf_evlist__disable, - * monitored process is dead now. - */ - - perf_evlist__for_each_mmap(evlist, map, false) { - if (perf_mmap__read_init(map) < 0) - continue; - - while ((event = perf_mmap__read_event(map)) != NULL) { - count++; - perf_mmap__consume(map); - } - - perf_mmap__read_done(map); - } - - /* calls perf_evlist__munmap/perf_evlist__close */ - perf_evlist__delete(evlist); - - perf_thread_map__put(threads); - perf_cpu_map__put(cpus); - - /* - * The generated prctl calls should match the - * number of events in the buffer. - */ - __T("failed count", count == 100); - - return 0; -} - -static int test_mmap_cpus(void) -{ - struct perf_evlist *evlist; - struct perf_evsel *evsel; - struct perf_mmap *map; - struct perf_cpu_map *cpus; - struct perf_event_attr attr = { - .type = PERF_TYPE_TRACEPOINT, - .sample_period = 1, - .wakeup_watermark = 1, - .disabled = 1, - }; - cpu_set_t saved_mask; - char path[PATH_MAX]; - int id, err, cpu, tmp; - union perf_event *event; - int count = 0; - - snprintf(path, PATH_MAX, "%s/kernel/debug/tracing/events/syscalls/sys_enter_prctl/id", - sysfs__mountpoint()); - - if (filename__read_int(path, &id)) { - fprintf(stderr, "error: failed to get tracepoint id: %s\n", path); - return -1; - } - - attr.config = id; - - cpus = perf_cpu_map__new(NULL); - __T("failed to create cpus", cpus); - - evlist = perf_evlist__new(); - __T("failed to create evlist", evlist); - - evsel = perf_evsel__new(&attr); - __T("failed to create evsel1", evsel); - - perf_evlist__add(evlist, evsel); - - perf_evlist__set_maps(evlist, cpus, NULL); - - err = perf_evlist__open(evlist); - __T("failed to open evlist", err == 0); - - err = perf_evlist__mmap(evlist, 4); - __T("failed to mmap evlist", err == 0); - - perf_evlist__enable(evlist); - - err = sched_getaffinity(0, sizeof(saved_mask), &saved_mask); - __T("sched_getaffinity failed", err == 0); - - perf_cpu_map__for_each_cpu(cpu, tmp, cpus) { - cpu_set_t mask; - - CPU_ZERO(&mask); - CPU_SET(cpu, &mask); - - err = sched_setaffinity(0, sizeof(mask), &mask); - __T("sched_setaffinity failed", err == 0); - - prctl(0, 0, 0, 0, 0); - } - - err = sched_setaffinity(0, sizeof(saved_mask), &saved_mask); - __T("sched_setaffinity failed", err == 0); - - perf_evlist__disable(evlist); - - perf_evlist__for_each_mmap(evlist, map, false) { - if (perf_mmap__read_init(map) < 0) - continue; - - while ((event = perf_mmap__read_event(map)) != NULL) { - count++; - perf_mmap__consume(map); - } - - perf_mmap__read_done(map); - } - - /* calls perf_evlist__munmap/perf_evlist__close */ - perf_evlist__delete(evlist); - - /* - * The generated prctl events should match the - * number of cpus or be bigger (we are system-wide). - */ - __T("failed count", count >= perf_cpu_map__nr(cpus)); - - perf_cpu_map__put(cpus); - - return 0; -} - -int main(int argc, char **argv) -{ - __T_START; - - libperf_init(libperf_print); - - test_stat_cpu(); - test_stat_thread(); - test_stat_thread_enable(); - test_mmap_thread(); - test_mmap_cpus(); - - __T_END; - return 0; -} diff --git a/tools/perf/lib/tests/test-evsel.c b/tools/perf/lib/tests/test-evsel.c deleted file mode 100644 index 135722ac965b..000000000000 --- a/tools/perf/lib/tests/test-evsel.c +++ /dev/null @@ -1,135 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include <stdarg.h> -#include <stdio.h> -#include <linux/perf_event.h> -#include <perf/cpumap.h> -#include <perf/threadmap.h> -#include <perf/evsel.h> -#include <internal/tests.h> - -static int libperf_print(enum libperf_print_level level, - const char *fmt, va_list ap) -{ - return vfprintf(stderr, fmt, ap); -} - -static int test_stat_cpu(void) -{ - struct perf_cpu_map *cpus; - struct perf_evsel *evsel; - struct perf_event_attr attr = { - .type = PERF_TYPE_SOFTWARE, - .config = PERF_COUNT_SW_CPU_CLOCK, - }; - int err, cpu, tmp; - - cpus = perf_cpu_map__new(NULL); - __T("failed to create cpus", cpus); - - evsel = perf_evsel__new(&attr); - __T("failed to create evsel", evsel); - - err = perf_evsel__open(evsel, cpus, NULL); - __T("failed to open evsel", err == 0); - - perf_cpu_map__for_each_cpu(cpu, tmp, cpus) { - struct perf_counts_values counts = { .val = 0 }; - - perf_evsel__read(evsel, cpu, 0, &counts); - __T("failed to read value for evsel", counts.val != 0); - } - - perf_evsel__close(evsel); - perf_evsel__delete(evsel); - - perf_cpu_map__put(cpus); - return 0; -} - -static int test_stat_thread(void) -{ - struct perf_counts_values counts = { .val = 0 }; - struct perf_thread_map *threads; - struct perf_evsel *evsel; - struct perf_event_attr attr = { - .type = PERF_TYPE_SOFTWARE, - .config = PERF_COUNT_SW_TASK_CLOCK, - }; - int err; - - threads = perf_thread_map__new_dummy(); - __T("failed to create threads", threads); - - perf_thread_map__set_pid(threads, 0, 0); - - evsel = perf_evsel__new(&attr); - __T("failed to create evsel", evsel); - - err = perf_evsel__open(evsel, NULL, threads); - __T("failed to open evsel", err == 0); - - perf_evsel__read(evsel, 0, 0, &counts); - __T("failed to read value for evsel", counts.val != 0); - - perf_evsel__close(evsel); - perf_evsel__delete(evsel); - - perf_thread_map__put(threads); - return 0; -} - -static int test_stat_thread_enable(void) -{ - struct perf_counts_values counts = { .val = 0 }; - struct perf_thread_map *threads; - struct perf_evsel *evsel; - struct perf_event_attr attr = { - .type = PERF_TYPE_SOFTWARE, - .config = PERF_COUNT_SW_TASK_CLOCK, - .disabled = 1, - }; - int err; - - threads = perf_thread_map__new_dummy(); - __T("failed to create threads", threads); - - perf_thread_map__set_pid(threads, 0, 0); - - evsel = perf_evsel__new(&attr); - __T("failed to create evsel", evsel); - - err = perf_evsel__open(evsel, NULL, threads); - __T("failed to open evsel", err == 0); - - perf_evsel__read(evsel, 0, 0, &counts); - __T("failed to read value for evsel", counts.val == 0); - - err = perf_evsel__enable(evsel); - __T("failed to enable evsel", err == 0); - - perf_evsel__read(evsel, 0, 0, &counts); - __T("failed to read value for evsel", counts.val != 0); - - err = perf_evsel__disable(evsel); - __T("failed to enable evsel", err == 0); - - perf_evsel__close(evsel); - perf_evsel__delete(evsel); - - perf_thread_map__put(threads); - return 0; -} - -int main(int argc, char **argv) -{ - __T_START; - - libperf_init(libperf_print); - - test_stat_cpu(); - test_stat_thread(); - test_stat_thread_enable(); - - __T_END; - return 0; -} diff --git a/tools/perf/lib/tests/test-threadmap.c b/tools/perf/lib/tests/test-threadmap.c deleted file mode 100644 index 7dc4d6fbedde..000000000000 --- a/tools/perf/lib/tests/test-threadmap.c +++ /dev/null @@ -1,31 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include <stdarg.h> -#include <stdio.h> -#include <perf/threadmap.h> -#include <internal/tests.h> - -static int libperf_print(enum libperf_print_level level, - const char *fmt, va_list ap) -{ - return vfprintf(stderr, fmt, ap); -} - -int main(int argc, char **argv) -{ - struct perf_thread_map *threads; - - __T_START; - - libperf_init(libperf_print); - - threads = perf_thread_map__new_dummy(); - if (!threads) - return -1; - - perf_thread_map__get(threads); - perf_thread_map__put(threads); - perf_thread_map__put(threads); - - __T_END; - return 0; -} diff --git a/tools/perf/lib/threadmap.c b/tools/perf/lib/threadmap.c deleted file mode 100644 index e92c368b0a6c..000000000000 --- a/tools/perf/lib/threadmap.c +++ /dev/null @@ -1,91 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include <perf/threadmap.h> -#include <stdlib.h> -#include <linux/refcount.h> -#include <internal/threadmap.h> -#include <string.h> -#include <asm/bug.h> -#include <stdio.h> - -static void perf_thread_map__reset(struct perf_thread_map *map, int start, int nr) -{ - size_t size = (nr - start) * sizeof(map->map[0]); - - memset(&map->map[start], 0, size); - map->err_thread = -1; -} - -struct perf_thread_map *perf_thread_map__realloc(struct perf_thread_map *map, int nr) -{ - size_t size = sizeof(*map) + sizeof(map->map[0]) * nr; - int start = map ? map->nr : 0; - - map = realloc(map, size); - /* - * We only realloc to add more items, let's reset new items. - */ - if (map) - perf_thread_map__reset(map, start, nr); - - return map; -} - -#define thread_map__alloc(__nr) perf_thread_map__realloc(NULL, __nr) - -void perf_thread_map__set_pid(struct perf_thread_map *map, int thread, pid_t pid) -{ - map->map[thread].pid = pid; -} - -char *perf_thread_map__comm(struct perf_thread_map *map, int thread) -{ - return map->map[thread].comm; -} - -struct perf_thread_map *perf_thread_map__new_dummy(void) -{ - struct perf_thread_map *threads = thread_map__alloc(1); - - if (threads != NULL) { - perf_thread_map__set_pid(threads, 0, -1); - threads->nr = 1; - refcount_set(&threads->refcnt, 1); - } - return threads; -} - -static void perf_thread_map__delete(struct perf_thread_map *threads) -{ - if (threads) { - int i; - - WARN_ONCE(refcount_read(&threads->refcnt) != 0, - "thread map refcnt unbalanced\n"); - for (i = 0; i < threads->nr; i++) - free(perf_thread_map__comm(threads, i)); - free(threads); - } -} - -struct perf_thread_map *perf_thread_map__get(struct perf_thread_map *map) -{ - if (map) - refcount_inc(&map->refcnt); - return map; -} - -void perf_thread_map__put(struct perf_thread_map *map) -{ - if (map && refcount_dec_and_test(&map->refcnt)) - perf_thread_map__delete(map); -} - -int perf_thread_map__nr(struct perf_thread_map *threads) -{ - return threads ? threads->nr : 1; -} - -pid_t perf_thread_map__pid(struct perf_thread_map *map, int thread) -{ - return map->map[thread].pid; -} diff --git a/tools/perf/lib/xyarray.c b/tools/perf/lib/xyarray.c deleted file mode 100644 index dcd901d154bb..000000000000 --- a/tools/perf/lib/xyarray.c +++ /dev/null @@ -1,33 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include <internal/xyarray.h> -#include <linux/zalloc.h> -#include <stdlib.h> -#include <string.h> - -struct xyarray *xyarray__new(int xlen, int ylen, size_t entry_size) -{ - size_t row_size = ylen * entry_size; - struct xyarray *xy = zalloc(sizeof(*xy) + xlen * row_size); - - if (xy != NULL) { - xy->entry_size = entry_size; - xy->row_size = row_size; - xy->entries = xlen * ylen; - xy->max_x = xlen; - xy->max_y = ylen; - } - - return xy; -} - -void xyarray__reset(struct xyarray *xy) -{ - size_t n = xy->entries * xy->entry_size; - - memset(xy->contents, 0, n); -} - -void xyarray__delete(struct xyarray *xy) -{ - free(xy); -} diff --git a/tools/perf/pmu-events/arch/s390/cf_z13/extended.json b/tools/perf/pmu-events/arch/s390/cf_z13/extended.json index 436ce33f1182..5da8296b667e 100644 --- a/tools/perf/pmu-events/arch/s390/cf_z13/extended.json +++ b/tools/perf/pmu-events/arch/s390/cf_z13/extended.json @@ -32,7 +32,7 @@ "EventCode": "132", "EventName": "DTLB1_GPAGE_WRITES", "BriefDescription": "DTLB1 Two-Gigabyte Page Writes", - "PublicDescription": "Counter:132 Name:DTLB1_GPAGE_WRITES A translation entry has been written to the Level-1 Data Translation Lookaside Buffer for a two-gigabyte page." + "PublicDescription": "A translation entry has been written to the Level-1 Data Translation Lookaside Buffer for a two-gigabyte page." }, { "Unit": "CPU-M-CF", diff --git a/tools/perf/pmu-events/arch/s390/cf_z14/extended.json b/tools/perf/pmu-events/arch/s390/cf_z14/extended.json index 68618152ea2c..89e070727e1b 100644 --- a/tools/perf/pmu-events/arch/s390/cf_z14/extended.json +++ b/tools/perf/pmu-events/arch/s390/cf_z14/extended.json @@ -4,7 +4,7 @@ "EventCode": "128", "EventName": "L1D_RO_EXCL_WRITES", "BriefDescription": "L1D Read-only Exclusive Writes", - "PublicDescription": "L1D_RO_EXCL_WRITES A directory write to the Level-1 Data cache where the line was originally in a Read-Only state in the cache but has been updated to be in the Exclusive state that allows stores to the cache line" + "PublicDescription": "A directory write to the Level-1 Data cache where the line was originally in a Read-Only state in the cache but has been updated to be in the Exclusive state that allows stores to the cache line" }, { "Unit": "CPU-M-CF", diff --git a/tools/perf/pmu-events/arch/x86/broadwell/bdw-metrics.json b/tools/perf/pmu-events/arch/x86/broadwell/bdw-metrics.json index bc7151d639d7..45a34ce4fe89 100644 --- a/tools/perf/pmu-events/arch/x86/broadwell/bdw-metrics.json +++ b/tools/perf/pmu-events/arch/x86/broadwell/bdw-metrics.json @@ -297,7 +297,7 @@ }, { "BriefDescription": "Fraction of cycles spent in Kernel mode", - "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC:u / CPU_CLK_UNHALTED.REF_TSC", + "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC:k / CPU_CLK_UNHALTED.REF_TSC", "MetricGroup": "Summary", "MetricName": "Kernel_Utilization" }, diff --git a/tools/perf/pmu-events/arch/x86/broadwellde/bdwde-metrics.json b/tools/perf/pmu-events/arch/x86/broadwellde/bdwde-metrics.json index 49c5f123d811..961fe4395758 100644 --- a/tools/perf/pmu-events/arch/x86/broadwellde/bdwde-metrics.json +++ b/tools/perf/pmu-events/arch/x86/broadwellde/bdwde-metrics.json @@ -115,7 +115,7 @@ }, { "BriefDescription": "Fraction of cycles spent in Kernel mode", - "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC:u / CPU_CLK_UNHALTED.REF_TSC", + "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC:k / CPU_CLK_UNHALTED.REF_TSC", "MetricGroup": "Summary", "MetricName": "Kernel_Utilization" }, diff --git a/tools/perf/pmu-events/arch/x86/broadwellx/bdx-metrics.json b/tools/perf/pmu-events/arch/x86/broadwellx/bdx-metrics.json index 113d19e92678..746734ce09be 100644 --- a/tools/perf/pmu-events/arch/x86/broadwellx/bdx-metrics.json +++ b/tools/perf/pmu-events/arch/x86/broadwellx/bdx-metrics.json @@ -297,7 +297,7 @@ }, { "BriefDescription": "Fraction of cycles spent in Kernel mode", - "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC:u / CPU_CLK_UNHALTED.REF_TSC", + "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC:k / CPU_CLK_UNHALTED.REF_TSC", "MetricGroup": "Summary", "MetricName": "Kernel_Utilization" }, diff --git a/tools/perf/pmu-events/arch/x86/cascadelakex/clx-metrics.json b/tools/perf/pmu-events/arch/x86/cascadelakex/clx-metrics.json index 2ba32af9bc36..f94653229dd4 100644 --- a/tools/perf/pmu-events/arch/x86/cascadelakex/clx-metrics.json +++ b/tools/perf/pmu-events/arch/x86/cascadelakex/clx-metrics.json @@ -315,7 +315,7 @@ }, { "BriefDescription": "Fraction of cycles spent in Kernel mode", - "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC:u / CPU_CLK_UNHALTED.REF_TSC", + "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC:k / CPU_CLK_UNHALTED.REF_TSC", "MetricGroup": "Summary", "MetricName": "Kernel_Utilization" }, diff --git a/tools/perf/pmu-events/arch/x86/haswell/hsw-metrics.json b/tools/perf/pmu-events/arch/x86/haswell/hsw-metrics.json index c80f16fde6d0..5402cd3120f9 100644 --- a/tools/perf/pmu-events/arch/x86/haswell/hsw-metrics.json +++ b/tools/perf/pmu-events/arch/x86/haswell/hsw-metrics.json @@ -267,7 +267,7 @@ }, { "BriefDescription": "Fraction of cycles spent in Kernel mode", - "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC:u / CPU_CLK_UNHALTED.REF_TSC", + "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC:k / CPU_CLK_UNHALTED.REF_TSC", "MetricGroup": "Summary", "MetricName": "Kernel_Utilization" }, diff --git a/tools/perf/pmu-events/arch/x86/haswellx/hsx-metrics.json b/tools/perf/pmu-events/arch/x86/haswellx/hsx-metrics.json index e501729c3dd1..832f3cb40b34 100644 --- a/tools/perf/pmu-events/arch/x86/haswellx/hsx-metrics.json +++ b/tools/perf/pmu-events/arch/x86/haswellx/hsx-metrics.json @@ -267,7 +267,7 @@ }, { "BriefDescription": "Fraction of cycles spent in Kernel mode", - "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC:u / CPU_CLK_UNHALTED.REF_TSC", + "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC:k / CPU_CLK_UNHALTED.REF_TSC", "MetricGroup": "Summary", "MetricName": "Kernel_Utilization" }, diff --git a/tools/perf/pmu-events/arch/x86/ivybridge/ivb-metrics.json b/tools/perf/pmu-events/arch/x86/ivybridge/ivb-metrics.json index e2446966b651..d69b2a8fc0bc 100644 --- a/tools/perf/pmu-events/arch/x86/ivybridge/ivb-metrics.json +++ b/tools/perf/pmu-events/arch/x86/ivybridge/ivb-metrics.json @@ -285,7 +285,7 @@ }, { "BriefDescription": "Fraction of cycles spent in Kernel mode", - "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC:u / CPU_CLK_UNHALTED.REF_TSC", + "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC:k / CPU_CLK_UNHALTED.REF_TSC", "MetricGroup": "Summary", "MetricName": "Kernel_Utilization" }, diff --git a/tools/perf/pmu-events/arch/x86/ivytown/ivt-metrics.json b/tools/perf/pmu-events/arch/x86/ivytown/ivt-metrics.json index 9294769dec64..5f465fd81315 100644 --- a/tools/perf/pmu-events/arch/x86/ivytown/ivt-metrics.json +++ b/tools/perf/pmu-events/arch/x86/ivytown/ivt-metrics.json @@ -285,7 +285,7 @@ }, { "BriefDescription": "Fraction of cycles spent in Kernel mode", - "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC:u / CPU_CLK_UNHALTED.REF_TSC", + "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC:k / CPU_CLK_UNHALTED.REF_TSC", "MetricGroup": "Summary", "MetricName": "Kernel_Utilization" }, diff --git a/tools/perf/pmu-events/arch/x86/jaketown/jkt-metrics.json b/tools/perf/pmu-events/arch/x86/jaketown/jkt-metrics.json index 603ff9c2e9a1..3e909b306003 100644 --- a/tools/perf/pmu-events/arch/x86/jaketown/jkt-metrics.json +++ b/tools/perf/pmu-events/arch/x86/jaketown/jkt-metrics.json @@ -171,7 +171,7 @@ }, { "BriefDescription": "Fraction of cycles spent in Kernel mode", - "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC:u / CPU_CLK_UNHALTED.REF_TSC", + "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC:k / CPU_CLK_UNHALTED.REF_TSC", "MetricGroup": "Summary", "MetricName": "Kernel_Utilization" }, diff --git a/tools/perf/pmu-events/arch/x86/sandybridge/snb-metrics.json b/tools/perf/pmu-events/arch/x86/sandybridge/snb-metrics.json index c6b485b3a2cb..50c053235752 100644 --- a/tools/perf/pmu-events/arch/x86/sandybridge/snb-metrics.json +++ b/tools/perf/pmu-events/arch/x86/sandybridge/snb-metrics.json @@ -171,7 +171,7 @@ }, { "BriefDescription": "Fraction of cycles spent in Kernel mode", - "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC:u / CPU_CLK_UNHALTED.REF_TSC", + "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC:k / CPU_CLK_UNHALTED.REF_TSC", "MetricGroup": "Summary", "MetricName": "Kernel_Utilization" }, diff --git a/tools/perf/pmu-events/arch/x86/skylake/skl-metrics.json b/tools/perf/pmu-events/arch/x86/skylake/skl-metrics.json index 0ca539bb60f6..e7feb60f9fa9 100644 --- a/tools/perf/pmu-events/arch/x86/skylake/skl-metrics.json +++ b/tools/perf/pmu-events/arch/x86/skylake/skl-metrics.json @@ -303,7 +303,7 @@ }, { "BriefDescription": "Fraction of cycles spent in Kernel mode", - "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC:u / CPU_CLK_UNHALTED.REF_TSC", + "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC:k / CPU_CLK_UNHALTED.REF_TSC", "MetricGroup": "Summary", "MetricName": "Kernel_Utilization" }, diff --git a/tools/perf/pmu-events/arch/x86/skylakex/skx-metrics.json b/tools/perf/pmu-events/arch/x86/skylakex/skx-metrics.json index 047d7e11aa6f..21d7a0c2c2e8 100644 --- a/tools/perf/pmu-events/arch/x86/skylakex/skx-metrics.json +++ b/tools/perf/pmu-events/arch/x86/skylakex/skx-metrics.json @@ -315,7 +315,7 @@ }, { "BriefDescription": "Fraction of cycles spent in Kernel mode", - "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC:u / CPU_CLK_UNHALTED.REF_TSC", + "MetricExpr": "CPU_CLK_UNHALTED.REF_TSC:k / CPU_CLK_UNHALTED.REF_TSC", "MetricGroup": "Summary", "MetricName": "Kernel_Utilization" }, diff --git a/tools/perf/tests/Build b/tools/perf/tests/Build index a3c595fba943..1692529639b0 100644 --- a/tools/perf/tests/Build +++ b/tools/perf/tests/Build @@ -54,6 +54,7 @@ perf-y += unit_number__scnprintf.o perf-y += mem2node.o perf-y += maps.o perf-y += time-utils-test.o +perf-y += genelf.o $(OUTPUT)tests/llvm-src-base.c: tests/bpf-script-example.c tests/Build $(call rule_mkdir) diff --git a/tools/perf/tests/bp_signal.c b/tools/perf/tests/bp_signal.c index 415903b48578..da8ec1e8e064 100644 --- a/tools/perf/tests/bp_signal.c +++ b/tools/perf/tests/bp_signal.c @@ -263,20 +263,20 @@ int test__bp_signal(struct test *test __maybe_unused, int subtest __maybe_unused if (count1 == 11) pr_debug("failed: RF EFLAG recursion issue detected\n"); else - pr_debug("failed: wrong count for bp1%lld\n", count1); + pr_debug("failed: wrong count for bp1: %lld, expected 1\n", count1); } if (overflows != 3) - pr_debug("failed: wrong overflow hit\n"); + pr_debug("failed: wrong overflow (%d) hit, expected 3\n", overflows); if (overflows_2 != 3) - pr_debug("failed: wrong overflow_2 hit\n"); + pr_debug("failed: wrong overflow_2 (%d) hit, expected 3\n", overflows_2); if (count2 != 3) - pr_debug("failed: wrong count for bp2\n"); + pr_debug("failed: wrong count for bp2 (%lld), expected 3\n", count2); if (count3 != 2) - pr_debug("failed: wrong count for bp3\n"); + pr_debug("failed: wrong count for bp3 (%lld), expected 2\n", count3); return count1 == 1 && overflows == 3 && count2 == 3 && overflows_2 == 3 && count3 == 2 ? TEST_OK : TEST_FAIL; diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c index 7115aa32a51e..5f05db75cdd8 100644 --- a/tools/perf/tests/builtin-test.c +++ b/tools/perf/tests/builtin-test.c @@ -260,6 +260,11 @@ static struct test generic_tests[] = { .func = test__cpu_map_print, }, { + .desc = "Merge cpu map", + .func = test__cpu_map_merge, + }, + + { .desc = "Probe SDT events", .func = test__sdt_event, }, @@ -297,6 +302,10 @@ static struct test generic_tests[] = { .func = test__time_utils, }, { + .desc = "Test jit_write_elf", + .func = test__jit_write_elf, + }, + { .desc = "maps__merge_in", .func = test__maps__merge_in, }, diff --git a/tools/perf/tests/cpumap.c b/tools/perf/tests/cpumap.c index 8a0d236202b0..4ac56741ac5f 100644 --- a/tools/perf/tests/cpumap.c +++ b/tools/perf/tests/cpumap.c @@ -120,3 +120,19 @@ int test__cpu_map_print(struct test *test __maybe_unused, int subtest __maybe_un TEST_ASSERT_VAL("failed to convert map", cpu_map_print("1-10,12-20,22-30,32-40")); return 0; } + +int test__cpu_map_merge(struct test *test __maybe_unused, int subtest __maybe_unused) +{ + struct perf_cpu_map *a = perf_cpu_map__new("4,2,1"); + struct perf_cpu_map *b = perf_cpu_map__new("4,5,7"); + struct perf_cpu_map *c = perf_cpu_map__merge(a, b); + char buf[100]; + + TEST_ASSERT_VAL("failed to merge map: bad nr", c->nr == 5); + cpu_map__snprint(c, buf, sizeof(buf)); + TEST_ASSERT_VAL("failed to merge map: bad result", !strcmp(buf, "1-2,4-5,7")); + perf_cpu_map__put(a); + perf_cpu_map__put(b); + perf_cpu_map__put(c); + return 0; +} diff --git a/tools/perf/tests/event-times.c b/tools/perf/tests/event-times.c index 1ee8704e2284..1e8a9f5c356d 100644 --- a/tools/perf/tests/event-times.c +++ b/tools/perf/tests/event-times.c @@ -125,7 +125,7 @@ static int attach__cpu_disabled(struct evlist *evlist) evsel->core.attr.disabled = 1; - err = perf_evsel__open_per_cpu(evsel, cpus); + err = perf_evsel__open_per_cpu(evsel, cpus, -1); if (err) { if (err == -EACCES) return TEST_SKIP; @@ -152,7 +152,7 @@ static int attach__cpu_enabled(struct evlist *evlist) return -1; } - err = perf_evsel__open_per_cpu(evsel, cpus); + err = perf_evsel__open_per_cpu(evsel, cpus, -1); if (err == -EACCES) return TEST_SKIP; diff --git a/tools/perf/tests/genelf.c b/tools/perf/tests/genelf.c new file mode 100644 index 000000000000..f797f9823e89 --- /dev/null +++ b/tools/perf/tests/genelf.c @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: GPL-2.0-only +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <linux/compiler.h> + +#include "debug.h" +#include "tests.h" + +#ifdef HAVE_JITDUMP +#include <libelf.h> +#include "../util/genelf.h" +#endif + +#define TEMPL "/tmp/perf-test-XXXXXX" + +int test__jit_write_elf(struct test *test __maybe_unused, + int subtest __maybe_unused) +{ +#ifdef HAVE_JITDUMP + static unsigned char x86_code[] = { + 0xBB, 0x2A, 0x00, 0x00, 0x00, /* movl $42, %ebx */ + 0xB8, 0x01, 0x00, 0x00, 0x00, /* movl $1, %eax */ + 0xCD, 0x80 /* int $0x80 */ + }; + char path[PATH_MAX]; + int fd, ret; + + strcpy(path, TEMPL); + + fd = mkstemp(path); + if (fd < 0) { + perror("mkstemp failed"); + return TEST_FAIL; + } + + pr_info("Writing jit code to: %s\n", path); + + ret = jit_write_elf(fd, 0, "main", x86_code, sizeof(x86_code), + NULL, 0, NULL, 0, 0); + close(fd); + + unlink(path); + + return ret ? TEST_FAIL : 0; +#else + return TEST_SKIP; +#endif +} diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h index 25aea387e2bf..9a160fef47c9 100644 --- a/tools/perf/tests/tests.h +++ b/tools/perf/tests/tests.h @@ -98,6 +98,7 @@ int test__event_update(struct test *test, int subtest); int test__event_times(struct test *test, int subtest); int test__backward_ring_buffer(struct test *test, int subtest); int test__cpu_map_print(struct test *test, int subtest); +int test__cpu_map_merge(struct test *test, int subtest); int test__sdt_event(struct test *test, int subtest); int test__is_printable_array(struct test *test, int subtest); int test__bitmap_print(struct test *test, int subtest); @@ -109,6 +110,7 @@ int test__unit_number__scnprint(struct test *test, int subtest); int test__mem2node(struct test *t, int subtest); int test__maps__merge_in(struct test *t, int subtest); int test__time_utils(struct test *t, int subtest); +int test__jit_write_elf(struct test *test, int subtest); bool test__bp_signal_is_supported(void); bool test__bp_account_is_supported(void); diff --git a/tools/perf/trace/beauty/clone.c b/tools/perf/trace/beauty/clone.c index 1a8d3be2030e..062ca849c8fd 100644 --- a/tools/perf/trace/beauty/clone.c +++ b/tools/perf/trace/beauty/clone.c @@ -45,6 +45,7 @@ static size_t clone__scnprintf_flags(unsigned long flags, char *bf, size_t size, P_FLAG(NEWPID); P_FLAG(NEWNET); P_FLAG(IO); + P_FLAG(CLEAR_SIGHAND); #undef P_FLAG if (flags) diff --git a/tools/perf/trace/beauty/sockaddr.c b/tools/perf/trace/beauty/sockaddr.c index 173c8f760763..e0c13e6a5788 100644 --- a/tools/perf/trace/beauty/sockaddr.c +++ b/tools/perf/trace/beauty/sockaddr.c @@ -72,5 +72,5 @@ size_t syscall_arg__scnprintf_sockaddr(char *bf, size_t size, struct syscall_arg if (arg->augmented.args) return syscall_arg__scnprintf_augmented_sockaddr(arg, bf, size); - return scnprintf(bf, size, "%#x", arg->val); + return scnprintf(bf, size, "%#lx", arg->val); } diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index d4d3558fdef4..f36dee499320 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c @@ -18,7 +18,9 @@ #include "../../util/evlist.h" #include "../../util/header.h" #include "../../util/hist.h" +#include "../../util/machine.h" #include "../../util/map.h" +#include "../../util/maps.h" #include "../../util/symbol.h" #include "../../util/map_symbol.h" #include "../../util/branch.h" @@ -391,6 +393,57 @@ static void hist_entry__init_have_children(struct hist_entry *he) he->init_have_children = true; } +static bool hist_browser__selection_has_children(struct hist_browser *browser) +{ + struct hist_entry *he = browser->he_selection; + struct map_symbol *ms = browser->selection; + + if (!he || !ms) + return false; + + if (ms == &he->ms) + return he->has_children; + + return container_of(ms, struct callchain_list, ms)->has_children; +} + +static bool hist_browser__he_selection_unfolded(struct hist_browser *browser) +{ + return browser->he_selection ? browser->he_selection->unfolded : false; +} + +static bool hist_browser__selection_unfolded(struct hist_browser *browser) +{ + struct hist_entry *he = browser->he_selection; + struct map_symbol *ms = browser->selection; + + if (!he || !ms) + return false; + + if (ms == &he->ms) + return he->unfolded; + + return container_of(ms, struct callchain_list, ms)->unfolded; +} + +static char *hist_browser__selection_sym_name(struct hist_browser *browser, char *bf, size_t size) +{ + struct hist_entry *he = browser->he_selection; + struct map_symbol *ms = browser->selection; + struct callchain_list *callchain_entry; + + if (!he || !ms) + return NULL; + + if (ms == &he->ms) { + hist_entry__sym_snprintf(he, bf, size, 0); + return bf + 4; // skip the level, e.g. '[k] ' + } + + callchain_entry = container_of(ms, struct callchain_list, ms); + return callchain_list__sym_name(callchain_entry, bf, size, browser->show_dso); +} + static bool hist_browser__toggle_fold(struct hist_browser *browser) { struct hist_entry *he = browser->he_selection; @@ -624,10 +677,81 @@ static int hist_browser__title(struct hist_browser *browser, char *bf, size_t si return browser->title ? browser->title(browser, bf, size) : 0; } +static int hist_browser__handle_hotkey(struct hist_browser *browser, bool warn_lost_event, char *title, int key) +{ + switch (key) { + case K_TIMER: { + struct hist_browser_timer *hbt = browser->hbt; + u64 nr_entries; + + WARN_ON_ONCE(!hbt); + + if (hbt) + hbt->timer(hbt->arg); + + if (hist_browser__has_filter(browser) || symbol_conf.report_hierarchy) + hist_browser__update_nr_entries(browser); + + nr_entries = hist_browser__nr_entries(browser); + ui_browser__update_nr_entries(&browser->b, nr_entries); + + if (warn_lost_event && + (browser->hists->stats.nr_lost_warned != + browser->hists->stats.nr_events[PERF_RECORD_LOST])) { + browser->hists->stats.nr_lost_warned = + browser->hists->stats.nr_events[PERF_RECORD_LOST]; + ui_browser__warn_lost_events(&browser->b); + } + + hist_browser__title(browser, title, sizeof(title)); + ui_browser__show_title(&browser->b, title); + break; + } + case 'D': { /* Debug */ + struct hist_entry *h = rb_entry(browser->b.top, struct hist_entry, rb_node); + static int seq; + + ui_helpline__pop(); + ui_helpline__fpush("%d: nr_ent=(%d,%d), etl: %d, rows=%d, idx=%d, fve: idx=%d, row_off=%d, nrows=%d", + seq++, browser->b.nr_entries, browser->hists->nr_entries, + browser->b.extra_title_lines, browser->b.rows, + browser->b.index, browser->b.top_idx, h->row_offset, h->nr_rows); + } + break; + case 'C': + /* Collapse the whole world. */ + hist_browser__set_folding(browser, false); + break; + case 'c': + /* Collapse the selected entry. */ + hist_browser__set_folding_selected(browser, false); + break; + case 'E': + /* Expand the whole world. */ + hist_browser__set_folding(browser, true); + break; + case 'e': + /* Expand the selected entry. */ + hist_browser__set_folding_selected(browser, !hist_browser__he_selection_unfolded(browser)); + break; + case 'H': + browser->show_headers = !browser->show_headers; + hist_browser__update_rows(browser); + break; + case '+': + if (hist_browser__toggle_fold(browser)) + break; + /* fall thru */ + default: + return -1; + } + + return 0; +} + int hist_browser__run(struct hist_browser *browser, const char *help, - bool warn_lost_event) + bool warn_lost_event, int key) { - int key; char title[160]; struct hist_browser_timer *hbt = browser->hbt; int delay_secs = hbt ? hbt->refresh : 0; @@ -640,79 +764,14 @@ int hist_browser__run(struct hist_browser *browser, const char *help, if (ui_browser__show(&browser->b, title, "%s", help) < 0) return -1; + if (key && hist_browser__handle_hotkey(browser, warn_lost_event, title, key)) + goto out; + while (1) { key = ui_browser__run(&browser->b, delay_secs); - switch (key) { - case K_TIMER: { - u64 nr_entries; - - WARN_ON_ONCE(!hbt); - - if (hbt) - hbt->timer(hbt->arg); - - if (hist_browser__has_filter(browser) || - symbol_conf.report_hierarchy) - hist_browser__update_nr_entries(browser); - - nr_entries = hist_browser__nr_entries(browser); - ui_browser__update_nr_entries(&browser->b, nr_entries); - - if (warn_lost_event && - (browser->hists->stats.nr_lost_warned != - browser->hists->stats.nr_events[PERF_RECORD_LOST])) { - browser->hists->stats.nr_lost_warned = - browser->hists->stats.nr_events[PERF_RECORD_LOST]; - ui_browser__warn_lost_events(&browser->b); - } - - hist_browser__title(browser, title, sizeof(title)); - ui_browser__show_title(&browser->b, title); - continue; - } - case 'D': { /* Debug */ - static int seq; - struct hist_entry *h = rb_entry(browser->b.top, - struct hist_entry, rb_node); - ui_helpline__pop(); - ui_helpline__fpush("%d: nr_ent=(%d,%d), etl: %d, rows=%d, idx=%d, fve: idx=%d, row_off=%d, nrows=%d", - seq++, browser->b.nr_entries, - browser->hists->nr_entries, - browser->b.extra_title_lines, - browser->b.rows, - browser->b.index, - browser->b.top_idx, - h->row_offset, h->nr_rows); - } - break; - case 'C': - /* Collapse the whole world. */ - hist_browser__set_folding(browser, false); - break; - case 'c': - /* Collapse the selected entry. */ - hist_browser__set_folding_selected(browser, false); + if (hist_browser__handle_hotkey(browser, warn_lost_event, title, key)) break; - case 'E': - /* Expand the whole world. */ - hist_browser__set_folding(browser, true); - break; - case 'e': - /* Expand the selected entry. */ - hist_browser__set_folding_selected(browser, true); - break; - case 'H': - browser->show_headers = !browser->show_headers; - hist_browser__update_rows(browser); - break; - case K_ENTER: - if (hist_browser__toggle_fold(browser)) - break; - /* fall thru */ - default: - goto out; - } } out: ui_browser__hide(&browser->b); @@ -2339,7 +2398,7 @@ close_file_and_continue: closedir(pwd_dir); if (nr_options) { - choice = ui__popup_menu(nr_options, options); + choice = ui__popup_menu(nr_options, options, NULL); if (choice < nr_options && choice >= 0) { tmp = strdup(abs_path[choice]); if (tmp) { @@ -2411,7 +2470,8 @@ add_annotate_opt(struct hist_browser *browser __maybe_unused, struct popup_action *act, char **optstr, struct map_symbol *ms) { - if (ms->sym == NULL || ms->map->dso->annotate_warned) + if (ms->sym == NULL || ms->map->dso->annotate_warned || + symbol__annotation(ms->sym)->src == NULL) return 0; if (asprintf(optstr, "Annotate %s", ms->sym->name) < 0) @@ -2484,11 +2544,8 @@ add_thread_opt(struct hist_browser *browser, struct popup_action *act, return 1; } -static int -do_zoom_dso(struct hist_browser *browser, struct popup_action *act) +static int hists_browser__zoom_map(struct hist_browser *browser, struct map *map) { - struct map *map = act->ms.map; - if (!hists__has(browser->hists, dso) || map == NULL) return 0; @@ -2511,13 +2568,19 @@ do_zoom_dso(struct hist_browser *browser, struct popup_action *act) } static int +do_zoom_dso(struct hist_browser *browser, struct popup_action *act) +{ + return hists_browser__zoom_map(browser, act->ms.map); +} + +static int add_dso_opt(struct hist_browser *browser, struct popup_action *act, char **optstr, struct map *map) { if (!hists__has(browser->hists, dso) || map == NULL) return 0; - if (asprintf(optstr, "Zoom %s %s DSO", + if (asprintf(optstr, "Zoom %s %s DSO (use the 'k' hotkey to zoom directly into the kernel)", browser->hists->dso_filter ? "out of" : "into", __map__is_kernel(map) ? "the Kernel" : map->dso->short_name) < 0) return 0; @@ -2527,6 +2590,28 @@ add_dso_opt(struct hist_browser *browser, struct popup_action *act, return 1; } +static int do_toggle_callchain(struct hist_browser *browser, struct popup_action *act __maybe_unused) +{ + hist_browser__toggle_fold(browser); + return 0; +} + +static int add_callchain_toggle_opt(struct hist_browser *browser, struct popup_action *act, char **optstr) +{ + char sym_name[512]; + + if (!hist_browser__selection_has_children(browser)) + return 0; + + if (asprintf(optstr, "%s [%s] callchain (one level, same as '+' hotkey, use 'e'/'c' for the whole main level entry)", + hist_browser__selection_unfolded(browser) ? "Collapse" : "Expand", + hist_browser__selection_sym_name(browser, sym_name, sizeof(sym_name))) < 0) + return 0; + + act->fn = do_toggle_callchain; + return 1; +} + static int do_browse_map(struct hist_browser *browser __maybe_unused, struct popup_action *act) @@ -2858,12 +2943,15 @@ static int perf_evsel__hists_browse(struct evsel *evsel, int nr_events, "For symbolic views (--sort has sym):\n\n" \ "ENTER Zoom into DSO/Threads & Annotate current symbol\n" \ "ESC Zoom out\n" \ + "+ Expand/Collapse one callchain level\n" \ "a Annotate current symbol\n" \ "C Collapse all callchains\n" \ "d Zoom into current DSO\n" \ + "e Expand/Collapse main entry callchains\n" \ "E Expand all callchains\n" \ "F Toggle percentage of filtered entries\n" \ "H Display column headers\n" \ + "k Zoom into the kernel map\n" \ "L Change percent limit\n" \ "m Display context menu\n" \ "S Zoom into current Processor Socket\n" \ @@ -2914,13 +3002,13 @@ static int perf_evsel__hists_browse(struct evsel *evsel, int nr_events, while (1) { struct thread *thread = NULL; struct map *map = NULL; - int choice = 0; + int choice; int socked_id = -1; - nr_options = 0; - - key = hist_browser__run(browser, helpline, - warn_lost_event); + key = 0; // reset key +do_hotkey: // key came straight from options ui__popup_menu() + choice = nr_options = 0; + key = hist_browser__run(browser, helpline, warn_lost_event, key); if (browser->he_selection != NULL) { thread = hist_browser__selected_thread(browser); @@ -2950,6 +3038,14 @@ static int perf_evsel__hists_browse(struct evsel *evsel, int nr_events, browser->selection->map->dso->annotate_warned) continue; + if (symbol__annotation(browser->selection->sym)->src == NULL) { + ui_browser__warning(&browser->b, delay_secs * 2, + "No samples for the \"%s\" symbol.\n\n" + "Probably appeared just in a callchain", + browser->selection->sym->name); + continue; + } + actions->ms.map = browser->selection->map; actions->ms.sym = browser->selection->sym; do_annotate(browser, actions); @@ -2961,6 +3057,10 @@ static int perf_evsel__hists_browse(struct evsel *evsel, int nr_events, actions->ms.map = map; do_zoom_dso(browser, actions); continue; + case 'k': + if (browser->selection != NULL) + hists_browser__zoom_map(browser, browser->selection->maps->machine->vmlinux_map); + continue; case 'V': verbose = (verbose + 1) % 4; browser->show_dso = verbose > 0; @@ -3062,6 +3162,7 @@ static int perf_evsel__hists_browse(struct evsel *evsel, int nr_events, continue; } + actions->ms.map = map; top = pstack__peek(browser->pstack); if (top == &browser->hists->dso_filter) { /* @@ -3135,6 +3236,7 @@ skip_annotation: &options[nr_options], thread); nr_options += add_dso_opt(browser, &actions[nr_options], &options[nr_options], map); + nr_options += add_callchain_toggle_opt(browser, &actions[nr_options], &options[nr_options]); nr_options += add_map_opt(browser, &actions[nr_options], &options[nr_options], browser->selection ? @@ -3193,10 +3295,13 @@ skip_scripting: do { struct popup_action *act; - choice = ui__popup_menu(nr_options, options); - if (choice == -1 || choice >= nr_options) + choice = ui__popup_menu(nr_options, options, &key); + if (choice == -1) break; + if (choice == nr_options) + goto do_hotkey; + act = &actions[choice]; key = act->fn(browser, act); } while (key == 1); @@ -3492,7 +3597,7 @@ int block_hists_tui_browse(struct block_hist *bh, struct evsel *evsel, memset(&action, 0, sizeof(action)); while (1) { - key = hist_browser__run(browser, "? - help", true); + key = hist_browser__run(browser, "? - help", true, 0); switch (key) { case 'q': diff --git a/tools/perf/ui/browsers/hists.h b/tools/perf/ui/browsers/hists.h index 078f2f2c7abd..1e938d9ffa5e 100644 --- a/tools/perf/ui/browsers/hists.h +++ b/tools/perf/ui/browsers/hists.h @@ -34,7 +34,7 @@ struct hist_browser { struct hist_browser *hist_browser__new(struct hists *hists); void hist_browser__delete(struct hist_browser *browser); int hist_browser__run(struct hist_browser *browser, const char *help, - bool warn_lost_event); + bool warn_lost_event, int key); void hist_browser__init(struct hist_browser *browser, struct hists *hists); #endif /* _PERF_UI_BROWSER_HISTS_H_ */ diff --git a/tools/perf/ui/browsers/res_sample.c b/tools/perf/ui/browsers/res_sample.c index 76d356a18790..7cb2d6678039 100644 --- a/tools/perf/ui/browsers/res_sample.c +++ b/tools/perf/ui/browsers/res_sample.c @@ -56,7 +56,7 @@ int res_sample_browse(struct res_sample *res_samples, int num_res, return -1; } } - choice = ui__popup_menu(num_res, names); + choice = ui__popup_menu(num_res, names, NULL); for (i = 0; i < num_res; i++) zfree(&names[i]); free(names); diff --git a/tools/perf/ui/browsers/scripts.c b/tools/perf/ui/browsers/scripts.c index fc733a6354d4..47d2c7a8cbe1 100644 --- a/tools/perf/ui/browsers/scripts.c +++ b/tools/perf/ui/browsers/scripts.c @@ -126,7 +126,7 @@ static int list_scripts(char *script_name, bool *custom, SCRIPT_FULLPATH_LEN); if (num < 0) num = 0; - choice = ui__popup_menu(num + max_std, (char * const *)names); + choice = ui__popup_menu(num + max_std, (char * const *)names, NULL); if (choice < 0) { ret = -1; goto out; diff --git a/tools/perf/ui/gtk/Build b/tools/perf/ui/gtk/Build index ec22e899a224..eef708c502f4 100644 --- a/tools/perf/ui/gtk/Build +++ b/tools/perf/ui/gtk/Build @@ -1,4 +1,4 @@ -CFLAGS_gtk += -fPIC $(GTK_CFLAGS) +CFLAGS_gtk += -fPIC $(GTK_CFLAGS) -Wno-deprecated-declarations gtk-y += browser.o gtk-y += hists.o @@ -7,3 +7,8 @@ gtk-y += util.o gtk-y += helpline.o gtk-y += progress.o gtk-y += annotate.o +gtk-y += zalloc.o + +$(OUTPUT)ui/gtk/zalloc.o: ../lib/zalloc.c FORCE + $(call rule_mkdir) + $(call if_changed_dep,cc_o_c) diff --git a/tools/perf/ui/tui/util.c b/tools/perf/ui/tui/util.c index b98dd0e31dc1..0f562e2cb1e8 100644 --- a/tools/perf/ui/tui/util.c +++ b/tools/perf/ui/tui/util.c @@ -23,7 +23,7 @@ static void ui_browser__argv_write(struct ui_browser *browser, ui_browser__write_nstring(browser, *arg, browser->width); } -static int popup_menu__run(struct ui_browser *menu) +static int popup_menu__run(struct ui_browser *menu, int *keyp) { int key; @@ -45,6 +45,11 @@ static int popup_menu__run(struct ui_browser *menu) key = -1; break; default: + if (keyp) { + *keyp = key; + key = menu->nr_entries; + break; + } continue; } @@ -55,7 +60,7 @@ static int popup_menu__run(struct ui_browser *menu) return key; } -int ui__popup_menu(int argc, char * const argv[]) +int ui__popup_menu(int argc, char * const argv[], int *keyp) { struct ui_browser menu = { .entries = (void *)argv, @@ -64,8 +69,7 @@ int ui__popup_menu(int argc, char * const argv[]) .write = ui_browser__argv_write, .nr_entries = argc, }; - - return popup_menu__run(&menu); + return popup_menu__run(&menu, keyp); } int ui_browser__input_window(const char *title, const char *text, char *input, diff --git a/tools/perf/ui/util.h b/tools/perf/ui/util.h index 40891942f465..e30cea807564 100644 --- a/tools/perf/ui/util.h +++ b/tools/perf/ui/util.h @@ -5,7 +5,7 @@ #include <stdarg.h> int ui__getch(int delay_secs); -int ui__popup_menu(int argc, char * const argv[]); +int ui__popup_menu(int argc, char * const argv[], int *keyp); int ui__help_window(const char *text); int ui__dialog_yesno(const char *msg); void __ui__info_window(const char *title, const char *text, const char *exit_msg); diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index f5e77ed237e8..ca73fb74ad03 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -1966,14 +1966,20 @@ static int symbol__disassemble(struct symbol *sym, struct annotate_args *args) err = asprintf(&command, "%s %s%s --start-address=0x%016" PRIx64 " --stop-address=0x%016" PRIx64 - " -l -d %s %s -C \"$1\"", + " -l -d %s %s %s %c%s%c %s%s -C \"$1\"", opts->objdump_path ?: "objdump", opts->disassembler_style ? "-M " : "", opts->disassembler_style ?: "", map__rip_2objdump(map, sym->start), map__rip_2objdump(map, sym->end), opts->show_asm_raw ? "" : "--no-show-raw-insn", - opts->annotate_src ? "-S" : ""); + opts->annotate_src ? "-S" : "", + opts->prefix ? "--prefix " : "", + opts->prefix ? '"' : ' ', + opts->prefix ?: "", + opts->prefix ? '"' : ' ', + opts->prefix_strip ? "--prefix-strip=" : "", + opts->prefix_strip ?: ""); if (err < 0) { pr_err("Failure allocating memory for the command to run\n"); @@ -3204,3 +3210,12 @@ out: free(str1); return err; } + +int annotate_check_args(struct annotation_options *args) +{ + if (args->prefix_strip && !args->prefix) { + pr_err("--prefix-strip requires --prefix\n"); + return -1; + } + return 0; +} diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 7075d98f69d9..455403e8fede 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -94,6 +94,8 @@ struct annotation_options { int context; const char *objdump_path; const char *disassembler_style; + const char *prefix; + const char *prefix_strip; unsigned int percent_type; }; @@ -415,4 +417,7 @@ void annotation_config__init(void); int annotate_parse_percent_type(const struct option *opt, const char *_str, int unset); + +int annotate_check_args(struct annotation_options *args); + #endif /* __PERF_ANNOTATE_H */ diff --git a/tools/perf/util/c++/clang.cpp b/tools/perf/util/c++/clang.cpp index fc361c3f8570..c8885dfa3667 100644 --- a/tools/perf/util/c++/clang.cpp +++ b/tools/perf/util/c++/clang.cpp @@ -71,7 +71,11 @@ getModuleFromSource(llvm::opt::ArgStringList CFlags, CompilerInstance Clang; Clang.createDiagnostics(); +#if CLANG_VERSION_MAJOR < 9 Clang.setVirtualFileSystem(&*VFS); +#else + Clang.createFileManager(&*VFS); +#endif #if CLANG_VERSION_MAJOR < 4 IntrusiveRefCntPtr<CompilerInvocation> CI = diff --git a/tools/perf/util/cpumap.h b/tools/perf/util/cpumap.h index 57943f3685f8..3a442f021468 100644 --- a/tools/perf/util/cpumap.h +++ b/tools/perf/util/cpumap.h @@ -63,4 +63,5 @@ int cpu_map__build_map(struct perf_cpu_map *cpus, struct perf_cpu_map **res, int cpu_map__cpu(struct perf_cpu_map *cpus, int idx); bool cpu_map__has(struct perf_cpu_map *cpus, int cpu); + #endif /* __PERF_CPUMAP_H */ diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index fdce590d2278..1548237b6558 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -18,6 +18,7 @@ #include "debug.h" #include "units.h" #include <internal/lib.h> // page_size +#include "affinity.h" #include "../perf.h" #include "asm/bug.h" #include "bpf-event.h" @@ -342,14 +343,63 @@ static int perf_evlist__nr_threads(struct evlist *evlist, return perf_thread_map__nr(evlist->core.threads); } +void evlist__cpu_iter_start(struct evlist *evlist) +{ + struct evsel *pos; + + /* + * Reset the per evsel cpu_iter. This is needed because + * each evsel's cpumap may have a different index space, + * and some operations need the index to modify + * the FD xyarray (e.g. open, close) + */ + evlist__for_each_entry(evlist, pos) + pos->cpu_iter = 0; +} + +bool evsel__cpu_iter_skip_no_inc(struct evsel *ev, int cpu) +{ + if (ev->cpu_iter >= ev->core.cpus->nr) + return true; + if (cpu >= 0 && ev->core.cpus->map[ev->cpu_iter] != cpu) + return true; + return false; +} + +bool evsel__cpu_iter_skip(struct evsel *ev, int cpu) +{ + if (!evsel__cpu_iter_skip_no_inc(ev, cpu)) { + ev->cpu_iter++; + return false; + } + return true; +} + void evlist__disable(struct evlist *evlist) { struct evsel *pos; + struct affinity affinity; + int cpu, i; + + if (affinity__setup(&affinity) < 0) + return; + evlist__for_each_cpu(evlist, i, cpu) { + affinity__set(&affinity, cpu); + + evlist__for_each_entry(evlist, pos) { + if (evsel__cpu_iter_skip(pos, cpu)) + continue; + if (pos->disabled || !perf_evsel__is_group_leader(pos) || !pos->core.fd) + continue; + evsel__disable_cpu(pos, pos->cpu_iter - 1); + } + } + affinity__cleanup(&affinity); evlist__for_each_entry(evlist, pos) { - if (pos->disabled || !perf_evsel__is_group_leader(pos) || !pos->core.fd) + if (!perf_evsel__is_group_leader(pos) || !pos->core.fd) continue; - evsel__disable(pos); + pos->disabled = true; } evlist->enabled = false; @@ -358,11 +408,28 @@ void evlist__disable(struct evlist *evlist) void evlist__enable(struct evlist *evlist) { struct evsel *pos; + struct affinity affinity; + int cpu, i; + + if (affinity__setup(&affinity) < 0) + return; + evlist__for_each_cpu(evlist, i, cpu) { + affinity__set(&affinity, cpu); + + evlist__for_each_entry(evlist, pos) { + if (evsel__cpu_iter_skip(pos, cpu)) + continue; + if (!perf_evsel__is_group_leader(pos) || !pos->core.fd) + continue; + evsel__enable_cpu(pos, pos->cpu_iter - 1); + } + } + affinity__cleanup(&affinity); evlist__for_each_entry(evlist, pos) { if (!perf_evsel__is_group_leader(pos) || !pos->core.fd) continue; - evsel__enable(pos); + pos->disabled = false; } evlist->enabled = true; @@ -1137,9 +1204,35 @@ void perf_evlist__set_selected(struct evlist *evlist, void evlist__close(struct evlist *evlist) { struct evsel *evsel; + struct affinity affinity; + int cpu, i; - evlist__for_each_entry_reverse(evlist, evsel) - evsel__close(evsel); + /* + * With perf record core.cpus is usually NULL. + * Use the old method to handle this for now. + */ + if (!evlist->core.cpus) { + evlist__for_each_entry_reverse(evlist, evsel) + evsel__close(evsel); + return; + } + + if (affinity__setup(&affinity) < 0) + return; + evlist__for_each_cpu(evlist, i, cpu) { + affinity__set(&affinity, cpu); + + evlist__for_each_entry_reverse(evlist, evsel) { + if (evsel__cpu_iter_skip(evsel, cpu)) + continue; + perf_evsel__close_cpu(&evsel->core, evsel->cpu_iter - 1); + } + } + affinity__cleanup(&affinity); + evlist__for_each_entry_reverse(evlist, evsel) { + perf_evsel__free_fd(&evsel->core); + perf_evsel__free_id(&evsel->core); + } } static int perf_evlist__create_syswide_maps(struct evlist *evlist) @@ -1577,7 +1670,8 @@ void perf_evlist__force_leader(struct evlist *evlist) } struct evsel *perf_evlist__reset_weak_group(struct evlist *evsel_list, - struct evsel *evsel) + struct evsel *evsel, + bool close) { struct evsel *c2, *leader; bool is_open = true; @@ -1594,10 +1688,15 @@ struct evsel *perf_evlist__reset_weak_group(struct evlist *evsel_list, if (c2 == evsel) is_open = false; if (c2->leader == leader) { - if (is_open) + if (is_open && close) perf_evsel__close(&c2->core); c2->leader = c2; c2->core.nr_members = 0; + /* + * Set this for all former members of the group + * to indicate they get reopened. + */ + c2->reset_group = true; } } return leader; diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index 3655b9ebb147..f5bd5c386df1 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h @@ -334,9 +334,17 @@ void perf_evlist__to_front(struct evlist *evlist, #define evlist__for_each_entry_safe(evlist, tmp, evsel) \ __evlist__for_each_entry_safe(&(evlist)->core.entries, tmp, evsel) +#define evlist__for_each_cpu(evlist, index, cpu) \ + evlist__cpu_iter_start(evlist); \ + perf_cpu_map__for_each_cpu (cpu, index, (evlist)->core.all_cpus) + void perf_evlist__set_tracking_event(struct evlist *evlist, struct evsel *tracking_evsel); +void evlist__cpu_iter_start(struct evlist *evlist); +bool evsel__cpu_iter_skip(struct evsel *ev, int cpu); +bool evsel__cpu_iter_skip_no_inc(struct evsel *ev, int cpu); + struct evsel * perf_evlist__find_evsel_by_str(struct evlist *evlist, const char *str); @@ -348,5 +356,6 @@ bool perf_evlist__exclude_kernel(struct evlist *evlist); void perf_evlist__force_leader(struct evlist *evlist); struct evsel *perf_evlist__reset_weak_group(struct evlist *evlist, - struct evsel *evsel); + struct evsel *evsel, + bool close); #endif /* __PERF_EVLIST_H */ diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index f4dea055b080..a69e64236120 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -1223,16 +1223,27 @@ int perf_evsel__append_addr_filter(struct evsel *evsel, const char *filter) return perf_evsel__append_filter(evsel, "%s,%s", filter); } +/* Caller has to clear disabled after going through all CPUs. */ +int evsel__enable_cpu(struct evsel *evsel, int cpu) +{ + return perf_evsel__enable_cpu(&evsel->core, cpu); +} + int evsel__enable(struct evsel *evsel) { int err = perf_evsel__enable(&evsel->core); if (!err) evsel->disabled = false; - return err; } +/* Caller has to set disabled after going through all CPUs. */ +int evsel__disable_cpu(struct evsel *evsel, int cpu) +{ + return perf_evsel__disable_cpu(&evsel->core, cpu); +} + int evsel__disable(struct evsel *evsel) { int err = perf_evsel__disable(&evsel->core); @@ -1587,8 +1598,9 @@ static int perf_event_open(struct evsel *evsel, return fd; } -int evsel__open(struct evsel *evsel, struct perf_cpu_map *cpus, - struct perf_thread_map *threads) +static int evsel__open_cpu(struct evsel *evsel, struct perf_cpu_map *cpus, + struct perf_thread_map *threads, + int start_cpu, int end_cpu) { int cpu, thread, nthreads; unsigned long flags = PERF_FLAG_FD_CLOEXEC; @@ -1665,7 +1677,7 @@ retry_sample_id: display_attr(&evsel->core.attr); - for (cpu = 0; cpu < cpus->nr; cpu++) { + for (cpu = start_cpu; cpu < end_cpu; cpu++) { for (thread = 0; thread < nthreads; thread++) { int fd, group_fd; @@ -1843,6 +1855,12 @@ out_close: return err; } +int evsel__open(struct evsel *evsel, struct perf_cpu_map *cpus, + struct perf_thread_map *threads) +{ + return evsel__open_cpu(evsel, cpus, threads, 0, cpus ? cpus->nr : 1); +} + void evsel__close(struct evsel *evsel) { perf_evsel__close(&evsel->core); @@ -1850,9 +1868,14 @@ void evsel__close(struct evsel *evsel) } int perf_evsel__open_per_cpu(struct evsel *evsel, - struct perf_cpu_map *cpus) + struct perf_cpu_map *cpus, + int cpu) { - return evsel__open(evsel, cpus, NULL); + if (cpu == -1) + return evsel__open_cpu(evsel, cpus, NULL, 0, + cpus ? cpus->nr : 1); + + return evsel__open_cpu(evsel, cpus, NULL, cpu, cpu + 1); } int perf_evsel__open_per_thread(struct evsel *evsel, diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index ddc5ee6f6592..dc14f4a823cd 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h @@ -86,6 +86,7 @@ struct evsel { struct list_head config_terms; struct bpf_object *bpf_obj; int bpf_fd; + int err; bool auto_merge_stats; bool merged_stat; const char * metric_expr; @@ -94,7 +95,10 @@ struct evsel { struct evsel *metric_leader; bool collect_stat; bool weak_group; + bool reset_group; + bool errored; bool percore; + int cpu_iter; const char *pmu_name; struct { perf_evsel__sb_cb_t *cb; @@ -218,11 +222,14 @@ int perf_evsel__set_filter(struct evsel *evsel, const char *filter); int perf_evsel__append_tp_filter(struct evsel *evsel, const char *filter); int perf_evsel__append_addr_filter(struct evsel *evsel, const char *filter); +int evsel__enable_cpu(struct evsel *evsel, int cpu); int evsel__enable(struct evsel *evsel); int evsel__disable(struct evsel *evsel); +int evsel__disable_cpu(struct evsel *evsel, int cpu); int perf_evsel__open_per_cpu(struct evsel *evsel, - struct perf_cpu_map *cpus); + struct perf_cpu_map *cpus, + int cpu); int perf_evsel__open_per_thread(struct evsel *evsel, struct perf_thread_map *threads); int evsel__open(struct evsel *evsel, struct perf_cpu_map *cpus, diff --git a/tools/perf/util/expr.y b/tools/perf/util/expr.y index f9a20a39b64a..7d226241f1d7 100644 --- a/tools/perf/util/expr.y +++ b/tools/perf/util/expr.y @@ -12,7 +12,8 @@ #define MAXIDLEN 256 %} -%pure-parser +%define api.pure full + %parse-param { double *final_val } %parse-param { struct parse_ctx *ctx } %parse-param { const char **pp } diff --git a/tools/perf/util/genelf.c b/tools/perf/util/genelf.c index f9f18b8b1df9..aed49806a09b 100644 --- a/tools/perf/util/genelf.c +++ b/tools/perf/util/genelf.c @@ -8,15 +8,12 @@ */ #include <sys/types.h> -#include <stdio.h> -#include <getopt.h> #include <stddef.h> #include <libelf.h> #include <string.h> #include <stdlib.h> #include <unistd.h> #include <inttypes.h> -#include <limits.h> #include <fcntl.h> #include <err.h> #ifdef HAVE_DWARF_SUPPORT @@ -31,8 +28,6 @@ #define NT_GNU_BUILD_ID 3 #endif -#define JVMTI - #define BUILD_ID_URANDOM /* different uuid for each run */ #ifdef HAVE_LIBCRYPTO @@ -511,44 +506,3 @@ error: return retval; } - -#ifndef JVMTI - -static unsigned char x86_code[] = { - 0xBB, 0x2A, 0x00, 0x00, 0x00, /* movl $42, %ebx */ - 0xB8, 0x01, 0x00, 0x00, 0x00, /* movl $1, %eax */ - 0xCD, 0x80 /* int $0x80 */ -}; - -static struct options options; - -int main(int argc, char **argv) -{ - int c, fd, ret; - - while ((c = getopt(argc, argv, "o:h")) != -1) { - switch (c) { - case 'o': - options.output = optarg; - break; - case 'h': - printf("Usage: genelf -o output_file [-h]\n"); - return 0; - default: - errx(1, "unknown option"); - } - } - - fd = open(options.output, O_CREAT|O_TRUNC|O_RDWR, 0666); - if (fd == -1) - err(1, "cannot create file %s", options.output); - - ret = jit_write_elf(fd, "main", x86_code, sizeof(x86_code)); - close(fd); - - if (ret != 0) - unlink(options.output); - - return ret; -} -#endif diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index becc2d109423..4246e7447e54 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -850,7 +850,7 @@ int __weak strcmp_cpuid_str(const char *mapcpuid, const char *cpuid) */ int __weak get_cpuid(char *buffer __maybe_unused, size_t sz __maybe_unused) { - return -1; + return ENOSYS; /* Not implemented */ } static int write_cpuid(struct feat_fd *ff, @@ -1089,21 +1089,18 @@ static void cpu_cache_level__fprintf(FILE *out, struct cpu_cache_level *c) fprintf(out, "L%d %-15s %8s [%s]\n", c->level, c->type, c->size, c->map); } -static int build_caches(struct cpu_cache_level caches[], u32 size, u32 *cntp) +#define MAX_CACHE_LVL 4 + +static int build_caches(struct cpu_cache_level caches[], u32 *cntp) { u32 i, cnt = 0; - long ncpus; u32 nr, cpu; u16 level; - ncpus = sysconf(_SC_NPROCESSORS_CONF); - if (ncpus < 0) - return -1; - - nr = (u32)(ncpus & UINT_MAX); + nr = cpu__max_cpu(); for (cpu = 0; cpu < nr; cpu++) { - for (level = 0; level < 10; level++) { + for (level = 0; level < MAX_CACHE_LVL; level++) { struct cpu_cache_level c; int err; @@ -1123,18 +1120,12 @@ static int build_caches(struct cpu_cache_level caches[], u32 size, u32 *cntp) caches[cnt++] = c; else cpu_cache_level__free(&c); - - if (WARN_ONCE(cnt == size, "way too many cpu caches..")) - goto out; } } - out: *cntp = cnt; return 0; } -#define MAX_CACHE_LVL 4 - static int write_cache(struct feat_fd *ff, struct evlist *evlist __maybe_unused) { @@ -1143,7 +1134,7 @@ static int write_cache(struct feat_fd *ff, u32 cnt = 0, i, version = 1; int ret; - ret = build_caches(caches, max_caches, &cnt); + ret = build_caches(caches, &cnt); if (ret) goto out; @@ -2931,7 +2922,7 @@ int perf_header__fprintf_info(struct perf_session *session, FILE *fp, bool full) if (ret == -1) return -1; - stctime = st.st_ctime; + stctime = st.st_mtime; fprintf(fp, "# captured on : %s", ctime(&stctime)); fprintf(fp, "# header version : %u\n", header->version); diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index 45286900aacb..0aa63aeb58ec 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h @@ -339,10 +339,10 @@ static inline void perf_hpp__prepend_sort_field(struct perf_hpp_fmt *format) list_for_each_entry_safe(format, tmp, &(_list)->sorts, sort_list) #define hists__for_each_format(hists, format) \ - perf_hpp_list__for_each_format((hists)->hpp_list, fmt) + perf_hpp_list__for_each_format((hists)->hpp_list, format) #define hists__for_each_sort_list(hists, format) \ - perf_hpp_list__for_each_sort_list((hists)->hpp_list, fmt) + perf_hpp_list__for_each_sort_list((hists)->hpp_list, format) extern struct perf_hpp_fmt perf_hpp__format[]; diff --git a/tools/perf/util/include/linux/linkage.h b/tools/perf/util/include/linux/linkage.h index f01d48a8d707..b8a5159361b4 100644 --- a/tools/perf/util/include/linux/linkage.h +++ b/tools/perf/util/include/linux/linkage.h @@ -5,10 +5,93 @@ /* linkage.h ... for including arch/x86/lib/memcpy_64.S */ -#define ENTRY(name) \ - .globl name; \ +/* Some toolchains use other characters (e.g. '`') to mark new line in macro */ +#ifndef ASM_NL +#define ASM_NL ; +#endif + +#ifndef __ALIGN +#define __ALIGN .align 4,0x90 +#define __ALIGN_STR ".align 4,0x90" +#endif + +/* SYM_T_FUNC -- type used by assembler to mark functions */ +#ifndef SYM_T_FUNC +#define SYM_T_FUNC STT_FUNC +#endif + +/* SYM_A_* -- align the symbol? */ +#define SYM_A_ALIGN ALIGN + +/* SYM_L_* -- linkage of symbols */ +#define SYM_L_GLOBAL(name) .globl name +#define SYM_L_LOCAL(name) /* nothing */ + +#define ALIGN __ALIGN + +/* === generic annotations === */ + +/* SYM_ENTRY -- use only if you have to for non-paired symbols */ +#ifndef SYM_ENTRY +#define SYM_ENTRY(name, linkage, align...) \ + linkage(name) ASM_NL \ + align ASM_NL \ name: +#endif + +/* SYM_START -- use only if you have to */ +#ifndef SYM_START +#define SYM_START(name, linkage, align...) \ + SYM_ENTRY(name, linkage, align) +#endif + +/* SYM_END -- use only if you have to */ +#ifndef SYM_END +#define SYM_END(name, sym_type) \ + .type name sym_type ASM_NL \ + .size name, .-name +#endif + +/* + * SYM_FUNC_START_ALIAS -- use where there are two global names for one + * function + */ +#ifndef SYM_FUNC_START_ALIAS +#define SYM_FUNC_START_ALIAS(name) \ + SYM_START(name, SYM_L_GLOBAL, SYM_A_ALIGN) +#endif + +/* SYM_FUNC_START -- use for global functions */ +#ifndef SYM_FUNC_START +/* + * The same as SYM_FUNC_START_ALIAS, but we will need to distinguish these two + * later. + */ +#define SYM_FUNC_START(name) \ + SYM_START(name, SYM_L_GLOBAL, SYM_A_ALIGN) +#endif + +/* SYM_FUNC_START_LOCAL -- use for local functions */ +#ifndef SYM_FUNC_START_LOCAL +/* the same as SYM_FUNC_START_LOCAL_ALIAS, see comment near SYM_FUNC_START */ +#define SYM_FUNC_START_LOCAL(name) \ + SYM_START(name, SYM_L_LOCAL, SYM_A_ALIGN) +#endif + +/* SYM_FUNC_END_ALIAS -- the end of LOCAL_ALIASed or ALIASed function */ +#ifndef SYM_FUNC_END_ALIAS +#define SYM_FUNC_END_ALIAS(name) \ + SYM_END(name, SYM_T_FUNC) +#endif -#define ENDPROC(name) +/* + * SYM_FUNC_END -- the end of SYM_FUNC_START_LOCAL, SYM_FUNC_START, + * SYM_FUNC_START_WEAK, ... + */ +#ifndef SYM_FUNC_END +/* the same as SYM_FUNC_END_ALIAS, see comment near SYM_FUNC_START */ +#define SYM_FUNC_END(name) \ + SYM_END(name, SYM_T_FUNC) +#endif #endif /* PERF_LINUX_LINKAGE_H_ */ diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index 416d174d223c..c8c5410315e8 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c @@ -2446,6 +2446,7 @@ static int append_inlines(struct callchain_cursor *cursor, struct map_symbol *ms list_for_each_entry(ilist, &inline_node->val, list) { struct map_symbol ilist_ms = { + .maps = ms->maps, .map = map, .sym = ilist->symbol, }; diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c index 6a4d350d5cdb..02aee946b6c1 100644 --- a/tools/perf/util/metricgroup.c +++ b/tools/perf/util/metricgroup.c @@ -103,8 +103,11 @@ static struct evsel *find_evsel_group(struct evlist *perf_evlist, if (!strcmp(ev->name, ids[i])) { if (!metric_events[i]) metric_events[i] = ev; + i++; + if (i == idnum) + break; } else { - if (++i == idnum) { + if (i + 1 == idnum) { /* Discard the whole match and start again */ i = 0; memset(metric_events, 0, @@ -124,7 +127,7 @@ static struct evsel *find_evsel_group(struct evlist *perf_evlist, } } - if (i != idnum - 1) { + if (i != idnum) { /* Not whole match */ return NULL; } diff --git a/tools/perf/util/mmap.c b/tools/perf/util/mmap.c index 063d1b93c53d..3b664fa673a6 100644 --- a/tools/perf/util/mmap.c +++ b/tools/perf/util/mmap.c @@ -23,6 +23,18 @@ #include "mmap.h" #include "../perf.h" #include <internal/lib.h> /* page_size */ +#include <linux/bitmap.h> + +#define MASK_SIZE 1023 +void mmap_cpu_mask__scnprintf(struct mmap_cpu_mask *mask, const char *tag) +{ + char buf[MASK_SIZE + 1]; + size_t len; + + len = bitmap_scnprintf(mask->bits, mask->nbits, buf, MASK_SIZE); + buf[len] = '\0'; + pr_debug("%p: %s mask[%zd]: %s\n", mask, tag, mask->nbits, buf); +} size_t mmap__mmap_len(struct mmap *map) { @@ -207,6 +219,8 @@ static void perf_mmap__aio_munmap(struct mmap *map __maybe_unused) void mmap__munmap(struct mmap *map) { + bitmap_free(map->affinity_mask.bits); + perf_mmap__aio_munmap(map); if (map->data != NULL) { munmap(map->data, mmap__mmap_len(map)); @@ -215,7 +229,7 @@ void mmap__munmap(struct mmap *map) auxtrace_mmap__munmap(&map->auxtrace_mmap); } -static void build_node_mask(int node, cpu_set_t *mask) +static void build_node_mask(int node, struct mmap_cpu_mask *mask) { int c, cpu, nr_cpus; const struct perf_cpu_map *cpu_map = NULL; @@ -228,17 +242,23 @@ static void build_node_mask(int node, cpu_set_t *mask) for (c = 0; c < nr_cpus; c++) { cpu = cpu_map->map[c]; /* map c index to online cpu index */ if (cpu__get_node(cpu) == node) - CPU_SET(cpu, mask); + set_bit(cpu, mask->bits); } } -static void perf_mmap__setup_affinity_mask(struct mmap *map, struct mmap_params *mp) +static int perf_mmap__setup_affinity_mask(struct mmap *map, struct mmap_params *mp) { - CPU_ZERO(&map->affinity_mask); + map->affinity_mask.nbits = cpu__max_cpu(); + map->affinity_mask.bits = bitmap_alloc(map->affinity_mask.nbits); + if (!map->affinity_mask.bits) + return -1; + if (mp->affinity == PERF_AFFINITY_NODE && cpu__max_node() > 1) build_node_mask(cpu__get_node(map->core.cpu), &map->affinity_mask); else if (mp->affinity == PERF_AFFINITY_CPU) - CPU_SET(map->core.cpu, &map->affinity_mask); + set_bit(map->core.cpu, map->affinity_mask.bits); + + return 0; } int mmap__mmap(struct mmap *map, struct mmap_params *mp, int fd, int cpu) @@ -249,7 +269,15 @@ int mmap__mmap(struct mmap *map, struct mmap_params *mp, int fd, int cpu) return -1; } - perf_mmap__setup_affinity_mask(map, mp); + if (mp->affinity != PERF_AFFINITY_SYS && + perf_mmap__setup_affinity_mask(map, mp)) { + pr_debug2("failed to alloc mmap affinity mask, error %d\n", + errno); + return -1; + } + + if (verbose == 2) + mmap_cpu_mask__scnprintf(&map->affinity_mask, "mmap"); map->core.flush = mp->flush; diff --git a/tools/perf/util/mmap.h b/tools/perf/util/mmap.h index bee4e83f7109..9d5f589f02ae 100644 --- a/tools/perf/util/mmap.h +++ b/tools/perf/util/mmap.h @@ -15,6 +15,15 @@ #include "event.h" struct aiocb; + +struct mmap_cpu_mask { + unsigned long *bits; + size_t nbits; +}; + +#define MMAP_CPU_MASK_BYTES(m) \ + (BITS_TO_LONGS(((struct mmap_cpu_mask *)m)->nbits) * sizeof(unsigned long)) + /** * struct mmap - perf's ring buffer mmap details * @@ -31,7 +40,7 @@ struct mmap { int nr_cblocks; } aio; #endif - cpu_set_t affinity_mask; + struct mmap_cpu_mask affinity_mask; void *data; int comp_level; }; @@ -52,4 +61,6 @@ int perf_mmap__push(struct mmap *md, void *to, size_t mmap__mmap_len(struct mmap *map); +void mmap_cpu_mask__scnprintf(struct mmap_cpu_mask *mask, const char *tag); + #endif /*__PERF_MMAP_H */ diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y index e2eea4e601b4..94f8bcd83582 100644 --- a/tools/perf/util/parse-events.y +++ b/tools/perf/util/parse-events.y @@ -1,4 +1,4 @@ -%pure-parser +%define api.pure full %parse-param {void *_parse_state} %parse-param {void *scanner} %lex-param {void* scanner} diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index 345b5ccc90f6..ab0cfd790ad0 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c @@ -324,8 +324,7 @@ static int _hist_entry__sym_snprintf(struct map_symbol *ms, return ret; } -static int hist_entry__sym_snprintf(struct hist_entry *he, char *bf, - size_t size, unsigned int width) +int hist_entry__sym_snprintf(struct hist_entry *he, char *bf, size_t size, unsigned int width) { return _hist_entry__sym_snprintf(&he->ms, he->ip, he->level, bf, size, width); @@ -2681,12 +2680,12 @@ static int setup_sort_list(struct perf_hpp_list *list, char *str, ret = sort_dimension__add(list, tok, evlist, level); if (ret == -EINVAL) { if (!cacheline_size() && !strncasecmp(tok, "dcacheline", strlen(tok))) - pr_err("The \"dcacheline\" --sort key needs to know the cacheline size and it couldn't be determined on this system"); + ui__error("The \"dcacheline\" --sort key needs to know the cacheline size and it couldn't be determined on this system"); else - pr_err("Invalid --sort key: `%s'", tok); + ui__error("Invalid --sort key: `%s'", tok); break; } else if (ret == -ESRCH) { - pr_err("Unknown --sort key: `%s'", tok); + ui__error("Unknown --sort key: `%s'", tok); break; } } @@ -2743,7 +2742,7 @@ static int setup_sort_order(struct evlist *evlist) return 0; if (sort_order[1] == '\0') { - pr_err("Invalid --sort key: `+'"); + ui__error("Invalid --sort key: `+'"); return -EINVAL; } @@ -2959,6 +2958,9 @@ int output_field_add(struct perf_hpp_list *list, char *tok) if (strncasecmp(tok, sd->name, strlen(tok))) continue; + if (sort__mode != SORT_MODE__MEMORY) + return -EINVAL; + return __sort_dimension__add_output(list, sd); } @@ -2968,6 +2970,9 @@ int output_field_add(struct perf_hpp_list *list, char *tok) if (strncasecmp(tok, sd->name, strlen(tok))) continue; + if (sort__mode != SORT_MODE__BRANCH) + return -EINVAL; + return __sort_dimension__add_output(list, sd); } @@ -3034,7 +3039,7 @@ static int __setup_output_field(void) strp++; if (!strlen(strp)) { - pr_err("Invalid --fields key: `+'"); + ui__error("Invalid --fields key: `+'"); goto out; } diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h index 5aff9542d9b7..6c862d62d052 100644 --- a/tools/perf/util/sort.h +++ b/tools/perf/util/sort.h @@ -164,6 +164,8 @@ static __pure inline bool hist_entry__has_callchains(struct hist_entry *he) return he->callchain_size != 0; } +int hist_entry__sym_snprintf(struct hist_entry *he, char *bf, size_t size, unsigned int width); + static inline bool hist_entry__has_pairs(struct hist_entry *he) { return !list_empty(&he->pairs.node); diff --git a/tools/perf/util/stat.c b/tools/perf/util/stat.c index 332cb730785b..5f26137b8d60 100644 --- a/tools/perf/util/stat.c +++ b/tools/perf/util/stat.c @@ -464,7 +464,8 @@ size_t perf_event__fprintf_stat_config(union perf_event *event, FILE *fp) int create_perf_stat_counter(struct evsel *evsel, struct perf_stat_config *config, - struct target *target) + struct target *target, + int cpu) { struct perf_event_attr *attr = &evsel->core.attr; struct evsel *leader = evsel->leader; @@ -518,7 +519,7 @@ int create_perf_stat_counter(struct evsel *evsel, } if (target__has_cpu(target) && !target__has_per_thread(target)) - return perf_evsel__open_per_cpu(evsel, evsel__cpus(evsel)); + return perf_evsel__open_per_cpu(evsel, evsel__cpus(evsel), cpu); return perf_evsel__open_per_thread(evsel, evsel->core.threads); } diff --git a/tools/perf/util/stat.h b/tools/perf/util/stat.h index bfa9aaf36ce6..fb990efa54a8 100644 --- a/tools/perf/util/stat.h +++ b/tools/perf/util/stat.h @@ -214,7 +214,8 @@ size_t perf_event__fprintf_stat_config(union perf_event *event, FILE *fp); int create_perf_stat_counter(struct evsel *evsel, struct perf_stat_config *config, - struct target *target); + struct target *target, + int cpu); void perf_evlist__print_counters(struct evlist *evlist, struct perf_stat_config *config, diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c index 6658fbf196e6..1965aefccb02 100644 --- a/tools/perf/util/symbol-elf.c +++ b/tools/perf/util/symbol-elf.c @@ -920,6 +920,9 @@ static int dso__process_kernel_symbol(struct dso *dso, struct map *map, if (curr_map == NULL) return -1; + if (curr_dso->kernel) + map__kmap(curr_map)->kmaps = kmaps; + if (adjust_kernel_syms) { curr_map->start = shdr->sh_addr + ref_reloc(kmap); curr_map->end = curr_map->start + shdr->sh_size; |