diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2019-09-17 02:06:21 +0200 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2019-09-17 02:06:21 +0200 |
commit | 772c1d06bd402f7ee72c61a18c2db74cd74b6758 (patch) | |
tree | e362fc7e158b3580d810a26189ecf91ec8a4f141 /tools/perf/util | |
parent | Merge branch 'locking-core-for-linus' of git://git.kernel.org/pub/scm/linux/k... (diff) | |
parent | kprobes: Prohibit probing on BUG() and WARN() address (diff) | |
download | linux-772c1d06bd402f7ee72c61a18c2db74cd74b6758.tar.xz linux-772c1d06bd402f7ee72c61a18c2db74cd74b6758.zip |
Merge branch 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull perf updates from Ingo Molnar:
"Kernel side changes:
- Improved kbprobes robustness
- Intel PEBS support for PT hardware tracing
- Other Intel PT improvements: high order pages memory footprint
reduction and various related cleanups
- Misc cleanups
The perf tooling side has been very busy in this cycle, with over 300
commits. This is an incomplete high-level summary of the many
improvements done by over 30 developers:
- Lots of updates to the following tools:
'perf c2c'
'perf config'
'perf record'
'perf report'
'perf script'
'perf test'
'perf top'
'perf trace'
- Updates to libperf and libtraceevent, and a consolidation of the
proliferation of x86 instruction decoder libraries.
- Vendor event updates for Intel and PowerPC CPUs,
- Updates to hardware tracing tooling for ARM and Intel CPUs,
- ... and lots of other changes and cleanups - see the shortlog and
Git log for details"
* 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (322 commits)
kprobes: Prohibit probing on BUG() and WARN() address
perf/x86: Make more stuff static
x86, perf: Fix the dependency of the x86 insn decoder selftest
objtool: Ignore intentional differences for the x86 insn decoder
objtool: Update sync-check.sh from perf's check-headers.sh
perf build: Ignore intentional differences for the x86 insn decoder
perf intel-pt: Use shared x86 insn decoder
perf intel-pt: Remove inat.c from build dependency list
perf: Update .gitignore file
objtool: Move x86 insn decoder to a common location
perf metricgroup: Support multiple events for metricgroup
perf metricgroup: Scale the metric result
perf pmu: Change convert_scale from static to global
perf symbols: Move mem_info and branch_info out of symbol.h
perf auxtrace: Uninline functions that touch perf_session
perf tools: Remove needless evlist.h include directives
perf tools: Remove needless evlist.h include directives
perf tools: Remove needless thread_map.h include directives
perf tools: Remove needless thread.h include directives
perf tools: Remove needless map.h include directives
...
Diffstat (limited to 'tools/perf/util')
173 files changed, 3397 insertions, 6252 deletions
diff --git a/tools/perf/util/Build b/tools/perf/util/Build index 14f812bb07a7..0b4d8e0d474c 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build @@ -1,6 +1,7 @@ perf-y += annotate.o perf-y += block-range.o perf-y += build-id.o +perf-y += cacheline.o perf-y += config.o perf-y += ctype.o perf-y += db-export.o @@ -9,6 +10,7 @@ perf-y += event.o perf-y += evlist.o perf-y += evsel.o perf-y += evsel_fprintf.o +perf-y += evswitch.o perf-y += find_bit.o perf-y += get_current_dir_name.o perf-y += kallsyms.o @@ -26,7 +28,6 @@ perf-y += rbtree.o perf-y += libstring.o perf-y += bitmap.o perf-y += hweight.o -perf-y += zalloc.o perf-y += smt.o perf-y += strbuf.o perf-y += string.o @@ -35,6 +36,7 @@ perf-y += strfilter.o perf-y += top.o perf-y += usage.o perf-y += dso.o +perf-y += dsos.o perf-y += symbol.o perf-y += symbol_fprintf.o perf-y += color.o @@ -70,7 +72,6 @@ perf-y += svghelper.o perf-y += sort.o perf-y += hist.o perf-y += util.o -perf-y += xyarray.o perf-y += cpumap.o perf-y += cputopo.o perf-y += cgroup.o @@ -150,6 +151,8 @@ perf-$(CONFIG_ZLIB) += zlib.o perf-$(CONFIG_LZMA) += lzma.o perf-$(CONFIG_ZSTD) += zstd.o +perf-$(CONFIG_LIBCAP) += cap.o + perf-y += demangle-java.o perf-y += demangle-rust.o @@ -243,7 +246,3 @@ $(OUTPUT)util/hweight.o: ../lib/hweight.c FORCE $(OUTPUT)util/vsprintf.o: ../lib/vsprintf.c FORCE $(call rule_mkdir) $(call if_changed_dep,cc_o_c) - -$(OUTPUT)util/zalloc.o: ../lib/zalloc.c FORCE - $(call rule_mkdir) - $(call if_changed_dep,cc_o_c) diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 163536720149..1748f528b6e9 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -9,6 +9,7 @@ #include <errno.h> #include <inttypes.h> #include <libgen.h> +#include <stdlib.h> #include <bpf/bpf.h> #include <bpf/btf.h> #include <bpf/libbpf.h> @@ -19,9 +20,12 @@ #include "build-id.h" #include "color.h" #include "config.h" -#include "cache.h" +#include "dso.h" +#include "env.h" #include "map.h" +#include "map_groups.h" #include "symbol.h" +#include "srcline.h" #include "units.h" #include "debug.h" #include "annotate.h" @@ -37,6 +41,7 @@ #include <linux/kernel.h> #include <linux/string.h> #include <bpf/libbpf.h> +#include <subcmd/parse-options.h> /* FIXME: For the HE_COLORSET */ #include "ui/browser.h" @@ -929,14 +934,14 @@ alloc_histograms: } static int symbol__inc_addr_samples(struct symbol *sym, struct map *map, - struct perf_evsel *evsel, u64 addr, + struct evsel *evsel, u64 addr, struct perf_sample *sample) { struct annotated_source *src; if (sym == NULL) return 0; - src = symbol__hists(sym, evsel->evlist->nr_entries); + src = symbol__hists(sym, evsel->evlist->core.nr_entries); return (src) ? __symbol__inc_addr_samples(sym, map, src, evsel->idx, addr, sample) : 0; } @@ -1080,13 +1085,13 @@ void annotation__compute_ipc(struct annotation *notes, size_t size) } int addr_map_symbol__inc_samples(struct addr_map_symbol *ams, struct perf_sample *sample, - struct perf_evsel *evsel) + struct evsel *evsel) { return symbol__inc_addr_samples(ams->sym, ams->map, evsel, ams->al_addr, sample); } int hist_entry__inc_addr_samples(struct hist_entry *he, struct perf_sample *sample, - struct perf_evsel *evsel, u64 ip) + struct evsel *evsel, u64 ip) { return symbol__inc_addr_samples(he->ms.sym, he->ms.map, evsel, ip, sample); } @@ -1134,7 +1139,7 @@ struct annotate_args { size_t privsize; struct arch *arch; struct map_symbol ms; - struct perf_evsel *evsel; + struct evsel *evsel; struct annotation_options *options; s64 offset; char *line; @@ -1165,12 +1170,12 @@ static struct annotation_line * annotation_line__new(struct annotate_args *args, size_t privsize) { struct annotation_line *al; - struct perf_evsel *evsel = args->evsel; + struct evsel *evsel = args->evsel; size_t size = privsize + sizeof(*al); int nr = 1; if (perf_evsel__is_group_event(evsel)) - nr = evsel->nr_members; + nr = evsel->core.nr_members; size += sizeof(al->data[0]) * nr; @@ -1359,7 +1364,7 @@ static int disasm_line__print(struct disasm_line *dl, u64 start, int addr_fmt_wi static int annotation_line__print(struct annotation_line *al, struct symbol *sym, u64 start, - struct perf_evsel *evsel, u64 len, int min_pcnt, int printed, + struct evsel *evsel, u64 len, int min_pcnt, int printed, int max_lines, struct annotation_line *queue, int addr_fmt_width, int percent_type) { @@ -1448,7 +1453,7 @@ annotation_line__print(struct annotation_line *al, struct symbol *sym, u64 start return -1; if (perf_evsel__is_group_event(evsel)) - width *= evsel->nr_members; + width *= evsel->core.nr_members; if (!*al->line) printf(" %*s:\n", width, " "); @@ -2011,10 +2016,10 @@ static void calc_percent(struct sym_hist *sym_hist, } static void annotation__calc_percent(struct annotation *notes, - struct perf_evsel *leader, s64 len) + struct evsel *leader, s64 len) { struct annotation_line *al, *next; - struct perf_evsel *evsel; + struct evsel *evsel; list_for_each_entry(al, ¬es->src->source, node) { s64 end; @@ -2041,7 +2046,7 @@ static void annotation__calc_percent(struct annotation *notes, } } -void symbol__calc_percent(struct symbol *sym, struct perf_evsel *evsel) +void symbol__calc_percent(struct symbol *sym, struct evsel *evsel) { struct annotation *notes = symbol__annotation(sym); @@ -2049,7 +2054,7 @@ void symbol__calc_percent(struct symbol *sym, struct perf_evsel *evsel) } int symbol__annotate(struct symbol *sym, struct map *map, - struct perf_evsel *evsel, size_t privsize, + struct evsel *evsel, size_t privsize, struct annotation_options *options, struct arch **parch) { @@ -2214,7 +2219,7 @@ static void print_summary(struct rb_root *root, const char *filename) } } -static void symbol__annotate_hits(struct symbol *sym, struct perf_evsel *evsel) +static void symbol__annotate_hits(struct symbol *sym, struct evsel *evsel) { struct annotation *notes = symbol__annotation(sym); struct sym_hist *h = annotation__histogram(notes, evsel->idx); @@ -2241,7 +2246,7 @@ static int annotated_source__addr_fmt_width(struct list_head *lines, u64 start) } int symbol__annotate_printf(struct symbol *sym, struct map *map, - struct perf_evsel *evsel, + struct evsel *evsel, struct annotation_options *opts) { struct dso *dso = map->dso; @@ -2272,7 +2277,7 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, len = symbol__size(sym); if (perf_evsel__is_group_event(evsel)) { - width *= evsel->nr_members; + width *= evsel->core.nr_members; perf_evsel__group_desc(evsel, buf, sizeof(buf)); evsel_name = buf; } @@ -2405,7 +2410,7 @@ static int symbol__annotate_fprintf2(struct symbol *sym, FILE *fp, return 0; } -int map_symbol__annotation_dump(struct map_symbol *ms, struct perf_evsel *evsel, +int map_symbol__annotation_dump(struct map_symbol *ms, struct evsel *evsel, struct annotation_options *opts) { const char *ev_name = perf_evsel__name(evsel); @@ -2657,7 +2662,7 @@ static void symbol__calc_lines(struct symbol *sym, struct map *map, } int symbol__tty_annotate2(struct symbol *sym, struct map *map, - struct perf_evsel *evsel, + struct evsel *evsel, struct annotation_options *opts) { struct dso *dso = map->dso; @@ -2685,7 +2690,7 @@ int symbol__tty_annotate2(struct symbol *sym, struct map *map, } int symbol__tty_annotate(struct symbol *sym, struct map *map, - struct perf_evsel *evsel, + struct evsel *evsel, struct annotation_options *opts) { struct dso *dso = map->dso; @@ -2956,7 +2961,7 @@ void annotation_line__write(struct annotation_line *al, struct annotation *notes wops->write_graph); } -int symbol__annotate2(struct symbol *sym, struct map *map, struct perf_evsel *evsel, +int symbol__annotate2(struct symbol *sym, struct map *map, struct evsel *evsel, struct annotation_options *options, struct arch **parch) { struct annotation *notes = symbol__annotation(sym); @@ -2968,7 +2973,7 @@ int symbol__annotate2(struct symbol *sym, struct map *map, struct perf_evsel *ev return -1; if (perf_evsel__is_group_event(evsel)) - nr_pcnt = evsel->nr_members; + nr_pcnt = evsel->core.nr_members; err = symbol__annotate(sym, map, evsel, 0, options, parch); if (err) diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 5bc0cf655d37..d94be9140e31 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -20,7 +20,7 @@ struct map_symbol; struct addr_map_symbol; struct option; struct perf_sample; -struct perf_evsel; +struct evsel; struct symbol; struct ins { @@ -216,12 +216,12 @@ void annotation_line__write(struct annotation_line *al, struct annotation *notes int __annotation__scnprintf_samples_period(struct annotation *notes, char *bf, size_t size, - struct perf_evsel *evsel, + struct evsel *evsel, bool show_freq); int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw, int max_ins_name); size_t disasm__fprintf(struct list_head *head, FILE *fp); -void symbol__calc_percent(struct symbol *sym, struct perf_evsel *evsel); +void symbol__calc_percent(struct symbol *sym, struct evsel *evsel); struct sym_hist { u64 nr_samples; @@ -245,7 +245,7 @@ struct cyc_hist { /** struct annotated_source - symbols with hits have this attached as in sannotation * * @histograms: Array of addr hit histograms per event being monitored - * nr_histograms: This may not be the same as evsel->evlist->nr_entries if + * nr_histograms: This may not be the same as evsel->evlist->core.nr_entries if * we have more than a group in a evlist, where we will want * to see each group separately, that is why symbol__annotate2() * sets src->nr_histograms to evsel->nr_members. @@ -335,24 +335,24 @@ static inline struct annotation *symbol__annotation(struct symbol *sym) } int addr_map_symbol__inc_samples(struct addr_map_symbol *ams, struct perf_sample *sample, - struct perf_evsel *evsel); + struct evsel *evsel); int addr_map_symbol__account_cycles(struct addr_map_symbol *ams, struct addr_map_symbol *start, unsigned cycles); int hist_entry__inc_addr_samples(struct hist_entry *he, struct perf_sample *sample, - struct perf_evsel *evsel, u64 addr); + struct evsel *evsel, u64 addr); struct annotated_source *symbol__hists(struct symbol *sym, int nr_hists); void symbol__annotate_zero_histograms(struct symbol *sym); int symbol__annotate(struct symbol *sym, struct map *map, - struct perf_evsel *evsel, size_t privsize, + struct evsel *evsel, size_t privsize, struct annotation_options *options, struct arch **parch); int symbol__annotate2(struct symbol *sym, struct map *map, - struct perf_evsel *evsel, + struct evsel *evsel, struct annotation_options *options, struct arch **parch); @@ -378,32 +378,32 @@ int symbol__strerror_disassemble(struct symbol *sym, struct map *map, int errnum, char *buf, size_t buflen); int symbol__annotate_printf(struct symbol *sym, struct map *map, - struct perf_evsel *evsel, + struct evsel *evsel, struct annotation_options *options); void symbol__annotate_zero_histogram(struct symbol *sym, int evidx); void symbol__annotate_decay_histogram(struct symbol *sym, int evidx); void annotated_source__purge(struct annotated_source *as); -int map_symbol__annotation_dump(struct map_symbol *ms, struct perf_evsel *evsel, +int map_symbol__annotation_dump(struct map_symbol *ms, struct evsel *evsel, struct annotation_options *opts); bool ui__has_annotation(void); int symbol__tty_annotate(struct symbol *sym, struct map *map, - struct perf_evsel *evsel, struct annotation_options *opts); + struct evsel *evsel, struct annotation_options *opts); int symbol__tty_annotate2(struct symbol *sym, struct map *map, - struct perf_evsel *evsel, struct annotation_options *opts); + struct evsel *evsel, struct annotation_options *opts); #ifdef HAVE_SLANG_SUPPORT int symbol__tui_annotate(struct symbol *sym, struct map *map, - struct perf_evsel *evsel, + struct evsel *evsel, struct hist_browser_timer *hbt, struct annotation_options *opts); #else static inline int symbol__tui_annotate(struct symbol *sym __maybe_unused, struct map *map __maybe_unused, - struct perf_evsel *evsel __maybe_unused, + struct evsel *evsel __maybe_unused, struct hist_browser_timer *hbt __maybe_unused, struct annotation_options *opts __maybe_unused) { diff --git a/tools/perf/util/arm-spe.c b/tools/perf/util/arm-spe.c index a314e5b26e9d..8a7340f6a2a2 100644 --- a/tools/perf/util/arm-spe.c +++ b/tools/perf/util/arm-spe.c @@ -8,6 +8,8 @@ #include <errno.h> #include <byteswap.h> #include <inttypes.h> +#include <unistd.h> +#include <stdlib.h> #include <linux/kernel.h> #include <linux/types.h> #include <linux/bitops.h> @@ -17,10 +19,8 @@ #include "cpumap.h" #include "color.h" #include "evsel.h" -#include "evlist.h" #include "machine.h" #include "session.h" -#include "thread.h" #include "debug.h" #include "auxtrace.h" #include "arm-spe.h" @@ -181,7 +181,7 @@ static const char * const arm_spe_info_fmts[] = { [ARM_SPE_PMU_TYPE] = " PMU Type %"PRId64"\n", }; -static void arm_spe_print_info(u64 *arr) +static void arm_spe_print_info(__u64 *arr) { if (!dump_trace) return; @@ -192,12 +192,12 @@ static void arm_spe_print_info(u64 *arr) int arm_spe_process_auxtrace_info(union perf_event *event, struct perf_session *session) { - struct auxtrace_info_event *auxtrace_info = &event->auxtrace_info; + struct perf_record_auxtrace_info *auxtrace_info = &event->auxtrace_info; size_t min_sz = sizeof(u64) * ARM_SPE_PMU_TYPE; struct arm_spe *spe; int err; - if (auxtrace_info->header.size < sizeof(struct auxtrace_info_event) + + if (auxtrace_info->header.size < sizeof(struct perf_record_auxtrace_info) + min_sz) return -EINVAL; diff --git a/tools/perf/util/auxtrace.c b/tools/perf/util/auxtrace.c index ec0af36697c4..6f25224a3def 100644 --- a/tools/perf/util/auxtrace.c +++ b/tools/perf/util/auxtrace.c @@ -26,7 +26,6 @@ #include <linux/list.h> #include <linux/zalloc.h> -#include "../perf.h" #include "evlist.h" #include "dso.h" #include "map.h" @@ -41,6 +40,7 @@ #include <linux/hash.h> #include "event.h" +#include "record.h" #include "session.h" #include "debug.h" #include <subcmd/parse-options.h> @@ -50,6 +50,7 @@ #include "intel-bts.h" #include "arm-spe.h" #include "s390-cpumsf.h" +#include "util.h" #include <linux/ctype.h> #include "symbol/kallsyms.h" @@ -124,20 +125,20 @@ void auxtrace_mmap_params__init(struct auxtrace_mmap_params *mp, } void auxtrace_mmap_params__set_idx(struct auxtrace_mmap_params *mp, - struct perf_evlist *evlist, int idx, + struct evlist *evlist, int idx, bool per_cpu) { mp->idx = idx; if (per_cpu) { - mp->cpu = evlist->cpus->map[idx]; - if (evlist->threads) - mp->tid = thread_map__pid(evlist->threads, 0); + mp->cpu = evlist->core.cpus->map[idx]; + if (evlist->core.threads) + mp->tid = perf_thread_map__pid(evlist->core.threads, 0); else mp->tid = -1; } else { mp->cpu = -1; - mp->tid = thread_map__pid(evlist->threads, idx); + mp->tid = perf_thread_map__pid(evlist->core.threads, idx); } } @@ -385,7 +386,7 @@ static int auxtrace_queues__add_indexed_event(struct auxtrace_queues *queues, return err; if (event->header.type == PERF_RECORD_AUXTRACE) { - if (event->header.size < sizeof(struct auxtrace_event) || + if (event->header.size < sizeof(struct perf_record_auxtrace) || event->header.size != sz) { err = -EINVAL; goto out; @@ -503,7 +504,7 @@ void auxtrace_heap__pop(struct auxtrace_heap *heap) } size_t auxtrace_record__info_priv_size(struct auxtrace_record *itr, - struct perf_evlist *evlist) + struct evlist *evlist) { if (itr) return itr->info_priv_size(itr, evlist); @@ -518,7 +519,7 @@ static int auxtrace_not_supported(void) int auxtrace_record__info_fill(struct auxtrace_record *itr, struct perf_session *session, - struct auxtrace_info_event *auxtrace_info, + struct perf_record_auxtrace_info *auxtrace_info, size_t priv_size) { if (itr) @@ -539,9 +540,9 @@ int auxtrace_record__snapshot_start(struct auxtrace_record *itr) return 0; } -int auxtrace_record__snapshot_finish(struct auxtrace_record *itr) +int auxtrace_record__snapshot_finish(struct auxtrace_record *itr, bool on_exit) { - if (itr && itr->snapshot_finish) + if (!on_exit && itr && itr->snapshot_finish) return itr->snapshot_finish(itr); return 0; } @@ -556,7 +557,7 @@ int auxtrace_record__find_snapshot(struct auxtrace_record *itr, int idx, } int auxtrace_record__options(struct auxtrace_record *itr, - struct perf_evlist *evlist, + struct evlist *evlist, struct record_opts *opts) { if (itr) @@ -577,6 +578,16 @@ int auxtrace_parse_snapshot_options(struct auxtrace_record *itr, if (!str) return 0; + /* PMU-agnostic options */ + switch (*str) { + case 'e': + opts->auxtrace_snapshot_on_exit = true; + str++; + break; + default: + break; + } + if (itr) return itr->parse_snapshot_options(itr, opts, str); @@ -585,7 +596,7 @@ int auxtrace_parse_snapshot_options(struct auxtrace_record *itr, } struct auxtrace_record *__weak -auxtrace_record__init(struct perf_evlist *evlist __maybe_unused, int *err) +auxtrace_record__init(struct evlist *evlist __maybe_unused, int *err) { *err = 0; return NULL; @@ -848,13 +859,13 @@ void auxtrace_buffer__free(struct auxtrace_buffer *buffer) free(buffer); } -void auxtrace_synth_error(struct auxtrace_error_event *auxtrace_error, int type, +void auxtrace_synth_error(struct perf_record_auxtrace_error *auxtrace_error, int type, int code, int cpu, pid_t pid, pid_t tid, u64 ip, const char *msg, u64 timestamp) { size_t size; - memset(auxtrace_error, 0, sizeof(struct auxtrace_error_event)); + memset(auxtrace_error, 0, sizeof(struct perf_record_auxtrace_error)); auxtrace_error->header.type = PERF_RECORD_AUXTRACE_ERROR; auxtrace_error->type = type; @@ -883,12 +894,12 @@ int perf_event__synthesize_auxtrace_info(struct auxtrace_record *itr, pr_debug2("Synthesizing auxtrace information\n"); priv_size = auxtrace_record__info_priv_size(itr, session->evlist); - ev = zalloc(sizeof(struct auxtrace_info_event) + priv_size); + ev = zalloc(sizeof(struct perf_record_auxtrace_info) + priv_size); if (!ev) return -ENOMEM; ev->auxtrace_info.header.type = PERF_RECORD_AUXTRACE_INFO; - ev->auxtrace_info.header.size = sizeof(struct auxtrace_info_event) + + ev->auxtrace_info.header.size = sizeof(struct perf_record_auxtrace_info) + priv_size; err = auxtrace_record__info_fill(itr, session, &ev->auxtrace_info, priv_size); @@ -932,7 +943,7 @@ s64 perf_event__process_auxtrace(struct perf_session *session, s64 err; if (dump_trace) - fprintf(stdout, " size: %#"PRIx64" offset: %#"PRIx64" ref: %#"PRIx64" idx: %u tid: %d cpu: %d\n", + fprintf(stdout, " size: %#"PRI_lx64" offset: %#"PRI_lx64" ref: %#"PRI_lx64" idx: %u tid: %d cpu: %d\n", event->auxtrace.size, event->auxtrace.offset, event->auxtrace.reference, event->auxtrace.idx, event->auxtrace.tid, event->auxtrace.cpu); @@ -964,6 +975,7 @@ void itrace_synth_opts__set_default(struct itrace_synth_opts *synth_opts, synth_opts->transactions = true; synth_opts->ptwrites = true; synth_opts->pwr_events = true; + synth_opts->other_events = true; synth_opts->errors = true; if (no_sample) { synth_opts->period_type = PERF_ITRACE_PERIOD_INSTRUCTIONS; @@ -1061,6 +1073,9 @@ int itrace_parse_synth_opts(const struct option *opt, const char *str, case 'p': synth_opts->pwr_events = true; break; + case 'o': + synth_opts->other_events = true; + break; case 'e': synth_opts->errors = true; break; @@ -1154,7 +1169,7 @@ static const char *auxtrace_error_name(int type) size_t perf_event__fprintf_auxtrace_error(union perf_event *event, FILE *fp) { - struct auxtrace_error_event *e = &event->auxtrace_error; + struct perf_record_auxtrace_error *e = &event->auxtrace_error; unsigned long long nsecs = e->time; const char *msg = e->msg; int ret; @@ -1174,7 +1189,7 @@ size_t perf_event__fprintf_auxtrace_error(union perf_event *event, FILE *fp) if (!e->fmt) msg = (const char *)&e->time; - ret += fprintf(fp, " cpu %d pid %d tid %d ip %#"PRIx64" code %u: %s\n", + ret += fprintf(fp, " cpu %d pid %d tid %d ip %#"PRI_lx64" code %u: %s\n", e->cpu, e->pid, e->tid, e->ip, e->code, msg); return ret; } @@ -1182,7 +1197,7 @@ size_t perf_event__fprintf_auxtrace_error(union perf_event *event, FILE *fp) void perf_session__auxtrace_error_inc(struct perf_session *session, union perf_event *event) { - struct auxtrace_error_event *e = &event->auxtrace_error; + struct perf_record_auxtrace_error *e = &event->auxtrace_error; if (e->type < PERF_AUXTRACE_ERROR_MAX) session->evlist->stats.nr_auxtrace_errors[e->type] += 1; @@ -2084,7 +2099,7 @@ static char *addr_filter__to_str(struct addr_filter *filt) return err < 0 ? NULL : filter; } -static int parse_addr_filter(struct perf_evsel *evsel, const char *filter, +static int parse_addr_filter(struct evsel *evsel, const char *filter, int max_nr) { struct addr_filters filts; @@ -2135,19 +2150,19 @@ out_exit: return err; } -static struct perf_pmu *perf_evsel__find_pmu(struct perf_evsel *evsel) +static struct perf_pmu *perf_evsel__find_pmu(struct evsel *evsel) { struct perf_pmu *pmu = NULL; while ((pmu = perf_pmu__scan(pmu)) != NULL) { - if (pmu->type == evsel->attr.type) + if (pmu->type == evsel->core.attr.type) break; } return pmu; } -static int perf_evsel__nr_addr_filter(struct perf_evsel *evsel) +static int perf_evsel__nr_addr_filter(struct evsel *evsel) { struct perf_pmu *pmu = perf_evsel__find_pmu(evsel); int nr_addr_filters = 0; @@ -2160,9 +2175,9 @@ static int perf_evsel__nr_addr_filter(struct perf_evsel *evsel) return nr_addr_filters; } -int auxtrace_parse_filters(struct perf_evlist *evlist) +int auxtrace_parse_filters(struct evlist *evlist) { - struct perf_evsel *evsel; + struct evsel *evsel; char *filter; int err, max_nr; @@ -2181,3 +2196,36 @@ int auxtrace_parse_filters(struct perf_evlist *evlist) return 0; } + +int auxtrace__process_event(struct perf_session *session, union perf_event *event, + struct perf_sample *sample, struct perf_tool *tool) +{ + if (!session->auxtrace) + return 0; + + return session->auxtrace->process_event(session, event, sample, tool); +} + +int auxtrace__flush_events(struct perf_session *session, struct perf_tool *tool) +{ + if (!session->auxtrace) + return 0; + + return session->auxtrace->flush_events(session, tool); +} + +void auxtrace__free_events(struct perf_session *session) +{ + if (!session->auxtrace) + return; + + return session->auxtrace->free_events(session); +} + +void auxtrace__free(struct perf_session *session) +{ + if (!session->auxtrace) + return; + + return session->auxtrace->free(session); +} diff --git a/tools/perf/util/auxtrace.h b/tools/perf/util/auxtrace.h index e9b4c5edf78b..37e70dc01436 100644 --- a/tools/perf/util/auxtrace.h +++ b/tools/perf/util/auxtrace.h @@ -15,22 +15,25 @@ #include <linux/perf_event.h> #include <linux/types.h> #include <asm/bitsperlong.h> +#include <asm/barrier.h> -#include "../perf.h" #include "event.h" -#include "session.h" -#include "debug.h" union perf_event; struct perf_session; -struct perf_evlist; +struct evlist; struct perf_tool; struct perf_mmap; struct option; struct record_opts; -struct auxtrace_info_event; +struct perf_record_auxtrace_info; struct events_stats; +enum auxtrace_error_type { + PERF_AUXTRACE_ERROR_ITRACE = 1, + PERF_AUXTRACE_ERROR_MAX +}; + /* Auxtrace records must have the same alignment as perf event records */ #define PERF_AUXTRACE_RECORD_ALIGNMENT 8 @@ -60,6 +63,8 @@ enum itrace_period_type { * @transactions: whether to synthesize events for transactions * @ptwrites: whether to synthesize events for ptwrites * @pwr_events: whether to synthesize power events + * @other_events: whether to synthesize other events recorded due to the use of + * aux_output * @errors: whether to synthesize decoder error events * @dont_decode: whether to skip decoding entirely * @log: write a decoding log @@ -86,6 +91,7 @@ struct itrace_synth_opts { bool transactions; bool ptwrites; bool pwr_events; + bool other_events; bool errors; bool dont_decode; bool log; @@ -309,13 +315,13 @@ struct auxtrace_mmap_params { */ struct auxtrace_record { int (*recording_options)(struct auxtrace_record *itr, - struct perf_evlist *evlist, + struct evlist *evlist, struct record_opts *opts); size_t (*info_priv_size)(struct auxtrace_record *itr, - struct perf_evlist *evlist); + struct evlist *evlist); int (*info_fill)(struct auxtrace_record *itr, struct perf_session *session, - struct auxtrace_info_event *auxtrace_info, + struct perf_record_auxtrace_info *auxtrace_info, size_t priv_size); void (*free)(struct auxtrace_record *itr); int (*snapshot_start)(struct auxtrace_record *itr); @@ -373,6 +379,8 @@ struct addr_filters { int cnt; }; +struct auxtrace_cache; + #ifdef HAVE_AUXTRACE_SUPPORT /* @@ -432,7 +440,7 @@ void auxtrace_mmap_params__init(struct auxtrace_mmap_params *mp, unsigned int auxtrace_pages, bool auxtrace_overwrite); void auxtrace_mmap_params__set_idx(struct auxtrace_mmap_params *mp, - struct perf_evlist *evlist, int idx, + struct evlist *evlist, int idx, bool per_cpu); typedef int (*process_auxtrace_t)(struct perf_tool *tool, @@ -482,24 +490,24 @@ int auxtrace_cache__add(struct auxtrace_cache *c, u32 key, struct auxtrace_cache_entry *entry); void *auxtrace_cache__lookup(struct auxtrace_cache *c, u32 key); -struct auxtrace_record *auxtrace_record__init(struct perf_evlist *evlist, +struct auxtrace_record *auxtrace_record__init(struct evlist *evlist, int *err); int auxtrace_parse_snapshot_options(struct auxtrace_record *itr, struct record_opts *opts, const char *str); int auxtrace_record__options(struct auxtrace_record *itr, - struct perf_evlist *evlist, + struct evlist *evlist, struct record_opts *opts); size_t auxtrace_record__info_priv_size(struct auxtrace_record *itr, - struct perf_evlist *evlist); + struct evlist *evlist); int auxtrace_record__info_fill(struct auxtrace_record *itr, struct perf_session *session, - struct auxtrace_info_event *auxtrace_info, + struct perf_record_auxtrace_info *auxtrace_info, size_t priv_size); void auxtrace_record__free(struct auxtrace_record *itr); int auxtrace_record__snapshot_start(struct auxtrace_record *itr); -int auxtrace_record__snapshot_finish(struct auxtrace_record *itr); +int auxtrace_record__snapshot_finish(struct auxtrace_record *itr, bool on_exit); int auxtrace_record__find_snapshot(struct auxtrace_record *itr, int idx, struct auxtrace_mmap *mm, unsigned char *data, u64 *head, u64 *old); @@ -512,7 +520,7 @@ int auxtrace_index__process(int fd, u64 size, struct perf_session *session, bool needs_swap); void auxtrace_index__free(struct list_head *head); -void auxtrace_synth_error(struct auxtrace_error_event *auxtrace_error, int type, +void auxtrace_synth_error(struct perf_record_auxtrace_error *auxtrace_error, int type, int code, int cpu, pid_t pid, pid_t tid, u64 ip, const char *msg, u64 timestamp); @@ -540,43 +548,13 @@ void addr_filters__init(struct addr_filters *filts); void addr_filters__exit(struct addr_filters *filts); int addr_filters__parse_bare_filter(struct addr_filters *filts, const char *filter); -int auxtrace_parse_filters(struct perf_evlist *evlist); - -static inline int auxtrace__process_event(struct perf_session *session, - union perf_event *event, - struct perf_sample *sample, - struct perf_tool *tool) -{ - if (!session->auxtrace) - return 0; - - return session->auxtrace->process_event(session, event, sample, tool); -} - -static inline int auxtrace__flush_events(struct perf_session *session, - struct perf_tool *tool) -{ - if (!session->auxtrace) - return 0; - - return session->auxtrace->flush_events(session, tool); -} +int auxtrace_parse_filters(struct evlist *evlist); -static inline void auxtrace__free_events(struct perf_session *session) -{ - if (!session->auxtrace) - return; - - return session->auxtrace->free_events(session); -} - -static inline void auxtrace__free(struct perf_session *session) -{ - if (!session->auxtrace) - return; - - return session->auxtrace->free(session); -} +int auxtrace__process_event(struct perf_session *session, union perf_event *event, + struct perf_sample *sample, struct perf_tool *tool); +int auxtrace__flush_events(struct perf_session *session, struct perf_tool *tool); +void auxtrace__free_events(struct perf_session *session); +void auxtrace__free(struct perf_session *session); #define ITRACE_HELP \ " i: synthesize instructions events\n" \ @@ -611,9 +589,10 @@ void itrace_synth_opts__clear_time_range(struct itrace_synth_opts *opts) } #else +#include "debug.h" static inline struct auxtrace_record * -auxtrace_record__init(struct perf_evlist *evlist __maybe_unused, +auxtrace_record__init(struct evlist *evlist __maybe_unused, int *err) { *err = 0; @@ -636,7 +615,7 @@ perf_event__synthesize_auxtrace_info(struct auxtrace_record *itr __maybe_unused, static inline int auxtrace_record__options(struct auxtrace_record *itr __maybe_unused, - struct perf_evlist *evlist __maybe_unused, + struct evlist *evlist __maybe_unused, struct record_opts *opts __maybe_unused) { return 0; @@ -733,7 +712,7 @@ void auxtrace_index__free(struct list_head *head __maybe_unused) } static inline -int auxtrace_parse_filters(struct perf_evlist *evlist __maybe_unused) +int auxtrace_parse_filters(struct evlist *evlist __maybe_unused) { return 0; } @@ -747,7 +726,7 @@ void auxtrace_mmap_params__init(struct auxtrace_mmap_params *mp, unsigned int auxtrace_pages, bool auxtrace_overwrite); void auxtrace_mmap_params__set_idx(struct auxtrace_mmap_params *mp, - struct perf_evlist *evlist, int idx, + struct evlist *evlist, int idx, bool per_cpu); #define ITRACE_HELP "" diff --git a/tools/perf/util/bpf-event.c b/tools/perf/util/bpf-event.c index 2a4a0da35632..7a3d4b125323 100644 --- a/tools/perf/util/bpf-event.c +++ b/tools/perf/util/bpf-event.c @@ -8,12 +8,14 @@ #include <linux/err.h> #include "bpf-event.h" #include "debug.h" +#include "dso.h" #include "symbol.h" #include "machine.h" #include "env.h" #include "session.h" #include "map.h" #include "evlist.h" +#include "record.h" #define ptr_to_u64(ptr) ((__u64)(unsigned long)(ptr)) @@ -34,7 +36,7 @@ static int machine__process_bpf_event_load(struct machine *machine, struct bpf_prog_info_linear *info_linear; struct bpf_prog_info_node *info_node; struct perf_env *env = machine->env; - int id = event->bpf_event.id; + int id = event->bpf.id; unsigned int i; /* perf-record, no need to handle bpf-event */ @@ -63,14 +65,13 @@ static int machine__process_bpf_event_load(struct machine *machine, return 0; } -int machine__process_bpf_event(struct machine *machine __maybe_unused, - union perf_event *event, - struct perf_sample *sample __maybe_unused) +int machine__process_bpf(struct machine *machine, union perf_event *event, + struct perf_sample *sample) { if (dump_trace) - perf_event__fprintf_bpf_event(event, stdout); + perf_event__fprintf_bpf(event, stdout); - switch (event->bpf_event.type) { + switch (event->bpf.type) { case PERF_BPF_EVENT_PROG_LOAD: return machine__process_bpf_event_load(machine, event, sample); @@ -82,8 +83,7 @@ int machine__process_bpf_event(struct machine *machine __maybe_unused, */ break; default: - pr_debug("unexpected bpf_event type of %d\n", - event->bpf_event.type); + pr_debug("unexpected bpf event type of %d\n", event->bpf.type); break; } return 0; @@ -160,8 +160,8 @@ static int perf_event__synthesize_one_bpf_prog(struct perf_session *session, union perf_event *event, struct record_opts *opts) { - struct ksymbol_event *ksymbol_event = &event->ksymbol_event; - struct bpf_event *bpf_event = &event->bpf_event; + struct perf_record_ksymbol *ksymbol_event = &event->ksymbol; + struct perf_record_bpf_event *bpf_event = &event->bpf; struct bpf_prog_info_linear *info_linear; struct perf_tool *tool = session->tool; struct bpf_prog_info_node *info_node; @@ -229,10 +229,10 @@ static int perf_event__synthesize_one_bpf_prog(struct perf_session *session, __u64 *prog_addrs = (__u64 *)(uintptr_t)(info->jited_ksyms); int name_len; - *ksymbol_event = (struct ksymbol_event){ + *ksymbol_event = (struct perf_record_ksymbol) { .header = { .type = PERF_RECORD_KSYMBOL, - .size = offsetof(struct ksymbol_event, name), + .size = offsetof(struct perf_record_ksymbol, name), }, .addr = prog_addrs[i], .len = prog_lens[i], @@ -253,10 +253,10 @@ static int perf_event__synthesize_one_bpf_prog(struct perf_session *session, if (!opts->no_bpf_event) { /* Synthesize PERF_RECORD_BPF_EVENT */ - *bpf_event = (struct bpf_event){ + *bpf_event = (struct perf_record_bpf_event) { .header = { .type = PERF_RECORD_BPF_EVENT, - .size = sizeof(struct bpf_event), + .size = sizeof(struct perf_record_bpf_event), }, .type = PERF_BPF_EVENT_PROG_LOAD, .flags = 0, @@ -301,7 +301,7 @@ int perf_event__synthesize_bpf_events(struct perf_session *session, int err; int fd; - event = malloc(sizeof(event->bpf_event) + KSYM_NAME_LEN + machine->id_hdr_size); + event = malloc(sizeof(event->bpf) + KSYM_NAME_LEN + machine->id_hdr_size); if (!event) return -1; while (true) { @@ -398,9 +398,9 @@ static int bpf_event__sb_cb(union perf_event *event, void *data) if (event->header.type != PERF_RECORD_BPF_EVENT) return -1; - switch (event->bpf_event.type) { + switch (event->bpf.type) { case PERF_BPF_EVENT_PROG_LOAD: - perf_env__add_bpf_info(env, event->bpf_event.id); + perf_env__add_bpf_info(env, event->bpf.id); case PERF_BPF_EVENT_PROG_UNLOAD: /* @@ -410,15 +410,14 @@ static int bpf_event__sb_cb(union perf_event *event, void *data) */ break; default: - pr_debug("unexpected bpf_event type of %d\n", - event->bpf_event.type); + pr_debug("unexpected bpf event type of %d\n", event->bpf.type); break; } return 0; } -int bpf_event__add_sb_event(struct perf_evlist **evlist, +int bpf_event__add_sb_event(struct evlist **evlist, struct perf_env *env) { struct perf_event_attr attr = { diff --git a/tools/perf/util/bpf-event.h b/tools/perf/util/bpf-event.h index 04c33b3bfe28..a01c2fd68c03 100644 --- a/tools/perf/util/bpf-event.h +++ b/tools/perf/util/bpf-event.h @@ -13,6 +13,7 @@ struct machine; union perf_event; struct perf_env; struct perf_sample; +struct perf_session; struct record_opts; struct evlist; struct target; @@ -30,22 +31,22 @@ struct btf_node { }; #ifdef HAVE_LIBBPF_SUPPORT -int machine__process_bpf_event(struct machine *machine, union perf_event *event, - struct perf_sample *sample); +int machine__process_bpf(struct machine *machine, union perf_event *event, + struct perf_sample *sample); int perf_event__synthesize_bpf_events(struct perf_session *session, perf_event__handler_t process, struct machine *machine, struct record_opts *opts); -int bpf_event__add_sb_event(struct perf_evlist **evlist, +int bpf_event__add_sb_event(struct evlist **evlist, struct perf_env *env); void bpf_event__print_bpf_prog_info(struct bpf_prog_info *info, struct perf_env *env, FILE *fp); #else -static inline int machine__process_bpf_event(struct machine *machine __maybe_unused, - union perf_event *event __maybe_unused, - struct perf_sample *sample __maybe_unused) +static inline int machine__process_bpf(struct machine *machine __maybe_unused, + union perf_event *event __maybe_unused, + struct perf_sample *sample __maybe_unused) { return 0; } @@ -58,7 +59,7 @@ static inline int perf_event__synthesize_bpf_events(struct perf_session *session return 0; } -static inline int bpf_event__add_sb_event(struct perf_evlist **evlist __maybe_unused, +static inline int bpf_event__add_sb_event(struct evlist **evlist __maybe_unused, struct perf_env *env __maybe_unused) { return 0; diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c index c61974a50aa5..37283e865352 100644 --- a/tools/perf/util/bpf-loader.c +++ b/tools/perf/util/bpf-loader.c @@ -14,7 +14,7 @@ #include <linux/string.h> #include <linux/zalloc.h> #include <errno.h> -#include "perf.h" +#include <stdlib.h> #include "debug.h" #include "evlist.h" #include "bpf-loader.h" @@ -23,9 +23,12 @@ #include "probe-finder.h" // for MAX_PROBES #include "parse-events.h" #include "strfilter.h" +#include "util.h" #include "llvm-utils.h" #include "c++/clang-c.h" +#include <internal/xyarray.h> + static int libbpf_perf_print(enum libbpf_print_level level __attribute__((unused)), const char *fmt, va_list args) { @@ -763,7 +766,7 @@ int bpf__foreach_event(struct bpf_object *obj, if (priv->is_tp) { fd = bpf_program__fd(prog); - err = (*func)(priv->sys_name, priv->evt_name, fd, arg); + err = (*func)(priv->sys_name, priv->evt_name, fd, obj, arg); if (err) { pr_debug("bpf: tracepoint call back failed, stop iterate\n"); return err; @@ -788,7 +791,7 @@ int bpf__foreach_event(struct bpf_object *obj, return fd; } - err = (*func)(tev->group, tev->event, fd, arg); + err = (*func)(tev->group, tev->event, fd, obj, arg); if (err) { pr_debug("bpf: call back failed, stop iterate\n"); return err; @@ -817,7 +820,7 @@ struct bpf_map_op { } k; union { u64 value; - struct perf_evsel *evsel; + struct evsel *evsel; } v; }; @@ -1043,7 +1046,7 @@ __bpf_map__config_value(struct bpf_map *map, static int bpf_map__config_value(struct bpf_map *map, struct parse_events_term *term, - struct perf_evlist *evlist __maybe_unused) + struct evlist *evlist __maybe_unused) { if (!term->err_val) { pr_debug("Config value not set\n"); @@ -1061,9 +1064,9 @@ bpf_map__config_value(struct bpf_map *map, static int __bpf_map__config_event(struct bpf_map *map, struct parse_events_term *term, - struct perf_evlist *evlist) + struct evlist *evlist) { - struct perf_evsel *evsel; + struct evsel *evsel; const struct bpf_map_def *def; struct bpf_map_op *op; const char *map_name = bpf_map__name(map); @@ -1103,7 +1106,7 @@ __bpf_map__config_event(struct bpf_map *map, static int bpf_map__config_event(struct bpf_map *map, struct parse_events_term *term, - struct perf_evlist *evlist) + struct evlist *evlist) { if (!term->err_val) { pr_debug("Config value not set\n"); @@ -1121,7 +1124,7 @@ bpf_map__config_event(struct bpf_map *map, struct bpf_obj_config__map_func { const char *config_opt; int (*config_func)(struct bpf_map *, struct parse_events_term *, - struct perf_evlist *); + struct evlist *); }; struct bpf_obj_config__map_func bpf_obj_config__map_funcs[] = { @@ -1169,7 +1172,7 @@ config_map_indices_range_check(struct parse_events_term *term, static int bpf__obj_config_map(struct bpf_object *obj, struct parse_events_term *term, - struct perf_evlist *evlist, + struct evlist *evlist, int *key_scan_pos) { /* key is "map:<mapname>.<config opt>" */ @@ -1228,7 +1231,7 @@ out: int bpf__config_obj(struct bpf_object *obj, struct parse_events_term *term, - struct perf_evlist *evlist, + struct evlist *evlist, int *error_pos) { int key_scan_pos = 0; @@ -1401,9 +1404,9 @@ apply_config_value_for_key(int map_fd, void *pkey, static int apply_config_evsel_for_key(const char *name, int map_fd, void *pkey, - struct perf_evsel *evsel) + struct evsel *evsel) { - struct xyarray *xy = evsel->fd; + struct xyarray *xy = evsel->core.fd; struct perf_event_attr *attr; unsigned int key, events; bool check_pass = false; @@ -1421,7 +1424,7 @@ apply_config_evsel_for_key(const char *name, int map_fd, void *pkey, return -BPF_LOADER_ERRNO__OBJCONF_MAP_EVTDIM; } - attr = &evsel->attr; + attr = &evsel->core.attr; if (attr->inherit) { pr_debug("ERROR: Can't put inherit event into map %s\n", name); return -BPF_LOADER_ERRNO__OBJCONF_MAP_EVTINH; @@ -1523,11 +1526,11 @@ int bpf__apply_obj_config(void) (strcmp(name, \ bpf_map__name(pos)) == 0)) -struct perf_evsel *bpf__setup_output_event(struct perf_evlist *evlist, const char *name) +struct evsel *bpf__setup_output_event(struct evlist *evlist, const char *name) { struct bpf_map_priv *tmpl_priv = NULL; struct bpf_object *obj, *tmp; - struct perf_evsel *evsel = NULL; + struct evsel *evsel = NULL; struct bpf_map *map; int err; bool need_init = false; @@ -1600,9 +1603,9 @@ struct perf_evsel *bpf__setup_output_event(struct perf_evlist *evlist, const cha return evsel; } -int bpf__setup_stdout(struct perf_evlist *evlist) +int bpf__setup_stdout(struct evlist *evlist) { - struct perf_evsel *evsel = bpf__setup_output_event(evlist, "__bpf_stdout__"); + struct evsel *evsel = bpf__setup_output_event(evlist, "__bpf_stdout__"); return PTR_ERR_OR_ZERO(evsel); } @@ -1756,7 +1759,7 @@ int bpf__strerror_load(struct bpf_object *obj, int bpf__strerror_config_obj(struct bpf_object *obj __maybe_unused, struct parse_events_term *term __maybe_unused, - struct perf_evlist *evlist __maybe_unused, + struct evlist *evlist __maybe_unused, int *error_pos __maybe_unused, int err, char *buf, size_t size) { @@ -1780,7 +1783,7 @@ int bpf__strerror_apply_obj_config(int err, char *buf, size_t size) return 0; } -int bpf__strerror_setup_output_event(struct perf_evlist *evlist __maybe_unused, +int bpf__strerror_setup_output_event(struct evlist *evlist __maybe_unused, int err, char *buf, size_t size) { bpf__strerror_head(err, buf, size); diff --git a/tools/perf/util/bpf-loader.h b/tools/perf/util/bpf-loader.h index 3f46856e3330..25251d63164c 100644 --- a/tools/perf/util/bpf-loader.h +++ b/tools/perf/util/bpf-loader.h @@ -39,14 +39,14 @@ enum bpf_loader_errno { __BPF_LOADER_ERRNO__END, }; -struct perf_evsel; -struct perf_evlist; +struct evsel; +struct evlist; struct bpf_object; struct parse_events_term; #define PERF_BPF_PROBE_GROUP "perf_bpf_probe" typedef int (*bpf_prog_iter_callback_t)(const char *group, const char *event, - int fd, void *arg); + int fd, struct bpf_object *obj, void *arg); #ifdef HAVE_LIBBPF_SUPPORT struct bpf_object *bpf__prepare_load(const char *filename, bool source); @@ -70,18 +70,18 @@ int bpf__foreach_event(struct bpf_object *obj, bpf_prog_iter_callback_t func, void *arg); int bpf__config_obj(struct bpf_object *obj, struct parse_events_term *term, - struct perf_evlist *evlist, int *error_pos); + struct evlist *evlist, int *error_pos); int bpf__strerror_config_obj(struct bpf_object *obj, struct parse_events_term *term, - struct perf_evlist *evlist, + struct evlist *evlist, int *error_pos, int err, char *buf, size_t size); int bpf__apply_obj_config(void); int bpf__strerror_apply_obj_config(int err, char *buf, size_t size); -int bpf__setup_stdout(struct perf_evlist *evlist); -struct perf_evsel *bpf__setup_output_event(struct perf_evlist *evlist, const char *name); -int bpf__strerror_setup_output_event(struct perf_evlist *evlist, int err, char *buf, size_t size); +int bpf__setup_stdout(struct evlist *evlist); +struct evsel *bpf__setup_output_event(struct evlist *evlist, const char *name); +int bpf__strerror_setup_output_event(struct evlist *evlist, int err, char *buf, size_t size); #else #include <errno.h> #include <string.h> @@ -119,7 +119,7 @@ bpf__foreach_event(struct bpf_object *obj __maybe_unused, static inline int bpf__config_obj(struct bpf_object *obj __maybe_unused, struct parse_events_term *term __maybe_unused, - struct perf_evlist *evlist __maybe_unused, + struct evlist *evlist __maybe_unused, int *error_pos __maybe_unused) { return 0; @@ -132,13 +132,13 @@ bpf__apply_obj_config(void) } static inline int -bpf__setup_stdout(struct perf_evlist *evlist __maybe_unused) +bpf__setup_stdout(struct evlist *evlist __maybe_unused) { return 0; } -static inline struct perf_evsel * -bpf__setup_output_event(struct perf_evlist *evlist __maybe_unused, const char *name __maybe_unused) +static inline struct evsel * +bpf__setup_output_event(struct evlist *evlist __maybe_unused, const char *name __maybe_unused) { return NULL; } @@ -182,7 +182,7 @@ static inline int bpf__strerror_load(struct bpf_object *obj __maybe_unused, static inline int bpf__strerror_config_obj(struct bpf_object *obj __maybe_unused, struct parse_events_term *term __maybe_unused, - struct perf_evlist *evlist __maybe_unused, + struct evlist *evlist __maybe_unused, int *error_pos __maybe_unused, int err __maybe_unused, char *buf, size_t size) @@ -198,7 +198,7 @@ bpf__strerror_apply_obj_config(int err __maybe_unused, } static inline int -bpf__strerror_setup_output_event(struct perf_evlist *evlist __maybe_unused, +bpf__strerror_setup_output_event(struct evlist *evlist __maybe_unused, int err __maybe_unused, char *buf, size_t size) { return __bpf_strerror(buf, size); @@ -206,7 +206,7 @@ bpf__strerror_setup_output_event(struct perf_evlist *evlist __maybe_unused, #endif -static inline int bpf__strerror_setup_stdout(struct perf_evlist *evlist, int err, char *buf, size_t size) +static inline int bpf__strerror_setup_stdout(struct evlist *evlist, int err, char *buf, size_t size) { return bpf__strerror_setup_output_event(evlist, err, buf, size); } diff --git a/tools/perf/util/bpf-prologue.c b/tools/perf/util/bpf-prologue.c index 77e4891e17b0..b020a8678eb9 100644 --- a/tools/perf/util/bpf-prologue.c +++ b/tools/perf/util/bpf-prologue.c @@ -8,12 +8,12 @@ */ #include <bpf/libbpf.h> -#include "perf.h" #include "debug.h" #include "bpf-loader.h" #include "bpf-prologue.h" #include "probe-finder.h" #include <errno.h> +#include <stdlib.h> #include <dwarf-regs.h> #include <linux/filter.h> diff --git a/tools/perf/util/branch.c b/tools/perf/util/branch.c index a4fce2729e50..9d1e090084a2 100644 --- a/tools/perf/util/branch.c +++ b/tools/perf/util/branch.c @@ -1,7 +1,8 @@ -#include "perf.h" #include "util/util.h" #include "util/debug.h" +#include "util/map_symbol.h" #include "util/branch.h" +#include <linux/kernel.h> static bool cross_area(u64 addr1, u64 addr2, int size) { diff --git a/tools/perf/util/branch.h b/tools/perf/util/branch.h index 64f96b79f1d7..06f66dad0b79 100644 --- a/tools/perf/util/branch.h +++ b/tools/perf/util/branch.h @@ -16,6 +16,14 @@ struct branch_flags { u64 reserved:40; }; +struct branch_info { + struct addr_map_symbol from; + struct addr_map_symbol to; + struct branch_flags flags; + char *srcline_from; + char *srcline_to; +}; + struct branch_entry { u64 from; u64 to; diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c index f1abfab7aa8c..e5fb77755d9e 100644 --- a/tools/perf/util/build-id.c +++ b/tools/perf/util/build-id.c @@ -13,6 +13,7 @@ #include <stdio.h> #include <sys/stat.h> #include <sys/types.h> +#include "dso.h" #include "build-id.h" #include "event.h" #include "namespaces.h" @@ -37,7 +38,7 @@ static bool no_buildid_cache; int build_id__mark_dso_hit(struct perf_tool *tool __maybe_unused, union perf_event *event, struct perf_sample *sample, - struct perf_evsel *evsel __maybe_unused, + struct evsel *evsel __maybe_unused, struct machine *machine) { struct addr_location al; @@ -295,7 +296,7 @@ static int write_buildid(const char *name, size_t name_len, u8 *build_id, pid_t pid, u16 misc, struct feat_fd *fd) { int err; - struct build_id_event b; + struct perf_record_header_build_id b; size_t len; len = name_len + 1; diff --git a/tools/perf/util/build-id.h b/tools/perf/util/build-id.h index 93668f38f1ed..aad419bb165c 100644 --- a/tools/perf/util/build-id.h +++ b/tools/perf/util/build-id.h @@ -24,7 +24,7 @@ char *dso__build_id_filename(const struct dso *dso, char *bf, size_t size, bool is_debug); int build_id__mark_dso_hit(struct perf_tool *tool, union perf_event *event, - struct perf_sample *sample, struct perf_evsel *evsel, + struct perf_sample *sample, struct evsel *evsel, struct machine *machine); int dsos__hit_all(struct perf_session *session); diff --git a/tools/perf/util/c++/clang-c.h b/tools/perf/util/c++/clang-c.h index e513366f2ee0..2df8a45bd088 100644 --- a/tools/perf/util/c++/clang-c.h +++ b/tools/perf/util/c++/clang-c.h @@ -3,7 +3,6 @@ #define PERF_UTIL_CLANG_C_H #include <stddef.h> /* for size_t */ -#include <util-cxx.h> /* for __maybe_unused */ #ifdef __cplusplus extern "C" { @@ -22,6 +21,7 @@ extern int perf_clang__compile_bpf(const char *filename, #else #include <errno.h> +#include <linux/compiler.h> /* for __maybe_unused */ static inline void perf_clang__init(void) { } static inline void perf_clang__cleanup(void) { } diff --git a/tools/perf/util/c++/clang-test.cpp b/tools/perf/util/c++/clang-test.cpp index 7b042a5ebc68..21b23605f78b 100644 --- a/tools/perf/util/c++/clang-test.cpp +++ b/tools/perf/util/c++/clang-test.cpp @@ -1,10 +1,12 @@ // SPDX-License-Identifier: GPL-2.0 #include "clang.h" #include "clang-c.h" +extern "C" { +#include "../util.h" +} #include "llvm/IR/Function.h" #include "llvm/IR/LLVMContext.h" -#include <util-cxx.h> #include <tests/llvm.h> #include <string> diff --git a/tools/perf/util/cacheline.c b/tools/perf/util/cacheline.c new file mode 100644 index 000000000000..e98b5250a517 --- /dev/null +++ b/tools/perf/util/cacheline.c @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: GPL-2.0 +#include "cacheline.h" +#include <unistd.h> + +#ifdef _SC_LEVEL1_DCACHE_LINESIZE +#define cache_line_size(cacheline_sizep) *cacheline_sizep = sysconf(_SC_LEVEL1_DCACHE_LINESIZE) +#else +#include <api/fs/fs.h> +#include "debug.h" +static void cache_line_size(int *cacheline_sizep) +{ + if (sysfs__read_int("devices/system/cpu/cpu0/cache/index0/coherency_line_size", cacheline_sizep)) + pr_debug("cannot determine cache line size"); +} +#endif + +int cacheline_size(void) +{ + static int size; + + if (!size) + cache_line_size(&size); + + return size; +} diff --git a/tools/perf/util/cacheline.h b/tools/perf/util/cacheline.h new file mode 100644 index 000000000000..dec8c0fb1f4a --- /dev/null +++ b/tools/perf/util/cacheline.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef PERF_CACHELINE_H +#define PERF_CACHELINE_H + +#include <linux/compiler.h> + +int __pure cacheline_size(void); + +static inline u64 cl_address(u64 address) +{ + /* return the cacheline of the address */ + return (address & ~(cacheline_size() - 1)); +} + +static inline u64 cl_offset(u64 address) +{ + /* return the cacheline of the address */ + return (address & (cacheline_size() - 1)); +} + +#endif // PERF_CACHELINE_H diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c index 8d7d8f62fcca..c14646c1f2eb 100644 --- a/tools/perf/util/callchain.c +++ b/tools/perf/util/callchain.c @@ -16,10 +16,13 @@ #include <stdbool.h> #include <errno.h> #include <math.h> +#include <linux/string.h> #include <linux/zalloc.h> #include "asm/bug.h" +#include "debug.h" +#include "dso.h" #include "hist.h" #include "sort.h" #include "machine.h" @@ -27,6 +30,7 @@ #include "callchain.h" #include "branch.h" #include "symbol.h" +#include "../perf.h" #define CALLCHAIN_PARAM_DEFAULT \ .mode = CHAIN_GRAPH_ABS, \ @@ -1077,7 +1081,7 @@ int callchain_cursor_append(struct callchain_cursor *cursor, int sample__resolve_callchain(struct perf_sample *sample, struct callchain_cursor *cursor, struct symbol **parent, - struct perf_evsel *evsel, struct addr_location *al, + struct evsel *evsel, struct addr_location *al, int max_stack) { if (sample->callchain == NULL && !symbol_conf.show_branchflag_count) diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h index 80e056a3d882..b042ceef4114 100644 --- a/tools/perf/util/callchain.h +++ b/tools/perf/util/callchain.h @@ -8,6 +8,7 @@ #include "map_symbol.h" #include "branch.h" +struct evsel; struct map; #define HELP_PAD "\t\t\t\t" @@ -236,7 +237,7 @@ int record_opts__parse_callchain(struct record_opts *record, int sample__resolve_callchain(struct perf_sample *sample, struct callchain_cursor *cursor, struct symbol **parent, - struct perf_evsel *evsel, struct addr_location *al, + struct evsel *evsel, struct addr_location *al, int max_stack); int hist_entry__append_callchain(struct hist_entry *he, struct perf_sample *sample); int fill_callchain_info(struct addr_location *al, struct callchain_cursor_node *node, diff --git a/tools/perf/util/cap.c b/tools/perf/util/cap.c new file mode 100644 index 000000000000..c3ba841bbf37 --- /dev/null +++ b/tools/perf/util/cap.c @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Capability utilities + */ + +#ifdef HAVE_LIBCAP_SUPPORT + +#include "cap.h" +#include <stdbool.h> +#include <sys/capability.h> + +bool perf_cap__capable(cap_value_t cap) +{ + cap_flag_value_t val; + cap_t caps = cap_get_proc(); + + if (!caps) + return false; + + if (cap_get_flag(caps, cap, CAP_EFFECTIVE, &val) != 0) + val = CAP_CLEAR; + + if (cap_free(caps) != 0) + return false; + + return val == CAP_SET; +} + +#endif /* HAVE_LIBCAP_SUPPORT */ diff --git a/tools/perf/util/cap.h b/tools/perf/util/cap.h new file mode 100644 index 000000000000..051dc590ceee --- /dev/null +++ b/tools/perf/util/cap.h @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __PERF_CAP_H +#define __PERF_CAP_H + +#include <stdbool.h> +#include <linux/capability.h> +#include <linux/compiler.h> + +#ifdef HAVE_LIBCAP_SUPPORT + +#include <sys/capability.h> + +bool perf_cap__capable(cap_value_t cap); + +#else + +#include <unistd.h> +#include <sys/types.h> + +static inline bool perf_cap__capable(int cap __maybe_unused) +{ + return geteuid() == 0; +} + +#endif /* HAVE_LIBCAP_SUPPORT */ + +/* For older systems */ +#ifndef CAP_SYSLOG +#define CAP_SYSLOG 34 +#endif + +#endif /* __PERF_CAP_H */ diff --git a/tools/perf/util/cgroup.c b/tools/perf/util/cgroup.c index 484c29830a81..4881d4af3381 100644 --- a/tools/perf/util/cgroup.c +++ b/tools/perf/util/cgroup.c @@ -1,5 +1,4 @@ // SPDX-License-Identifier: GPL-2.0 -#include "../perf.h" #include <subcmd/parse-options.h> #include "evsel.h" #include "cgroup.h" @@ -9,6 +8,8 @@ #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> +#include <stdlib.h> +#include <string.h> int nr_cgroups; @@ -90,9 +91,9 @@ static int open_cgroup(const char *name) return fd; } -static struct cgroup *evlist__find_cgroup(struct perf_evlist *evlist, const char *str) +static struct cgroup *evlist__find_cgroup(struct evlist *evlist, const char *str) { - struct perf_evsel *counter; + struct evsel *counter; /* * check if cgrp is already defined, if so we reuse it */ @@ -130,16 +131,16 @@ out_err: return NULL; } -struct cgroup *evlist__findnew_cgroup(struct perf_evlist *evlist, const char *name) +struct cgroup *evlist__findnew_cgroup(struct evlist *evlist, const char *name) { struct cgroup *cgroup = evlist__find_cgroup(evlist, name); return cgroup ?: cgroup__new(name); } -static int add_cgroup(struct perf_evlist *evlist, const char *str) +static int add_cgroup(struct evlist *evlist, const char *str) { - struct perf_evsel *counter; + struct evsel *counter; struct cgroup *cgrp = evlist__findnew_cgroup(evlist, str); int n; @@ -184,15 +185,15 @@ struct cgroup *cgroup__get(struct cgroup *cgroup) return cgroup; } -static void evsel__set_default_cgroup(struct perf_evsel *evsel, struct cgroup *cgroup) +static void evsel__set_default_cgroup(struct evsel *evsel, struct cgroup *cgroup) { if (evsel->cgrp == NULL) evsel->cgrp = cgroup__get(cgroup); } -void evlist__set_default_cgroup(struct perf_evlist *evlist, struct cgroup *cgroup) +void evlist__set_default_cgroup(struct evlist *evlist, struct cgroup *cgroup) { - struct perf_evsel *evsel; + struct evsel *evsel; evlist__for_each_entry(evlist, evsel) evsel__set_default_cgroup(evsel, cgroup); @@ -201,14 +202,14 @@ void evlist__set_default_cgroup(struct perf_evlist *evlist, struct cgroup *cgrou int parse_cgroups(const struct option *opt, const char *str, int unset __maybe_unused) { - struct perf_evlist *evlist = *(struct perf_evlist **)opt->value; - struct perf_evsel *counter; + struct evlist *evlist = *(struct evlist **)opt->value; + struct evsel *counter; struct cgroup *cgrp = NULL; const char *p, *e, *eos = str + strlen(str); char *s; int ret, i; - if (list_empty(&evlist->entries)) { + if (list_empty(&evlist->core.entries)) { fprintf(stderr, "must define events before cgroups\n"); return -1; } diff --git a/tools/perf/util/cgroup.h b/tools/perf/util/cgroup.h index f033a80c1b14..2ec11f01090d 100644 --- a/tools/perf/util/cgroup.h +++ b/tools/perf/util/cgroup.h @@ -18,11 +18,11 @@ extern int nr_cgroups; /* number of explicit cgroups defined */ struct cgroup *cgroup__get(struct cgroup *cgroup); void cgroup__put(struct cgroup *cgroup); -struct perf_evlist; +struct evlist; -struct cgroup *evlist__findnew_cgroup(struct perf_evlist *evlist, const char *name); +struct cgroup *evlist__findnew_cgroup(struct evlist *evlist, const char *name); -void evlist__set_default_cgroup(struct perf_evlist *evlist, struct cgroup *cgroup); +void evlist__set_default_cgroup(struct evlist *evlist, struct cgroup *cgroup); int parse_cgroups(const struct option *opt, const char *str, int unset); diff --git a/tools/perf/util/cloexec.c b/tools/perf/util/cloexec.c index 06f48312c5ed..4e904fcb2783 100644 --- a/tools/perf/util/cloexec.c +++ b/tools/perf/util/cloexec.c @@ -2,12 +2,14 @@ #include <errno.h> #include <sched.h> #include "util.h" -#include "../perf.h" +#include "../perf-sys.h" #include "cloexec.h" +#include "event.h" #include "asm/bug.h" #include "debug.h" #include <unistd.h> #include <sys/syscall.h> +#include <linux/string.h> static unsigned long flag = PERF_FLAG_FD_CLOEXEC; diff --git a/tools/perf/util/color.c b/tools/perf/util/color.c index 39b8c4ec4e2e..bffbdd216a6a 100644 --- a/tools/perf/util/color.c +++ b/tools/perf/util/color.c @@ -1,8 +1,9 @@ // SPDX-License-Identifier: GPL-2.0 #include <linux/kernel.h> -#include "cache.h" +#include <subcmd/pager.h> #include <stdlib.h> #include <stdio.h> +#include <string.h> #include "color.h" #include <math.h> #include <unistd.h> diff --git a/tools/perf/util/color_config.c b/tools/perf/util/color_config.c index 817dc56e7e95..dc09ba7cb31e 100644 --- a/tools/perf/util/color_config.c +++ b/tools/perf/util/color_config.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 #include <linux/kernel.h> -#include "cache.h" +#include <subcmd/pager.h> +#include <string.h> #include "config.h" #include <stdlib.h> #include <stdio.h> diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c index 042ffbc8c53f..0bc9c4d7fdc5 100644 --- a/tools/perf/util/config.c +++ b/tools/perf/util/config.c @@ -17,9 +17,13 @@ #include "util/event.h" /* proc_map_timeout */ #include "util/hist.h" /* perf_hist_config */ #include "util/llvm-utils.h" /* perf_llvm_config */ +#include "build-id.h" +#include "debug.h" #include "config.h" +#include "debug.h" #include <sys/types.h> #include <sys/stat.h> +#include <stdlib.h> #include <unistd.h> #include <linux/string.h> #include <linux/zalloc.h> diff --git a/tools/perf/util/counts.c b/tools/perf/util/counts.c index 88be9c4365e0..f94e1a23dad6 100644 --- a/tools/perf/util/counts.c +++ b/tools/perf/util/counts.c @@ -19,6 +19,15 @@ struct perf_counts *perf_counts__new(int ncpus, int nthreads) } counts->values = values; + + values = xyarray__new(ncpus, nthreads, sizeof(bool)); + if (!values) { + xyarray__delete(counts->values); + free(counts); + return NULL; + } + + counts->loaded = values; } return counts; @@ -27,6 +36,7 @@ struct perf_counts *perf_counts__new(int ncpus, int nthreads) void perf_counts__delete(struct perf_counts *counts) { if (counts) { + xyarray__delete(counts->loaded); xyarray__delete(counts->values); free(counts); } @@ -34,21 +44,22 @@ void perf_counts__delete(struct perf_counts *counts) static void perf_counts__reset(struct perf_counts *counts) { + xyarray__reset(counts->loaded); xyarray__reset(counts->values); } -void perf_evsel__reset_counts(struct perf_evsel *evsel) +void perf_evsel__reset_counts(struct evsel *evsel) { perf_counts__reset(evsel->counts); } -int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus, int nthreads) +int perf_evsel__alloc_counts(struct evsel *evsel, int ncpus, int nthreads) { evsel->counts = perf_counts__new(ncpus, nthreads); return evsel->counts != NULL ? 0 : -ENOMEM; } -void perf_evsel__free_counts(struct perf_evsel *evsel) +void perf_evsel__free_counts(struct evsel *evsel) { perf_counts__delete(evsel->counts); evsel->counts = NULL; diff --git a/tools/perf/util/counts.h b/tools/perf/util/counts.h index 0d1050ccc586..92196df4945f 100644 --- a/tools/perf/util/counts.h +++ b/tools/perf/util/counts.h @@ -2,24 +2,18 @@ #ifndef __PERF_COUNTS_H #define __PERF_COUNTS_H -#include "xyarray.h" - -struct perf_counts_values { - union { - struct { - u64 val; - u64 ena; - u64 run; - }; - u64 values[3]; - }; - bool loaded; -}; +#include <linux/types.h> +#include <internal/xyarray.h> +#include <perf/evsel.h> +#include <stdbool.h> + +struct evsel; struct perf_counts { s8 scaled; struct perf_counts_values aggr; struct xyarray *values; + struct xyarray *loaded; }; @@ -29,11 +23,23 @@ perf_counts(struct perf_counts *counts, int cpu, int thread) return xyarray__entry(counts->values, cpu, thread); } +static inline bool +perf_counts__is_loaded(struct perf_counts *counts, int cpu, int thread) +{ + return *((bool *) xyarray__entry(counts->loaded, cpu, thread)); +} + +static inline void +perf_counts__set_loaded(struct perf_counts *counts, int cpu, int thread, bool loaded) +{ + *((bool *) xyarray__entry(counts->loaded, cpu, thread)) = loaded; +} + struct perf_counts *perf_counts__new(int ncpus, int nthreads); void perf_counts__delete(struct perf_counts *counts); -void perf_evsel__reset_counts(struct perf_evsel *evsel); -int perf_evsel__alloc_counts(struct perf_evsel *evsel, int ncpus, int nthreads); -void perf_evsel__free_counts(struct perf_evsel *evsel); +void perf_evsel__reset_counts(struct evsel *evsel); +int perf_evsel__alloc_counts(struct evsel *evsel, int ncpus, int nthreads); +void perf_evsel__free_counts(struct evsel *evsel); #endif /* __PERF_COUNTS_H */ diff --git a/tools/perf/util/cpumap.c b/tools/perf/util/cpumap.c index 39cce66b4ebc..a22c1114e880 100644 --- a/tools/perf/util/cpumap.c +++ b/tools/perf/util/cpumap.c @@ -1,7 +1,8 @@ // SPDX-License-Identifier: GPL-2.0 #include <api/fs/fs.h> -#include "../perf.h" #include "cpumap.h" +#include "debug.h" +#include "event.h" #include <assert.h> #include <dirent.h> #include <stdio.h> @@ -17,190 +18,11 @@ static int max_present_cpu_num; static int max_node_num; static int *cpunode_map; -static struct cpu_map *cpu_map__default_new(void) +static struct perf_cpu_map *cpu_map__from_entries(struct cpu_map_entries *cpus) { - struct cpu_map *cpus; - int nr_cpus; + struct perf_cpu_map *map; - 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 cpu_map *cpu_map__trim_new(int nr_cpus, int *tmp_cpus) -{ - size_t payload_size = nr_cpus * sizeof(int); - struct 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 cpu_map *cpu_map__read(FILE *file) -{ - struct 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; - - 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 cpu_map *cpu_map__read_all_cpu_map(void) -{ - struct cpu_map *cpus = NULL; - FILE *onlnf; - - onlnf = fopen("/sys/devices/system/cpu/online", "r"); - if (!onlnf) - return cpu_map__default_new(); - - cpus = cpu_map__read(onlnf); - fclose(onlnf); - return cpus; -} - -struct cpu_map *cpu_map__new(const char *cpu_list) -{ - struct 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; - } - - 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 = cpu_map__dummy_new(); -invalid: - free(tmp_cpus); -out: - return cpus; -} - -static struct cpu_map *cpu_map__from_entries(struct cpu_map_entries *cpus) -{ - struct cpu_map *map; - - map = cpu_map__empty_new(cpus->nr); + map = perf_cpu_map__empty_new(cpus->nr); if (map) { unsigned i; @@ -220,14 +42,14 @@ static struct cpu_map *cpu_map__from_entries(struct cpu_map_entries *cpus) return map; } -static struct cpu_map *cpu_map__from_mask(struct cpu_map_mask *mask) +static struct perf_cpu_map *cpu_map__from_mask(struct perf_record_record_cpu_map *mask) { - struct cpu_map *map; + struct perf_cpu_map *map; int nr, nbits = mask->nr * mask->long_size * BITS_PER_BYTE; nr = bitmap_weight(mask->mask, nbits); - map = cpu_map__empty_new(nr); + map = perf_cpu_map__empty_new(nr); if (map) { int cpu, i = 0; @@ -238,15 +60,15 @@ static struct cpu_map *cpu_map__from_mask(struct cpu_map_mask *mask) } -struct cpu_map *cpu_map__new_data(struct cpu_map_data *data) +struct perf_cpu_map *cpu_map__new_data(struct perf_record_cpu_map_data *data) { if (data->type == PERF_CPU_MAP__CPUS) return cpu_map__from_entries((struct cpu_map_entries *)data->data); else - return cpu_map__from_mask((struct cpu_map_mask *)data->data); + return cpu_map__from_mask((struct perf_record_record_cpu_map *)data->data); } -size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp) +size_t cpu_map__fprintf(struct perf_cpu_map *map, FILE *fp) { #define BUFSIZE 1024 char buf[BUFSIZE]; @@ -256,22 +78,9 @@ size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp) #undef BUFSIZE } -struct cpu_map *cpu_map__dummy_new(void) +struct perf_cpu_map *perf_cpu_map__empty_new(int nr) { - struct 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; -} - -struct cpu_map *cpu_map__empty_new(int nr) -{ - struct cpu_map *cpus = malloc(sizeof(*cpus) + sizeof(int) * nr); + struct perf_cpu_map *cpus = malloc(sizeof(*cpus) + sizeof(int) * nr); if (cpus != NULL) { int i; @@ -286,28 +95,6 @@ struct cpu_map *cpu_map__empty_new(int nr) return cpus; } -static void cpu_map__delete(struct cpu_map *map) -{ - if (map) { - WARN_ONCE(refcount_read(&map->refcnt) != 0, - "cpu_map refcnt unbalanced\n"); - free(map); - } -} - -struct cpu_map *cpu_map__get(struct cpu_map *map) -{ - if (map) - refcount_inc(&map->refcnt); - return map; -} - -void cpu_map__put(struct cpu_map *map) -{ - if (map && refcount_dec_and_test(&map->refcnt)) - cpu_map__delete(map); -} - static int cpu__get_topology_int(int cpu, const char *name, int *value) { char path[PATH_MAX]; @@ -324,7 +111,7 @@ int cpu_map__get_socket_id(int cpu) return ret ?: value; } -int cpu_map__get_socket(struct cpu_map *map, int idx, void *data __maybe_unused) +int cpu_map__get_socket(struct perf_cpu_map *map, int idx, void *data __maybe_unused) { int cpu; @@ -341,11 +128,11 @@ static int cmp_ids(const void *a, const void *b) return *(int *)a - *(int *)b; } -int cpu_map__build_map(struct cpu_map *cpus, struct cpu_map **res, - int (*f)(struct cpu_map *map, int cpu, void *data), +int cpu_map__build_map(struct perf_cpu_map *cpus, struct perf_cpu_map **res, + int (*f)(struct perf_cpu_map *map, int cpu, void *data), void *data) { - struct cpu_map *c; + struct perf_cpu_map *c; int nr = cpus->nr; int cpu, s1, s2; @@ -380,7 +167,7 @@ int cpu_map__get_die_id(int cpu) return ret ?: value; } -int cpu_map__get_die(struct cpu_map *map, int idx, void *data) +int cpu_map__get_die(struct perf_cpu_map *map, int idx, void *data) { int cpu, die_id, s; @@ -419,7 +206,7 @@ int cpu_map__get_core_id(int cpu) return ret ?: value; } -int cpu_map__get_core(struct cpu_map *map, int idx, void *data) +int cpu_map__get_core(struct perf_cpu_map *map, int idx, void *data) { int cpu, s_die; @@ -448,17 +235,17 @@ int cpu_map__get_core(struct cpu_map *map, int idx, void *data) return (s_die << 16) | (cpu & 0xffff); } -int cpu_map__build_socket_map(struct cpu_map *cpus, struct cpu_map **sockp) +int cpu_map__build_socket_map(struct perf_cpu_map *cpus, struct perf_cpu_map **sockp) { return cpu_map__build_map(cpus, sockp, cpu_map__get_socket, NULL); } -int cpu_map__build_die_map(struct cpu_map *cpus, struct cpu_map **diep) +int cpu_map__build_die_map(struct perf_cpu_map *cpus, struct perf_cpu_map **diep) { return cpu_map__build_map(cpus, diep, cpu_map__get_die, NULL); } -int cpu_map__build_core_map(struct cpu_map *cpus, struct cpu_map **corep) +int cpu_map__build_core_map(struct perf_cpu_map *cpus, struct perf_cpu_map **corep) { return cpu_map__build_map(cpus, corep, cpu_map__get_core, NULL); } @@ -670,29 +457,17 @@ int cpu__setup_cpunode_map(void) return 0; } -bool cpu_map__has(struct cpu_map *cpus, int cpu) +bool cpu_map__has(struct perf_cpu_map *cpus, int cpu) { - return cpu_map__idx(cpus, cpu) != -1; -} - -int cpu_map__idx(struct cpu_map *cpus, int cpu) -{ - int i; - - for (i = 0; i < cpus->nr; ++i) { - if (cpus->map[i] == cpu) - return i; - } - - return -1; + return perf_cpu_map__idx(cpus, cpu) != -1; } -int cpu_map__cpu(struct cpu_map *cpus, int idx) +int cpu_map__cpu(struct perf_cpu_map *cpus, int idx) { return cpus->map[idx]; } -size_t cpu_map__snprint(struct cpu_map *map, char *buf, size_t size) +size_t cpu_map__snprint(struct perf_cpu_map *map, char *buf, size_t size) { int i, cpu, start = -1; bool first = true; @@ -744,7 +519,7 @@ static char hex_char(unsigned char val) return '?'; } -size_t cpu_map__snprint_mask(struct cpu_map *map, char *buf, size_t size) +size_t cpu_map__snprint_mask(struct perf_cpu_map *map, char *buf, size_t size) { int i, cpu; char *ptr = buf; @@ -784,12 +559,12 @@ size_t cpu_map__snprint_mask(struct cpu_map *map, char *buf, size_t size) return ptr - buf; } -const struct cpu_map *cpu_map__online(void) /* thread unsafe */ +const struct perf_cpu_map *cpu_map__online(void) /* thread unsafe */ { - static const struct cpu_map *online = NULL; + static const struct perf_cpu_map *online = NULL; if (!online) - online = cpu_map__new(NULL); /* from /sys/devices/system/cpu/online */ + online = perf_cpu_map__new(NULL); /* from /sys/devices/system/cpu/online */ return online; } diff --git a/tools/perf/util/cpumap.h b/tools/perf/util/cpumap.h index 1265f0e33920..2553bef1279d 100644 --- a/tools/perf/util/cpumap.h +++ b/tools/perf/util/cpumap.h @@ -4,40 +4,28 @@ #include <stdio.h> #include <stdbool.h> -#include <linux/refcount.h> +#include <internal/cpumap.h> +#include <perf/cpumap.h> -#include "perf.h" -#include "util/debug.h" +struct perf_record_cpu_map_data; -struct cpu_map { - refcount_t refcnt; - int nr; - int map[]; -}; - -struct cpu_map *cpu_map__new(const char *cpu_list); -struct cpu_map *cpu_map__empty_new(int nr); -struct cpu_map *cpu_map__dummy_new(void); -struct cpu_map *cpu_map__new_data(struct cpu_map_data *data); -struct cpu_map *cpu_map__read(FILE *file); -size_t cpu_map__snprint(struct cpu_map *map, char *buf, size_t size); -size_t cpu_map__snprint_mask(struct cpu_map *map, char *buf, size_t size); -size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp); +struct perf_cpu_map *perf_cpu_map__empty_new(int nr); +struct perf_cpu_map *cpu_map__new_data(struct perf_record_cpu_map_data *data); +size_t cpu_map__snprint(struct perf_cpu_map *map, char *buf, size_t size); +size_t cpu_map__snprint_mask(struct perf_cpu_map *map, char *buf, size_t size); +size_t cpu_map__fprintf(struct perf_cpu_map *map, FILE *fp); int cpu_map__get_socket_id(int cpu); -int cpu_map__get_socket(struct cpu_map *map, int idx, void *data); +int cpu_map__get_socket(struct perf_cpu_map *map, int idx, void *data); int cpu_map__get_die_id(int cpu); -int cpu_map__get_die(struct cpu_map *map, int idx, void *data); +int cpu_map__get_die(struct perf_cpu_map *map, int idx, void *data); int cpu_map__get_core_id(int cpu); -int cpu_map__get_core(struct cpu_map *map, int idx, void *data); -int cpu_map__build_socket_map(struct cpu_map *cpus, struct cpu_map **sockp); -int cpu_map__build_die_map(struct cpu_map *cpus, struct cpu_map **diep); -int cpu_map__build_core_map(struct cpu_map *cpus, struct cpu_map **corep); -const struct cpu_map *cpu_map__online(void); /* thread unsafe */ - -struct cpu_map *cpu_map__get(struct cpu_map *map); -void cpu_map__put(struct cpu_map *map); +int cpu_map__get_core(struct perf_cpu_map *map, int idx, void *data); +int cpu_map__build_socket_map(struct perf_cpu_map *cpus, struct perf_cpu_map **sockp); +int cpu_map__build_die_map(struct perf_cpu_map *cpus, struct perf_cpu_map **diep); +int cpu_map__build_core_map(struct perf_cpu_map *cpus, struct perf_cpu_map **corep); +const struct perf_cpu_map *cpu_map__online(void); /* thread unsafe */ -static inline int cpu_map__socket(struct cpu_map *sock, int s) +static inline int cpu_map__socket(struct perf_cpu_map *sock, int s) { if (!sock || s > sock->nr || s < 0) return 0; @@ -59,16 +47,6 @@ static inline int cpu_map__id_to_cpu(int id) return id & 0xffff; } -static inline int cpu_map__nr(const struct cpu_map *map) -{ - return map ? map->nr : 1; -} - -static inline bool cpu_map__empty(const struct cpu_map *map) -{ - return map ? map->map[0] == -1 : true; -} - int cpu__setup_cpunode_map(void); int cpu__max_node(void); @@ -76,11 +54,10 @@ int cpu__max_cpu(void); int cpu__max_present_cpu(void); int cpu__get_node(int cpu); -int cpu_map__build_map(struct cpu_map *cpus, struct cpu_map **res, - int (*f)(struct cpu_map *map, int cpu, void *data), +int cpu_map__build_map(struct perf_cpu_map *cpus, struct perf_cpu_map **res, + int (*f)(struct perf_cpu_map *map, int cpu, void *data), void *data); -int cpu_map__cpu(struct cpu_map *cpus, int idx); -bool cpu_map__has(struct cpu_map *cpus, int cpu); -int cpu_map__idx(struct cpu_map *cpus, int cpu); +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/cputopo.c b/tools/perf/util/cputopo.c index 64336a280967..1b52402a8923 100644 --- a/tools/perf/util/cputopo.c +++ b/tools/perf/util/cputopo.c @@ -3,11 +3,14 @@ #include <sys/utsname.h> #include <inttypes.h> #include <stdlib.h> +#include <string.h> #include <api/fs/fs.h> #include <linux/zalloc.h> +#include <perf/cpumap.h> #include "cputopo.h" #include "cpumap.h" +#include "debug.h" #include "env.h" #define CORE_SIB_FMT \ @@ -176,13 +179,13 @@ struct cpu_topology *cpu_topology__new(void) size_t sz; long ncpus; int ret = -1; - struct cpu_map *map; + struct perf_cpu_map *map; bool has_die = has_die_topology(); ncpus = cpu__max_present_cpu(); /* build online CPU map */ - map = cpu_map__new(NULL); + map = perf_cpu_map__new(NULL); if (map == NULL) { pr_debug("failed to get system cpumap\n"); return NULL; @@ -219,7 +222,7 @@ struct cpu_topology *cpu_topology__new(void) } out_free: - cpu_map__put(map); + perf_cpu_map__put(map); if (ret) { cpu_topology__delete(tp); tp = NULL; @@ -289,7 +292,7 @@ err: struct numa_topology *numa_topology__new(void) { - struct cpu_map *node_map = NULL; + struct perf_cpu_map *node_map = NULL; struct numa_topology *tp = NULL; char path[MAXPATHLEN]; char *buf = NULL; @@ -312,7 +315,7 @@ struct numa_topology *numa_topology__new(void) if (c) *c = '\0'; - node_map = cpu_map__new(buf); + node_map = perf_cpu_map__new(buf); if (!node_map) goto out; @@ -335,7 +338,7 @@ struct numa_topology *numa_topology__new(void) out: free(buf); fclose(fp); - cpu_map__put(node_map); + perf_cpu_map__put(node_map); return tp; } diff --git a/tools/perf/util/cputopo.h b/tools/perf/util/cputopo.h index bae2f1d41856..7bf6b811f715 100644 --- a/tools/perf/util/cputopo.h +++ b/tools/perf/util/cputopo.h @@ -3,7 +3,6 @@ #define __PERF_CPUTOPO_H #include <linux/types.h> -#include "env.h" struct cpu_topology { u32 core_sib; diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c index 3d1c34fc4d68..707afdbd9529 100644 --- a/tools/perf/util/cs-etm.c +++ b/tools/perf/util/cs-etm.c @@ -21,14 +21,18 @@ #include "cs-etm.h" #include "cs-etm-decoder/cs-etm-decoder.h" #include "debug.h" +#include "dso.h" #include "evlist.h" #include "intlist.h" #include "machine.h" #include "map.h" #include "perf.h" +#include "session.h" +#include "map_symbol.h" +#include "branch.h" #include "symbol.h" +#include "tool.h" #include "thread.h" -#include "thread_map.h" #include "thread-stack.h" #include <tools/libc_compat.h> #include "util.h" @@ -1076,6 +1080,35 @@ bool cs_etm__etmq_is_timeless(struct cs_etm_queue *etmq) return !!etmq->etm->timeless_decoding; } +static void cs_etm__copy_insn(struct cs_etm_queue *etmq, + u64 trace_chan_id, + const struct cs_etm_packet *packet, + struct perf_sample *sample) +{ + /* + * It's pointless to read instructions for the CS_ETM_DISCONTINUITY + * packet, so directly bail out with 'insn_len' = 0. + */ + if (packet->sample_type == CS_ETM_DISCONTINUITY) { + sample->insn_len = 0; + return; + } + + /* + * T32 instruction size might be 32-bit or 16-bit, decide by calling + * cs_etm__t32_instr_size(). + */ + if (packet->isa == CS_ETM_ISA_T32) + sample->insn_len = cs_etm__t32_instr_size(etmq, trace_chan_id, + sample->ip); + /* Otherwise, A64 and A32 instruction size are always 32-bit. */ + else + sample->insn_len = 4; + + cs_etm__mem_access(etmq, trace_chan_id, sample->ip, + sample->insn_len, (void *)sample->insn); +} + static int cs_etm__synth_instruction_sample(struct cs_etm_queue *etmq, struct cs_etm_traceid_queue *tidq, u64 addr, u64 period) @@ -1097,9 +1130,10 @@ static int cs_etm__synth_instruction_sample(struct cs_etm_queue *etmq, sample.period = period; sample.cpu = tidq->packet->cpu; sample.flags = tidq->prev_packet->flags; - sample.insn_len = 1; sample.cpumode = event->sample.header.misc; + cs_etm__copy_insn(etmq, tidq->trace_chan_id, tidq->packet, &sample); + if (etm->synth_opts.last_branch) { cs_etm__copy_last_branch_rb(etmq, tidq); sample.branch_stack = tidq->last_branch; @@ -1159,6 +1193,9 @@ static int cs_etm__synth_branch_sample(struct cs_etm_queue *etmq, sample.flags = tidq->prev_packet->flags; sample.cpumode = event->sample.header.misc; + cs_etm__copy_insn(etmq, tidq->trace_chan_id, tidq->prev_packet, + &sample); + /* * perf report cannot handle events without a branch stack */ @@ -1222,15 +1259,15 @@ static int cs_etm__synth_event(struct perf_session *session, static int cs_etm__synth_events(struct cs_etm_auxtrace *etm, struct perf_session *session) { - struct perf_evlist *evlist = session->evlist; - struct perf_evsel *evsel; + struct evlist *evlist = session->evlist; + struct evsel *evsel; struct perf_event_attr attr; bool found = false; u64 id; int err; evlist__for_each_entry(evlist, evsel) { - if (evsel->attr.type == etm->pmu_type) { + if (evsel->core.attr.type == etm->pmu_type) { found = true; break; } @@ -1244,7 +1281,7 @@ static int cs_etm__synth_events(struct cs_etm_auxtrace *etm, memset(&attr, 0, sizeof(struct perf_event_attr)); attr.size = sizeof(struct perf_event_attr); attr.type = PERF_TYPE_HARDWARE; - attr.sample_type = evsel->attr.sample_type & PERF_SAMPLE_MASK; + attr.sample_type = evsel->core.attr.sample_type & PERF_SAMPLE_MASK; attr.sample_type |= PERF_SAMPLE_IP | PERF_SAMPLE_TID | PERF_SAMPLE_PERIOD; if (etm->timeless_decoding) @@ -1252,13 +1289,13 @@ static int cs_etm__synth_events(struct cs_etm_auxtrace *etm, else attr.sample_type |= PERF_SAMPLE_TIME; - attr.exclude_user = evsel->attr.exclude_user; - attr.exclude_kernel = evsel->attr.exclude_kernel; - attr.exclude_hv = evsel->attr.exclude_hv; - attr.exclude_host = evsel->attr.exclude_host; - attr.exclude_guest = evsel->attr.exclude_guest; - attr.sample_id_all = evsel->attr.sample_id_all; - attr.read_format = evsel->attr.read_format; + attr.exclude_user = evsel->core.attr.exclude_user; + attr.exclude_kernel = evsel->core.attr.exclude_kernel; + attr.exclude_hv = evsel->core.attr.exclude_hv; + attr.exclude_host = evsel->core.attr.exclude_host; + attr.exclude_guest = evsel->core.attr.exclude_guest; + attr.sample_id_all = evsel->core.attr.sample_id_all; + attr.read_format = evsel->core.attr.read_format; /* create new id val to be a fixed offset from evsel id */ id = evsel->id[0] + 1000000000; @@ -2294,8 +2331,8 @@ static int cs_etm__process_auxtrace_event(struct perf_session *session, static bool cs_etm__is_timeless_decoding(struct cs_etm_auxtrace *etm) { - struct perf_evsel *evsel; - struct perf_evlist *evlist = etm->session->evlist; + struct evsel *evsel; + struct evlist *evlist = etm->session->evlist; bool timeless_decoding = true; /* @@ -2303,7 +2340,7 @@ static bool cs_etm__is_timeless_decoding(struct cs_etm_auxtrace *etm) * with the time bit set. */ evlist__for_each_entry(evlist, evsel) { - if ((evsel->attr.sample_type & PERF_SAMPLE_TIME)) + if ((evsel->core.attr.sample_type & PERF_SAMPLE_TIME)) timeless_decoding = false; } @@ -2337,7 +2374,7 @@ static const char * const cs_etmv4_priv_fmts[] = { [CS_ETMV4_TRCAUTHSTATUS] = " TRCAUTHSTATUS %llx\n", }; -static void cs_etm__print_auxtrace_info(u64 *val, int num) +static void cs_etm__print_auxtrace_info(__u64 *val, int num) { int i, j, cpu = 0; @@ -2360,7 +2397,7 @@ static void cs_etm__print_auxtrace_info(u64 *val, int num) int cs_etm__process_auxtrace_info(union perf_event *event, struct perf_session *session) { - struct auxtrace_info_event *auxtrace_info = &event->auxtrace_info; + struct perf_record_auxtrace_info *auxtrace_info = &event->auxtrace_info; struct cs_etm_auxtrace *etm = NULL; struct int_node *inode; unsigned int pmu_type; diff --git a/tools/perf/util/cs-etm.h b/tools/perf/util/cs-etm.h index bc848fd095f4..650ecc2a6349 100644 --- a/tools/perf/util/cs-etm.h +++ b/tools/perf/util/cs-etm.h @@ -8,9 +8,10 @@ #define INCLUDE__UTIL_PERF_CS_ETM_H__ #include "util/event.h" -#include "util/session.h" #include <linux/bits.h> +struct perf_session; + /* Versionning header in case things need tro change in the future. That way * decoding of old snapshot is still possible. */ diff --git a/tools/perf/util/data-convert-bt.c b/tools/perf/util/data-convert-bt.c index ddbcd59f2d9b..0c268449959c 100644 --- a/tools/perf/util/data-convert-bt.c +++ b/tools/perf/util/data-convert-bt.c @@ -413,7 +413,7 @@ static int add_tracepoint_fields_values(struct ctf_writer *cw, static int add_tracepoint_values(struct ctf_writer *cw, struct bt_ctf_event_class *event_class, struct bt_ctf_event *event, - struct perf_evsel *evsel, + struct evsel *evsel, struct perf_sample *sample) { struct tep_format_field *common_fields = evsel->tp_format->format.common_fields; @@ -584,10 +584,10 @@ put_len_type: static int add_generic_values(struct ctf_writer *cw, struct bt_ctf_event *event, - struct perf_evsel *evsel, + struct evsel *evsel, struct perf_sample *sample) { - u64 type = evsel->attr.sample_type; + u64 type = evsel->core.attr.sample_type; int ret; /* @@ -753,11 +753,11 @@ static struct ctf_stream *ctf_stream(struct ctf_writer *cw, int cpu) } static int get_sample_cpu(struct ctf_writer *cw, struct perf_sample *sample, - struct perf_evsel *evsel) + struct evsel *evsel) { int cpu = 0; - if (evsel->attr.sample_type & PERF_SAMPLE_CPU) + if (evsel->core.attr.sample_type & PERF_SAMPLE_CPU) cpu = sample->cpu; if (cpu > cw->stream_cnt) { @@ -785,7 +785,7 @@ static bool is_flush_needed(struct ctf_stream *cs) static int process_sample_event(struct perf_tool *tool, union perf_event *_event, struct perf_sample *sample, - struct perf_evsel *evsel, + struct evsel *evsel, struct machine *machine __maybe_unused) { struct convert *c = container_of(tool, struct convert, tool); @@ -795,7 +795,7 @@ static int process_sample_event(struct perf_tool *tool, struct bt_ctf_event_class *event_class; struct bt_ctf_event *event; int ret; - unsigned long type = evsel->attr.sample_type; + unsigned long type = evsel->core.attr.sample_type; if (WARN_ONCE(!priv, "Failed to setup all events.\n")) return 0; @@ -820,7 +820,7 @@ static int process_sample_event(struct perf_tool *tool, if (ret) return -1; - if (evsel->attr.type == PERF_TYPE_TRACEPOINT) { + if (evsel->core.attr.type == PERF_TYPE_TRACEPOINT) { ret = add_tracepoint_values(cw, event_class, event, evsel, sample); if (ret) @@ -1051,7 +1051,7 @@ static int add_tracepoint_fields_types(struct ctf_writer *cw, } static int add_tracepoint_types(struct ctf_writer *cw, - struct perf_evsel *evsel, + struct evsel *evsel, struct bt_ctf_event_class *class) { struct tep_format_field *common_fields = evsel->tp_format->format.common_fields; @@ -1084,10 +1084,10 @@ static int add_bpf_output_types(struct ctf_writer *cw, return bt_ctf_event_class_add_field(class, seq_type, "raw_data"); } -static int add_generic_types(struct ctf_writer *cw, struct perf_evsel *evsel, +static int add_generic_types(struct ctf_writer *cw, struct evsel *evsel, struct bt_ctf_event_class *event_class) { - u64 type = evsel->attr.sample_type; + u64 type = evsel->core.attr.sample_type; /* * missing: @@ -1150,14 +1150,14 @@ static int add_generic_types(struct ctf_writer *cw, struct perf_evsel *evsel, return 0; } -static int add_event(struct ctf_writer *cw, struct perf_evsel *evsel) +static int add_event(struct ctf_writer *cw, struct evsel *evsel) { struct bt_ctf_event_class *event_class; struct evsel_priv *priv; const char *name = perf_evsel__name(evsel); int ret; - pr("Adding event '%s' (type %d)\n", name, evsel->attr.type); + pr("Adding event '%s' (type %d)\n", name, evsel->core.attr.type); event_class = bt_ctf_event_class_create(name); if (!event_class) @@ -1167,7 +1167,7 @@ static int add_event(struct ctf_writer *cw, struct perf_evsel *evsel) if (ret) goto err; - if (evsel->attr.type == PERF_TYPE_TRACEPOINT) { + if (evsel->core.attr.type == PERF_TYPE_TRACEPOINT) { ret = add_tracepoint_types(cw, evsel, event_class); if (ret) goto err; @@ -1201,8 +1201,8 @@ err: static int setup_events(struct ctf_writer *cw, struct perf_session *session) { - struct perf_evlist *evlist = session->evlist; - struct perf_evsel *evsel; + struct evlist *evlist = session->evlist; + struct evsel *evsel; int ret; evlist__for_each_entry(evlist, evsel) { @@ -1308,8 +1308,8 @@ static int setup_non_sample_events(struct ctf_writer *cw, static void cleanup_events(struct perf_session *session) { - struct perf_evlist *evlist = session->evlist; - struct perf_evsel *evsel; + struct evlist *evlist = session->evlist; + struct evsel *evsel; evlist__for_each_entry(evlist, evsel) { struct evsel_priv *priv; @@ -1319,7 +1319,7 @@ static void cleanup_events(struct perf_session *session) zfree(&evsel->priv); } - perf_evlist__delete(evlist); + evlist__delete(evlist); session->evlist = NULL; } diff --git a/tools/perf/util/data.c b/tools/perf/util/data.c index 1d1b97a92c3f..e75c3a279fe8 100644 --- a/tools/perf/util/data.c +++ b/tools/perf/util/data.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 #include <linux/compiler.h> #include <linux/kernel.h> +#include <linux/string.h> #include <linux/zalloc.h> #include <sys/types.h> #include <sys/stat.h> @@ -9,7 +10,6 @@ #include <unistd.h> #include <string.h> #include <asm/bug.h> -#include <sys/types.h> #include <dirent.h> #include "data.h" diff --git a/tools/perf/util/db-export.c b/tools/perf/util/db-export.c index ffbb3e7d3288..752227b265e7 100644 --- a/tools/perf/util/db-export.c +++ b/tools/perf/util/db-export.c @@ -7,6 +7,7 @@ #include <errno.h> #include <stdlib.h> +#include "dso.h" #include "evsel.h" #include "machine.h" #include "thread.h" @@ -32,7 +33,7 @@ void db_export__exit(struct db_export *dbe) dbe->crp = NULL; } -int db_export__evsel(struct db_export *dbe, struct perf_evsel *evsel) +int db_export__evsel(struct db_export *dbe, struct evsel *evsel) { if (evsel->db_id) return 0; @@ -209,7 +210,7 @@ static struct call_path *call_path_from_sample(struct db_export *dbe, struct machine *machine, struct thread *thread, struct perf_sample *sample, - struct perf_evsel *evsel) + struct evsel *evsel) { u64 kernel_start = machine__kernel_start(machine); struct call_path *current = &dbe->cpr->call_path; @@ -341,7 +342,7 @@ static int db_export__threads(struct db_export *dbe, struct thread *thread, } int db_export__sample(struct db_export *dbe, union perf_event *event, - struct perf_sample *sample, struct perf_evsel *evsel, + struct perf_sample *sample, struct evsel *evsel, struct addr_location *al) { struct thread *thread = al->thread; @@ -388,8 +389,8 @@ int db_export__sample(struct db_export *dbe, union perf_event *event, } } - if ((evsel->attr.sample_type & PERF_SAMPLE_ADDR) && - sample_addr_correlates_sym(&evsel->attr)) { + if ((evsel->core.attr.sample_type & PERF_SAMPLE_ADDR) && + sample_addr_correlates_sym(&evsel->core.attr)) { struct addr_location addr_al; thread__resolve(thread, &addr_al, sample); diff --git a/tools/perf/util/db-export.h b/tools/perf/util/db-export.h index ba1f62a5fe10..9c3d38f5a40d 100644 --- a/tools/perf/util/db-export.h +++ b/tools/perf/util/db-export.h @@ -10,7 +10,7 @@ #include <linux/types.h> #include <linux/list.h> -struct perf_evsel; +struct evsel; struct machine; struct thread; struct comm; @@ -25,7 +25,7 @@ struct call_return; struct export_sample { union perf_event *event; struct perf_sample *sample; - struct perf_evsel *evsel; + struct evsel *evsel; struct addr_location *al; u64 db_id; u64 comm_db_id; @@ -39,7 +39,7 @@ struct export_sample { }; struct db_export { - int (*export_evsel)(struct db_export *dbe, struct perf_evsel *evsel); + int (*export_evsel)(struct db_export *dbe, struct evsel *evsel); int (*export_machine)(struct db_export *dbe, struct machine *machine); int (*export_thread)(struct db_export *dbe, struct thread *thread, u64 main_thread_db_id, struct machine *machine); @@ -79,7 +79,7 @@ struct db_export { int db_export__init(struct db_export *dbe); void db_export__exit(struct db_export *dbe); -int db_export__evsel(struct db_export *dbe, struct perf_evsel *evsel); +int db_export__evsel(struct db_export *dbe, struct evsel *evsel); int db_export__machine(struct db_export *dbe, struct machine *machine); int db_export__thread(struct db_export *dbe, struct thread *thread, struct machine *machine, struct thread *main_thread); @@ -96,7 +96,7 @@ int db_export__symbol(struct db_export *dbe, struct symbol *sym, int db_export__branch_type(struct db_export *dbe, u32 branch_type, const char *name); int db_export__sample(struct db_export *dbe, union perf_event *event, - struct perf_sample *sample, struct perf_evsel *evsel, + struct perf_sample *sample, struct evsel *evsel, struct addr_location *al); int db_export__branch_types(struct db_export *dbe); diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c index 3780fe42453b..a1b59bd35519 100644 --- a/tools/perf/util/debug.c +++ b/tools/perf/util/debug.c @@ -1,8 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* For general debugging purposes */ -#include "../perf.h" - #include <inttypes.h> #include <string.h> #include <stdarg.h> @@ -10,17 +8,19 @@ #include <stdlib.h> #include <sys/wait.h> #include <api/debug.h> +#include <linux/kernel.h> #include <linux/time64.h> #ifdef HAVE_BACKTRACE_SUPPORT #include <execinfo.h> #endif -#include "cache.h" #include "color.h" #include "event.h" #include "debug.h" #include "print_binary.h" #include "util.h" #include "target.h" +#include "ui/helpline.h" +#include "ui/ui.h" #include <linux/ctype.h> diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h index 77445dfc5c7d..b2deee987ffa 100644 --- a/tools/perf/util/debug.h +++ b/tools/perf/util/debug.h @@ -4,11 +4,7 @@ #define __PERF_DEBUG_H #include <stdbool.h> -#include <string.h> #include <linux/compiler.h> -#include "event.h" -#include "../ui/helpline.h" -#include "../ui/progress.h" #include "../ui/util.h" extern int verbose; @@ -42,6 +38,8 @@ extern int debug_data_convert; #define STRERR_BUFSIZE 128 /* For the buffer size of str_error_r */ +union perf_event; + int dump_printf(const char *fmt, ...) __printf(1, 2); void trace_event(union perf_event *event); diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c index ebc9d46c15a7..e11ddf86f2b3 100644 --- a/tools/perf/util/dso.c +++ b/tools/perf/util/dso.c @@ -10,16 +10,18 @@ #include <unistd.h> #include <errno.h> #include <fcntl.h> -#include <libgen.h> +#include <stdlib.h> #include <bpf/libbpf.h> #include "bpf-event.h" #include "compress.h" +#include "env.h" #include "namespaces.h" #include "path.h" #include "map.h" #include "symbol.h" #include "srcline.h" #include "dso.h" +#include "dsos.h" #include "machine.h" #include "auxtrace.h" #include "util.h" /* O_CLOEXEC for older systems */ @@ -1094,66 +1096,6 @@ struct dso *machine__findnew_kernel(struct machine *machine, const char *name, return dso; } -/* - * Find a matching entry and/or link current entry to RB tree. - * Either one of the dso or name parameter must be non-NULL or the - * function will not work. - */ -static struct dso *__dso__findlink_by_longname(struct rb_root *root, - struct dso *dso, const char *name) -{ - struct rb_node **p = &root->rb_node; - struct rb_node *parent = NULL; - - if (!name) - name = dso->long_name; - /* - * Find node with the matching name - */ - while (*p) { - struct dso *this = rb_entry(*p, struct dso, rb_node); - int rc = strcmp(name, this->long_name); - - parent = *p; - if (rc == 0) { - /* - * In case the new DSO is a duplicate of an existing - * one, print a one-time warning & put the new entry - * at the end of the list of duplicates. - */ - if (!dso || (dso == this)) - return this; /* Find matching dso */ - /* - * The core kernel DSOs may have duplicated long name. - * In this case, the short name should be different. - * Comparing the short names to differentiate the DSOs. - */ - rc = strcmp(dso->short_name, this->short_name); - if (rc == 0) { - pr_err("Duplicated dso name: %s\n", name); - return NULL; - } - } - if (rc < 0) - p = &parent->rb_left; - else - p = &parent->rb_right; - } - if (dso) { - /* Add new node and rebalance tree */ - rb_link_node(&dso->rb_node, parent, p); - rb_insert_color(&dso->rb_node, root); - dso->root = root; - } - return NULL; -} - -static inline struct dso *__dso__find_by_longname(struct rb_root *root, - const char *name) -{ - return __dso__findlink_by_longname(root, NULL, name); -} - void dso__set_long_name(struct dso *dso, const char *name, bool name_allocated) { struct rb_root *root = dso->root; @@ -1167,7 +1109,7 @@ void dso__set_long_name(struct dso *dso, const char *name, bool name_allocated) if (root) { rb_erase(&dso->rb_node, root); /* - * __dso__findlink_by_longname() isn't guaranteed to add it + * __dsos__findnew_link_by_longname() isn't guaranteed to add it * back, so a clean removal is required here. */ RB_CLEAR_NODE(&dso->rb_node); @@ -1179,7 +1121,7 @@ void dso__set_long_name(struct dso *dso, const char *name, bool name_allocated) dso->long_name_allocated = name_allocated; if (root) - __dso__findlink_by_longname(root, dso, NULL); + __dsos__findnew_link_by_longname(root, dso, NULL); } void dso__set_short_name(struct dso *dso, const char *name, bool name_allocated) @@ -1195,38 +1137,6 @@ void dso__set_short_name(struct dso *dso, const char *name, bool name_allocated) dso->short_name_allocated = name_allocated; } -static void dso__set_basename(struct dso *dso) -{ - char *base, *lname; - int tid; - - if (sscanf(dso->long_name, "/tmp/perf-%d.map", &tid) == 1) { - if (asprintf(&base, "[JIT] tid %d", tid) < 0) - return; - } else { - /* - * basename() may modify path buffer, so we must pass - * a copy. - */ - lname = strdup(dso->long_name); - if (!lname) - return; - - /* - * basename() may return a pointer to internal - * storage which is reused in subsequent calls - * so copy the result. - */ - base = strdup(basename(lname)); - - free(lname); - - if (!base) - return; - } - dso__set_short_name(dso, base, true); -} - int dso__name_len(const struct dso *dso) { if (!dso) @@ -1377,143 +1287,6 @@ int dso__kernel_module_get_build_id(struct dso *dso, return 0; } -bool __dsos__read_build_ids(struct list_head *head, bool with_hits) -{ - bool have_build_id = false; - struct dso *pos; - struct nscookie nsc; - - list_for_each_entry(pos, head, node) { - if (with_hits && !pos->hit && !dso__is_vdso(pos)) - continue; - if (pos->has_build_id) { - have_build_id = true; - continue; - } - nsinfo__mountns_enter(pos->nsinfo, &nsc); - if (filename__read_build_id(pos->long_name, pos->build_id, - sizeof(pos->build_id)) > 0) { - have_build_id = true; - pos->has_build_id = true; - } - nsinfo__mountns_exit(&nsc); - } - - return have_build_id; -} - -void __dsos__add(struct dsos *dsos, struct dso *dso) -{ - list_add_tail(&dso->node, &dsos->head); - __dso__findlink_by_longname(&dsos->root, dso, NULL); - /* - * It is now in the linked list, grab a reference, then garbage collect - * this when needing memory, by looking at LRU dso instances in the - * list with atomic_read(&dso->refcnt) == 1, i.e. no references - * anywhere besides the one for the list, do, under a lock for the - * list: remove it from the list, then a dso__put(), that probably will - * be the last and will then call dso__delete(), end of life. - * - * That, or at the end of the 'struct machine' lifetime, when all - * 'struct dso' instances will be removed from the list, in - * dsos__exit(), if they have no other reference from some other data - * structure. - * - * E.g.: after processing a 'perf.data' file and storing references - * to objects instantiated while processing events, we will have - * references to the 'thread', 'map', 'dso' structs all from 'struct - * hist_entry' instances, but we may not need anything not referenced, - * so we might as well call machines__exit()/machines__delete() and - * garbage collect it. - */ - dso__get(dso); -} - -void dsos__add(struct dsos *dsos, struct dso *dso) -{ - down_write(&dsos->lock); - __dsos__add(dsos, dso); - up_write(&dsos->lock); -} - -struct dso *__dsos__find(struct dsos *dsos, const char *name, bool cmp_short) -{ - struct dso *pos; - - if (cmp_short) { - list_for_each_entry(pos, &dsos->head, node) - if (strcmp(pos->short_name, name) == 0) - return pos; - return NULL; - } - return __dso__find_by_longname(&dsos->root, name); -} - -struct dso *dsos__find(struct dsos *dsos, const char *name, bool cmp_short) -{ - struct dso *dso; - down_read(&dsos->lock); - dso = __dsos__find(dsos, name, cmp_short); - up_read(&dsos->lock); - return dso; -} - -struct dso *__dsos__addnew(struct dsos *dsos, const char *name) -{ - struct dso *dso = dso__new(name); - - if (dso != NULL) { - __dsos__add(dsos, dso); - dso__set_basename(dso); - /* Put dso here because __dsos_add already got it */ - dso__put(dso); - } - return dso; -} - -struct dso *__dsos__findnew(struct dsos *dsos, const char *name) -{ - struct dso *dso = __dsos__find(dsos, name, false); - - return dso ? dso : __dsos__addnew(dsos, name); -} - -struct dso *dsos__findnew(struct dsos *dsos, const char *name) -{ - struct dso *dso; - down_write(&dsos->lock); - dso = dso__get(__dsos__findnew(dsos, name)); - up_write(&dsos->lock); - return dso; -} - -size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp, - bool (skip)(struct dso *dso, int parm), int parm) -{ - struct dso *pos; - size_t ret = 0; - - list_for_each_entry(pos, head, node) { - if (skip && skip(pos, parm)) - continue; - ret += dso__fprintf_buildid(pos, fp); - ret += fprintf(fp, " %s\n", pos->long_name); - } - return ret; -} - -size_t __dsos__fprintf(struct list_head *head, FILE *fp) -{ - struct dso *pos; - size_t ret = 0; - - list_for_each_entry(pos, head, node) { - ret += dso__fprintf(pos, fp); - } - - return ret; -} - size_t dso__fprintf_buildid(struct dso *dso, FILE *fp) { char sbuild_id[SBUILD_ID_SIZE]; diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h index 6e3f63781e51..e4dddb76770d 100644 --- a/tools/perf/util/dso.h +++ b/tools/perf/util/dso.h @@ -2,13 +2,13 @@ #ifndef __PERF_DSO #define __PERF_DSO +#include <pthread.h> #include <linux/refcount.h> #include <linux/types.h> #include <linux/rbtree.h> #include <sys/types.h> #include <stdbool.h> #include <stdio.h> -#include "rwsem.h" #include <linux/bitops.h> #include "build-id.h" @@ -16,6 +16,9 @@ struct machine; struct map; struct perf_env; +#define DSO__NAME_KALLSYMS "[kernel.kallsyms]" +#define DSO__NAME_KCORE "[kernel.kcore]" + enum dso_binary_type { DSO_BINARY_TYPE__KALLSYMS = 0, DSO_BINARY_TYPE__GUEST_KALLSYMS, @@ -126,16 +129,6 @@ struct dso_cache { char data[0]; }; -/* - * DSOs are put into both a list for fast iteration and rbtree for fast - * long name lookup. - */ -struct dsos { - struct list_head head; - struct rb_root root; /* rbtree root sorted by long name */ - struct rw_semaphore lock; -}; - struct auxtrace_cache; struct dso { @@ -344,21 +337,8 @@ struct map *dso__new_map(const char *name); struct dso *machine__findnew_kernel(struct machine *machine, const char *name, const char *short_name, int dso_type); -void __dsos__add(struct dsos *dsos, struct dso *dso); -void dsos__add(struct dsos *dsos, struct dso *dso); -struct dso *__dsos__addnew(struct dsos *dsos, const char *name); -struct dso *__dsos__find(struct dsos *dsos, const char *name, bool cmp_short); -struct dso *dsos__find(struct dsos *dsos, const char *name, bool cmp_short); -struct dso *__dsos__findnew(struct dsos *dsos, const char *name); -struct dso *dsos__findnew(struct dsos *dsos, const char *name); -bool __dsos__read_build_ids(struct list_head *head, bool with_hits); - void dso__reset_find_symbol_cache(struct dso *dso); -size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp, - bool (skip)(struct dso *dso, int parm), int parm); -size_t __dsos__fprintf(struct list_head *head, FILE *fp); - size_t dso__fprintf_buildid(struct dso *dso, FILE *fp); size_t dso__fprintf_symbols_by_name(struct dso *dso, FILE *fp); size_t dso__fprintf(struct dso *dso, FILE *fp); diff --git a/tools/perf/util/dsos.c b/tools/perf/util/dsos.c new file mode 100644 index 000000000000..3ea80d203587 --- /dev/null +++ b/tools/perf/util/dsos.c @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: GPL-2.0 +#include "debug.h" +#include "dsos.h" +#include "dso.h" +#include "vdso.h" +#include "namespaces.h" +#include <libgen.h> +#include <stdlib.h> +#include <string.h> +#include <symbol.h> // filename__read_build_id + +bool __dsos__read_build_ids(struct list_head *head, bool with_hits) +{ + bool have_build_id = false; + struct dso *pos; + struct nscookie nsc; + + list_for_each_entry(pos, head, node) { + if (with_hits && !pos->hit && !dso__is_vdso(pos)) + continue; + if (pos->has_build_id) { + have_build_id = true; + continue; + } + nsinfo__mountns_enter(pos->nsinfo, &nsc); + if (filename__read_build_id(pos->long_name, pos->build_id, + sizeof(pos->build_id)) > 0) { + have_build_id = true; + pos->has_build_id = true; + } + nsinfo__mountns_exit(&nsc); + } + + return have_build_id; +} + +/* + * Find a matching entry and/or link current entry to RB tree. + * Either one of the dso or name parameter must be non-NULL or the + * function will not work. + */ +struct dso *__dsos__findnew_link_by_longname(struct rb_root *root, struct dso *dso, const char *name) +{ + struct rb_node **p = &root->rb_node; + struct rb_node *parent = NULL; + + if (!name) + name = dso->long_name; + /* + * Find node with the matching name + */ + while (*p) { + struct dso *this = rb_entry(*p, struct dso, rb_node); + int rc = strcmp(name, this->long_name); + + parent = *p; + if (rc == 0) { + /* + * In case the new DSO is a duplicate of an existing + * one, print a one-time warning & put the new entry + * at the end of the list of duplicates. + */ + if (!dso || (dso == this)) + return this; /* Find matching dso */ + /* + * The core kernel DSOs may have duplicated long name. + * In this case, the short name should be different. + * Comparing the short names to differentiate the DSOs. + */ + rc = strcmp(dso->short_name, this->short_name); + if (rc == 0) { + pr_err("Duplicated dso name: %s\n", name); + return NULL; + } + } + if (rc < 0) + p = &parent->rb_left; + else + p = &parent->rb_right; + } + if (dso) { + /* Add new node and rebalance tree */ + rb_link_node(&dso->rb_node, parent, p); + rb_insert_color(&dso->rb_node, root); + dso->root = root; + } + return NULL; +} + +void __dsos__add(struct dsos *dsos, struct dso *dso) +{ + list_add_tail(&dso->node, &dsos->head); + __dsos__findnew_link_by_longname(&dsos->root, dso, NULL); + /* + * It is now in the linked list, grab a reference, then garbage collect + * this when needing memory, by looking at LRU dso instances in the + * list with atomic_read(&dso->refcnt) == 1, i.e. no references + * anywhere besides the one for the list, do, under a lock for the + * list: remove it from the list, then a dso__put(), that probably will + * be the last and will then call dso__delete(), end of life. + * + * That, or at the end of the 'struct machine' lifetime, when all + * 'struct dso' instances will be removed from the list, in + * dsos__exit(), if they have no other reference from some other data + * structure. + * + * E.g.: after processing a 'perf.data' file and storing references + * to objects instantiated while processing events, we will have + * references to the 'thread', 'map', 'dso' structs all from 'struct + * hist_entry' instances, but we may not need anything not referenced, + * so we might as well call machines__exit()/machines__delete() and + * garbage collect it. + */ + dso__get(dso); +} + +void dsos__add(struct dsos *dsos, struct dso *dso) +{ + down_write(&dsos->lock); + __dsos__add(dsos, dso); + up_write(&dsos->lock); +} + +struct dso *__dsos__find(struct dsos *dsos, const char *name, bool cmp_short) +{ + struct dso *pos; + + if (cmp_short) { + list_for_each_entry(pos, &dsos->head, node) + if (strcmp(pos->short_name, name) == 0) + return pos; + return NULL; + } + return __dsos__findnew_by_longname(&dsos->root, name); +} + +struct dso *dsos__find(struct dsos *dsos, const char *name, bool cmp_short) +{ + struct dso *dso; + down_read(&dsos->lock); + dso = __dsos__find(dsos, name, cmp_short); + up_read(&dsos->lock); + return dso; +} + +static void dso__set_basename(struct dso *dso) +{ + char *base, *lname; + int tid; + + if (sscanf(dso->long_name, "/tmp/perf-%d.map", &tid) == 1) { + if (asprintf(&base, "[JIT] tid %d", tid) < 0) + return; + } else { + /* + * basename() may modify path buffer, so we must pass + * a copy. + */ + lname = strdup(dso->long_name); + if (!lname) + return; + + /* + * basename() may return a pointer to internal + * storage which is reused in subsequent calls + * so copy the result. + */ + base = strdup(basename(lname)); + + free(lname); + + if (!base) + return; + } + dso__set_short_name(dso, base, true); +} + +struct dso *__dsos__addnew(struct dsos *dsos, const char *name) +{ + struct dso *dso = dso__new(name); + + if (dso != NULL) { + __dsos__add(dsos, dso); + dso__set_basename(dso); + /* Put dso here because __dsos_add already got it */ + dso__put(dso); + } + return dso; +} + +struct dso *__dsos__findnew(struct dsos *dsos, const char *name) +{ + struct dso *dso = __dsos__find(dsos, name, false); + + return dso ? dso : __dsos__addnew(dsos, name); +} + +struct dso *dsos__findnew(struct dsos *dsos, const char *name) +{ + struct dso *dso; + down_write(&dsos->lock); + dso = dso__get(__dsos__findnew(dsos, name)); + up_write(&dsos->lock); + return dso; +} + +size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp, + bool (skip)(struct dso *dso, int parm), int parm) +{ + struct dso *pos; + size_t ret = 0; + + list_for_each_entry(pos, head, node) { + if (skip && skip(pos, parm)) + continue; + ret += dso__fprintf_buildid(pos, fp); + ret += fprintf(fp, " %s\n", pos->long_name); + } + return ret; +} + +size_t __dsos__fprintf(struct list_head *head, FILE *fp) +{ + struct dso *pos; + size_t ret = 0; + + list_for_each_entry(pos, head, node) { + ret += dso__fprintf(pos, fp); + } + + return ret; +} diff --git a/tools/perf/util/dsos.h b/tools/perf/util/dsos.h new file mode 100644 index 000000000000..32f1fbee0feb --- /dev/null +++ b/tools/perf/util/dsos.h @@ -0,0 +1,44 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __PERF_DSOS +#define __PERF_DSOS + +#include <stdbool.h> +#include <stdio.h> +#include <linux/list.h> +#include <linux/rbtree.h> +#include "rwsem.h" + +struct dso; + +/* + * DSOs are put into both a list for fast iteration and rbtree for fast + * long name lookup. + */ +struct dsos { + struct list_head head; + struct rb_root root; /* rbtree root sorted by long name */ + struct rw_semaphore lock; +}; + +void __dsos__add(struct dsos *dsos, struct dso *dso); +void dsos__add(struct dsos *dsos, struct dso *dso); +struct dso *__dsos__addnew(struct dsos *dsos, const char *name); +struct dso *__dsos__find(struct dsos *dsos, const char *name, bool cmp_short); +struct dso *dsos__find(struct dsos *dsos, const char *name, bool cmp_short); +struct dso *__dsos__findnew(struct dsos *dsos, const char *name); +struct dso *dsos__findnew(struct dsos *dsos, const char *name); + +struct dso *__dsos__findnew_link_by_longname(struct rb_root *root, struct dso *dso, const char *name); + +static inline struct dso *__dsos__findnew_by_longname(struct rb_root *root, const char *name) +{ + return __dsos__findnew_link_by_longname(root, NULL, name); +} + +bool __dsos__read_build_ids(struct list_head *head, bool with_hits); + +size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp, + bool (skip)(struct dso *dso, int parm), int parm); +size_t __dsos__fprintf(struct list_head *head, FILE *fp); + +#endif /* __PERF_DSOS */ diff --git a/tools/perf/util/dwarf-aux.c b/tools/perf/util/dwarf-aux.c index 03b2de1f5a35..df6cee5c071f 100644 --- a/tools/perf/util/dwarf-aux.c +++ b/tools/perf/util/dwarf-aux.c @@ -9,6 +9,7 @@ #include <stdlib.h> #include "debug.h" #include "dwarf-aux.h" +#include "strbuf.h" #include "string2.h" /** diff --git a/tools/perf/util/dwarf-aux.h b/tools/perf/util/dwarf-aux.h index 0489b0cf8e2c..f204e5892403 100644 --- a/tools/perf/util/dwarf-aux.h +++ b/tools/perf/util/dwarf-aux.h @@ -10,6 +10,8 @@ #include <elfutils/libdwfl.h> #include <elfutils/version.h> +struct strbuf; + /* Find the realpath of the target file */ const char *cu_find_realpath(Dwarf_Die *cu_die, const char *fname); diff --git a/tools/perf/util/env.c b/tools/perf/util/env.c index 9909ec40c6d2..3baca06786fb 100644 --- a/tools/perf/util/env.c +++ b/tools/perf/util/env.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 #include "cpumap.h" +#include "debug.h" #include "env.h" #include <linux/ctype.h> #include <linux/zalloc.h> @@ -8,6 +9,7 @@ #include <sys/utsname.h> #include <bpf/libbpf.h> #include <stdlib.h> +#include <string.h> struct perf_env perf_env; @@ -179,7 +181,7 @@ void perf_env__exit(struct perf_env *env) zfree(&env->cpu); for (i = 0; i < env->nr_numa_nodes; i++) - cpu_map__put(env->numa_nodes[i].map); + perf_cpu_map__put(env->numa_nodes[i].map); zfree(&env->numa_nodes); for (i = 0; i < env->caches_cnt; i++) diff --git a/tools/perf/util/env.h b/tools/perf/util/env.h index d5d9865aa812..d8e083d42610 100644 --- a/tools/perf/util/env.h +++ b/tools/perf/util/env.h @@ -27,7 +27,7 @@ struct numa_node { u32 node; u64 mem_total; u64 mem_free; - struct cpu_map *map; + struct perf_cpu_map *map; }; struct memory_node { diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index f1f4848947ce..f4afbb858ebb 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -1,4 +1,3 @@ -// SPDX-License-Identifier: GPL-2.0 #include <dirent.h> #include <errno.h> #include <fcntl.h> @@ -12,6 +11,7 @@ #include <api/fs/fs.h> #include <linux/perf_event.h> #include <linux/zalloc.h> +#include "dso.h" #include "event.h" #include "debug.h" #include "hist.h" @@ -21,6 +21,7 @@ #include "strlist.h" #include "thread.h" #include "thread_map.h" +#include "time-utils.h" #include <linux/ctype.h> #include "map.h" #include "symbol.h" @@ -29,6 +30,8 @@ #include "stat.h" #include "session.h" #include "bpf-event.h" +#include "tool.h" +#include "../perf.h" #define DEFAULT_PROC_MAP_PARSE_TIMEOUT 500 @@ -387,7 +390,7 @@ int perf_event__synthesize_mmap_events(struct perf_tool *tool, strcpy(execname, ""); /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */ - n = sscanf(bf, "%"PRIx64"-%"PRIx64" %s %"PRIx64" %x:%x %u %[^\n]\n", + n = sscanf(bf, "%"PRI_lx64"-%"PRI_lx64" %s %"PRI_lx64" %x:%x %u %[^\n]\n", &event->mmap2.start, &event->mmap2.len, prot, &event->mmap2.pgoff, &event->mmap2.maj, &event->mmap2.min, @@ -616,7 +619,7 @@ static int __event__synthesize_thread(union perf_event *comm_event, } int perf_event__synthesize_thread_map(struct perf_tool *tool, - struct thread_map *threads, + struct perf_thread_map *threads, perf_event__handler_t process, struct machine *machine, bool mmap_data) @@ -647,7 +650,7 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool, for (thread = 0; thread < threads->nr; ++thread) { if (__event__synthesize_thread(comm_event, mmap_event, fork_event, namespaces_event, - thread_map__pid(threads, thread), 0, + perf_thread_map__pid(threads, thread), 0, process, tool, machine, mmap_data)) { err = -1; @@ -658,12 +661,12 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool, * comm.pid is set to thread group id by * perf_event__synthesize_comm */ - if ((int) comm_event->comm.pid != thread_map__pid(threads, thread)) { + if ((int) comm_event->comm.pid != perf_thread_map__pid(threads, thread)) { bool need_leader = true; /* is thread group leader in thread_map? */ for (j = 0; j < threads->nr; ++j) { - if ((int) comm_event->comm.pid == thread_map__pid(threads, j)) { + if ((int) comm_event->comm.pid == perf_thread_map__pid(threads, j)) { need_leader = false; break; } @@ -913,11 +916,13 @@ static int __perf_event__synthesize_kernel_mmap(struct perf_tool *tool, int err; union perf_event *event; - if (symbol_conf.kptr_restrict) - return -1; if (map == NULL) return -1; + kmap = map__kmap(map); + if (!kmap->ref_reloc_sym) + return -1; + /* * We should get this from /sys/kernel/sections/.text, but till that is * available use this, and after it is use this as a fallback for older @@ -940,7 +945,6 @@ static int __perf_event__synthesize_kernel_mmap(struct perf_tool *tool, event->header.misc = PERF_RECORD_MISC_GUEST_KERNEL; } - kmap = map__kmap(map); size = snprintf(event->mmap.filename, sizeof(event->mmap.filename), "%s%s", machine->mmap_name, kmap->ref_reloc_sym->name) + 1; size = PERF_ALIGN(size, sizeof(u64)); @@ -972,7 +976,7 @@ int perf_event__synthesize_kernel_mmap(struct perf_tool *tool, } int perf_event__synthesize_thread_map2(struct perf_tool *tool, - struct thread_map *threads, + struct perf_thread_map *threads, perf_event__handler_t process, struct machine *machine) { @@ -991,13 +995,13 @@ int perf_event__synthesize_thread_map2(struct perf_tool *tool, event->thread_map.nr = threads->nr; for (i = 0; i < threads->nr; i++) { - struct thread_map_event_entry *entry = &event->thread_map.entries[i]; - char *comm = thread_map__comm(threads, i); + struct perf_record_thread_map_entry *entry = &event->thread_map.entries[i]; + char *comm = perf_thread_map__comm(threads, i); if (!comm) comm = (char *) ""; - entry->pid = thread_map__pid(threads, i); + entry->pid = perf_thread_map__pid(threads, i); strncpy((char *) &entry->comm, comm, sizeof(entry->comm)); } @@ -1008,7 +1012,7 @@ int perf_event__synthesize_thread_map2(struct perf_tool *tool, } static void synthesize_cpus(struct cpu_map_entries *cpus, - struct cpu_map *map) + struct perf_cpu_map *map) { int i; @@ -1018,8 +1022,8 @@ static void synthesize_cpus(struct cpu_map_entries *cpus, cpus->cpu[i] = map->map[i]; } -static void synthesize_mask(struct cpu_map_mask *mask, - struct cpu_map *map, int max) +static void synthesize_mask(struct perf_record_record_cpu_map *mask, + struct perf_cpu_map *map, int max) { int i; @@ -1030,12 +1034,12 @@ static void synthesize_mask(struct cpu_map_mask *mask, set_bit(map->map[i], mask->mask); } -static size_t cpus_size(struct cpu_map *map) +static size_t cpus_size(struct perf_cpu_map *map) { return sizeof(struct cpu_map_entries) + map->nr * sizeof(u16); } -static size_t mask_size(struct cpu_map *map, int *max) +static size_t mask_size(struct perf_cpu_map *map, int *max) { int i; @@ -1049,26 +1053,26 @@ static size_t mask_size(struct cpu_map *map, int *max) *max = bit; } - return sizeof(struct cpu_map_mask) + BITS_TO_LONGS(*max) * sizeof(long); + return sizeof(struct perf_record_record_cpu_map) + BITS_TO_LONGS(*max) * sizeof(long); } -void *cpu_map_data__alloc(struct cpu_map *map, size_t *size, u16 *type, int *max) +void *cpu_map_data__alloc(struct perf_cpu_map *map, size_t *size, u16 *type, int *max) { size_t size_cpus, size_mask; - bool is_dummy = cpu_map__empty(map); + bool is_dummy = perf_cpu_map__empty(map); /* * Both array and mask data have variable size based * on the number of cpus and their actual values. - * The size of the 'struct cpu_map_data' is: + * The size of the 'struct perf_record_cpu_map_data' is: * * array = size of 'struct cpu_map_entries' + * number of cpus * sizeof(u64) * - * mask = size of 'struct cpu_map_mask' + + * mask = size of 'struct perf_record_record_cpu_map' + * maximum cpu bit converted to size of longs * - * and finaly + the size of 'struct cpu_map_data'. + * and finaly + the size of 'struct perf_record_cpu_map_data'. */ size_cpus = cpus_size(map); size_mask = mask_size(map, max); @@ -1081,12 +1085,12 @@ void *cpu_map_data__alloc(struct cpu_map *map, size_t *size, u16 *type, int *max *type = PERF_CPU_MAP__MASK; } - *size += sizeof(struct cpu_map_data); + *size += sizeof(struct perf_record_cpu_map_data); *size = PERF_ALIGN(*size, sizeof(u64)); return zalloc(*size); } -void cpu_map_data__synthesize(struct cpu_map_data *data, struct cpu_map *map, +void cpu_map_data__synthesize(struct perf_record_cpu_map_data *data, struct perf_cpu_map *map, u16 type, int max) { data->type = type; @@ -1096,16 +1100,16 @@ void cpu_map_data__synthesize(struct cpu_map_data *data, struct cpu_map *map, synthesize_cpus((struct cpu_map_entries *) data->data, map); break; case PERF_CPU_MAP__MASK: - synthesize_mask((struct cpu_map_mask *) data->data, map, max); + synthesize_mask((struct perf_record_record_cpu_map *)data->data, map, max); default: break; }; } -static struct cpu_map_event* cpu_map_event__new(struct cpu_map *map) +static struct perf_record_cpu_map *cpu_map_event__new(struct perf_cpu_map *map) { - size_t size = sizeof(struct cpu_map_event); - struct cpu_map_event *event; + size_t size = sizeof(struct perf_record_cpu_map); + struct perf_record_cpu_map *event; int max; u16 type; @@ -1122,11 +1126,11 @@ static struct cpu_map_event* cpu_map_event__new(struct cpu_map *map) } int perf_event__synthesize_cpu_map(struct perf_tool *tool, - struct cpu_map *map, + struct perf_cpu_map *map, perf_event__handler_t process, struct machine *machine) { - struct cpu_map_event *event; + struct perf_record_cpu_map *event; int err; event = cpu_map_event__new(map); @@ -1144,7 +1148,7 @@ int perf_event__synthesize_stat_config(struct perf_tool *tool, perf_event__handler_t process, struct machine *machine) { - struct stat_config_event *event; + struct perf_record_stat_config *event; int size, i = 0, err; size = sizeof(*event); @@ -1183,7 +1187,7 @@ int perf_event__synthesize_stat(struct perf_tool *tool, perf_event__handler_t process, struct machine *machine) { - struct stat_event event; + struct perf_record_stat event; event.header.type = PERF_RECORD_STAT; event.header.size = sizeof(event); @@ -1204,7 +1208,7 @@ int perf_event__synthesize_stat_round(struct perf_tool *tool, perf_event__handler_t process, struct machine *machine) { - struct stat_round_event event; + struct perf_record_stat_round event; event.header.type = PERF_RECORD_STAT_ROUND; event.header.size = sizeof(event); @@ -1217,7 +1221,7 @@ int perf_event__synthesize_stat_round(struct perf_tool *tool, } void perf_event__read_stat_config(struct perf_stat_config *config, - struct stat_config_event *event) + struct perf_record_stat_config *event) { unsigned i; @@ -1234,7 +1238,7 @@ void perf_event__read_stat_config(struct perf_stat_config *config, CASE(INTERVAL, interval) #undef CASE default: - pr_warning("unknown stat config term %" PRIu64 "\n", + pr_warning("unknown stat config term %" PRI_lu64 "\n", event->data[i].tag); } } @@ -1343,17 +1347,17 @@ int perf_event__process_ksymbol(struct perf_tool *tool __maybe_unused, return machine__process_ksymbol(machine, event, sample); } -int perf_event__process_bpf_event(struct perf_tool *tool __maybe_unused, - union perf_event *event, - struct perf_sample *sample __maybe_unused, - struct machine *machine) +int perf_event__process_bpf(struct perf_tool *tool __maybe_unused, + union perf_event *event, + struct perf_sample *sample, + struct machine *machine) { - return machine__process_bpf_event(machine, event, sample); + return machine__process_bpf(machine, event, sample); } size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp) { - return fprintf(fp, " %d/%d: [%#" PRIx64 "(%#" PRIx64 ") @ %#" PRIx64 "]: %c %s\n", + return fprintf(fp, " %d/%d: [%#" PRI_lx64 "(%#" PRI_lx64 ") @ %#" PRI_lx64 "]: %c %s\n", event->mmap.pid, event->mmap.tid, event->mmap.start, event->mmap.len, event->mmap.pgoff, (event->header.misc & PERF_RECORD_MISC_MMAP_DATA) ? 'r' : 'x', @@ -1362,8 +1366,8 @@ size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp) size_t perf_event__fprintf_mmap2(union perf_event *event, FILE *fp) { - return fprintf(fp, " %d/%d: [%#" PRIx64 "(%#" PRIx64 ") @ %#" PRIx64 - " %02x:%02x %"PRIu64" %"PRIu64"]: %c%c%c%c %s\n", + return fprintf(fp, " %d/%d: [%#" PRI_lx64 "(%#" PRI_lx64 ") @ %#" PRI_lx64 + " %02x:%02x %"PRI_lu64" %"PRI_lu64"]: %c%c%c%c %s\n", event->mmap2.pid, event->mmap2.tid, event->mmap2.start, event->mmap2.len, event->mmap2.pgoff, event->mmap2.maj, event->mmap2.min, event->mmap2.ino, @@ -1377,7 +1381,7 @@ size_t perf_event__fprintf_mmap2(union perf_event *event, FILE *fp) size_t perf_event__fprintf_thread_map(union perf_event *event, FILE *fp) { - struct thread_map *threads = thread_map__new_event(&event->thread_map); + struct perf_thread_map *threads = thread_map__new_event(&event->thread_map); size_t ret; ret = fprintf(fp, " nr: "); @@ -1387,13 +1391,13 @@ size_t perf_event__fprintf_thread_map(union perf_event *event, FILE *fp) else ret += fprintf(fp, "failed to get threads from event\n"); - thread_map__put(threads); + perf_thread_map__put(threads); return ret; } size_t perf_event__fprintf_cpu_map(union perf_event *event, FILE *fp) { - struct cpu_map *cpus = cpu_map__new_data(&event->cpu_map.data); + struct perf_cpu_map *cpus = cpu_map__new_data(&event->cpu_map.data); size_t ret; ret = fprintf(fp, ": "); @@ -1403,7 +1407,7 @@ size_t perf_event__fprintf_cpu_map(union perf_event *event, FILE *fp) else ret += fprintf(fp, "failed to get cpumap from event\n"); - cpu_map__put(cpus); + perf_cpu_map__put(cpus); return ret; } @@ -1448,7 +1452,7 @@ int perf_event__process_exit(struct perf_tool *tool __maybe_unused, size_t perf_event__fprintf_aux(union perf_event *event, FILE *fp) { - return fprintf(fp, " offset: %#"PRIx64" size: %#"PRIx64" flags: %#"PRIx64" [%s%s%s]\n", + return fprintf(fp, " offset: %#"PRI_lx64" size: %#"PRI_lx64" flags: %#"PRI_lx64" [%s%s%s]\n", event->aux.aux_offset, event->aux.aux_size, event->aux.flags, event->aux.flags & PERF_AUX_FLAG_TRUNCATED ? "T" : "", @@ -1480,22 +1484,21 @@ size_t perf_event__fprintf_switch(union perf_event *event, FILE *fp) static size_t perf_event__fprintf_lost(union perf_event *event, FILE *fp) { - return fprintf(fp, " lost %" PRIu64 "\n", event->lost.lost); + return fprintf(fp, " lost %" PRI_lu64 "\n", event->lost.lost); } size_t perf_event__fprintf_ksymbol(union perf_event *event, FILE *fp) { - return fprintf(fp, " addr %" PRIx64 " len %u type %u flags 0x%x name %s\n", - event->ksymbol_event.addr, event->ksymbol_event.len, - event->ksymbol_event.ksym_type, - event->ksymbol_event.flags, event->ksymbol_event.name); + return fprintf(fp, " addr %" PRI_lx64 " len %u type %u flags 0x%x name %s\n", + event->ksymbol.addr, event->ksymbol.len, + event->ksymbol.ksym_type, + event->ksymbol.flags, event->ksymbol.name); } -size_t perf_event__fprintf_bpf_event(union perf_event *event, FILE *fp) +size_t perf_event__fprintf_bpf(union perf_event *event, FILE *fp) { return fprintf(fp, " type %u, flags %u, id %u\n", - event->bpf_event.type, event->bpf_event.flags, - event->bpf_event.id); + event->bpf.type, event->bpf.flags, event->bpf.id); } size_t perf_event__fprintf(union perf_event *event, FILE *fp) @@ -1537,7 +1540,7 @@ size_t perf_event__fprintf(union perf_event *event, FILE *fp) ret += perf_event__fprintf_ksymbol(event, fp); break; case PERF_RECORD_BPF_EVENT: - ret += perf_event__fprintf_bpf_event(event, fp); + ret += perf_event__fprintf_bpf(event, fp); break; default: ret += fprintf(fp, "\n"); diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index 1f1da6082806..47ad81d47b1a 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h @@ -1,114 +1,39 @@ /* SPDX-License-Identifier: GPL-2.0 */ #ifndef __PERF_RECORD_H #define __PERF_RECORD_H - -#include <limits.h> +/* + * The linux/stddef.h isn't need here, but is needed for __always_inline used + * in files included from uapi/linux/perf_event.h such as + * /usr/include/linux/swab.h and /usr/include/linux/byteorder/little_endian.h, + * detected in at least musl libc, used in Alpine Linux. -acme + */ #include <stdio.h> -#include <linux/kernel.h> -#include <linux/bpf.h> -#include <linux/perf_event.h> +#include <linux/stddef.h> +#include <perf/event.h> +#include <linux/types.h> -#include "../perf.h" -#include "build-id.h" #include "perf_regs.h" -struct mmap_event { - struct perf_event_header header; - u32 pid, tid; - u64 start; - u64 len; - u64 pgoff; - char filename[PATH_MAX]; -}; - -struct mmap2_event { - 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 comm_event { - struct perf_event_header header; - u32 pid, tid; - char comm[16]; -}; - -struct namespaces_event { - struct perf_event_header header; - u32 pid, tid; - u64 nr_namespaces; - struct perf_ns_link_info link_info[]; -}; - -struct fork_event { - struct perf_event_header header; - u32 pid, ppid; - u32 tid, ptid; - u64 time; -}; - -struct lost_event { - struct perf_event_header header; - u64 id; - u64 lost; -}; - -struct lost_samples_event { - struct perf_event_header header; - u64 lost; -}; +struct dso; +struct machine; +struct perf_event_attr; +#ifdef __LP64__ /* - * PERF_FORMAT_ENABLED | PERF_FORMAT_RUNNING | PERF_FORMAT_ID + * /usr/include/inttypes.h uses just 'lu' for PRIu64, but we end up defining + * __u64 as long long unsigned int, and then -Werror=format= kicks in and + * complains of the mismatched types, so use these two special extra PRI + * macros to overcome that. */ -struct read_event { - struct perf_event_header header; - u32 pid, tid; - u64 value; - u64 time_enabled; - u64 time_running; - u64 id; -}; - -struct throttle_event { - struct perf_event_header header; - u64 time; - u64 id; - u64 stream_id; -}; - -#ifndef KSYM_NAME_LEN -#define KSYM_NAME_LEN 256 +#define PRI_lu64 "l" PRIu64 +#define PRI_lx64 "l" PRIx64 +#define PRI_ld64 "l" PRId64 +#else +#define PRI_lu64 PRIu64 +#define PRI_lx64 PRIx64 +#define PRI_ld64 PRId64 #endif -struct ksymbol_event { - struct perf_event_header header; - u64 addr; - u32 len; - u16 ksym_type; - u16 flags; - char name[KSYM_NAME_LEN]; -}; - -struct bpf_event { - struct perf_event_header header; - u16 type; - u16 flags; - u32 id; - - /* for bpf_prog types */ - u8 tag[BPF_TAG_SIZE]; // prog tag -}; - #define PERF_SAMPLE_MASK \ (PERF_SAMPLE_IP | PERF_SAMPLE_TID | \ PERF_SAMPLE_TIME | PERF_SAMPLE_ADDR | \ @@ -119,11 +44,6 @@ struct bpf_event { /* perf sample has 16 bits size limit */ #define PERF_SAMPLE_MAX_SIZE (1 << 16) -struct sample_event { - struct perf_event_header header; - u64 array[]; -}; - struct regs_dump { u64 abi; u64 mask; @@ -231,41 +151,6 @@ struct perf_sample { PERF_MEM_S(LOCK, NA) |\ PERF_MEM_S(TLB, NA)) -struct build_id_event { - struct perf_event_header header; - pid_t pid; - u8 build_id[PERF_ALIGN(BUILD_ID_SIZE, sizeof(u64))]; - char filename[]; -}; - -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 -}; - -enum auxtrace_error_type { - PERF_AUXTRACE_ERROR_ITRACE = 1, - PERF_AUXTRACE_ERROR_MAX -}; - /* Attribute type for custom synthesized events */ #define PERF_TYPE_SYNTH (INT_MAX + 1U) @@ -387,295 +272,16 @@ static inline void *perf_synth__raw_data(void *p) #define perf_sample__bad_synth_size(s, d) ((s)->raw_size < sizeof(d) - 4) -/* - * The kernel collects the number of events it couldn't send in a stretch and - * when possible sends this number in a PERF_RECORD_LOST event. The number of - * such "chunks" of lost events is stored in .nr_events[PERF_EVENT_LOST] while - * total_lost tells exactly how many events the kernel in fact lost, i.e. it is - * the sum of all struct lost_event.lost fields reported. - * - * The kernel discards mixed up samples and sends the number in a - * PERF_RECORD_LOST_SAMPLES event. The number of lost-samples events is stored - * in .nr_events[PERF_RECORD_LOST_SAMPLES] while total_lost_samples tells - * exactly how many samples the kernel in fact dropped, i.e. it is the sum of - * all struct lost_samples_event.lost fields reported. - * - * The total_period is needed because by default auto-freq is used, so - * multipling nr_events[PERF_EVENT_SAMPLE] by a frequency isn't possible to get - * the total number of low level events, it is necessary to to sum all struct - * sample_event.period and stash the result in total_period. - */ -struct events_stats { - u64 total_period; - u64 total_non_filtered_period; - u64 total_lost; - u64 total_lost_samples; - u64 total_aux_lost; - u64 total_aux_partial; - u64 total_invalid_chains; - u32 nr_events[PERF_RECORD_HEADER_MAX]; - u32 nr_non_filtered_samples; - u32 nr_lost_warned; - u32 nr_unknown_events; - u32 nr_invalid_chains; - u32 nr_unknown_id; - u32 nr_unprocessable_samples; - u32 nr_auxtrace_errors[PERF_AUXTRACE_ERROR_MAX]; - u32 nr_proc_map_timeout; -}; - -enum { - PERF_CPU_MAP__CPUS = 0, - PERF_CPU_MAP__MASK = 1, -}; - -struct cpu_map_entries { - u16 nr; - u16 cpu[]; -}; - -struct cpu_map_mask { - u16 nr; - u16 long_size; - unsigned long mask[]; -}; - -struct cpu_map_data { - u16 type; - char data[]; -}; - -struct cpu_map_event { - struct perf_event_header header; - struct cpu_map_data data; -}; - -struct attr_event { - struct perf_event_header header; - struct perf_event_attr attr; - u64 id[]; -}; - -enum { - PERF_EVENT_UPDATE__UNIT = 0, - PERF_EVENT_UPDATE__SCALE = 1, - PERF_EVENT_UPDATE__NAME = 2, - PERF_EVENT_UPDATE__CPUS = 3, -}; - -struct event_update_event_cpus { - struct cpu_map_data cpus; -}; - -struct event_update_event_scale { - double scale; -}; - -struct event_update_event { - 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 event_type_event { - struct perf_event_header header; - struct perf_trace_event_type event_type; -}; - -struct tracing_data_event { - struct perf_event_header header; - u32 size; -}; - -struct id_index_entry { - u64 id; - u64 idx; - u64 cpu; - u64 tid; -}; - -struct id_index_event { - struct perf_event_header header; - u64 nr; - struct id_index_entry entries[0]; -}; - -struct auxtrace_info_event { - struct perf_event_header header; - u32 type; - u32 reserved__; /* For alignment */ - u64 priv[]; -}; - -struct auxtrace_event { - 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 auxtrace_error_event { - 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 aux_event { - struct perf_event_header header; - u64 aux_offset; - u64 aux_size; - u64 flags; -}; - -struct itrace_start_event { - struct perf_event_header header; - u32 pid, tid; -}; - -struct context_switch_event { - struct perf_event_header header; - u32 next_prev_pid; - u32 next_prev_tid; -}; - -struct thread_map_event_entry { - u64 pid; - char comm[16]; -}; - -struct thread_map_event { - struct perf_event_header header; - u64 nr; - struct thread_map_event_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 stat_config_event_entry { - u64 tag; - u64 val; -}; - -struct stat_config_event { - struct perf_event_header header; - u64 nr; - struct stat_config_event_entry data[]; -}; - -struct stat_event { - struct perf_event_header header; - - u64 id; - u32 cpu; - u32 thread; - - union { - struct { - u64 val; - u64 ena; - u64 run; - }; - u64 values[3]; - }; -}; - enum { PERF_STAT_ROUND_TYPE__INTERVAL = 0, PERF_STAT_ROUND_TYPE__FINAL = 1, }; -struct stat_round_event { - struct perf_event_header header; - u64 type; - u64 time; -}; - -struct time_conv_event { - struct perf_event_header header; - u64 time_shift; - u64 time_mult; - u64 time_zero; -}; - -struct feature_event { - struct perf_event_header header; - u64 feat_id; - char data[]; -}; - -struct compressed_event { - struct perf_event_header header; - char data[]; -}; - -union perf_event { - struct perf_event_header header; - struct mmap_event mmap; - struct mmap2_event mmap2; - struct comm_event comm; - struct namespaces_event namespaces; - struct fork_event fork; - struct lost_event lost; - struct lost_samples_event lost_samples; - struct read_event read; - struct throttle_event throttle; - struct sample_event sample; - struct attr_event attr; - struct event_update_event event_update; - struct event_type_event event_type; - struct tracing_data_event tracing_data; - struct build_id_event build_id; - struct id_index_event id_index; - struct auxtrace_info_event auxtrace_info; - struct auxtrace_event auxtrace; - struct auxtrace_error_event auxtrace_error; - struct aux_event aux; - struct itrace_start_event itrace_start; - struct context_switch_event context_switch; - struct thread_map_event thread_map; - struct cpu_map_event cpu_map; - struct stat_config_event stat_config; - struct stat_event stat; - struct stat_round_event stat_round; - struct time_conv_event time_conv; - struct feature_event feat; - struct ksymbol_event ksymbol_event; - struct bpf_event bpf_event; - struct compressed_event pack; -}; - void perf_event__print_totals(void); struct perf_tool; -struct thread_map; -struct cpu_map; +struct perf_thread_map; +struct perf_cpu_map; struct perf_stat_config; struct perf_counts_values; @@ -685,15 +291,15 @@ typedef int (*perf_event__handler_t)(struct perf_tool *tool, struct machine *machine); int perf_event__synthesize_thread_map(struct perf_tool *tool, - struct thread_map *threads, + struct perf_thread_map *threads, perf_event__handler_t process, struct machine *machine, bool mmap_data); int perf_event__synthesize_thread_map2(struct perf_tool *tool, - struct thread_map *threads, + struct perf_thread_map *threads, perf_event__handler_t process, struct machine *machine); int perf_event__synthesize_cpu_map(struct perf_tool *tool, - struct cpu_map *cpus, + struct perf_cpu_map *cpus, perf_event__handler_t process, struct machine *machine); int perf_event__synthesize_threads(struct perf_tool *tool, @@ -708,7 +314,7 @@ int perf_event__synthesize_stat_config(struct perf_tool *tool, perf_event__handler_t process, struct machine *machine); void perf_event__read_stat_config(struct perf_stat_config *config, - struct stat_config_event *event); + struct perf_record_stat_config *event); int perf_event__synthesize_stat(struct perf_tool *tool, u32 cpu, u32 thread, u64 id, struct perf_counts_values *count, @@ -770,10 +376,10 @@ int perf_event__process_ksymbol(struct perf_tool *tool, union perf_event *event, struct perf_sample *sample, struct machine *machine); -int perf_event__process_bpf_event(struct perf_tool *tool, - union perf_event *event, - struct perf_sample *sample, - struct machine *machine); +int perf_event__process_bpf(struct perf_tool *tool, + union perf_event *event, + struct perf_sample *sample, + struct machine *machine); int perf_tool__process_synth_event(struct perf_tool *tool, union perf_event *event, struct machine *machine, @@ -838,19 +444,20 @@ size_t perf_event__fprintf_thread_map(union perf_event *event, FILE *fp); size_t perf_event__fprintf_cpu_map(union perf_event *event, FILE *fp); size_t perf_event__fprintf_namespaces(union perf_event *event, FILE *fp); size_t perf_event__fprintf_ksymbol(union perf_event *event, FILE *fp); -size_t perf_event__fprintf_bpf_event(union perf_event *event, FILE *fp); +size_t perf_event__fprintf_bpf(union perf_event *event, FILE *fp); size_t perf_event__fprintf(union perf_event *event, FILE *fp); int kallsyms__get_function_start(const char *kallsyms_filename, const char *symbol_name, u64 *addr); -void *cpu_map_data__alloc(struct cpu_map *map, size_t *size, u16 *type, int *max); -void cpu_map_data__synthesize(struct cpu_map_data *data, struct cpu_map *map, +void *cpu_map_data__alloc(struct perf_cpu_map *map, size_t *size, u16 *type, int *max); +void cpu_map_data__synthesize(struct perf_record_cpu_map_data *data, struct perf_cpu_map *map, u16 type, int max); void event_attr_init(struct perf_event_attr *attr); int perf_event_paranoid(void); +bool perf_event_paranoid_check(int max_level); extern int sysctl_perf_event_max_stack; extern int sysctl_perf_event_max_contexts_per_stack; diff --git a/tools/perf/util/events_stats.h b/tools/perf/util/events_stats.h new file mode 100644 index 000000000000..859cb34fcff2 --- /dev/null +++ b/tools/perf/util/events_stats.h @@ -0,0 +1,51 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __PERF_EVENTS_STATS_ +#define __PERF_EVENTS_STATS_ + +#include <stdio.h> +#include <perf/event.h> +#include <linux/types.h> +#include "auxtrace.h" + +/* + * The kernel collects the number of events it couldn't send in a stretch and + * when possible sends this number in a PERF_RECORD_LOST event. The number of + * such "chunks" of lost events is stored in .nr_events[PERF_EVENT_LOST] while + * total_lost tells exactly how many events the kernel in fact lost, i.e. it is + * the sum of all struct perf_record_lost.lost fields reported. + * + * The kernel discards mixed up samples and sends the number in a + * PERF_RECORD_LOST_SAMPLES event. The number of lost-samples events is stored + * in .nr_events[PERF_RECORD_LOST_SAMPLES] while total_lost_samples tells + * exactly how many samples the kernel in fact dropped, i.e. it is the sum of + * all struct perf_record_lost_samples.lost fields reported. + * + * The total_period is needed because by default auto-freq is used, so + * multipling nr_events[PERF_EVENT_SAMPLE] by a frequency isn't possible to get + * the total number of low level events, it is necessary to to sum all struct + * perf_record_sample.period and stash the result in total_period. + */ +struct events_stats { + u64 total_period; + u64 total_non_filtered_period; + u64 total_lost; + u64 total_lost_samples; + u64 total_aux_lost; + u64 total_aux_partial; + u64 total_invalid_chains; + u32 nr_events[PERF_RECORD_HEADER_MAX]; + u32 nr_non_filtered_samples; + u32 nr_lost_warned; + u32 nr_unknown_events; + u32 nr_invalid_chains; + u32 nr_unknown_id; + u32 nr_unprocessable_samples; + u32 nr_auxtrace_errors[PERF_AUXTRACE_ERROR_MAX]; + u32 nr_proc_map_timeout; +}; + +void events_stats__inc(struct events_stats *stats, u32 type); + +size_t events_stats__fprintf(struct events_stats *stats, FILE *fp); + +#endif /* __PERF_EVENTS_STATS_ */ diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index b0364d923f76..095924aa186b 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -16,10 +16,14 @@ #include "evsel.h" #include "debug.h" #include "units.h" +#include "util.h" +#include "../perf.h" #include "asm/bug.h" #include "bpf-event.h" #include <signal.h> #include <unistd.h> +#include <sched.h> +#include <stdlib.h> #include "parse-events.h" #include <subcmd/parse-options.h> @@ -32,57 +36,63 @@ #include <linux/hash.h> #include <linux/log2.h> #include <linux/err.h> +#include <linux/string.h> #include <linux/zalloc.h> +#include <perf/evlist.h> +#include <perf/evsel.h> +#include <perf/cpumap.h> + +#include <internal/xyarray.h> #ifdef LACKS_SIGQUEUE_PROTOTYPE int sigqueue(pid_t pid, int sig, const union sigval value); #endif -#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) +#define FD(e, x, y) (*(int *)xyarray__entry(e->core.fd, x, y)) #define SID(e, x, y) xyarray__entry(e->sample_id, x, y) -void perf_evlist__init(struct perf_evlist *evlist, struct cpu_map *cpus, - struct thread_map *threads) +void evlist__init(struct evlist *evlist, struct perf_cpu_map *cpus, + struct perf_thread_map *threads) { int i; for (i = 0; i < PERF_EVLIST__HLIST_SIZE; ++i) INIT_HLIST_HEAD(&evlist->heads[i]); - INIT_LIST_HEAD(&evlist->entries); - perf_evlist__set_maps(evlist, cpus, threads); + perf_evlist__init(&evlist->core); + perf_evlist__set_maps(&evlist->core, cpus, threads); fdarray__init(&evlist->pollfd, 64); evlist->workload.pid = -1; evlist->bkw_mmap_state = BKW_MMAP_NOTREADY; } -struct perf_evlist *perf_evlist__new(void) +struct evlist *evlist__new(void) { - struct perf_evlist *evlist = zalloc(sizeof(*evlist)); + struct evlist *evlist = zalloc(sizeof(*evlist)); if (evlist != NULL) - perf_evlist__init(evlist, NULL, NULL); + evlist__init(evlist, NULL, NULL); return evlist; } -struct perf_evlist *perf_evlist__new_default(void) +struct evlist *perf_evlist__new_default(void) { - struct perf_evlist *evlist = perf_evlist__new(); + struct evlist *evlist = evlist__new(); if (evlist && perf_evlist__add_default(evlist)) { - perf_evlist__delete(evlist); + evlist__delete(evlist); evlist = NULL; } return evlist; } -struct perf_evlist *perf_evlist__new_dummy(void) +struct evlist *perf_evlist__new_dummy(void) { - struct perf_evlist *evlist = perf_evlist__new(); + struct evlist *evlist = evlist__new(); if (evlist && perf_evlist__add_dummy(evlist)) { - perf_evlist__delete(evlist); + evlist__delete(evlist); evlist = NULL; } @@ -96,17 +106,17 @@ struct perf_evlist *perf_evlist__new_dummy(void) * Events with compatible sample types all have the same id_pos * and is_pos. For convenience, put a copy on evlist. */ -void perf_evlist__set_id_pos(struct perf_evlist *evlist) +void perf_evlist__set_id_pos(struct evlist *evlist) { - struct perf_evsel *first = perf_evlist__first(evlist); + struct evsel *first = perf_evlist__first(evlist); evlist->id_pos = first->id_pos; evlist->is_pos = first->is_pos; } -static void perf_evlist__update_id_pos(struct perf_evlist *evlist) +static void perf_evlist__update_id_pos(struct evlist *evlist) { - struct perf_evsel *evsel; + struct evsel *evsel; evlist__for_each_entry(evlist, evsel) perf_evsel__calc_id_pos(evsel); @@ -114,161 +124,132 @@ static void perf_evlist__update_id_pos(struct perf_evlist *evlist) perf_evlist__set_id_pos(evlist); } -static void perf_evlist__purge(struct perf_evlist *evlist) +static void perf_evlist__purge(struct evlist *evlist) { - struct perf_evsel *pos, *n; + struct evsel *pos, *n; evlist__for_each_entry_safe(evlist, n, pos) { - list_del_init(&pos->node); + list_del_init(&pos->core.node); pos->evlist = NULL; - perf_evsel__delete(pos); + evsel__delete(pos); } - evlist->nr_entries = 0; + evlist->core.nr_entries = 0; } -void perf_evlist__exit(struct perf_evlist *evlist) +void perf_evlist__exit(struct evlist *evlist) { zfree(&evlist->mmap); zfree(&evlist->overwrite_mmap); fdarray__exit(&evlist->pollfd); } -void perf_evlist__delete(struct perf_evlist *evlist) +void evlist__delete(struct evlist *evlist) { if (evlist == NULL) return; perf_evlist__munmap(evlist); - perf_evlist__close(evlist); - cpu_map__put(evlist->cpus); - thread_map__put(evlist->threads); - evlist->cpus = NULL; - evlist->threads = NULL; + evlist__close(evlist); + perf_cpu_map__put(evlist->core.cpus); + perf_thread_map__put(evlist->core.threads); + evlist->core.cpus = NULL; + evlist->core.threads = NULL; perf_evlist__purge(evlist); perf_evlist__exit(evlist); free(evlist); } -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) { - cpu_map__put(evsel->cpus); - evsel->cpus = cpu_map__get(evlist->cpus); - } else if (evsel->cpus != evsel->own_cpus) { - cpu_map__put(evsel->cpus); - evsel->cpus = cpu_map__get(evsel->own_cpus); - } - - thread_map__put(evsel->threads); - evsel->threads = thread_map__get(evlist->threads); -} - -static void perf_evlist__propagate_maps(struct perf_evlist *evlist) -{ - struct perf_evsel *evsel; - - evlist__for_each_entry(evlist, evsel) - __perf_evlist__propagate_maps(evlist, evsel); -} - -void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry) +void evlist__add(struct evlist *evlist, struct evsel *entry) { entry->evlist = evlist; - list_add_tail(&entry->node, &evlist->entries); - entry->idx = evlist->nr_entries; + entry->idx = evlist->core.nr_entries; entry->tracking = !entry->idx; - if (!evlist->nr_entries++) - perf_evlist__set_id_pos(evlist); + perf_evlist__add(&evlist->core, &entry->core); - __perf_evlist__propagate_maps(evlist, entry); + if (evlist->core.nr_entries == 1) + perf_evlist__set_id_pos(evlist); } -void perf_evlist__remove(struct perf_evlist *evlist, struct perf_evsel *evsel) +void evlist__remove(struct evlist *evlist, struct evsel *evsel) { evsel->evlist = NULL; - list_del_init(&evsel->node); - evlist->nr_entries -= 1; + perf_evlist__remove(&evlist->core, &evsel->core); } -void perf_evlist__splice_list_tail(struct perf_evlist *evlist, +void perf_evlist__splice_list_tail(struct evlist *evlist, struct list_head *list) { - struct perf_evsel *evsel, *temp; + struct evsel *evsel, *temp; __evlist__for_each_entry_safe(list, temp, evsel) { - list_del_init(&evsel->node); - perf_evlist__add(evlist, evsel); + list_del_init(&evsel->core.node); + evlist__add(evlist, evsel); } } void __perf_evlist__set_leader(struct list_head *list) { - struct perf_evsel *evsel, *leader; + struct evsel *evsel, *leader; - leader = list_entry(list->next, struct perf_evsel, node); - evsel = list_entry(list->prev, struct perf_evsel, node); + leader = list_entry(list->next, struct evsel, core.node); + evsel = list_entry(list->prev, struct evsel, core.node); - leader->nr_members = evsel->idx - leader->idx + 1; + leader->core.nr_members = evsel->idx - leader->idx + 1; __evlist__for_each_entry(list, evsel) { evsel->leader = leader; } } -void perf_evlist__set_leader(struct perf_evlist *evlist) +void perf_evlist__set_leader(struct evlist *evlist) { - if (evlist->nr_entries) { - evlist->nr_groups = evlist->nr_entries > 1 ? 1 : 0; - __perf_evlist__set_leader(&evlist->entries); + if (evlist->core.nr_entries) { + evlist->nr_groups = evlist->core.nr_entries > 1 ? 1 : 0; + __perf_evlist__set_leader(&evlist->core.entries); } } -int __perf_evlist__add_default(struct perf_evlist *evlist, bool precise) +int __perf_evlist__add_default(struct evlist *evlist, bool precise) { - struct perf_evsel *evsel = perf_evsel__new_cycles(precise); + struct evsel *evsel = perf_evsel__new_cycles(precise); if (evsel == NULL) return -ENOMEM; - perf_evlist__add(evlist, evsel); + evlist__add(evlist, evsel); return 0; } -int perf_evlist__add_dummy(struct perf_evlist *evlist) +int perf_evlist__add_dummy(struct evlist *evlist) { struct perf_event_attr attr = { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_DUMMY, .size = sizeof(attr), /* to capture ABI version */ }; - struct perf_evsel *evsel = perf_evsel__new_idx(&attr, evlist->nr_entries); + struct evsel *evsel = perf_evsel__new_idx(&attr, evlist->core.nr_entries); if (evsel == NULL) return -ENOMEM; - perf_evlist__add(evlist, evsel); + evlist__add(evlist, evsel); return 0; } -static int perf_evlist__add_attrs(struct perf_evlist *evlist, +static int evlist__add_attrs(struct evlist *evlist, struct perf_event_attr *attrs, size_t nr_attrs) { - struct perf_evsel *evsel, *n; + struct evsel *evsel, *n; LIST_HEAD(head); size_t i; for (i = 0; i < nr_attrs; i++) { - evsel = perf_evsel__new_idx(attrs + i, evlist->nr_entries + i); + evsel = perf_evsel__new_idx(attrs + i, evlist->core.nr_entries + i); if (evsel == NULL) goto out_delete_partial_list; - list_add_tail(&evsel->node, &head); + list_add_tail(&evsel->core.node, &head); } perf_evlist__splice_list_tail(evlist, &head); @@ -277,11 +258,11 @@ static int perf_evlist__add_attrs(struct perf_evlist *evlist, out_delete_partial_list: __evlist__for_each_entry_safe(&head, n, evsel) - perf_evsel__delete(evsel); + evsel__delete(evsel); return -1; } -int __perf_evlist__add_default_attrs(struct perf_evlist *evlist, +int __perf_evlist__add_default_attrs(struct evlist *evlist, struct perf_event_attr *attrs, size_t nr_attrs) { size_t i; @@ -289,31 +270,31 @@ int __perf_evlist__add_default_attrs(struct perf_evlist *evlist, for (i = 0; i < nr_attrs; i++) event_attr_init(attrs + i); - return perf_evlist__add_attrs(evlist, attrs, nr_attrs); + return evlist__add_attrs(evlist, attrs, nr_attrs); } -struct perf_evsel * -perf_evlist__find_tracepoint_by_id(struct perf_evlist *evlist, int id) +struct evsel * +perf_evlist__find_tracepoint_by_id(struct evlist *evlist, int id) { - struct perf_evsel *evsel; + struct evsel *evsel; evlist__for_each_entry(evlist, evsel) { - if (evsel->attr.type == PERF_TYPE_TRACEPOINT && - (int)evsel->attr.config == id) + if (evsel->core.attr.type == PERF_TYPE_TRACEPOINT && + (int)evsel->core.attr.config == id) return evsel; } return NULL; } -struct perf_evsel * -perf_evlist__find_tracepoint_by_name(struct perf_evlist *evlist, +struct evsel * +perf_evlist__find_tracepoint_by_name(struct evlist *evlist, const char *name) { - struct perf_evsel *evsel; + struct evsel *evsel; evlist__for_each_entry(evlist, evsel) { - if ((evsel->attr.type == PERF_TYPE_TRACEPOINT) && + if ((evsel->core.attr.type == PERF_TYPE_TRACEPOINT) && (strcmp(evsel->name, name) == 0)) return evsel; } @@ -321,66 +302,66 @@ perf_evlist__find_tracepoint_by_name(struct perf_evlist *evlist, return NULL; } -int perf_evlist__add_newtp(struct perf_evlist *evlist, +int perf_evlist__add_newtp(struct evlist *evlist, const char *sys, const char *name, void *handler) { - struct perf_evsel *evsel = perf_evsel__newtp(sys, name); + struct evsel *evsel = perf_evsel__newtp(sys, name); if (IS_ERR(evsel)) return -1; evsel->handler = handler; - perf_evlist__add(evlist, evsel); + evlist__add(evlist, evsel); return 0; } -static int perf_evlist__nr_threads(struct perf_evlist *evlist, - struct perf_evsel *evsel) +static int perf_evlist__nr_threads(struct evlist *evlist, + struct evsel *evsel) { if (evsel->system_wide) return 1; else - return thread_map__nr(evlist->threads); + return perf_thread_map__nr(evlist->core.threads); } -void perf_evlist__disable(struct perf_evlist *evlist) +void evlist__disable(struct evlist *evlist) { - struct perf_evsel *pos; + struct evsel *pos; evlist__for_each_entry(evlist, pos) { - if (pos->disabled || !perf_evsel__is_group_leader(pos) || !pos->fd) + if (pos->disabled || !perf_evsel__is_group_leader(pos) || !pos->core.fd) continue; - perf_evsel__disable(pos); + evsel__disable(pos); } evlist->enabled = false; } -void perf_evlist__enable(struct perf_evlist *evlist) +void evlist__enable(struct evlist *evlist) { - struct perf_evsel *pos; + struct evsel *pos; evlist__for_each_entry(evlist, pos) { - if (!perf_evsel__is_group_leader(pos) || !pos->fd) + if (!perf_evsel__is_group_leader(pos) || !pos->core.fd) continue; - perf_evsel__enable(pos); + evsel__enable(pos); } evlist->enabled = true; } -void perf_evlist__toggle_enable(struct perf_evlist *evlist) +void perf_evlist__toggle_enable(struct evlist *evlist) { - (evlist->enabled ? perf_evlist__disable : perf_evlist__enable)(evlist); + (evlist->enabled ? evlist__disable : evlist__enable)(evlist); } -static int perf_evlist__enable_event_cpu(struct perf_evlist *evlist, - struct perf_evsel *evsel, int cpu) +static int perf_evlist__enable_event_cpu(struct evlist *evlist, + struct evsel *evsel, int cpu) { int thread; int nr_threads = perf_evlist__nr_threads(evlist, evsel); - if (!evsel->fd) + if (!evsel->core.fd) return -EINVAL; for (thread = 0; thread < nr_threads; thread++) { @@ -391,14 +372,14 @@ static int perf_evlist__enable_event_cpu(struct perf_evlist *evlist, return 0; } -static int perf_evlist__enable_event_thread(struct perf_evlist *evlist, - struct perf_evsel *evsel, +static int perf_evlist__enable_event_thread(struct evlist *evlist, + struct evsel *evsel, int thread) { int cpu; - int nr_cpus = cpu_map__nr(evlist->cpus); + int nr_cpus = perf_cpu_map__nr(evlist->core.cpus); - if (!evsel->fd) + if (!evsel->core.fd) return -EINVAL; for (cpu = 0; cpu < nr_cpus; cpu++) { @@ -409,10 +390,10 @@ static int perf_evlist__enable_event_thread(struct perf_evlist *evlist, return 0; } -int perf_evlist__enable_event_idx(struct perf_evlist *evlist, - struct perf_evsel *evsel, int idx) +int perf_evlist__enable_event_idx(struct evlist *evlist, + struct evsel *evsel, int idx) { - bool per_cpu_mmaps = !cpu_map__empty(evlist->cpus); + bool per_cpu_mmaps = !perf_cpu_map__empty(evlist->core.cpus); if (per_cpu_mmaps) return perf_evlist__enable_event_cpu(evlist, evsel, idx); @@ -420,12 +401,12 @@ int perf_evlist__enable_event_idx(struct perf_evlist *evlist, return perf_evlist__enable_event_thread(evlist, evsel, idx); } -int perf_evlist__alloc_pollfd(struct perf_evlist *evlist) +int perf_evlist__alloc_pollfd(struct evlist *evlist) { - int nr_cpus = cpu_map__nr(evlist->cpus); - int nr_threads = thread_map__nr(evlist->threads); + int nr_cpus = perf_cpu_map__nr(evlist->core.cpus); + int nr_threads = perf_thread_map__nr(evlist->core.threads); int nfds = 0; - struct perf_evsel *evsel; + struct evsel *evsel; evlist__for_each_entry(evlist, evsel) { if (evsel->system_wide) @@ -441,7 +422,7 @@ int perf_evlist__alloc_pollfd(struct perf_evlist *evlist) return 0; } -static int __perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd, +static int __perf_evlist__add_pollfd(struct evlist *evlist, int fd, struct perf_mmap *map, short revent) { int pos = fdarray__add(&evlist->pollfd, fd, revent | POLLERR | POLLHUP); @@ -458,7 +439,7 @@ static int __perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd, return pos; } -int perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd) +int perf_evlist__add_pollfd(struct evlist *evlist, int fd) { return __perf_evlist__add_pollfd(evlist, fd, NULL, POLLIN); } @@ -472,19 +453,19 @@ static void perf_evlist__munmap_filtered(struct fdarray *fda, int fd, perf_mmap__put(map); } -int perf_evlist__filter_pollfd(struct perf_evlist *evlist, short revents_and_mask) +int perf_evlist__filter_pollfd(struct 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) +int perf_evlist__poll(struct evlist *evlist, int timeout) { return fdarray__poll(&evlist->pollfd, timeout); } -static void perf_evlist__id_hash(struct perf_evlist *evlist, - struct perf_evsel *evsel, +static void perf_evlist__id_hash(struct evlist *evlist, + struct evsel *evsel, int cpu, int thread, u64 id) { int hash; @@ -496,15 +477,15 @@ static void perf_evlist__id_hash(struct perf_evlist *evlist, hlist_add_head(&sid->node, &evlist->heads[hash]); } -void perf_evlist__id_add(struct perf_evlist *evlist, struct perf_evsel *evsel, +void perf_evlist__id_add(struct evlist *evlist, struct 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 perf_evlist__id_add_fd(struct evlist *evlist, + struct evsel *evsel, int cpu, int thread, int fd) { u64 read_data[4] = { 0, }; @@ -528,13 +509,13 @@ int perf_evlist__id_add_fd(struct perf_evlist *evlist, if (perf_evlist__read_format(evlist) & PERF_FORMAT_GROUP) return -1; - if (!(evsel->attr.read_format & PERF_FORMAT_ID) || + if (!(evsel->core.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) + if (evsel->core.attr.read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) ++id_idx; - if (evsel->attr.read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) + if (evsel->core.attr.read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) ++id_idx; id = read_data[id_idx]; @@ -544,23 +525,23 @@ int perf_evlist__id_add_fd(struct perf_evlist *evlist, return 0; } -static void perf_evlist__set_sid_idx(struct perf_evlist *evlist, - struct perf_evsel *evsel, int idx, int cpu, +static void perf_evlist__set_sid_idx(struct evlist *evlist, + struct 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]; + if (evlist->core.cpus && cpu >= 0) + sid->cpu = evlist->core.cpus->map[cpu]; else sid->cpu = -1; - if (!evsel->system_wide && evlist->threads && thread >= 0) - sid->tid = thread_map__pid(evlist->threads, thread); + if (!evsel->system_wide && evlist->core.threads && thread >= 0) + sid->tid = perf_thread_map__pid(evlist->core.threads, thread); else sid->tid = -1; } -struct perf_sample_id *perf_evlist__id2sid(struct perf_evlist *evlist, u64 id) +struct perf_sample_id *perf_evlist__id2sid(struct evlist *evlist, u64 id) { struct hlist_head *head; struct perf_sample_id *sid; @@ -576,11 +557,11 @@ struct perf_sample_id *perf_evlist__id2sid(struct perf_evlist *evlist, u64 id) return NULL; } -struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id) +struct evsel *perf_evlist__id2evsel(struct evlist *evlist, u64 id) { struct perf_sample_id *sid; - if (evlist->nr_entries == 1 || !id) + if (evlist->core.nr_entries == 1 || !id) return perf_evlist__first(evlist); sid = perf_evlist__id2sid(evlist, id); @@ -593,7 +574,7 @@ struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id) return NULL; } -struct perf_evsel *perf_evlist__id2evsel_strict(struct perf_evlist *evlist, +struct evsel *perf_evlist__id2evsel_strict(struct evlist *evlist, u64 id) { struct perf_sample_id *sid; @@ -608,10 +589,10 @@ struct perf_evsel *perf_evlist__id2evsel_strict(struct perf_evlist *evlist, return NULL; } -static int perf_evlist__event2id(struct perf_evlist *evlist, +static int perf_evlist__event2id(struct evlist *evlist, union perf_event *event, u64 *id) { - const u64 *array = event->sample.array; + const __u64 *array = event->sample.array; ssize_t n; n = (event->header.size - sizeof(event->header)) >> 3; @@ -629,19 +610,19 @@ static int perf_evlist__event2id(struct perf_evlist *evlist, return 0; } -struct perf_evsel *perf_evlist__event2evsel(struct perf_evlist *evlist, +struct evsel *perf_evlist__event2evsel(struct evlist *evlist, union perf_event *event) { - struct perf_evsel *first = perf_evlist__first(evlist); + struct evsel *first = perf_evlist__first(evlist); struct hlist_head *head; struct perf_sample_id *sid; int hash; u64 id; - if (evlist->nr_entries == 1) + if (evlist->core.nr_entries == 1) return first; - if (!first->attr.sample_id_all && + if (!first->core.attr.sample_id_all && event->header.type != PERF_RECORD_SAMPLE) return first; @@ -662,7 +643,7 @@ struct perf_evsel *perf_evlist__event2evsel(struct perf_evlist *evlist, return NULL; } -static int perf_evlist__set_paused(struct perf_evlist *evlist, bool value) +static int perf_evlist__set_paused(struct evlist *evlist, bool value) { int i; @@ -682,17 +663,17 @@ static int perf_evlist__set_paused(struct perf_evlist *evlist, bool value) return 0; } -static int perf_evlist__pause(struct perf_evlist *evlist) +static int perf_evlist__pause(struct evlist *evlist) { return perf_evlist__set_paused(evlist, true); } -static int perf_evlist__resume(struct perf_evlist *evlist) +static int perf_evlist__resume(struct evlist *evlist) { return perf_evlist__set_paused(evlist, false); } -static void perf_evlist__munmap_nofree(struct perf_evlist *evlist) +static void perf_evlist__munmap_nofree(struct evlist *evlist) { int i; @@ -705,22 +686,22 @@ static void perf_evlist__munmap_nofree(struct perf_evlist *evlist) perf_mmap__munmap(&evlist->overwrite_mmap[i]); } -void perf_evlist__munmap(struct perf_evlist *evlist) +void perf_evlist__munmap(struct evlist *evlist) { perf_evlist__munmap_nofree(evlist); zfree(&evlist->mmap); zfree(&evlist->overwrite_mmap); } -static struct perf_mmap *perf_evlist__alloc_mmap(struct perf_evlist *evlist, +static struct perf_mmap *perf_evlist__alloc_mmap(struct evlist *evlist, bool overwrite) { int i; struct perf_mmap *map; - evlist->nr_mmaps = cpu_map__nr(evlist->cpus); - if (cpu_map__empty(evlist->cpus)) - evlist->nr_mmaps = thread_map__nr(evlist->threads); + evlist->nr_mmaps = perf_cpu_map__nr(evlist->core.cpus); + if (perf_cpu_map__empty(evlist->core.cpus)) + evlist->nr_mmaps = perf_thread_map__nr(evlist->core.threads); map = zalloc(evlist->nr_mmaps * sizeof(struct perf_mmap)); if (!map) return NULL; @@ -743,21 +724,21 @@ static struct perf_mmap *perf_evlist__alloc_mmap(struct perf_evlist *evlist, } static bool -perf_evlist__should_poll(struct perf_evlist *evlist __maybe_unused, - struct perf_evsel *evsel) +perf_evlist__should_poll(struct evlist *evlist __maybe_unused, + struct evsel *evsel) { - if (evsel->attr.write_backward) + if (evsel->core.attr.write_backward) return false; return true; } -static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx, +static int perf_evlist__mmap_per_evsel(struct evlist *evlist, int idx, struct mmap_params *mp, int cpu_idx, int thread, int *_output, int *_output_overwrite) { - struct perf_evsel *evsel; + struct evsel *evsel; int revent; - int evlist_cpu = cpu_map__cpu(evlist->cpus, cpu_idx); + int evlist_cpu = cpu_map__cpu(evlist->core.cpus, cpu_idx); evlist__for_each_entry(evlist, evsel) { struct perf_mmap *maps = evlist->mmap; @@ -766,7 +747,7 @@ static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx, int cpu; mp->prot = PROT_READ | PROT_WRITE; - if (evsel->attr.write_backward) { + if (evsel->core.attr.write_backward) { output = _output_overwrite; maps = evlist->overwrite_mmap; @@ -784,7 +765,7 @@ static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx, if (evsel->system_wide && thread) continue; - cpu = cpu_map__idx(evsel->cpus, evlist_cpu); + cpu = perf_cpu_map__idx(evsel->core.cpus, evlist_cpu); if (cpu == -1) continue; @@ -817,7 +798,7 @@ static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx, return -1; } - if (evsel->attr.read_format & PERF_FORMAT_ID) { + if (evsel->core.attr.read_format & PERF_FORMAT_ID) { if (perf_evlist__id_add_fd(evlist, evsel, cpu, thread, fd) < 0) return -1; @@ -829,12 +810,12 @@ static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx, return 0; } -static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist, +static int perf_evlist__mmap_per_cpu(struct evlist *evlist, struct mmap_params *mp) { int cpu, thread; - int nr_cpus = cpu_map__nr(evlist->cpus); - int nr_threads = thread_map__nr(evlist->threads); + int nr_cpus = perf_cpu_map__nr(evlist->core.cpus); + int nr_threads = perf_thread_map__nr(evlist->core.threads); pr_debug2("perf event ring buffer mmapped per cpu\n"); for (cpu = 0; cpu < nr_cpus; cpu++) { @@ -858,11 +839,11 @@ out_unmap: return -1; } -static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist, +static int perf_evlist__mmap_per_thread(struct evlist *evlist, struct mmap_params *mp) { int thread; - int nr_threads = thread_map__nr(evlist->threads); + int nr_threads = perf_thread_map__nr(evlist->core.threads); pr_debug2("perf event ring buffer mmapped per thread\n"); for (thread = 0; thread < nr_threads; thread++) { @@ -1006,14 +987,14 @@ int perf_evlist__parse_mmap_pages(const struct option *opt, const char *str, * * Return: %0 on success, negative error code otherwise. */ -int perf_evlist__mmap_ex(struct perf_evlist *evlist, unsigned int pages, +int perf_evlist__mmap_ex(struct evlist *evlist, unsigned int pages, unsigned int auxtrace_pages, bool auxtrace_overwrite, int nr_cblocks, int affinity, int flush, int comp_level) { - struct perf_evsel *evsel; - const struct cpu_map *cpus = evlist->cpus; - const struct thread_map *threads = evlist->threads; + struct evsel *evsel; + const struct perf_cpu_map *cpus = evlist->core.cpus; + const struct perf_thread_map *threads = evlist->core.threads; /* * Delay setting mp.prot: set it before calling perf_mmap__mmap. * Its value is decided by evsel's write_backward. @@ -1038,28 +1019,28 @@ int perf_evlist__mmap_ex(struct perf_evlist *evlist, unsigned int pages, auxtrace_pages, auxtrace_overwrite); evlist__for_each_entry(evlist, evsel) { - if ((evsel->attr.read_format & PERF_FORMAT_ID) && + if ((evsel->core.attr.read_format & PERF_FORMAT_ID) && evsel->sample_id == NULL && - perf_evsel__alloc_id(evsel, cpu_map__nr(cpus), threads->nr) < 0) + perf_evsel__alloc_id(evsel, perf_cpu_map__nr(cpus), threads->nr) < 0) return -ENOMEM; } - if (cpu_map__empty(cpus)) + if (perf_cpu_map__empty(cpus)) return perf_evlist__mmap_per_thread(evlist, &mp); return perf_evlist__mmap_per_cpu(evlist, &mp); } -int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages) +int perf_evlist__mmap(struct evlist *evlist, unsigned int pages) { return perf_evlist__mmap_ex(evlist, pages, 0, false, 0, PERF_AFFINITY_SYS, 1, 0); } -int perf_evlist__create_maps(struct perf_evlist *evlist, struct target *target) +int perf_evlist__create_maps(struct evlist *evlist, struct target *target) { bool all_threads = (target->per_thread && target->system_wide); - struct cpu_map *cpus; - struct thread_map *threads; + struct perf_cpu_map *cpus; + struct perf_thread_map *threads; /* * If specify '-a' and '--per-thread' to perf record, perf record @@ -1086,68 +1067,45 @@ int perf_evlist__create_maps(struct perf_evlist *evlist, struct target *target) return -1; if (target__uses_dummy_map(target)) - cpus = cpu_map__dummy_new(); + cpus = perf_cpu_map__dummy_new(); else - cpus = cpu_map__new(target->cpu_list); + cpus = perf_cpu_map__new(target->cpu_list); if (!cpus) goto out_delete_threads; - evlist->has_user_cpus = !!target->cpu_list; + evlist->core.has_user_cpus = !!target->cpu_list; - perf_evlist__set_maps(evlist, cpus, threads); + perf_evlist__set_maps(&evlist->core, cpus, threads); return 0; out_delete_threads: - thread_map__put(threads); + perf_thread_map__put(threads); return -1; } -void perf_evlist__set_maps(struct perf_evlist *evlist, struct cpu_map *cpus, - struct 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) { - cpu_map__put(evlist->cpus); - evlist->cpus = cpu_map__get(cpus); - } - - if (threads != evlist->threads) { - thread_map__put(evlist->threads); - evlist->threads = thread_map__get(threads); - } - - perf_evlist__propagate_maps(evlist); -} - -void __perf_evlist__set_sample_bit(struct perf_evlist *evlist, +void __perf_evlist__set_sample_bit(struct evlist *evlist, enum perf_event_sample_format bit) { - struct perf_evsel *evsel; + struct evsel *evsel; evlist__for_each_entry(evlist, evsel) __perf_evsel__set_sample_bit(evsel, bit); } -void __perf_evlist__reset_sample_bit(struct perf_evlist *evlist, +void __perf_evlist__reset_sample_bit(struct evlist *evlist, enum perf_event_sample_format bit) { - struct perf_evsel *evsel; + struct evsel *evsel; evlist__for_each_entry(evlist, evsel) __perf_evsel__reset_sample_bit(evsel, bit); } -int perf_evlist__apply_filters(struct perf_evlist *evlist, struct perf_evsel **err_evsel) +int perf_evlist__apply_filters(struct evlist *evlist, struct evsel **err_evsel) { - struct perf_evsel *evsel; + struct evsel *evsel; int err = 0; evlist__for_each_entry(evlist, evsel) { @@ -1158,7 +1116,7 @@ int perf_evlist__apply_filters(struct perf_evlist *evlist, struct perf_evsel **e * filters only work for tracepoint event, which doesn't have cpu limit. * So evlist and evsel should always be same. */ - err = perf_evsel__apply_filter(evsel, evsel->filter); + err = perf_evsel__apply_filter(&evsel->core, evsel->filter); if (err) { *err_evsel = evsel; break; @@ -1168,13 +1126,13 @@ int perf_evlist__apply_filters(struct perf_evlist *evlist, struct perf_evsel **e return err; } -int perf_evlist__set_tp_filter(struct perf_evlist *evlist, const char *filter) +int perf_evlist__set_tp_filter(struct evlist *evlist, const char *filter) { - struct perf_evsel *evsel; + struct evsel *evsel; int err = 0; evlist__for_each_entry(evlist, evsel) { - if (evsel->attr.type != PERF_TYPE_TRACEPOINT) + if (evsel->core.attr.type != PERF_TYPE_TRACEPOINT) continue; err = perf_evsel__set_filter(evsel, filter); @@ -1185,7 +1143,7 @@ int perf_evlist__set_tp_filter(struct perf_evlist *evlist, const char *filter) return err; } -int perf_evlist__set_tp_filter_pids(struct perf_evlist *evlist, size_t npids, pid_t *pids) +int perf_evlist__set_tp_filter_pids(struct evlist *evlist, size_t npids, pid_t *pids) { char *filter; int ret = -1; @@ -1212,16 +1170,16 @@ out_free: return ret; } -int perf_evlist__set_tp_filter_pid(struct perf_evlist *evlist, pid_t pid) +int perf_evlist__set_tp_filter_pid(struct evlist *evlist, pid_t pid) { return perf_evlist__set_tp_filter_pids(evlist, 1, &pid); } -bool perf_evlist__valid_sample_type(struct perf_evlist *evlist) +bool perf_evlist__valid_sample_type(struct evlist *evlist) { - struct perf_evsel *pos; + struct evsel *pos; - if (evlist->nr_entries == 1) + if (evlist->core.nr_entries == 1) return true; if (evlist->id_pos < 0 || evlist->is_pos < 0) @@ -1236,43 +1194,43 @@ bool perf_evlist__valid_sample_type(struct perf_evlist *evlist) return true; } -u64 __perf_evlist__combined_sample_type(struct perf_evlist *evlist) +u64 __perf_evlist__combined_sample_type(struct evlist *evlist) { - struct perf_evsel *evsel; + struct evsel *evsel; if (evlist->combined_sample_type) return evlist->combined_sample_type; evlist__for_each_entry(evlist, evsel) - evlist->combined_sample_type |= evsel->attr.sample_type; + evlist->combined_sample_type |= evsel->core.attr.sample_type; return evlist->combined_sample_type; } -u64 perf_evlist__combined_sample_type(struct perf_evlist *evlist) +u64 perf_evlist__combined_sample_type(struct evlist *evlist) { evlist->combined_sample_type = 0; return __perf_evlist__combined_sample_type(evlist); } -u64 perf_evlist__combined_branch_type(struct perf_evlist *evlist) +u64 perf_evlist__combined_branch_type(struct evlist *evlist) { - struct perf_evsel *evsel; + struct evsel *evsel; u64 branch_type = 0; evlist__for_each_entry(evlist, evsel) - branch_type |= evsel->attr.branch_sample_type; + branch_type |= evsel->core.attr.branch_sample_type; return branch_type; } -bool perf_evlist__valid_read_format(struct perf_evlist *evlist) +bool perf_evlist__valid_read_format(struct evlist *evlist) { - struct perf_evsel *first = perf_evlist__first(evlist), *pos = first; - u64 read_format = first->attr.read_format; - u64 sample_type = first->attr.sample_type; + struct evsel *first = perf_evlist__first(evlist), *pos = first; + u64 read_format = first->core.attr.read_format; + u64 sample_type = first->core.attr.sample_type; evlist__for_each_entry(evlist, pos) { - if (read_format != pos->attr.read_format) + if (read_format != pos->core.attr.read_format) return false; } @@ -1285,23 +1243,23 @@ bool perf_evlist__valid_read_format(struct perf_evlist *evlist) return true; } -u64 perf_evlist__read_format(struct perf_evlist *evlist) +u64 perf_evlist__read_format(struct evlist *evlist) { - struct perf_evsel *first = perf_evlist__first(evlist); - return first->attr.read_format; + struct evsel *first = perf_evlist__first(evlist); + return first->core.attr.read_format; } -u16 perf_evlist__id_hdr_size(struct perf_evlist *evlist) +u16 perf_evlist__id_hdr_size(struct evlist *evlist) { - struct perf_evsel *first = perf_evlist__first(evlist); + struct evsel *first = perf_evlist__first(evlist); struct perf_sample *data; u64 sample_type; u16 size = 0; - if (!first->attr.sample_id_all) + if (!first->core.attr.sample_id_all) goto out; - sample_type = first->attr.sample_type; + sample_type = first->core.attr.sample_type; if (sample_type & PERF_SAMPLE_TID) size += sizeof(data->tid) * 2; @@ -1324,42 +1282,42 @@ out: return size; } -bool perf_evlist__valid_sample_id_all(struct perf_evlist *evlist) +bool perf_evlist__valid_sample_id_all(struct evlist *evlist) { - struct perf_evsel *first = perf_evlist__first(evlist), *pos = first; + struct evsel *first = perf_evlist__first(evlist), *pos = first; evlist__for_each_entry_continue(evlist, pos) { - if (first->attr.sample_id_all != pos->attr.sample_id_all) + if (first->core.attr.sample_id_all != pos->core.attr.sample_id_all) return false; } return true; } -bool perf_evlist__sample_id_all(struct perf_evlist *evlist) +bool perf_evlist__sample_id_all(struct evlist *evlist) { - struct perf_evsel *first = perf_evlist__first(evlist); - return first->attr.sample_id_all; + struct evsel *first = perf_evlist__first(evlist); + return first->core.attr.sample_id_all; } -void perf_evlist__set_selected(struct perf_evlist *evlist, - struct perf_evsel *evsel) +void perf_evlist__set_selected(struct evlist *evlist, + struct evsel *evsel) { evlist->selected = evsel; } -void perf_evlist__close(struct perf_evlist *evlist) +void evlist__close(struct evlist *evlist) { - struct perf_evsel *evsel; + struct evsel *evsel; evlist__for_each_entry_reverse(evlist, evsel) - perf_evsel__close(evsel); + evsel__close(evsel); } -static int perf_evlist__create_syswide_maps(struct perf_evlist *evlist) +static int perf_evlist__create_syswide_maps(struct evlist *evlist) { - struct cpu_map *cpus; - struct thread_map *threads; + struct perf_cpu_map *cpus; + struct perf_thread_map *threads; int err = -ENOMEM; /* @@ -1371,32 +1329,32 @@ static int perf_evlist__create_syswide_maps(struct perf_evlist *evlist) * error, and we may not want to do that fallback to a * default cpu identity map :-\ */ - cpus = cpu_map__new(NULL); + cpus = perf_cpu_map__new(NULL); if (!cpus) goto out; - threads = thread_map__new_dummy(); + threads = perf_thread_map__new_dummy(); if (!threads) goto out_put; - perf_evlist__set_maps(evlist, cpus, threads); + perf_evlist__set_maps(&evlist->core, cpus, threads); out: return err; out_put: - cpu_map__put(cpus); + perf_cpu_map__put(cpus); goto out; } -int perf_evlist__open(struct perf_evlist *evlist) +int evlist__open(struct evlist *evlist) { - struct perf_evsel *evsel; + struct evsel *evsel; int err; /* * Default: one fd per CPU, all threads, aka systemwide * as sys_perf_event_open(cpu = -1, thread = -1) is EINVAL */ - if (evlist->threads == NULL && evlist->cpus == NULL) { + if (evlist->core.threads == NULL && evlist->core.cpus == NULL) { err = perf_evlist__create_syswide_maps(evlist); if (err < 0) goto out_err; @@ -1405,19 +1363,19 @@ int perf_evlist__open(struct perf_evlist *evlist) perf_evlist__update_id_pos(evlist); evlist__for_each_entry(evlist, evsel) { - err = perf_evsel__open(evsel, evsel->cpus, evsel->threads); + err = evsel__open(evsel, evsel->core.cpus, evsel->core.threads); if (err < 0) goto out_err; } return 0; out_err: - perf_evlist__close(evlist); + evlist__close(evlist); errno = -err; return err; } -int perf_evlist__prepare_workload(struct perf_evlist *evlist, struct target *target, +int perf_evlist__prepare_workload(struct evlist *evlist, struct target *target, const char *argv[], bool pipe_output, void (*exec_error)(int signo, siginfo_t *info, void *ucontext)) { @@ -1499,12 +1457,12 @@ int perf_evlist__prepare_workload(struct perf_evlist *evlist, struct target *tar } if (target__none(target)) { - if (evlist->threads == NULL) { + if (evlist->core.threads == NULL) { fprintf(stderr, "FATAL: evlist->threads need to be set at this point (%s:%d).\n", __func__, __LINE__); goto out_close_pipes; } - thread_map__set_pid(evlist->threads, 0, evlist->workload.pid); + perf_thread_map__set_pid(evlist->core.threads, 0, evlist->workload.pid); } close(child_ready_pipe[1]); @@ -1531,7 +1489,7 @@ out_close_ready_pipe: return -1; } -int perf_evlist__start_workload(struct perf_evlist *evlist) +int perf_evlist__start_workload(struct evlist *evlist) { if (evlist->workload.cork_fd > 0) { char bf = 0; @@ -1550,30 +1508,30 @@ int perf_evlist__start_workload(struct perf_evlist *evlist) return 0; } -int perf_evlist__parse_sample(struct perf_evlist *evlist, union perf_event *event, +int perf_evlist__parse_sample(struct evlist *evlist, union perf_event *event, struct perf_sample *sample) { - struct perf_evsel *evsel = perf_evlist__event2evsel(evlist, event); + struct evsel *evsel = perf_evlist__event2evsel(evlist, event); if (!evsel) return -EFAULT; return perf_evsel__parse_sample(evsel, event, sample); } -int perf_evlist__parse_sample_timestamp(struct perf_evlist *evlist, +int perf_evlist__parse_sample_timestamp(struct evlist *evlist, union perf_event *event, u64 *timestamp) { - struct perf_evsel *evsel = perf_evlist__event2evsel(evlist, event); + struct evsel *evsel = perf_evlist__event2evsel(evlist, event); if (!evsel) return -EFAULT; return perf_evsel__parse_sample_timestamp(evsel, event, timestamp); } -size_t perf_evlist__fprintf(struct perf_evlist *evlist, FILE *fp) +size_t perf_evlist__fprintf(struct evlist *evlist, FILE *fp) { - struct perf_evsel *evsel; + struct evsel *evsel; size_t printed = 0; evlist__for_each_entry(evlist, evsel) { @@ -1584,7 +1542,7 @@ size_t perf_evlist__fprintf(struct perf_evlist *evlist, FILE *fp) return printed + fprintf(fp, "\n"); } -int perf_evlist__strerror_open(struct perf_evlist *evlist, +int perf_evlist__strerror_open(struct evlist *evlist, int err, char *buf, size_t size) { int printed, value; @@ -1613,20 +1571,20 @@ int perf_evlist__strerror_open(struct perf_evlist *evlist, "Hint:\tThe current value is %d.", value); break; case EINVAL: { - struct perf_evsel *first = perf_evlist__first(evlist); + struct evsel *first = perf_evlist__first(evlist); int max_freq; if (sysctl__read_int("kernel/perf_event_max_sample_rate", &max_freq) < 0) goto out_default; - if (first->attr.sample_freq < (u64)max_freq) + if (first->core.attr.sample_freq < (u64)max_freq) goto out_default; printed = scnprintf(buf, size, "Error:\t%s.\n" "Hint:\tCheck /proc/sys/kernel/perf_event_max_sample_rate.\n" "Hint:\tThe current value is %d and %" PRIu64 " is being requested.", - emsg, max_freq, first->attr.sample_freq); + emsg, max_freq, first->core.attr.sample_freq); break; } default: @@ -1638,7 +1596,7 @@ out_default: return 0; } -int perf_evlist__strerror_mmap(struct perf_evlist *evlist, int err, char *buf, size_t size) +int perf_evlist__strerror_mmap(struct evlist *evlist, int err, char *buf, size_t size) { char sbuf[STRERR_BUFSIZE], *emsg = str_error_r(err, sbuf, sizeof(sbuf)); int pages_attempted = evlist->mmap_len / 1024, pages_max_per_user, printed = 0; @@ -1669,10 +1627,10 @@ int perf_evlist__strerror_mmap(struct perf_evlist *evlist, int err, char *buf, s return 0; } -void perf_evlist__to_front(struct perf_evlist *evlist, - struct perf_evsel *move_evsel) +void perf_evlist__to_front(struct evlist *evlist, + struct evsel *move_evsel) { - struct perf_evsel *evsel, *n; + struct evsel *evsel, *n; LIST_HEAD(move); if (move_evsel == perf_evlist__first(evlist)) @@ -1680,16 +1638,16 @@ void perf_evlist__to_front(struct perf_evlist *evlist, evlist__for_each_entry_safe(evlist, n, evsel) { if (evsel->leader == move_evsel->leader) - list_move_tail(&evsel->node, &move); + list_move_tail(&evsel->core.node, &move); } - list_splice(&move, &evlist->entries); + list_splice(&move, &evlist->core.entries); } -void perf_evlist__set_tracking_event(struct perf_evlist *evlist, - struct perf_evsel *tracking_evsel) +void perf_evlist__set_tracking_event(struct evlist *evlist, + struct evsel *tracking_evsel) { - struct perf_evsel *evsel; + struct evsel *evsel; if (tracking_evsel->tracking) return; @@ -1702,11 +1660,11 @@ void perf_evlist__set_tracking_event(struct perf_evlist *evlist, tracking_evsel->tracking = true; } -struct perf_evsel * -perf_evlist__find_evsel_by_str(struct perf_evlist *evlist, +struct evsel * +perf_evlist__find_evsel_by_str(struct evlist *evlist, const char *str) { - struct perf_evsel *evsel; + struct evsel *evsel; evlist__for_each_entry(evlist, evsel) { if (!evsel->name) @@ -1718,7 +1676,7 @@ perf_evlist__find_evsel_by_str(struct perf_evlist *evlist, return NULL; } -void perf_evlist__toggle_bkw_mmap(struct perf_evlist *evlist, +void perf_evlist__toggle_bkw_mmap(struct evlist *evlist, enum bkw_mmap_state state) { enum bkw_mmap_state old_state = evlist->bkw_mmap_state; @@ -1776,12 +1734,12 @@ state_err: return; } -bool perf_evlist__exclude_kernel(struct perf_evlist *evlist) +bool perf_evlist__exclude_kernel(struct evlist *evlist) { - struct perf_evsel *evsel; + struct evsel *evsel; evlist__for_each_entry(evlist, evsel) { - if (!evsel->attr.exclude_kernel) + if (!evsel->core.attr.exclude_kernel) return false; } @@ -1793,25 +1751,25 @@ bool perf_evlist__exclude_kernel(struct perf_evlist *evlist) * the group display. Set the artificial group and set the leader's * forced_leader flag to notify the display code. */ -void perf_evlist__force_leader(struct perf_evlist *evlist) +void perf_evlist__force_leader(struct evlist *evlist) { if (!evlist->nr_groups) { - struct perf_evsel *leader = perf_evlist__first(evlist); + struct evsel *leader = perf_evlist__first(evlist); perf_evlist__set_leader(evlist); leader->forced_leader = true; } } -struct perf_evsel *perf_evlist__reset_weak_group(struct perf_evlist *evsel_list, - struct perf_evsel *evsel) +struct evsel *perf_evlist__reset_weak_group(struct evlist *evsel_list, + struct evsel *evsel) { - struct perf_evsel *c2, *leader; + struct evsel *c2, *leader; bool is_open = true; leader = evsel->leader; pr_debug("Weak group for %s/%d failed\n", - leader->name, leader->nr_members); + leader->name, leader->core.nr_members); /* * for_each_group_member doesn't work here because it doesn't @@ -1822,24 +1780,24 @@ struct perf_evsel *perf_evlist__reset_weak_group(struct perf_evlist *evsel_list, is_open = false; if (c2->leader == leader) { if (is_open) - perf_evsel__close(c2); + evsel__close(c2); c2->leader = c2; - c2->nr_members = 0; + c2->core.nr_members = 0; } } return leader; } -int perf_evlist__add_sb_event(struct perf_evlist **evlist, +int perf_evlist__add_sb_event(struct evlist **evlist, struct perf_event_attr *attr, perf_evsel__sb_cb_t cb, void *data) { - struct perf_evsel *evsel; + struct evsel *evsel; bool new_evlist = (*evlist) == NULL; if (*evlist == NULL) - *evlist = perf_evlist__new(); + *evlist = evlist__new(); if (*evlist == NULL) return -1; @@ -1848,18 +1806,18 @@ int perf_evlist__add_sb_event(struct perf_evlist **evlist, attr->sample_id_all = 1; } - evsel = perf_evsel__new_idx(attr, (*evlist)->nr_entries); + evsel = perf_evsel__new_idx(attr, (*evlist)->core.nr_entries); if (!evsel) goto out_err; evsel->side_band.cb = cb; evsel->side_band.data = data; - perf_evlist__add(*evlist, evsel); + evlist__add(*evlist, evsel); return 0; out_err: if (new_evlist) { - perf_evlist__delete(*evlist); + evlist__delete(*evlist); *evlist = NULL; } return -1; @@ -1867,9 +1825,17 @@ out_err: static void *perf_evlist__poll_thread(void *arg) { - struct perf_evlist *evlist = arg; + struct evlist *evlist = arg; bool draining = false; int i, done = 0; + /* + * In order to read symbols from other namespaces perf to needs to call + * setns(2). This isn't permitted if the struct_fs has multiple users. + * unshare(2) the fs so that we may continue to setns into namespaces + * that we're observing when, for instance, reading the build-ids at + * the end of a 'perf record' session. + */ + unshare(CLONE_FS); while (!done) { bool got_data = false; @@ -1887,7 +1853,7 @@ static void *perf_evlist__poll_thread(void *arg) if (perf_mmap__read_init(map)) continue; while ((event = perf_mmap__read_event(map)) != NULL) { - struct perf_evsel *evsel = perf_evlist__event2evsel(evlist, event); + struct evsel *evsel = perf_evlist__event2evsel(evlist, event); if (evsel && evsel->side_band.cb) evsel->side_band.cb(event, evsel->side_band.data); @@ -1906,10 +1872,10 @@ static void *perf_evlist__poll_thread(void *arg) return NULL; } -int perf_evlist__start_sb_thread(struct perf_evlist *evlist, +int perf_evlist__start_sb_thread(struct evlist *evlist, struct target *target) { - struct perf_evsel *counter; + struct evsel *counter; if (!evlist) return 0; @@ -1918,8 +1884,8 @@ int perf_evlist__start_sb_thread(struct perf_evlist *evlist, goto out_delete_evlist; evlist__for_each_entry(evlist, counter) { - if (perf_evsel__open(counter, evlist->cpus, - evlist->threads) < 0) + if (evsel__open(counter, evlist->core.cpus, + evlist->core.threads) < 0) goto out_delete_evlist; } @@ -1927,7 +1893,7 @@ int perf_evlist__start_sb_thread(struct perf_evlist *evlist, goto out_delete_evlist; evlist__for_each_entry(evlist, counter) { - if (perf_evsel__enable(counter)) + if (evsel__enable(counter)) goto out_delete_evlist; } @@ -1938,16 +1904,16 @@ int perf_evlist__start_sb_thread(struct perf_evlist *evlist, return 0; out_delete_evlist: - perf_evlist__delete(evlist); + evlist__delete(evlist); evlist = NULL; return -1; } -void perf_evlist__stop_sb_thread(struct perf_evlist *evlist) +void perf_evlist__stop_sb_thread(struct evlist *evlist) { if (!evlist) return; evlist->thread.done = 1; pthread_join(evlist->thread.th, NULL); - perf_evlist__delete(evlist); + evlist__delete(evlist); } diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index 49354fe24d5f..a55f0f2546e5 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h @@ -8,30 +8,27 @@ #include <linux/list.h> #include <api/fd/array.h> #include <stdio.h> -#include "../perf.h" -#include "event.h" +#include <internal/evlist.h> +#include "events_stats.h" #include "evsel.h" #include "mmap.h" -#include "util.h" #include <signal.h> #include <unistd.h> struct pollfd; struct thread_map; -struct cpu_map; +struct perf_cpu_map; struct record_opts; #define PERF_EVLIST__HLIST_BITS 8 #define PERF_EVLIST__HLIST_SIZE (1 << PERF_EVLIST__HLIST_BITS) -struct perf_evlist { - struct list_head entries; +struct evlist { + struct perf_evlist core; struct hlist_head heads[PERF_EVLIST__HLIST_SIZE]; - int nr_entries; int nr_groups; int nr_mmaps; bool enabled; - bool has_user_cpus; size_t mmap_len; int id_pos; int is_pos; @@ -44,12 +41,10 @@ struct perf_evlist { struct fdarray pollfd; struct perf_mmap *mmap; struct perf_mmap *overwrite_mmap; - struct thread_map *threads; - struct cpu_map *cpus; - struct perf_evsel *selected; + struct evsel *selected; struct events_stats stats; struct perf_env *env; - void (*trace_event_sample_raw)(struct perf_evlist *evlist, + void (*trace_event_sample_raw)(struct evlist *evlist, union perf_event *event, struct perf_sample *sample); u64 first_sample_time; @@ -60,51 +55,51 @@ struct perf_evlist { } thread; }; -struct perf_evsel_str_handler { +struct evsel_str_handler { const char *name; void *handler; }; -struct perf_evlist *perf_evlist__new(void); -struct perf_evlist *perf_evlist__new_default(void); -struct perf_evlist *perf_evlist__new_dummy(void); -void perf_evlist__init(struct perf_evlist *evlist, struct cpu_map *cpus, - struct thread_map *threads); -void perf_evlist__exit(struct perf_evlist *evlist); -void perf_evlist__delete(struct perf_evlist *evlist); +struct evlist *evlist__new(void); +struct evlist *perf_evlist__new_default(void); +struct evlist *perf_evlist__new_dummy(void); +void evlist__init(struct evlist *evlist, struct perf_cpu_map *cpus, + struct perf_thread_map *threads); +void perf_evlist__exit(struct evlist *evlist); +void evlist__delete(struct evlist *evlist); -void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry); -void perf_evlist__remove(struct perf_evlist *evlist, struct perf_evsel *evsel); +void evlist__add(struct evlist *evlist, struct evsel *entry); +void evlist__remove(struct evlist *evlist, struct evsel *evsel); -int __perf_evlist__add_default(struct perf_evlist *evlist, bool precise); +int __perf_evlist__add_default(struct evlist *evlist, bool precise); -static inline int perf_evlist__add_default(struct perf_evlist *evlist) +static inline int perf_evlist__add_default(struct evlist *evlist) { return __perf_evlist__add_default(evlist, true); } -int __perf_evlist__add_default_attrs(struct perf_evlist *evlist, +int __perf_evlist__add_default_attrs(struct evlist *evlist, struct perf_event_attr *attrs, size_t nr_attrs); #define perf_evlist__add_default_attrs(evlist, array) \ __perf_evlist__add_default_attrs(evlist, array, ARRAY_SIZE(array)) -int perf_evlist__add_dummy(struct perf_evlist *evlist); +int perf_evlist__add_dummy(struct evlist *evlist); -int perf_evlist__add_sb_event(struct perf_evlist **evlist, +int perf_evlist__add_sb_event(struct evlist **evlist, struct perf_event_attr *attr, perf_evsel__sb_cb_t cb, void *data); -int perf_evlist__start_sb_thread(struct perf_evlist *evlist, +int perf_evlist__start_sb_thread(struct evlist *evlist, struct target *target); -void perf_evlist__stop_sb_thread(struct perf_evlist *evlist); +void perf_evlist__stop_sb_thread(struct evlist *evlist); -int perf_evlist__add_newtp(struct perf_evlist *evlist, +int perf_evlist__add_newtp(struct evlist *evlist, const char *sys, const char *name, void *handler); -void __perf_evlist__set_sample_bit(struct perf_evlist *evlist, +void __perf_evlist__set_sample_bit(struct evlist *evlist, enum perf_event_sample_format bit); -void __perf_evlist__reset_sample_bit(struct perf_evlist *evlist, +void __perf_evlist__reset_sample_bit(struct evlist *evlist, enum perf_event_sample_format bit); #define perf_evlist__set_sample_bit(evlist, bit) \ @@ -113,58 +108,58 @@ void __perf_evlist__reset_sample_bit(struct perf_evlist *evlist, #define perf_evlist__reset_sample_bit(evlist, bit) \ __perf_evlist__reset_sample_bit(evlist, PERF_SAMPLE_##bit) -int perf_evlist__set_tp_filter(struct perf_evlist *evlist, const char *filter); -int perf_evlist__set_tp_filter_pid(struct perf_evlist *evlist, pid_t pid); -int perf_evlist__set_tp_filter_pids(struct perf_evlist *evlist, size_t npids, pid_t *pids); +int perf_evlist__set_tp_filter(struct evlist *evlist, const char *filter); +int perf_evlist__set_tp_filter_pid(struct evlist *evlist, pid_t pid); +int perf_evlist__set_tp_filter_pids(struct evlist *evlist, size_t npids, pid_t *pids); -struct perf_evsel * -perf_evlist__find_tracepoint_by_id(struct perf_evlist *evlist, int id); +struct evsel * +perf_evlist__find_tracepoint_by_id(struct evlist *evlist, int id); -struct perf_evsel * -perf_evlist__find_tracepoint_by_name(struct perf_evlist *evlist, +struct evsel * +perf_evlist__find_tracepoint_by_name(struct evlist *evlist, const char *name); -void perf_evlist__id_add(struct perf_evlist *evlist, struct perf_evsel *evsel, +void perf_evlist__id_add(struct evlist *evlist, struct evsel *evsel, int cpu, int thread, u64 id); -int perf_evlist__id_add_fd(struct perf_evlist *evlist, - struct perf_evsel *evsel, +int perf_evlist__id_add_fd(struct evlist *evlist, + struct evsel *evsel, int cpu, int thread, int fd); -int perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd); -int perf_evlist__alloc_pollfd(struct perf_evlist *evlist); -int perf_evlist__filter_pollfd(struct perf_evlist *evlist, short revents_and_mask); +int perf_evlist__add_pollfd(struct evlist *evlist, int fd); +int perf_evlist__alloc_pollfd(struct evlist *evlist); +int perf_evlist__filter_pollfd(struct evlist *evlist, short revents_and_mask); -int perf_evlist__poll(struct perf_evlist *evlist, int timeout); +int perf_evlist__poll(struct evlist *evlist, int timeout); -struct perf_evsel *perf_evlist__id2evsel(struct perf_evlist *evlist, u64 id); -struct perf_evsel *perf_evlist__id2evsel_strict(struct perf_evlist *evlist, +struct evsel *perf_evlist__id2evsel(struct evlist *evlist, u64 id); +struct evsel *perf_evlist__id2evsel_strict(struct evlist *evlist, u64 id); -struct perf_sample_id *perf_evlist__id2sid(struct perf_evlist *evlist, u64 id); +struct perf_sample_id *perf_evlist__id2sid(struct evlist *evlist, u64 id); -void perf_evlist__toggle_bkw_mmap(struct perf_evlist *evlist, enum bkw_mmap_state state); +void perf_evlist__toggle_bkw_mmap(struct evlist *evlist, enum bkw_mmap_state state); -void perf_evlist__mmap_consume(struct perf_evlist *evlist, int idx); +void perf_evlist__mmap_consume(struct evlist *evlist, int idx); -int perf_evlist__open(struct perf_evlist *evlist); -void perf_evlist__close(struct perf_evlist *evlist); +int evlist__open(struct evlist *evlist); +void evlist__close(struct evlist *evlist); struct callchain_param; -void perf_evlist__set_id_pos(struct perf_evlist *evlist); +void perf_evlist__set_id_pos(struct evlist *evlist); bool perf_can_sample_identifier(void); bool perf_can_record_switch_events(void); bool perf_can_record_cpu_wide(void); -void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts, +void perf_evlist__config(struct evlist *evlist, struct record_opts *opts, struct callchain_param *callchain); int record_opts__config(struct record_opts *opts); -int perf_evlist__prepare_workload(struct perf_evlist *evlist, +int perf_evlist__prepare_workload(struct evlist *evlist, struct target *target, const char *argv[], bool pipe_output, void (*exec_error)(int signo, siginfo_t *info, void *ucontext)); -int perf_evlist__start_workload(struct perf_evlist *evlist); +int perf_evlist__start_workload(struct evlist *evlist); struct option; @@ -175,77 +170,75 @@ int perf_evlist__parse_mmap_pages(const struct option *opt, unsigned long perf_event_mlock_kb_in_pages(void); -int perf_evlist__mmap_ex(struct perf_evlist *evlist, unsigned int pages, +int perf_evlist__mmap_ex(struct evlist *evlist, unsigned int pages, unsigned int auxtrace_pages, bool auxtrace_overwrite, int nr_cblocks, int affinity, int flush, int comp_level); -int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages); -void perf_evlist__munmap(struct perf_evlist *evlist); +int perf_evlist__mmap(struct evlist *evlist, unsigned int pages); +void perf_evlist__munmap(struct evlist *evlist); size_t perf_evlist__mmap_size(unsigned long pages); -void perf_evlist__disable(struct perf_evlist *evlist); -void perf_evlist__enable(struct perf_evlist *evlist); -void perf_evlist__toggle_enable(struct perf_evlist *evlist); +void evlist__disable(struct evlist *evlist); +void evlist__enable(struct evlist *evlist); +void perf_evlist__toggle_enable(struct evlist *evlist); -int perf_evlist__enable_event_idx(struct perf_evlist *evlist, - struct perf_evsel *evsel, int idx); +int perf_evlist__enable_event_idx(struct evlist *evlist, + struct evsel *evsel, int idx); -void perf_evlist__set_selected(struct perf_evlist *evlist, - struct perf_evsel *evsel); +void perf_evlist__set_selected(struct evlist *evlist, + struct evsel *evsel); -void perf_evlist__set_maps(struct perf_evlist *evlist, struct cpu_map *cpus, - struct thread_map *threads); -int perf_evlist__create_maps(struct perf_evlist *evlist, struct target *target); -int perf_evlist__apply_filters(struct perf_evlist *evlist, struct perf_evsel **err_evsel); +int perf_evlist__create_maps(struct evlist *evlist, struct target *target); +int perf_evlist__apply_filters(struct evlist *evlist, struct evsel **err_evsel); void __perf_evlist__set_leader(struct list_head *list); -void perf_evlist__set_leader(struct perf_evlist *evlist); +void perf_evlist__set_leader(struct evlist *evlist); -u64 perf_evlist__read_format(struct perf_evlist *evlist); -u64 __perf_evlist__combined_sample_type(struct perf_evlist *evlist); -u64 perf_evlist__combined_sample_type(struct perf_evlist *evlist); -u64 perf_evlist__combined_branch_type(struct perf_evlist *evlist); -bool perf_evlist__sample_id_all(struct perf_evlist *evlist); -u16 perf_evlist__id_hdr_size(struct perf_evlist *evlist); +u64 perf_evlist__read_format(struct evlist *evlist); +u64 __perf_evlist__combined_sample_type(struct evlist *evlist); +u64 perf_evlist__combined_sample_type(struct evlist *evlist); +u64 perf_evlist__combined_branch_type(struct evlist *evlist); +bool perf_evlist__sample_id_all(struct evlist *evlist); +u16 perf_evlist__id_hdr_size(struct evlist *evlist); -int perf_evlist__parse_sample(struct perf_evlist *evlist, union perf_event *event, +int perf_evlist__parse_sample(struct evlist *evlist, union perf_event *event, struct perf_sample *sample); -int perf_evlist__parse_sample_timestamp(struct perf_evlist *evlist, +int perf_evlist__parse_sample_timestamp(struct evlist *evlist, union perf_event *event, u64 *timestamp); -bool perf_evlist__valid_sample_type(struct perf_evlist *evlist); -bool perf_evlist__valid_sample_id_all(struct perf_evlist *evlist); -bool perf_evlist__valid_read_format(struct perf_evlist *evlist); +bool perf_evlist__valid_sample_type(struct evlist *evlist); +bool perf_evlist__valid_sample_id_all(struct evlist *evlist); +bool perf_evlist__valid_read_format(struct evlist *evlist); -void perf_evlist__splice_list_tail(struct perf_evlist *evlist, +void perf_evlist__splice_list_tail(struct evlist *evlist, struct list_head *list); -static inline bool perf_evlist__empty(struct perf_evlist *evlist) +static inline bool perf_evlist__empty(struct evlist *evlist) { - return list_empty(&evlist->entries); + return list_empty(&evlist->core.entries); } -static inline struct perf_evsel *perf_evlist__first(struct perf_evlist *evlist) +static inline struct evsel *perf_evlist__first(struct evlist *evlist) { - return list_entry(evlist->entries.next, struct perf_evsel, node); + return list_entry(evlist->core.entries.next, struct evsel, core.node); } -static inline struct perf_evsel *perf_evlist__last(struct perf_evlist *evlist) +static inline struct evsel *perf_evlist__last(struct evlist *evlist) { - return list_entry(evlist->entries.prev, struct perf_evsel, node); + return list_entry(evlist->core.entries.prev, struct evsel, core.node); } -size_t perf_evlist__fprintf(struct perf_evlist *evlist, FILE *fp); +size_t perf_evlist__fprintf(struct evlist *evlist, FILE *fp); -int perf_evlist__strerror_open(struct perf_evlist *evlist, int err, char *buf, size_t size); -int perf_evlist__strerror_mmap(struct perf_evlist *evlist, int err, char *buf, size_t size); +int perf_evlist__strerror_open(struct evlist *evlist, int err, char *buf, size_t size); +int perf_evlist__strerror_mmap(struct evlist *evlist, int err, char *buf, size_t size); -bool perf_evlist__can_select_event(struct perf_evlist *evlist, const char *str); -void perf_evlist__to_front(struct perf_evlist *evlist, - struct perf_evsel *move_evsel); +bool perf_evlist__can_select_event(struct evlist *evlist, const char *str); +void perf_evlist__to_front(struct evlist *evlist, + struct evsel *move_evsel); /** * __evlist__for_each_entry - iterate thru all the evsels @@ -253,7 +246,7 @@ void perf_evlist__to_front(struct perf_evlist *evlist, * @evsel: struct evsel iterator */ #define __evlist__for_each_entry(list, evsel) \ - list_for_each_entry(evsel, list, node) + list_for_each_entry(evsel, list, core.node) /** * evlist__for_each_entry - iterate thru all the evsels @@ -261,7 +254,7 @@ void perf_evlist__to_front(struct perf_evlist *evlist, * @evsel: struct evsel iterator */ #define evlist__for_each_entry(evlist, evsel) \ - __evlist__for_each_entry(&(evlist)->entries, evsel) + __evlist__for_each_entry(&(evlist)->core.entries, evsel) /** * __evlist__for_each_entry_continue - continue iteration thru all the evsels @@ -269,7 +262,7 @@ void perf_evlist__to_front(struct perf_evlist *evlist, * @evsel: struct evsel iterator */ #define __evlist__for_each_entry_continue(list, evsel) \ - list_for_each_entry_continue(evsel, list, node) + list_for_each_entry_continue(evsel, list, core.node) /** * evlist__for_each_entry_continue - continue iteration thru all the evsels @@ -277,7 +270,7 @@ void perf_evlist__to_front(struct perf_evlist *evlist, * @evsel: struct evsel iterator */ #define evlist__for_each_entry_continue(evlist, evsel) \ - __evlist__for_each_entry_continue(&(evlist)->entries, evsel) + __evlist__for_each_entry_continue(&(evlist)->core.entries, evsel) /** * __evlist__for_each_entry_reverse - iterate thru all the evsels in reverse order @@ -285,7 +278,7 @@ void perf_evlist__to_front(struct perf_evlist *evlist, * @evsel: struct evsel iterator */ #define __evlist__for_each_entry_reverse(list, evsel) \ - list_for_each_entry_reverse(evsel, list, node) + list_for_each_entry_reverse(evsel, list, core.node) /** * evlist__for_each_entry_reverse - iterate thru all the evsels in reverse order @@ -293,7 +286,7 @@ void perf_evlist__to_front(struct perf_evlist *evlist, * @evsel: struct evsel iterator */ #define evlist__for_each_entry_reverse(evlist, evsel) \ - __evlist__for_each_entry_reverse(&(evlist)->entries, evsel) + __evlist__for_each_entry_reverse(&(evlist)->core.entries, evsel) /** * __evlist__for_each_entry_safe - safely iterate thru all the evsels @@ -302,7 +295,7 @@ void perf_evlist__to_front(struct perf_evlist *evlist, * @evsel: struct evsel iterator */ #define __evlist__for_each_entry_safe(list, tmp, evsel) \ - list_for_each_entry_safe(evsel, tmp, list, node) + list_for_each_entry_safe(evsel, tmp, list, core.node) /** * evlist__for_each_entry_safe - safely iterate thru all the evsels @@ -311,21 +304,21 @@ void perf_evlist__to_front(struct perf_evlist *evlist, * @tmp: struct evsel temp iterator */ #define evlist__for_each_entry_safe(evlist, tmp, evsel) \ - __evlist__for_each_entry_safe(&(evlist)->entries, tmp, evsel) + __evlist__for_each_entry_safe(&(evlist)->core.entries, tmp, evsel) -void perf_evlist__set_tracking_event(struct perf_evlist *evlist, - struct perf_evsel *tracking_evsel); +void perf_evlist__set_tracking_event(struct evlist *evlist, + struct evsel *tracking_evsel); -struct perf_evsel * -perf_evlist__find_evsel_by_str(struct perf_evlist *evlist, const char *str); +struct evsel * +perf_evlist__find_evsel_by_str(struct evlist *evlist, const char *str); -struct perf_evsel *perf_evlist__event2evsel(struct perf_evlist *evlist, +struct evsel *perf_evlist__event2evsel(struct evlist *evlist, union perf_event *event); -bool perf_evlist__exclude_kernel(struct perf_evlist *evlist); +bool perf_evlist__exclude_kernel(struct evlist *evlist); -void perf_evlist__force_leader(struct perf_evlist *evlist); +void perf_evlist__force_leader(struct evlist *evlist); -struct perf_evsel *perf_evlist__reset_weak_group(struct perf_evlist *evlist, - struct perf_evsel *evsel); +struct evsel *perf_evlist__reset_weak_group(struct evlist *evlist, + struct evsel *evsel); #endif /* __PERF_EVLIST_H */ diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 52459dd5ad0c..85825384f9e8 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -22,9 +22,12 @@ #include <sys/resource.h> #include <sys/types.h> #include <dirent.h> +#include <stdlib.h> +#include <perf/evsel.h> #include "asm/bug.h" #include "callchain.h" #include "cgroup.h" +#include "counts.h" #include "event.h" #include "evsel.h" #include "evlist.h" @@ -32,12 +35,16 @@ #include "thread_map.h" #include "target.h" #include "perf_regs.h" +#include "record.h" #include "debug.h" #include "trace-event.h" #include "stat.h" #include "string2.h" #include "memswap.h" +#include "util.h" +#include "../perf-sys.h" #include "util/parse-branch-options.h" +#include <internal/xyarray.h> #include <linux/ctype.h> @@ -45,30 +52,30 @@ struct perf_missing_features perf_missing_features; static clockid_t clockid; -static int perf_evsel__no_extra_init(struct perf_evsel *evsel __maybe_unused) +static int perf_evsel__no_extra_init(struct evsel *evsel __maybe_unused) { return 0; } void __weak test_attr__ready(void) { } -static void perf_evsel__no_extra_fini(struct perf_evsel *evsel __maybe_unused) +static void perf_evsel__no_extra_fini(struct evsel *evsel __maybe_unused) { } static struct { size_t size; - int (*init)(struct perf_evsel *evsel); - void (*fini)(struct perf_evsel *evsel); + int (*init)(struct evsel *evsel); + void (*fini)(struct evsel *evsel); } perf_evsel__object = { - .size = sizeof(struct perf_evsel), + .size = sizeof(struct evsel), .init = perf_evsel__no_extra_init, .fini = perf_evsel__no_extra_fini, }; int perf_evsel__object_config(size_t object_size, - int (*init)(struct perf_evsel *evsel), - void (*fini)(struct perf_evsel *evsel)) + int (*init)(struct evsel *evsel), + void (*fini)(struct evsel *evsel)) { if (object_size == 0) @@ -89,7 +96,7 @@ set_methods: return 0; } -#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) +#define FD(e, x, y) (*(int *)xyarray__entry(e->core.fd, x, y)) int __perf_evsel__sample_size(u64 sample_type) { @@ -113,7 +120,7 @@ int __perf_evsel__sample_size(u64 sample_type) * * This function returns the position of the event id (PERF_SAMPLE_ID or * PERF_SAMPLE_IDENTIFIER) in a sample event i.e. in the array of struct - * sample_event. + * perf_record_sample. */ static int __perf_evsel__calc_id_pos(u64 sample_type) { @@ -167,33 +174,33 @@ static int __perf_evsel__calc_is_pos(u64 sample_type) return idx; } -void perf_evsel__calc_id_pos(struct perf_evsel *evsel) +void perf_evsel__calc_id_pos(struct evsel *evsel) { - evsel->id_pos = __perf_evsel__calc_id_pos(evsel->attr.sample_type); - evsel->is_pos = __perf_evsel__calc_is_pos(evsel->attr.sample_type); + evsel->id_pos = __perf_evsel__calc_id_pos(evsel->core.attr.sample_type); + evsel->is_pos = __perf_evsel__calc_is_pos(evsel->core.attr.sample_type); } -void __perf_evsel__set_sample_bit(struct perf_evsel *evsel, +void __perf_evsel__set_sample_bit(struct evsel *evsel, enum perf_event_sample_format bit) { - if (!(evsel->attr.sample_type & bit)) { - evsel->attr.sample_type |= bit; + if (!(evsel->core.attr.sample_type & bit)) { + evsel->core.attr.sample_type |= bit; evsel->sample_size += sizeof(u64); perf_evsel__calc_id_pos(evsel); } } -void __perf_evsel__reset_sample_bit(struct perf_evsel *evsel, +void __perf_evsel__reset_sample_bit(struct evsel *evsel, enum perf_event_sample_format bit) { - if (evsel->attr.sample_type & bit) { - evsel->attr.sample_type &= ~bit; + if (evsel->core.attr.sample_type & bit) { + evsel->core.attr.sample_type &= ~bit; evsel->sample_size -= sizeof(u64); perf_evsel__calc_id_pos(evsel); } } -void perf_evsel__set_sample_id(struct perf_evsel *evsel, +void perf_evsel__set_sample_id(struct evsel *evsel, bool can_sample_identifier) { if (can_sample_identifier) { @@ -202,7 +209,7 @@ void perf_evsel__set_sample_id(struct perf_evsel *evsel, } else { perf_evsel__set_sample_bit(evsel, ID); } - evsel->attr.read_format |= PERF_FORMAT_ID; + evsel->core.attr.read_format |= PERF_FORMAT_ID; } /** @@ -213,7 +220,7 @@ void perf_evsel__set_sample_id(struct perf_evsel *evsel, * * Return %true if event is function trace event */ -bool perf_evsel__is_function_event(struct perf_evsel *evsel) +bool perf_evsel__is_function_event(struct evsel *evsel) { #define FUNCTION_EVENT "ftrace:function" @@ -223,19 +230,19 @@ bool perf_evsel__is_function_event(struct perf_evsel *evsel) #undef FUNCTION_EVENT } -void perf_evsel__init(struct perf_evsel *evsel, - struct perf_event_attr *attr, int idx) +void evsel__init(struct evsel *evsel, + struct perf_event_attr *attr, int idx) { + perf_evsel__init(&evsel->core, attr); evsel->idx = idx; evsel->tracking = !idx; - evsel->attr = *attr; evsel->leader = evsel; evsel->unit = ""; evsel->scale = 1.0; evsel->max_events = ULONG_MAX; evsel->evlist = NULL; + evsel->bpf_obj = NULL; evsel->bpf_fd = -1; - INIT_LIST_HEAD(&evsel->node); INIT_LIST_HEAD(&evsel->config_terms); perf_evsel__object.init(evsel); evsel->sample_size = __perf_evsel__sample_size(attr->sample_type); @@ -248,18 +255,18 @@ void perf_evsel__init(struct perf_evsel *evsel, evsel->pmu_name = NULL; } -struct perf_evsel *perf_evsel__new_idx(struct perf_event_attr *attr, int idx) +struct evsel *perf_evsel__new_idx(struct perf_event_attr *attr, int idx) { - struct perf_evsel *evsel = zalloc(perf_evsel__object.size); + struct evsel *evsel = zalloc(perf_evsel__object.size); if (!evsel) return NULL; - perf_evsel__init(evsel, attr, idx); + evsel__init(evsel, attr, idx); if (perf_evsel__is_bpf_output(evsel)) { - evsel->attr.sample_type |= (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | + evsel->core.attr.sample_type |= (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD), - evsel->attr.sample_period = 1; + evsel->core.attr.sample_period = 1; } if (perf_evsel__is_clock(evsel)) { @@ -278,17 +285,17 @@ struct perf_evsel *perf_evsel__new_idx(struct perf_event_attr *attr, int idx) static bool perf_event_can_profile_kernel(void) { - return geteuid() == 0 || perf_event_paranoid() == -1; + return perf_event_paranoid_check(1); } -struct perf_evsel *perf_evsel__new_cycles(bool precise) +struct evsel *perf_evsel__new_cycles(bool precise) { struct perf_event_attr attr = { .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_CPU_CYCLES, .exclude_kernel = !perf_event_can_profile_kernel(), }; - struct perf_evsel *evsel; + struct evsel *evsel; event_attr_init(&attr); @@ -300,7 +307,7 @@ struct perf_evsel *perf_evsel__new_cycles(bool precise) * to kick in when we return and before perf_evsel__open() is called. */ new_event: - evsel = perf_evsel__new(&attr); + evsel = evsel__new(&attr); if (evsel == NULL) goto out; @@ -315,7 +322,7 @@ new_event: out: return evsel; error_free: - perf_evsel__delete(evsel); + evsel__delete(evsel); evsel = NULL; goto out; } @@ -323,9 +330,9 @@ error_free: /* * Returns pointer with encoded error via <linux/err.h> interface. */ -struct perf_evsel *perf_evsel__newtp_idx(const char *sys, const char *name, int idx) +struct evsel *perf_evsel__newtp_idx(const char *sys, const char *name, int idx) { - struct perf_evsel *evsel = zalloc(perf_evsel__object.size); + struct evsel *evsel = zalloc(perf_evsel__object.size); int err = -ENOMEM; if (evsel == NULL) { @@ -349,7 +356,7 @@ struct perf_evsel *perf_evsel__newtp_idx(const char *sys, const char *name, int event_attr_init(&attr); attr.config = evsel->tp_format->id; attr.sample_period = 1; - perf_evsel__init(evsel, &attr, idx); + evsel__init(evsel, &attr, idx); } return evsel; @@ -382,10 +389,10 @@ static const char *__perf_evsel__hw_name(u64 config) return "unknown-hardware"; } -static int perf_evsel__add_modifiers(struct perf_evsel *evsel, char *bf, size_t size) +static int perf_evsel__add_modifiers(struct evsel *evsel, char *bf, size_t size) { int colon = 0, r = 0; - struct perf_event_attr *attr = &evsel->attr; + struct perf_event_attr *attr = &evsel->core.attr; bool exclude_guest_default = false; #define MOD_PRINT(context, mod) do { \ @@ -418,9 +425,9 @@ static int perf_evsel__add_modifiers(struct perf_evsel *evsel, char *bf, size_t return r; } -static int perf_evsel__hw_name(struct perf_evsel *evsel, char *bf, size_t size) +static int perf_evsel__hw_name(struct evsel *evsel, char *bf, size_t size) { - int r = scnprintf(bf, size, "%s", __perf_evsel__hw_name(evsel->attr.config)); + int r = scnprintf(bf, size, "%s", __perf_evsel__hw_name(evsel->core.attr.config)); return r + perf_evsel__add_modifiers(evsel, bf + r, size - r); } @@ -444,9 +451,9 @@ static const char *__perf_evsel__sw_name(u64 config) return "unknown-software"; } -static int perf_evsel__sw_name(struct perf_evsel *evsel, char *bf, size_t size) +static int perf_evsel__sw_name(struct evsel *evsel, char *bf, size_t size) { - int r = scnprintf(bf, size, "%s", __perf_evsel__sw_name(evsel->attr.config)); + int r = scnprintf(bf, size, "%s", __perf_evsel__sw_name(evsel->core.attr.config)); return r + perf_evsel__add_modifiers(evsel, bf + r, size - r); } @@ -468,9 +475,9 @@ static int __perf_evsel__bp_name(char *bf, size_t size, u64 addr, u64 type) return r; } -static int perf_evsel__bp_name(struct perf_evsel *evsel, char *bf, size_t size) +static int perf_evsel__bp_name(struct evsel *evsel, char *bf, size_t size) { - struct perf_event_attr *attr = &evsel->attr; + struct perf_event_attr *attr = &evsel->core.attr; int r = __perf_evsel__bp_name(bf, size, attr->bp_addr, attr->bp_type); return r + perf_evsel__add_modifiers(evsel, bf + r, size - r); } @@ -568,15 +575,15 @@ out_err: return scnprintf(bf, size, "%s", err); } -static int perf_evsel__hw_cache_name(struct perf_evsel *evsel, char *bf, size_t size) +static int perf_evsel__hw_cache_name(struct evsel *evsel, char *bf, size_t size) { - int ret = __perf_evsel__hw_cache_name(evsel->attr.config, bf, size); + int ret = __perf_evsel__hw_cache_name(evsel->core.attr.config, bf, size); return ret + perf_evsel__add_modifiers(evsel, bf + ret, size - ret); } -static int perf_evsel__raw_name(struct perf_evsel *evsel, char *bf, size_t size) +static int perf_evsel__raw_name(struct evsel *evsel, char *bf, size_t size) { - int ret = scnprintf(bf, size, "raw 0x%" PRIx64, evsel->attr.config); + int ret = scnprintf(bf, size, "raw 0x%" PRIx64, evsel->core.attr.config); return ret + perf_evsel__add_modifiers(evsel, bf + ret, size - ret); } @@ -586,7 +593,7 @@ static int perf_evsel__tool_name(char *bf, size_t size) return ret; } -const char *perf_evsel__name(struct perf_evsel *evsel) +const char *perf_evsel__name(struct evsel *evsel) { char bf[128]; @@ -596,7 +603,7 @@ const char *perf_evsel__name(struct perf_evsel *evsel) if (evsel->name) return evsel->name; - switch (evsel->attr.type) { + switch (evsel->core.attr.type) { case PERF_TYPE_RAW: perf_evsel__raw_name(evsel, bf, sizeof(bf)); break; @@ -626,7 +633,7 @@ const char *perf_evsel__name(struct perf_evsel *evsel) default: scnprintf(bf, sizeof(bf), "unknown attr type: %d", - evsel->attr.type); + evsel->core.attr.type); break; } @@ -638,7 +645,7 @@ out_unknown: return "unknown"; } -const char *perf_evsel__group_name(struct perf_evsel *evsel) +const char *perf_evsel__group_name(struct evsel *evsel) { return evsel->group_name ?: "anon group"; } @@ -653,10 +660,10 @@ const char *perf_evsel__group_name(struct perf_evsel *evsel) * For record -e 'cycles,instructions' and report --group * 'cycles:u, instructions:u' */ -int perf_evsel__group_desc(struct perf_evsel *evsel, char *buf, size_t size) +int perf_evsel__group_desc(struct evsel *evsel, char *buf, size_t size) { int ret = 0; - struct perf_evsel *pos; + struct evsel *pos; const char *group_name = perf_evsel__group_name(evsel); if (!evsel->forced_leader) @@ -675,12 +682,12 @@ int perf_evsel__group_desc(struct perf_evsel *evsel, char *buf, size_t size) return ret; } -static void __perf_evsel__config_callchain(struct perf_evsel *evsel, +static void __perf_evsel__config_callchain(struct evsel *evsel, struct record_opts *opts, struct callchain_param *param) { bool function = perf_evsel__is_function_event(evsel); - struct perf_event_attr *attr = &evsel->attr; + struct perf_event_attr *attr = &evsel->core.attr; perf_evsel__set_sample_bit(evsel, CALLCHAIN); @@ -734,7 +741,7 @@ static void __perf_evsel__config_callchain(struct perf_evsel *evsel, } } -void perf_evsel__config_callchain(struct perf_evsel *evsel, +void perf_evsel__config_callchain(struct evsel *evsel, struct record_opts *opts, struct callchain_param *param) { @@ -743,10 +750,10 @@ void perf_evsel__config_callchain(struct perf_evsel *evsel, } static void -perf_evsel__reset_callgraph(struct perf_evsel *evsel, +perf_evsel__reset_callgraph(struct evsel *evsel, struct callchain_param *param) { - struct perf_event_attr *attr = &evsel->attr; + struct perf_event_attr *attr = &evsel->core.attr; perf_evsel__reset_sample_bit(evsel, CALLCHAIN); if (param->record_mode == CALLCHAIN_LBR) { @@ -760,12 +767,12 @@ perf_evsel__reset_callgraph(struct perf_evsel *evsel, } } -static void apply_config_terms(struct perf_evsel *evsel, +static void apply_config_terms(struct evsel *evsel, struct record_opts *opts, bool track) { struct perf_evsel_config_term *term; struct list_head *config_terms = &evsel->config_terms; - struct perf_event_attr *attr = &evsel->attr; + struct perf_event_attr *attr = &evsel->core.attr; /* callgraph default */ struct callchain_param param = { .record_mode = callchain_param.record_mode, @@ -832,6 +839,9 @@ static void apply_config_terms(struct perf_evsel *evsel, break; case PERF_EVSEL__CONFIG_TERM_PERCORE: break; + case PERF_EVSEL__CONFIG_TERM_AUX_OUTPUT: + attr->aux_output = term->val.aux_output ? 1 : 0; + break; default: break; } @@ -878,17 +888,17 @@ static void apply_config_terms(struct perf_evsel *evsel, if (sample_address) { perf_evsel__set_sample_bit(evsel, ADDR); perf_evsel__set_sample_bit(evsel, DATA_SRC); - evsel->attr.mmap_data = track; + evsel->core.attr.mmap_data = track; } perf_evsel__config_callchain(evsel, opts, ¶m); } } } -static bool is_dummy_event(struct perf_evsel *evsel) +static bool is_dummy_event(struct evsel *evsel) { - return (evsel->attr.type == PERF_TYPE_SOFTWARE) && - (evsel->attr.config == PERF_COUNT_SW_DUMMY); + return (evsel->core.attr.type == PERF_TYPE_SOFTWARE) && + (evsel->core.attr.config == PERF_COUNT_SW_DUMMY); } /* @@ -919,11 +929,11 @@ static bool is_dummy_event(struct perf_evsel *evsel) * enable/disable events specifically, as there's no * initial traced exec call. */ -void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts, +void perf_evsel__config(struct evsel *evsel, struct record_opts *opts, struct callchain_param *callchain) { - struct perf_evsel *leader = evsel->leader; - struct perf_event_attr *attr = &evsel->attr; + struct evsel *leader = evsel->leader; + struct perf_event_attr *attr = &evsel->core.attr; int track = evsel->tracking; bool per_cpu = opts->target.default_per_cpu && !opts->target.per_thread; @@ -947,7 +957,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts, * Apply group format only if we belong to group * with more than one members. */ - if (leader->nr_members > 1) { + if (leader->core.nr_members > 1) { attr->read_format |= PERF_FORMAT_GROUP; attr->inherit = 0; } @@ -984,14 +994,14 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts, * event to follow the master sample_type to ease up * report. */ - attr->sample_type = leader->attr.sample_type; + attr->sample_type = leader->core.attr.sample_type; } if (opts->no_samples) attr->sample_freq = 0; if (opts->inherit_stat) { - evsel->attr.read_format |= + evsel->core.attr.read_format |= PERF_FORMAT_TOTAL_TIME_ENABLED | PERF_FORMAT_TOTAL_TIME_RUNNING | PERF_FORMAT_ID; @@ -1009,7 +1019,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts, * fault handler and its overall trickiness nature. */ if (perf_evsel__is_function_event(evsel)) - evsel->attr.exclude_callchain_user = 1; + evsel->core.attr.exclude_callchain_user = 1; if (callchain && callchain->enabled && !evsel->no_aux_samples) perf_evsel__config_callchain(evsel, opts, callchain); @@ -1065,8 +1075,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts, attr->mmap2 = track && !perf_missing_features.mmap2; attr->comm = track; attr->ksymbol = track && !perf_missing_features.ksymbol; - attr->bpf_event = track && !opts->no_bpf_event && - !perf_missing_features.bpf_event; + attr->bpf_event = track && !opts->no_bpf_event && !perf_missing_features.bpf; if (opts->record_namespaces) attr->namespaces = track; @@ -1078,7 +1087,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts, perf_evsel__set_sample_bit(evsel, TRANSACTION); if (opts->running_time) { - evsel->attr.read_format |= + evsel->core.attr.read_format |= PERF_FORMAT_TOTAL_TIME_ENABLED | PERF_FORMAT_TOTAL_TIME_RUNNING; } @@ -1124,8 +1133,8 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts, attr->exclude_user = 1; } - if (evsel->own_cpus || evsel->unit) - evsel->attr.read_format |= PERF_FORMAT_ID; + if (evsel->core.own_cpus || evsel->unit) + evsel->core.attr.read_format |= PERF_FORMAT_ID; /* * Apply event specific term settings, @@ -1152,48 +1161,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts, perf_evsel__reset_sample_bit(evsel, BRANCH_STACK); } -static 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 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__apply_filter(struct perf_evsel *evsel, const char *filter) -{ - return perf_evsel__run_ioctl(evsel, - PERF_EVENT_IOC_SET_FILTER, - (void *)filter); -} - -int perf_evsel__set_filter(struct perf_evsel *evsel, const char *filter) +int perf_evsel__set_filter(struct evsel *evsel, const char *filter) { char *new_filter = strdup(filter); @@ -1206,7 +1174,7 @@ int perf_evsel__set_filter(struct perf_evsel *evsel, const char *filter) return -1; } -static int perf_evsel__append_filter(struct perf_evsel *evsel, +static int perf_evsel__append_filter(struct evsel *evsel, const char *fmt, const char *filter) { char *new_filter; @@ -1223,19 +1191,19 @@ static int perf_evsel__append_filter(struct perf_evsel *evsel, return -1; } -int perf_evsel__append_tp_filter(struct perf_evsel *evsel, const char *filter) +int perf_evsel__append_tp_filter(struct evsel *evsel, const char *filter) { return perf_evsel__append_filter(evsel, "(%s) && (%s)", filter); } -int perf_evsel__append_addr_filter(struct perf_evsel *evsel, const char *filter) +int perf_evsel__append_addr_filter(struct evsel *evsel, const char *filter) { return perf_evsel__append_filter(evsel, "%s,%s", filter); } -int perf_evsel__enable(struct perf_evsel *evsel) +int evsel__enable(struct evsel *evsel) { - int err = perf_evsel__run_ioctl(evsel, PERF_EVENT_IOC_ENABLE, 0); + int err = perf_evsel__enable(&evsel->core); if (!err) evsel->disabled = false; @@ -1243,9 +1211,9 @@ int perf_evsel__enable(struct perf_evsel *evsel) return err; } -int perf_evsel__disable(struct perf_evsel *evsel) +int evsel__disable(struct evsel *evsel) { - int err = perf_evsel__run_ioctl(evsel, PERF_EVENT_IOC_DISABLE, 0); + int err = perf_evsel__disable(&evsel->core); /* * We mark it disabled here so that tools that disable a event can * ignore events after they disable it. I.e. the ring buffer may have @@ -1258,7 +1226,7 @@ int perf_evsel__disable(struct perf_evsel *evsel) return err; } -int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads) +int perf_evsel__alloc_id(struct evsel *evsel, int ncpus, int nthreads) { if (ncpus == 0 || nthreads == 0) return 0; @@ -1280,13 +1248,7 @@ int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads) return 0; } -static void perf_evsel__free_fd(struct perf_evsel *evsel) -{ - xyarray__delete(evsel->fd); - evsel->fd = NULL; -} - -static void perf_evsel__free_id(struct perf_evsel *evsel) +static void perf_evsel__free_id(struct evsel *evsel) { xyarray__delete(evsel->sample_id); evsel->sample_id = NULL; @@ -1294,7 +1256,7 @@ static void perf_evsel__free_id(struct perf_evsel *evsel) evsel->ids = 0; } -static void perf_evsel__free_config_terms(struct perf_evsel *evsel) +static void perf_evsel__free_config_terms(struct evsel *evsel) { struct perf_evsel_config_term *term, *h; @@ -1304,41 +1266,30 @@ static void perf_evsel__free_config_terms(struct perf_evsel *evsel) } } -void perf_evsel__close_fd(struct perf_evsel *evsel) +void perf_evsel__exit(struct 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) { - close(FD(evsel, cpu, thread)); - FD(evsel, cpu, thread) = -1; - } -} - -void perf_evsel__exit(struct perf_evsel *evsel) -{ - assert(list_empty(&evsel->node)); + assert(list_empty(&evsel->core.node)); assert(evsel->evlist == NULL); perf_evsel__free_counts(evsel); - perf_evsel__free_fd(evsel); + perf_evsel__free_fd(&evsel->core); perf_evsel__free_id(evsel); perf_evsel__free_config_terms(evsel); cgroup__put(evsel->cgrp); - cpu_map__put(evsel->cpus); - cpu_map__put(evsel->own_cpus); - thread_map__put(evsel->threads); + perf_cpu_map__put(evsel->core.cpus); + perf_cpu_map__put(evsel->core.own_cpus); + perf_thread_map__put(evsel->core.threads); zfree(&evsel->group_name); zfree(&evsel->name); perf_evsel__object.fini(evsel); } -void perf_evsel__delete(struct perf_evsel *evsel) +void evsel__delete(struct evsel *evsel) { perf_evsel__exit(evsel); free(evsel); } -void perf_evsel__compute_deltas(struct perf_evsel *evsel, int cpu, int thread, +void perf_evsel__compute_deltas(struct evsel *evsel, int cpu, int thread, struct perf_counts_values *count) { struct perf_counts_values tmp; @@ -1378,57 +1329,16 @@ void perf_counts_values__scale(struct perf_counts_values *count, *pscaled = scaled; } -static 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__read_one(struct perf_evsel *evsel, int cpu, int thread) +perf_evsel__read_one(struct evsel *evsel, int cpu, int thread) { struct perf_counts_values *count = perf_counts(evsel->counts, cpu, thread); - return perf_evsel__read(evsel, cpu, thread, count); + return perf_evsel__read(&evsel->core, cpu, thread, count); } static void -perf_evsel__set_count(struct perf_evsel *counter, int cpu, int thread, +perf_evsel__set_count(struct evsel *counter, int cpu, int thread, u64 val, u64 ena, u64 run) { struct perf_counts_values *count; @@ -1438,20 +1348,21 @@ perf_evsel__set_count(struct perf_evsel *counter, int cpu, int thread, count->val = val; count->ena = ena; count->run = run; - count->loaded = true; + + perf_counts__set_loaded(counter->counts, cpu, thread, true); } static int -perf_evsel__process_group_data(struct perf_evsel *leader, +perf_evsel__process_group_data(struct evsel *leader, int cpu, int thread, u64 *data) { - u64 read_format = leader->attr.read_format; + u64 read_format = leader->core.attr.read_format; struct sample_read_value *v; u64 nr, ena = 0, run = 0, i; nr = *data++; - if (nr != (u64) leader->nr_members) + if (nr != (u64) leader->core.nr_members) return -EINVAL; if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) @@ -1466,7 +1377,7 @@ perf_evsel__process_group_data(struct perf_evsel *leader, v[0].value, ena, run); for (i = 1; i < nr; i++) { - struct perf_evsel *counter; + struct evsel *counter; counter = perf_evlist__id2evsel(leader->evlist, v[i].id); if (!counter) @@ -1480,11 +1391,11 @@ perf_evsel__process_group_data(struct perf_evsel *leader, } static int -perf_evsel__read_group(struct perf_evsel *leader, int cpu, int thread) +perf_evsel__read_group(struct evsel *leader, int cpu, int thread) { struct perf_stat_evsel *ps = leader->stats; - u64 read_format = leader->attr.read_format; - int size = perf_evsel__read_size(leader); + u64 read_format = leader->core.attr.read_format; + int size = perf_evsel__read_size(&leader->core); u64 *data = ps->group_data; if (!(read_format & PERF_FORMAT_ID)) @@ -1510,9 +1421,9 @@ perf_evsel__read_group(struct perf_evsel *leader, int cpu, int thread) return perf_evsel__process_group_data(leader, cpu, thread, data); } -int perf_evsel__read_counter(struct perf_evsel *evsel, int cpu, int thread) +int perf_evsel__read_counter(struct evsel *evsel, int cpu, int thread) { - u64 read_format = evsel->attr.read_format; + u64 read_format = evsel->core.attr.read_format; if (read_format & PERF_FORMAT_GROUP) return perf_evsel__read_group(evsel, cpu, thread); @@ -1520,7 +1431,7 @@ int perf_evsel__read_counter(struct perf_evsel *evsel, int cpu, int thread) return perf_evsel__read_one(evsel, cpu, thread); } -int __perf_evsel__read_on_cpu(struct perf_evsel *evsel, +int __perf_evsel__read_on_cpu(struct evsel *evsel, int cpu, int thread, bool scale) { struct perf_counts_values count; @@ -1541,9 +1452,9 @@ int __perf_evsel__read_on_cpu(struct perf_evsel *evsel, return 0; } -static int get_group_fd(struct perf_evsel *evsel, int cpu, int thread) +static int get_group_fd(struct evsel *evsel, int cpu, int thread) { - struct perf_evsel *leader = evsel->leader; + struct evsel *leader = evsel->leader; int fd; if (perf_evsel__is_group_leader(evsel)) @@ -1553,7 +1464,7 @@ static int get_group_fd(struct perf_evsel *evsel, int cpu, int thread) * Leader must be already processed/open, * if not it's a bug. */ - BUG_ON(!leader->fd); + BUG_ON(!leader->core.fd); fd = FD(leader, cpu, thread); BUG_ON(fd == -1); @@ -1684,6 +1595,7 @@ int perf_event_attr__fprintf(FILE *fp, struct perf_event_attr *attr, PRINT_ATTRf(namespaces, p_unsigned); PRINT_ATTRf(ksymbol, p_unsigned); PRINT_ATTRf(bpf_event, p_unsigned); + PRINT_ATTRf(aux_output, p_unsigned); PRINT_ATTRn("{ wakeup_events, wakeup_watermark }", wakeup_events, p_unsigned); PRINT_ATTRf(bp_type, p_unsigned); @@ -1706,7 +1618,7 @@ static int __open_attr__fprintf(FILE *fp, const char *name, const char *val, return fprintf(fp, " %-32s %s\n", name, val); } -static void perf_evsel__remove_fd(struct perf_evsel *pos, +static void perf_evsel__remove_fd(struct evsel *pos, int nr_cpus, int nr_threads, int thread_idx) { @@ -1715,11 +1627,11 @@ static void perf_evsel__remove_fd(struct perf_evsel *pos, FD(pos, cpu, thread) = FD(pos, cpu, thread + 1); } -static int update_fds(struct perf_evsel *evsel, +static int update_fds(struct evsel *evsel, int nr_cpus, int cpu_idx, int nr_threads, int thread_idx) { - struct perf_evsel *pos; + struct evsel *pos; if (cpu_idx >= nr_cpus || thread_idx >= nr_threads) return -EINVAL; @@ -1739,12 +1651,12 @@ static int update_fds(struct perf_evsel *evsel, return 0; } -static bool ignore_missing_thread(struct perf_evsel *evsel, +static bool ignore_missing_thread(struct evsel *evsel, int nr_cpus, int cpu, - struct thread_map *threads, + struct perf_thread_map *threads, int thread, int err) { - pid_t ignore_pid = thread_map__pid(threads, thread); + pid_t ignore_pid = perf_thread_map__pid(threads, thread); if (!evsel->ignore_missing_thread) return false; @@ -1786,18 +1698,18 @@ static void display_attr(struct perf_event_attr *attr) } } -static int perf_event_open(struct perf_evsel *evsel, +static int perf_event_open(struct evsel *evsel, pid_t pid, int cpu, int group_fd, unsigned long flags) { - int precise_ip = evsel->attr.precise_ip; + int precise_ip = evsel->core.attr.precise_ip; int fd; while (1) { pr_debug2("sys_perf_event_open: pid %d cpu %d group_fd %d flags %#lx", pid, cpu, group_fd, flags); - fd = sys_perf_event_open(&evsel->attr, pid, cpu, group_fd, flags); + fd = sys_perf_event_open(&evsel->core.attr, pid, cpu, group_fd, flags); if (fd >= 0) break; @@ -1809,36 +1721,37 @@ static int perf_event_open(struct perf_evsel *evsel, * We tried all the precise_ip values, and it's * still failing, so leave it to standard fallback. */ - if (!evsel->attr.precise_ip) { - evsel->attr.precise_ip = precise_ip; + if (!evsel->core.attr.precise_ip) { + evsel->core.attr.precise_ip = precise_ip; break; } pr_debug2("\nsys_perf_event_open failed, error %d\n", -ENOTSUP); - evsel->attr.precise_ip--; - pr_debug2("decreasing precise_ip by one (%d)\n", evsel->attr.precise_ip); - display_attr(&evsel->attr); + evsel->core.attr.precise_ip--; + pr_debug2("decreasing precise_ip by one (%d)\n", evsel->core.attr.precise_ip); + display_attr(&evsel->core.attr); } return fd; } -int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, - struct thread_map *threads) +int evsel__open(struct evsel *evsel, struct perf_cpu_map *cpus, + struct perf_thread_map *threads) { int cpu, thread, nthreads; unsigned long flags = PERF_FLAG_FD_CLOEXEC; int pid = -1, err; enum { NO_CHANGE, SET_TO_MAX, INCREASED_MAX } set_rlimit = NO_CHANGE; - if (perf_missing_features.write_backward && evsel->attr.write_backward) + if ((perf_missing_features.write_backward && evsel->core.attr.write_backward) || + (perf_missing_features.aux_output && evsel->core.attr.aux_output)) return -EINVAL; if (cpus == NULL) { - static struct cpu_map *empty_cpu_map; + static struct perf_cpu_map *empty_cpu_map; if (empty_cpu_map == NULL) { - empty_cpu_map = cpu_map__dummy_new(); + empty_cpu_map = perf_cpu_map__dummy_new(); if (empty_cpu_map == NULL) return -ENOMEM; } @@ -1847,7 +1760,7 @@ int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, } if (threads == NULL) { - static struct thread_map *empty_thread_map; + static struct perf_thread_map *empty_thread_map; if (empty_thread_map == NULL) { empty_thread_map = thread_map__new_by_tid(-1); @@ -1863,8 +1776,8 @@ int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, else nthreads = threads->nr; - if (evsel->fd == NULL && - perf_evsel__alloc_fd(evsel, cpus->nr, nthreads) < 0) + if (evsel->core.fd == NULL && + perf_evsel__alloc_fd(&evsel->core, cpus->nr, nthreads) < 0) return -ENOMEM; if (evsel->cgrp) { @@ -1874,31 +1787,31 @@ int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, fallback_missing_features: if (perf_missing_features.clockid_wrong) - evsel->attr.clockid = CLOCK_MONOTONIC; /* should always work */ + evsel->core.attr.clockid = CLOCK_MONOTONIC; /* should always work */ if (perf_missing_features.clockid) { - evsel->attr.use_clockid = 0; - evsel->attr.clockid = 0; + evsel->core.attr.use_clockid = 0; + evsel->core.attr.clockid = 0; } if (perf_missing_features.cloexec) flags &= ~(unsigned long)PERF_FLAG_FD_CLOEXEC; if (perf_missing_features.mmap2) - evsel->attr.mmap2 = 0; + evsel->core.attr.mmap2 = 0; if (perf_missing_features.exclude_guest) - evsel->attr.exclude_guest = evsel->attr.exclude_host = 0; + evsel->core.attr.exclude_guest = evsel->core.attr.exclude_host = 0; if (perf_missing_features.lbr_flags) - evsel->attr.branch_sample_type &= ~(PERF_SAMPLE_BRANCH_NO_FLAGS | + evsel->core.attr.branch_sample_type &= ~(PERF_SAMPLE_BRANCH_NO_FLAGS | PERF_SAMPLE_BRANCH_NO_CYCLES); - if (perf_missing_features.group_read && evsel->attr.inherit) - evsel->attr.read_format &= ~(PERF_FORMAT_GROUP|PERF_FORMAT_ID); + if (perf_missing_features.group_read && evsel->core.attr.inherit) + evsel->core.attr.read_format &= ~(PERF_FORMAT_GROUP|PERF_FORMAT_ID); if (perf_missing_features.ksymbol) - evsel->attr.ksymbol = 0; - if (perf_missing_features.bpf_event) - evsel->attr.bpf_event = 0; + evsel->core.attr.ksymbol = 0; + if (perf_missing_features.bpf) + evsel->core.attr.bpf_event = 0; retry_sample_id: if (perf_missing_features.sample_id_all) - evsel->attr.sample_id_all = 0; + evsel->core.attr.sample_id_all = 0; - display_attr(&evsel->attr); + display_attr(&evsel->core.attr); for (cpu = 0; cpu < cpus->nr; cpu++) { @@ -1906,7 +1819,7 @@ retry_sample_id: int fd, group_fd; if (!evsel->cgrp && !evsel->system_wide) - pid = thread_map__pid(threads, thread); + pid = perf_thread_map__pid(threads, thread); group_fd = get_group_fd(evsel, cpu, thread); retry_open: @@ -2005,23 +1918,27 @@ try_fallback: * Must probe features in the order they were added to the * perf_event_attr interface. */ - if (!perf_missing_features.bpf_event && evsel->attr.bpf_event) { - perf_missing_features.bpf_event = true; + if (!perf_missing_features.aux_output && evsel->core.attr.aux_output) { + perf_missing_features.aux_output = true; + pr_debug2("Kernel has no attr.aux_output support, bailing out\n"); + goto out_close; + } else if (!perf_missing_features.bpf && evsel->core.attr.bpf_event) { + perf_missing_features.bpf = true; pr_debug2("switching off bpf_event\n"); goto fallback_missing_features; - } else if (!perf_missing_features.ksymbol && evsel->attr.ksymbol) { + } else if (!perf_missing_features.ksymbol && evsel->core.attr.ksymbol) { perf_missing_features.ksymbol = true; pr_debug2("switching off ksymbol\n"); goto fallback_missing_features; - } else if (!perf_missing_features.write_backward && evsel->attr.write_backward) { + } else if (!perf_missing_features.write_backward && evsel->core.attr.write_backward) { perf_missing_features.write_backward = true; pr_debug2("switching off write_backward\n"); goto out_close; - } else if (!perf_missing_features.clockid_wrong && evsel->attr.use_clockid) { + } else if (!perf_missing_features.clockid_wrong && evsel->core.attr.use_clockid) { perf_missing_features.clockid_wrong = true; pr_debug2("switching off clockid\n"); goto fallback_missing_features; - } else if (!perf_missing_features.clockid && evsel->attr.use_clockid) { + } else if (!perf_missing_features.clockid && evsel->core.attr.use_clockid) { perf_missing_features.clockid = true; pr_debug2("switching off use_clockid\n"); goto fallback_missing_features; @@ -2029,12 +1946,12 @@ try_fallback: perf_missing_features.cloexec = true; pr_debug2("switching off cloexec flag\n"); goto fallback_missing_features; - } else if (!perf_missing_features.mmap2 && evsel->attr.mmap2) { + } else if (!perf_missing_features.mmap2 && evsel->core.attr.mmap2) { perf_missing_features.mmap2 = true; pr_debug2("switching off mmap2\n"); goto fallback_missing_features; } else if (!perf_missing_features.exclude_guest && - (evsel->attr.exclude_guest || evsel->attr.exclude_host)) { + (evsel->core.attr.exclude_guest || evsel->core.attr.exclude_host)) { perf_missing_features.exclude_guest = true; pr_debug2("switching off exclude_guest, exclude_host\n"); goto fallback_missing_features; @@ -2043,15 +1960,15 @@ try_fallback: pr_debug2("switching off sample_id_all\n"); goto retry_sample_id; } else if (!perf_missing_features.lbr_flags && - (evsel->attr.branch_sample_type & + (evsel->core.attr.branch_sample_type & (PERF_SAMPLE_BRANCH_NO_CYCLES | PERF_SAMPLE_BRANCH_NO_FLAGS))) { perf_missing_features.lbr_flags = true; pr_debug2("switching off branch sample type no (cycles/flags)\n"); goto fallback_missing_features; } else if (!perf_missing_features.group_read && - evsel->attr.inherit && - (evsel->attr.read_format & PERF_FORMAT_GROUP) && + evsel->core.attr.inherit && + (evsel->core.attr.read_format & PERF_FORMAT_GROUP) && perf_evsel__is_group_leader(evsel)) { perf_missing_features.group_read = true; pr_debug2("switching off group read\n"); @@ -2071,34 +1988,30 @@ out_close: return err; } -void perf_evsel__close(struct perf_evsel *evsel) +void evsel__close(struct evsel *evsel) { - if (evsel->fd == NULL) - return; - - perf_evsel__close_fd(evsel); - perf_evsel__free_fd(evsel); + perf_evsel__close(&evsel->core); perf_evsel__free_id(evsel); } -int perf_evsel__open_per_cpu(struct perf_evsel *evsel, - struct cpu_map *cpus) +int perf_evsel__open_per_cpu(struct evsel *evsel, + struct perf_cpu_map *cpus) { - return perf_evsel__open(evsel, cpus, NULL); + return evsel__open(evsel, cpus, NULL); } -int perf_evsel__open_per_thread(struct perf_evsel *evsel, - struct thread_map *threads) +int perf_evsel__open_per_thread(struct evsel *evsel, + struct perf_thread_map *threads) { - return perf_evsel__open(evsel, NULL, threads); + return evsel__open(evsel, NULL, threads); } -static int perf_evsel__parse_id_sample(const struct perf_evsel *evsel, +static int perf_evsel__parse_id_sample(const struct evsel *evsel, const union perf_event *event, struct perf_sample *sample) { - u64 type = evsel->attr.sample_type; - const u64 *array = event->sample.array; + u64 type = evsel->core.attr.sample_type; + const __u64 *array = event->sample.array; bool swapped = evsel->needs_swap; union u64_swap u; @@ -2183,12 +2096,12 @@ perf_event__check_size(union perf_event *event, unsigned int sample_size) return 0; } -int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event, +int perf_evsel__parse_sample(struct evsel *evsel, union perf_event *event, struct perf_sample *data) { - u64 type = evsel->attr.sample_type; + u64 type = evsel->core.attr.sample_type; bool swapped = evsel->needs_swap; - const u64 *array; + const __u64 *array; u16 max_size = event->header.size; const void *endp = (void *)event + max_size; u64 sz; @@ -2202,14 +2115,14 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event, memset(data, 0, sizeof(*data)); data->cpu = data->pid = data->tid = -1; data->stream_id = data->id = data->time = -1ULL; - data->period = evsel->attr.sample_period; + data->period = evsel->core.attr.sample_period; data->cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; data->misc = event->header.misc; data->id = -1ULL; data->data_src = PERF_MEM_DATA_SRC_NONE; if (event->header.type != PERF_RECORD_SAMPLE) { - if (!evsel->attr.sample_id_all) + if (!evsel->core.attr.sample_id_all) return 0; return perf_evsel__parse_id_sample(evsel, event, data); } @@ -2282,7 +2195,7 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event, } if (type & PERF_SAMPLE_READ) { - u64 read_format = evsel->attr.read_format; + u64 read_format = evsel->core.attr.read_format; OVERFLOW_CHECK_u64(array); if (read_format & PERF_FORMAT_GROUP) @@ -2387,7 +2300,7 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event, array++; if (data->user_regs.abi) { - u64 mask = evsel->attr.sample_regs_user; + u64 mask = evsel->core.attr.sample_regs_user; sz = hweight64(mask) * sizeof(u64); OVERFLOW_CHECK(array, sz, max_size); @@ -2443,7 +2356,7 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event, array++; if (data->intr_regs.abi != PERF_SAMPLE_REGS_ABI_NONE) { - u64 mask = evsel->attr.sample_regs_intr; + u64 mask = evsel->core.attr.sample_regs_intr; sz = hweight64(mask) * sizeof(u64); OVERFLOW_CHECK(array, sz, max_size); @@ -2462,12 +2375,12 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event, return 0; } -int perf_evsel__parse_sample_timestamp(struct perf_evsel *evsel, +int perf_evsel__parse_sample_timestamp(struct evsel *evsel, union perf_event *event, u64 *timestamp) { - u64 type = evsel->attr.sample_type; - const u64 *array; + u64 type = evsel->core.attr.sample_type; + const __u64 *array; if (!(type & PERF_SAMPLE_TIME)) return -1; @@ -2477,7 +2390,7 @@ int perf_evsel__parse_sample_timestamp(struct perf_evsel *evsel, .time = -1ULL, }; - if (!evsel->attr.sample_id_all) + if (!evsel->core.attr.sample_id_all) return -1; if (perf_evsel__parse_id_sample(evsel, event, &data)) return -1; @@ -2509,7 +2422,7 @@ int perf_evsel__parse_sample_timestamp(struct perf_evsel *evsel, size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type, u64 read_format) { - size_t sz, result = sizeof(struct sample_event); + size_t sz, result = sizeof(struct perf_record_sample); if (type & PERF_SAMPLE_IDENTIFIER) result += sizeof(u64); @@ -2618,7 +2531,7 @@ int perf_event__synthesize_sample(union perf_event *event, u64 type, u64 read_format, const struct perf_sample *sample) { - u64 *array; + __u64 *array; size_t sz; /* * used for cross-endian analysis. See git commit 65014ab3 @@ -2783,12 +2696,12 @@ int perf_event__synthesize_sample(union perf_event *event, u64 type, return 0; } -struct tep_format_field *perf_evsel__field(struct perf_evsel *evsel, const char *name) +struct tep_format_field *perf_evsel__field(struct evsel *evsel, const char *name) { return tep_find_field(evsel->tp_format, name); } -void *perf_evsel__rawptr(struct perf_evsel *evsel, struct perf_sample *sample, +void *perf_evsel__rawptr(struct evsel *evsel, struct perf_sample *sample, const char *name) { struct tep_format_field *field = perf_evsel__field(evsel, name); @@ -2846,7 +2759,7 @@ u64 format_field__intval(struct tep_format_field *field, struct perf_sample *sam return 0; } -u64 perf_evsel__intval(struct perf_evsel *evsel, struct perf_sample *sample, +u64 perf_evsel__intval(struct evsel *evsel, struct perf_sample *sample, const char *name) { struct tep_format_field *field = perf_evsel__field(evsel, name); @@ -2857,14 +2770,14 @@ u64 perf_evsel__intval(struct perf_evsel *evsel, struct perf_sample *sample, return field ? format_field__intval(field, sample, evsel->needs_swap) : 0; } -bool perf_evsel__fallback(struct perf_evsel *evsel, int err, +bool perf_evsel__fallback(struct evsel *evsel, int err, char *msg, size_t msgsize) { int paranoid; if ((err == ENOENT || err == ENXIO || err == ENODEV) && - evsel->attr.type == PERF_TYPE_HARDWARE && - evsel->attr.config == PERF_COUNT_HW_CPU_CYCLES) { + evsel->core.attr.type == PERF_TYPE_HARDWARE && + evsel->core.attr.config == PERF_COUNT_HW_CPU_CYCLES) { /* * If it's cycles then fall back to hrtimer based * cpu-clock-tick sw counter, which is always available even if @@ -2876,12 +2789,12 @@ bool perf_evsel__fallback(struct perf_evsel *evsel, int err, scnprintf(msg, msgsize, "%s", "The cycles event is not supported, trying to fall back to cpu-clock-ticks"); - evsel->attr.type = PERF_TYPE_SOFTWARE; - evsel->attr.config = PERF_COUNT_SW_CPU_CLOCK; + evsel->core.attr.type = PERF_TYPE_SOFTWARE; + evsel->core.attr.config = PERF_COUNT_SW_CPU_CLOCK; zfree(&evsel->name); return true; - } else if (err == EACCES && !evsel->attr.exclude_kernel && + } else if (err == EACCES && !evsel->core.attr.exclude_kernel && (paranoid = perf_event_paranoid()) > 1) { const char *name = perf_evsel__name(evsel); char *new_name; @@ -2900,7 +2813,7 @@ bool perf_evsel__fallback(struct perf_evsel *evsel, int err, evsel->name = new_name; scnprintf(msg, msgsize, "kernel.perf_event_paranoid=%d, trying to fall back to excluding kernel samples", paranoid); - evsel->attr.exclude_kernel = 1; + evsel->core.attr.exclude_kernel = 1; return true; } @@ -2944,7 +2857,7 @@ static bool find_process(const char *name) return ret ? false : true; } -int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target, +int perf_evsel__open_strerror(struct evsel *evsel, struct target *target, int err, char *msg, size_t size) { char sbuf[STRERR_BUFSIZE]; @@ -2997,15 +2910,15 @@ int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target, "No such device - did you specify an out-of-range profile CPU?"); break; case EOPNOTSUPP: - if (evsel->attr.sample_period != 0) + if (evsel->core.attr.sample_period != 0) return scnprintf(msg, size, "%s: PMU Hardware doesn't support sampling/overflow-interrupts. Try 'perf stat'", perf_evsel__name(evsel)); - if (evsel->attr.precise_ip) + if (evsel->core.attr.precise_ip) return scnprintf(msg, size, "%s", "\'precise\' request may not be supported. Try removing 'p' modifier."); #if defined(__i386__) || defined(__x86_64__) - if (evsel->attr.type == PERF_TYPE_HARDWARE) + if (evsel->core.attr.type == PERF_TYPE_HARDWARE) return scnprintf(msg, size, "%s", "No hardware sampling interrupt available.\n"); #endif @@ -3017,12 +2930,14 @@ int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target, "We found oprofile daemon running, please stop it and try again."); break; case EINVAL: - if (evsel->attr.write_backward && perf_missing_features.write_backward) + if (evsel->core.attr.write_backward && perf_missing_features.write_backward) return scnprintf(msg, size, "Reading from overwrite event is not supported by this kernel."); if (perf_missing_features.clockid) return scnprintf(msg, size, "clockid feature not supported."); if (perf_missing_features.clockid_wrong) return scnprintf(msg, size, "wrong clockid (%d).", clockid); + if (perf_missing_features.aux_output) + return scnprintf(msg, size, "The 'aux_output' feature is not supported, update the kernel."); break; default: break; @@ -3035,19 +2950,19 @@ int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target, perf_evsel__name(evsel)); } -struct perf_env *perf_evsel__env(struct perf_evsel *evsel) +struct perf_env *perf_evsel__env(struct evsel *evsel) { if (evsel && evsel->evlist) return evsel->evlist->env; return NULL; } -static int store_evsel_ids(struct perf_evsel *evsel, struct perf_evlist *evlist) +static int store_evsel_ids(struct evsel *evsel, struct evlist *evlist) { int cpu, thread; - for (cpu = 0; cpu < xyarray__max_x(evsel->fd); cpu++) { - for (thread = 0; thread < xyarray__max_y(evsel->fd); + for (cpu = 0; cpu < xyarray__max_x(evsel->core.fd); cpu++) { + for (thread = 0; thread < xyarray__max_y(evsel->core.fd); thread++) { int fd = FD(evsel, cpu, thread); @@ -3060,10 +2975,10 @@ static int store_evsel_ids(struct perf_evsel *evsel, struct perf_evlist *evlist) return 0; } -int perf_evsel__store_ids(struct perf_evsel *evsel, struct perf_evlist *evlist) +int perf_evsel__store_ids(struct evsel *evsel, struct evlist *evlist) { - struct cpu_map *cpus = evsel->cpus; - struct thread_map *threads = evsel->threads; + struct perf_cpu_map *cpus = evsel->core.cpus; + struct perf_thread_map *threads = evsel->core.threads; if (perf_evsel__alloc_id(evsel, cpus->nr, threads->nr)) return -ENOMEM; diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index cad54e8ba522..68321d10eb2d 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h @@ -4,15 +4,18 @@ #include <linux/list.h> #include <stdbool.h> -#include <stddef.h> +#include <stdio.h> +#include <sys/types.h> #include <linux/perf_event.h> #include <linux/types.h> -#include "xyarray.h" +#include <internal/evsel.h> +#include <perf/evsel.h> #include "symbol_conf.h" -#include "cpumap.h" -#include "counts.h" +#include <internal/cpumap.h> -struct perf_evsel; +struct addr_location; +struct evsel; +union perf_event; /* * Per fd, to map back from PERF_SAMPLE_ID to evsel, only used when there are @@ -21,7 +24,14 @@ struct perf_evsel; struct perf_sample_id { struct hlist_node node; u64 id; - struct perf_evsel *evsel; + struct 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; @@ -51,6 +61,7 @@ enum term_type { PERF_EVSEL__CONFIG_TERM_DRV_CFG, PERF_EVSEL__CONFIG_TERM_BRANCH, PERF_EVSEL__CONFIG_TERM_PERCORE, + PERF_EVSEL__CONFIG_TERM_AUX_OUTPUT, }; struct perf_evsel_config_term { @@ -69,6 +80,7 @@ struct perf_evsel_config_term { char *branch; unsigned long max_events; bool percore; + bool aux_output; } val; bool weak; }; @@ -82,28 +94,29 @@ enum perf_tool_event { PERF_TOOL_DURATION_TIME = 1, }; -/** struct perf_evsel - event selector +struct bpf_object; +struct perf_counts; +struct xyarray; + +/** struct evsel - event selector * * @evlist - evlist this evsel is in, if it is in one. - * @node - To insert it into evlist->entries or in other list_heads, say in - * the event parsing routines. + * @core - libperf evsel object * @name - Can be set to retain the original event name passed by the user, * so that when showing results in tools such as 'perf stat', we * show the name used, not some alias. * @id_pos: the position of the event id (PERF_SAMPLE_ID or * PERF_SAMPLE_IDENTIFIER) in a sample event i.e. in the array of - * struct sample_event + * struct perf_record_sample * @is_pos: the position (counting backwards) of the event id (PERF_SAMPLE_ID or * PERF_SAMPLE_IDENTIFIER) in a non-sample event i.e. if sample_id_all * is used there is an id sample appended to non-sample events * @priv: And what is in its containing unnamed union are tool specific */ -struct perf_evsel { - struct list_head node; - struct perf_evlist *evlist; - struct perf_event_attr attr; +struct evsel { + struct perf_evsel core; + struct evlist *evlist; char *filter; - struct xyarray *fd; struct xyarray *sample_id; u64 *id; struct perf_counts *counts; @@ -122,9 +135,6 @@ struct perf_evsel { u64 db_id; struct cgroup *cgrp; void *handler; - struct cpu_map *cpus; - struct cpu_map *own_cpus; - struct thread_map *threads; unsigned int sample_size; int id_pos; int is_pos; @@ -145,19 +155,20 @@ struct perf_evsel { bool use_uncore_alias; /* parse modifier helper */ int exclude_GH; - int nr_members; int sample_read; unsigned long *per_pkg_mask; - struct perf_evsel *leader; + struct evsel *leader; char *group_name; bool cmdline_group_boundary; struct list_head config_terms; + struct bpf_object *bpf_obj; int bpf_fd; bool auto_merge_stats; bool merged_stat; const char * metric_expr; const char * metric_name; - struct perf_evsel **metric_events; + struct evsel **metric_events; + struct evsel *metric_leader; bool collect_stat; bool weak_group; bool percore; @@ -184,73 +195,73 @@ struct perf_missing_features { bool write_backward; bool group_read; bool ksymbol; - bool bpf_event; + bool bpf; + bool aux_output; }; extern struct perf_missing_features perf_missing_features; -struct cpu_map; +struct perf_cpu_map; struct target; struct thread_map; struct record_opts; -static inline struct cpu_map *perf_evsel__cpus(struct perf_evsel *evsel) +static inline struct perf_cpu_map *evsel__cpus(struct evsel *evsel) { - return evsel->cpus; + return perf_evsel__cpus(&evsel->core); } -static inline int perf_evsel__nr_cpus(struct perf_evsel *evsel) +static inline int perf_evsel__nr_cpus(struct evsel *evsel) { - return perf_evsel__cpus(evsel)->nr; + return evsel__cpus(evsel)->nr; } void perf_counts_values__scale(struct perf_counts_values *count, bool scale, s8 *pscaled); -void perf_evsel__compute_deltas(struct perf_evsel *evsel, int cpu, int thread, +void perf_evsel__compute_deltas(struct evsel *evsel, int cpu, int thread, struct perf_counts_values *count); int perf_evsel__object_config(size_t object_size, - int (*init)(struct perf_evsel *evsel), - void (*fini)(struct perf_evsel *evsel)); + int (*init)(struct evsel *evsel), + void (*fini)(struct evsel *evsel)); -struct perf_evsel *perf_evsel__new_idx(struct perf_event_attr *attr, int idx); +struct evsel *perf_evsel__new_idx(struct perf_event_attr *attr, int idx); -static inline struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr) +static inline struct evsel *evsel__new(struct perf_event_attr *attr) { return perf_evsel__new_idx(attr, 0); } -struct perf_evsel *perf_evsel__newtp_idx(const char *sys, const char *name, int idx); +struct evsel *perf_evsel__newtp_idx(const char *sys, const char *name, int idx); /* * Returns pointer with encoded error via <linux/err.h> interface. */ -static inline struct perf_evsel *perf_evsel__newtp(const char *sys, const char *name) +static inline struct evsel *perf_evsel__newtp(const char *sys, const char *name) { return perf_evsel__newtp_idx(sys, name, 0); } -struct perf_evsel *perf_evsel__new_cycles(bool precise); +struct evsel *perf_evsel__new_cycles(bool precise); struct tep_event *event_format__new(const char *sys, const char *name); -void perf_evsel__init(struct perf_evsel *evsel, - struct perf_event_attr *attr, int idx); -void perf_evsel__exit(struct perf_evsel *evsel); -void perf_evsel__delete(struct perf_evsel *evsel); +void evsel__init(struct evsel *evsel, struct perf_event_attr *attr, int idx); +void perf_evsel__exit(struct evsel *evsel); +void evsel__delete(struct evsel *evsel); struct callchain_param; -void perf_evsel__config(struct perf_evsel *evsel, +void perf_evsel__config(struct evsel *evsel, struct record_opts *opts, struct callchain_param *callchain); -void perf_evsel__config_callchain(struct perf_evsel *evsel, +void perf_evsel__config_callchain(struct evsel *evsel, struct record_opts *opts, struct callchain_param *callchain); int __perf_evsel__sample_size(u64 sample_type); -void perf_evsel__calc_id_pos(struct perf_evsel *evsel); +void perf_evsel__calc_id_pos(struct evsel *evsel); bool perf_evsel__is_cache_op_valid(u8 type, u8 op); @@ -266,17 +277,16 @@ extern const char *perf_evsel__hw_names[PERF_COUNT_HW_MAX]; extern const char *perf_evsel__sw_names[PERF_COUNT_SW_MAX]; int __perf_evsel__hw_cache_type_op_res_name(u8 type, u8 op, u8 result, char *bf, size_t size); -const char *perf_evsel__name(struct perf_evsel *evsel); +const char *perf_evsel__name(struct evsel *evsel); -const char *perf_evsel__group_name(struct perf_evsel *evsel); -int perf_evsel__group_desc(struct perf_evsel *evsel, char *buf, size_t size); +const char *perf_evsel__group_name(struct evsel *evsel); +int perf_evsel__group_desc(struct evsel *evsel, char *buf, size_t size); -int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads); -void perf_evsel__close_fd(struct perf_evsel *evsel); +int perf_evsel__alloc_id(struct evsel *evsel, int ncpus, int nthreads); -void __perf_evsel__set_sample_bit(struct perf_evsel *evsel, +void __perf_evsel__set_sample_bit(struct evsel *evsel, enum perf_event_sample_format bit); -void __perf_evsel__reset_sample_bit(struct perf_evsel *evsel, +void __perf_evsel__reset_sample_bit(struct evsel *evsel, enum perf_event_sample_format bit); #define perf_evsel__set_sample_bit(evsel, bit) \ @@ -285,33 +295,32 @@ void __perf_evsel__reset_sample_bit(struct perf_evsel *evsel, #define perf_evsel__reset_sample_bit(evsel, bit) \ __perf_evsel__reset_sample_bit(evsel, PERF_SAMPLE_##bit) -void perf_evsel__set_sample_id(struct perf_evsel *evsel, +void perf_evsel__set_sample_id(struct evsel *evsel, bool use_sample_identifier); -int perf_evsel__set_filter(struct perf_evsel *evsel, const char *filter); -int perf_evsel__append_tp_filter(struct perf_evsel *evsel, const char *filter); -int perf_evsel__append_addr_filter(struct perf_evsel *evsel, +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 perf_evsel__apply_filter(struct perf_evsel *evsel, const char *filter); -int perf_evsel__enable(struct perf_evsel *evsel); -int perf_evsel__disable(struct perf_evsel *evsel); - -int perf_evsel__open_per_cpu(struct perf_evsel *evsel, - struct cpu_map *cpus); -int perf_evsel__open_per_thread(struct perf_evsel *evsel, - struct thread_map *threads); -int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, - struct thread_map *threads); -void perf_evsel__close(struct perf_evsel *evsel); +int evsel__enable(struct evsel *evsel); +int evsel__disable(struct evsel *evsel); + +int perf_evsel__open_per_cpu(struct evsel *evsel, + struct perf_cpu_map *cpus); +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, + struct perf_thread_map *threads); +void evsel__close(struct evsel *evsel); struct perf_sample; -void *perf_evsel__rawptr(struct perf_evsel *evsel, struct perf_sample *sample, +void *perf_evsel__rawptr(struct evsel *evsel, struct perf_sample *sample, const char *name); -u64 perf_evsel__intval(struct perf_evsel *evsel, struct perf_sample *sample, +u64 perf_evsel__intval(struct evsel *evsel, struct perf_sample *sample, const char *name); -static inline char *perf_evsel__strval(struct perf_evsel *evsel, +static inline char *perf_evsel__strval(struct evsel *evsel, struct perf_sample *sample, const char *name) { @@ -322,31 +331,28 @@ struct tep_format_field; u64 format_field__intval(struct tep_format_field *field, struct perf_sample *sample, bool needs_swap); -struct tep_format_field *perf_evsel__field(struct perf_evsel *evsel, const char *name); +struct tep_format_field *perf_evsel__field(struct evsel *evsel, const char *name); #define perf_evsel__match(evsel, t, c) \ - (evsel->attr.type == PERF_TYPE_##t && \ - evsel->attr.config == PERF_COUNT_##c) + (evsel->core.attr.type == PERF_TYPE_##t && \ + evsel->core.attr.config == PERF_COUNT_##c) -static inline bool perf_evsel__match2(struct perf_evsel *e1, - struct perf_evsel *e2) +static inline bool perf_evsel__match2(struct evsel *e1, + struct evsel *e2) { - return (e1->attr.type == e2->attr.type) && - (e1->attr.config == e2->attr.config); + return (e1->core.attr.type == e2->core.attr.type) && + (e1->core.attr.config == e2->core.attr.config); } #define perf_evsel__cmp(a, b) \ ((a) && \ (b) && \ - (a)->attr.type == (b)->attr.type && \ - (a)->attr.config == (b)->attr.config) - -int perf_evsel__read(struct perf_evsel *evsel, int cpu, int thread, - struct perf_counts_values *count); + (a)->core.attr.type == (b)->core.attr.type && \ + (a)->core.attr.config == (b)->core.attr.config) -int perf_evsel__read_counter(struct perf_evsel *evsel, int cpu, int thread); +int perf_evsel__read_counter(struct evsel *evsel, int cpu, int thread); -int __perf_evsel__read_on_cpu(struct perf_evsel *evsel, +int __perf_evsel__read_on_cpu(struct evsel *evsel, int cpu, int thread, bool scale); /** @@ -356,7 +362,7 @@ int __perf_evsel__read_on_cpu(struct perf_evsel *evsel, * @cpu - CPU of interest * @thread - thread of interest */ -static inline int perf_evsel__read_on_cpu(struct perf_evsel *evsel, +static inline int perf_evsel__read_on_cpu(struct evsel *evsel, int cpu, int thread) { return __perf_evsel__read_on_cpu(evsel, cpu, thread, false); @@ -369,27 +375,27 @@ static inline int perf_evsel__read_on_cpu(struct perf_evsel *evsel, * @cpu - CPU of interest * @thread - thread of interest */ -static inline int perf_evsel__read_on_cpu_scaled(struct perf_evsel *evsel, +static inline int perf_evsel__read_on_cpu_scaled(struct evsel *evsel, int cpu, int thread) { return __perf_evsel__read_on_cpu(evsel, cpu, thread, true); } -int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event, +int perf_evsel__parse_sample(struct evsel *evsel, union perf_event *event, struct perf_sample *sample); -int perf_evsel__parse_sample_timestamp(struct perf_evsel *evsel, +int perf_evsel__parse_sample_timestamp(struct evsel *evsel, union perf_event *event, u64 *timestamp); -static inline struct perf_evsel *perf_evsel__next(struct perf_evsel *evsel) +static inline struct evsel *perf_evsel__next(struct evsel *evsel) { - return list_entry(evsel->node.next, struct perf_evsel, node); + return list_entry(evsel->core.node.next, struct evsel, core.node); } -static inline struct perf_evsel *perf_evsel__prev(struct perf_evsel *evsel) +static inline struct evsel *perf_evsel__prev(struct evsel *evsel) { - return list_entry(evsel->node.prev, struct perf_evsel, node); + return list_entry(evsel->core.node.prev, struct evsel, core.node); } /** @@ -399,7 +405,7 @@ static inline struct perf_evsel *perf_evsel__prev(struct perf_evsel *evsel) * * Return %true if @evsel is a group leader or a stand-alone event */ -static inline bool perf_evsel__is_group_leader(const struct perf_evsel *evsel) +static inline bool perf_evsel__is_group_leader(const struct evsel *evsel) { return evsel->leader == evsel; } @@ -412,22 +418,22 @@ static inline bool perf_evsel__is_group_leader(const struct perf_evsel *evsel) * Return %true iff event group view is enabled and @evsel is a actual group * leader which has other members in the group */ -static inline bool perf_evsel__is_group_event(struct perf_evsel *evsel) +static inline bool perf_evsel__is_group_event(struct evsel *evsel) { if (!symbol_conf.event_group) return false; - return perf_evsel__is_group_leader(evsel) && evsel->nr_members > 1; + return perf_evsel__is_group_leader(evsel) && evsel->core.nr_members > 1; } -bool perf_evsel__is_function_event(struct perf_evsel *evsel); +bool perf_evsel__is_function_event(struct evsel *evsel); -static inline bool perf_evsel__is_bpf_output(struct perf_evsel *evsel) +static inline bool perf_evsel__is_bpf_output(struct evsel *evsel) { return perf_evsel__match(evsel, SOFTWARE, SW_BPF_OUTPUT); } -static inline bool perf_evsel__is_clock(struct perf_evsel *evsel) +static inline bool perf_evsel__is_clock(struct evsel *evsel) { return perf_evsel__match(evsel, SOFTWARE, SW_CPU_CLOCK) || perf_evsel__match(evsel, SOFTWARE, SW_TASK_CLOCK); @@ -441,7 +447,7 @@ struct perf_attr_details { bool trace_fields; }; -int perf_evsel__fprintf(struct perf_evsel *evsel, +int perf_evsel__fprintf(struct evsel *evsel, struct perf_attr_details *details, FILE *fp); #define EVSEL__PRINT_IP (1<<0) @@ -464,36 +470,36 @@ int sample__fprintf_sym(struct perf_sample *sample, struct addr_location *al, int left_alignment, unsigned int print_opts, struct callchain_cursor *cursor, FILE *fp); -bool perf_evsel__fallback(struct perf_evsel *evsel, int err, +bool perf_evsel__fallback(struct evsel *evsel, int err, char *msg, size_t msgsize); -int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target, +int perf_evsel__open_strerror(struct evsel *evsel, struct target *target, int err, char *msg, size_t size); -static inline int perf_evsel__group_idx(struct perf_evsel *evsel) +static inline int perf_evsel__group_idx(struct evsel *evsel) { return evsel->idx - evsel->leader->idx; } /* Iterates group WITHOUT the leader. */ #define for_each_group_member(_evsel, _leader) \ -for ((_evsel) = list_entry((_leader)->node.next, struct perf_evsel, node); \ +for ((_evsel) = list_entry((_leader)->core.node.next, struct evsel, core.node); \ (_evsel) && (_evsel)->leader == (_leader); \ - (_evsel) = list_entry((_evsel)->node.next, struct perf_evsel, node)) + (_evsel) = list_entry((_evsel)->core.node.next, struct evsel, core.node)) /* Iterates group WITH the leader. */ #define for_each_group_evsel(_evsel, _leader) \ for ((_evsel) = _leader; \ (_evsel) && (_evsel)->leader == (_leader); \ - (_evsel) = list_entry((_evsel)->node.next, struct perf_evsel, node)) + (_evsel) = list_entry((_evsel)->core.node.next, struct evsel, core.node)) -static inline bool perf_evsel__has_branch_callstack(const struct perf_evsel *evsel) +static inline bool perf_evsel__has_branch_callstack(const struct evsel *evsel) { - return evsel->attr.branch_sample_type & PERF_SAMPLE_BRANCH_CALL_STACK; + return evsel->core.attr.branch_sample_type & PERF_SAMPLE_BRANCH_CALL_STACK; } -static inline bool evsel__has_callchain(const struct perf_evsel *evsel) +static inline bool evsel__has_callchain(const struct evsel *evsel) { - return (evsel->attr.sample_type & PERF_SAMPLE_CALLCHAIN) != 0; + return (evsel->core.attr.sample_type & PERF_SAMPLE_CALLCHAIN) != 0; } typedef int (*attr__fprintf_f)(FILE *, const char *, const char *, void *); @@ -501,7 +507,7 @@ typedef int (*attr__fprintf_f)(FILE *, const char *, const char *, void *); int perf_event_attr__fprintf(FILE *fp, struct perf_event_attr *attr, attr__fprintf_f attr__fprintf, void *priv); -struct perf_env *perf_evsel__env(struct perf_evsel *evsel); +struct perf_env *perf_evsel__env(struct evsel *evsel); -int perf_evsel__store_ids(struct perf_evsel *evsel, struct perf_evlist *evlist); +int perf_evsel__store_ids(struct evsel *evsel, struct evlist *evlist); #endif /* __PERF_EVSEL_H */ diff --git a/tools/perf/util/evsel_fprintf.c b/tools/perf/util/evsel_fprintf.c index 95ea147f9e18..496fec01f5d1 100644 --- a/tools/perf/util/evsel_fprintf.c +++ b/tools/perf/util/evsel_fprintf.c @@ -33,26 +33,26 @@ static int __print_attr__fprintf(FILE *fp, const char *name, const char *val, vo return comma_fprintf(fp, (bool *)priv, " %s: %s", name, val); } -int perf_evsel__fprintf(struct perf_evsel *evsel, +int perf_evsel__fprintf(struct evsel *evsel, struct perf_attr_details *details, FILE *fp) { bool first = true; int printed = 0; if (details->event_group) { - struct perf_evsel *pos; + struct evsel *pos; if (!perf_evsel__is_group_leader(evsel)) return 0; - if (evsel->nr_members > 1) + if (evsel->core.nr_members > 1) printed += fprintf(fp, "%s{", evsel->group_name ?: ""); printed += fprintf(fp, "%s", perf_evsel__name(evsel)); for_each_group_member(pos, evsel) printed += fprintf(fp, ",%s", perf_evsel__name(pos)); - if (evsel->nr_members > 1) + if (evsel->core.nr_members > 1) printed += fprintf(fp, "}"); goto out; } @@ -60,22 +60,22 @@ int perf_evsel__fprintf(struct perf_evsel *evsel, printed += fprintf(fp, "%s", perf_evsel__name(evsel)); if (details->verbose) { - printed += perf_event_attr__fprintf(fp, &evsel->attr, + printed += perf_event_attr__fprintf(fp, &evsel->core.attr, __print_attr__fprintf, &first); } else if (details->freq) { const char *term = "sample_freq"; - if (!evsel->attr.freq) + if (!evsel->core.attr.freq) term = "sample_period"; printed += comma_fprintf(fp, &first, " %s=%" PRIu64, - term, (u64)evsel->attr.sample_freq); + term, (u64)evsel->core.attr.sample_freq); } if (details->trace_fields) { struct tep_format_field *field; - if (evsel->attr.type != PERF_TYPE_TRACEPOINT) { + if (evsel->core.attr.type != PERF_TYPE_TRACEPOINT) { printed += comma_fprintf(fp, &first, " (not a tracepoint)"); goto out; } diff --git a/tools/perf/util/evswitch.c b/tools/perf/util/evswitch.c new file mode 100644 index 000000000000..3ba72f743d3c --- /dev/null +++ b/tools/perf/util/evswitch.c @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2019, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com> + +#include "evswitch.h" +#include "evlist.h" + +bool evswitch__discard(struct evswitch *evswitch, struct evsel *evsel) +{ + if (evswitch->on && evswitch->discarding) { + if (evswitch->on != evsel) + return true; + + evswitch->discarding = false; + + if (!evswitch->show_on_off_events) + return true; + + return false; + } + + if (evswitch->off && !evswitch->discarding) { + if (evswitch->off != evsel) + return false; + + evswitch->discarding = true; + + if (!evswitch->show_on_off_events) + return true; + } + + return false; +} + +static int evswitch__fprintf_enoent(FILE *fp, const char *evtype, const char *evname) +{ + int printed = fprintf(fp, "ERROR: switch-%s event not found (%s)\n", evtype, evname); + + return printed += fprintf(fp, "HINT: use 'perf evlist' to see the available event names\n"); +} + +int evswitch__init(struct evswitch *evswitch, struct evlist *evlist, FILE *fp) +{ + if (evswitch->on_name) { + evswitch->on = perf_evlist__find_evsel_by_str(evlist, evswitch->on_name); + if (evswitch->on == NULL) { + evswitch__fprintf_enoent(fp, "on", evswitch->on_name); + return -ENOENT; + } + evswitch->discarding = true; + } + + if (evswitch->off_name) { + evswitch->off = perf_evlist__find_evsel_by_str(evlist, evswitch->off_name); + if (evswitch->off == NULL) { + evswitch__fprintf_enoent(fp, "off", evswitch->off_name); + return -ENOENT; + } + } + + return 0; +} diff --git a/tools/perf/util/evswitch.h b/tools/perf/util/evswitch.h new file mode 100644 index 000000000000..fd30460b6218 --- /dev/null +++ b/tools/perf/util/evswitch.h @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2019, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com> +#ifndef __PERF_EVSWITCH_H +#define __PERF_EVSWITCH_H 1 + +#include <stdbool.h> +#include <stdio.h> + +struct evsel; +struct evlist; + +struct evswitch { + struct evsel *on, *off; + const char *on_name, *off_name; + bool discarding; + bool show_on_off_events; +}; + +int evswitch__init(struct evswitch *evswitch, struct evlist *evlist, FILE *fp); + +bool evswitch__discard(struct evswitch *evswitch, struct evsel *evsel); + +#define OPTS_EVSWITCH(evswitch) \ + OPT_STRING(0, "switch-on", &(evswitch)->on_name, \ + "event", "Consider events after the ocurrence of this event"), \ + OPT_STRING(0, "switch-off", &(evswitch)->off_name, \ + "event", "Stop considering events after the ocurrence of this event"), \ + OPT_BOOLEAN(0, "show-on-off-events", &(evswitch)->show_on_off_events, \ + "Show the on/off switch events, used with --switch-on and --switch-off") + +#endif /* __PERF_EVSWITCH_H */ diff --git a/tools/perf/util/expr.y b/tools/perf/util/expr.y index 432b8560cf51..f9a20a39b64a 100644 --- a/tools/perf/util/expr.y +++ b/tools/perf/util/expr.y @@ -2,9 +2,11 @@ %{ #include "util.h" #include "util/debug.h" +#include <stdlib.h> // strtod() #define IN_EXPR_Y 1 #include "expr.h" #include "smt.h" +#include <assert.h> #include <string.h> #define MAXIDLEN 256 diff --git a/tools/perf/util/genelf.c b/tools/perf/util/genelf.c index 7001247ebbd6..f9f18b8b1df9 100644 --- a/tools/perf/util/genelf.c +++ b/tools/perf/util/genelf.c @@ -14,6 +14,7 @@ #include <libelf.h> #include <string.h> #include <stdlib.h> +#include <unistd.h> #include <inttypes.h> #include <limits.h> #include <fcntl.h> @@ -22,9 +23,9 @@ #include <dwarf.h> #endif -#include "perf.h" #include "genelf.h" #include "../util/jitdump.h" +#include <linux/compiler.h> #ifndef NT_GNU_BUILD_ID #define NT_GNU_BUILD_ID 3 diff --git a/tools/perf/util/genelf_debug.c b/tools/perf/util/genelf_debug.c index 995e490c17fa..30e9f618f6cd 100644 --- a/tools/perf/util/genelf_debug.c +++ b/tools/perf/util/genelf_debug.c @@ -24,7 +24,6 @@ #include <err.h> #include <dwarf.h> -#include "perf.h" #include "genelf.h" #include "../util/jitdump.h" diff --git a/tools/perf/util/get_current_dir_name.c b/tools/perf/util/get_current_dir_name.c index 01f32f26552d..b205d929245f 100644 --- a/tools/perf/util/get_current_dir_name.c +++ b/tools/perf/util/get_current_dir_name.c @@ -5,7 +5,6 @@ #include "get_current_dir_name.h" #include <unistd.h> #include <stdlib.h> -#include <stdlib.h> /* Android's 'bionic' library, for one, doesn't have this */ diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 1903d7ec9797..b0c34dda30a0 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -20,12 +20,13 @@ #include <linux/time64.h> #include <dirent.h> #include <bpf/libbpf.h> +#include <perf/cpumap.h> +#include "dso.h" #include "evlist.h" #include "evsel.h" #include "header.h" #include "memswap.h" -#include "../perf.h" #include "trace-event.h" #include "session.h" #include "symbol.h" @@ -41,6 +42,7 @@ #include "tool.h" #include "time-utils.h" #include "units.h" +#include "util.h" #include "cputopo.h" #include "bpf-event.h" @@ -74,7 +76,7 @@ struct feat_fd { void *buf; /* Either buf != NULL or fd >= 0 */ ssize_t offset; size_t size; - struct perf_evsel *events; + struct evsel *events; }; void perf_header__set_feat(struct perf_header *header, int feat) @@ -299,16 +301,16 @@ static int do_read_bitmap(struct feat_fd *ff, unsigned long **pset, u64 *psize) } static int write_tracing_data(struct feat_fd *ff, - struct perf_evlist *evlist) + struct evlist *evlist) { if (WARN(ff->buf, "Error: calling %s in pipe-mode.\n", __func__)) return -1; - return read_tracing_data(ff->fd, &evlist->entries); + return read_tracing_data(ff->fd, &evlist->core.entries); } static int write_build_id(struct feat_fd *ff, - struct perf_evlist *evlist __maybe_unused) + struct evlist *evlist __maybe_unused) { struct perf_session *session; int err; @@ -332,7 +334,7 @@ static int write_build_id(struct feat_fd *ff, } static int write_hostname(struct feat_fd *ff, - struct perf_evlist *evlist __maybe_unused) + struct evlist *evlist __maybe_unused) { struct utsname uts; int ret; @@ -345,7 +347,7 @@ static int write_hostname(struct feat_fd *ff, } static int write_osrelease(struct feat_fd *ff, - struct perf_evlist *evlist __maybe_unused) + struct evlist *evlist __maybe_unused) { struct utsname uts; int ret; @@ -358,7 +360,7 @@ static int write_osrelease(struct feat_fd *ff, } static int write_arch(struct feat_fd *ff, - struct perf_evlist *evlist __maybe_unused) + struct evlist *evlist __maybe_unused) { struct utsname uts; int ret; @@ -371,7 +373,7 @@ static int write_arch(struct feat_fd *ff, } static int write_version(struct feat_fd *ff, - struct perf_evlist *evlist __maybe_unused) + struct evlist *evlist __maybe_unused) { return do_write_string(ff, perf_version_string); } @@ -432,9 +434,27 @@ done: } static int write_cpudesc(struct feat_fd *ff, - struct perf_evlist *evlist __maybe_unused) -{ + struct evlist *evlist __maybe_unused) +{ +#if defined(__powerpc__) || defined(__hppa__) || defined(__sparc__) +#define CPUINFO_PROC { "cpu", } +#elif defined(__s390__) +#define CPUINFO_PROC { "vendor_id", } +#elif defined(__sh__) +#define CPUINFO_PROC { "cpu type", } +#elif defined(__alpha__) || defined(__mips__) +#define CPUINFO_PROC { "cpu model", } +#elif defined(__arm__) +#define CPUINFO_PROC { "model name", "Processor", } +#elif defined(__arc__) +#define CPUINFO_PROC { "Processor", } +#elif defined(__xtensa__) +#define CPUINFO_PROC { "core ID", } +#else +#define CPUINFO_PROC { "model name", } +#endif const char *cpuinfo_procs[] = CPUINFO_PROC; +#undef CPUINFO_PROC unsigned int i; for (i = 0; i < ARRAY_SIZE(cpuinfo_procs); i++) { @@ -448,7 +468,7 @@ static int write_cpudesc(struct feat_fd *ff, static int write_nrcpus(struct feat_fd *ff, - struct perf_evlist *evlist __maybe_unused) + struct evlist *evlist __maybe_unused) { long nr; u32 nrc, nra; @@ -470,13 +490,13 @@ static int write_nrcpus(struct feat_fd *ff, } static int write_event_desc(struct feat_fd *ff, - struct perf_evlist *evlist) + struct evlist *evlist) { - struct perf_evsel *evsel; + struct evsel *evsel; u32 nre, nri, sz; int ret; - nre = evlist->nr_entries; + nre = evlist->core.nr_entries; /* * write number of events @@ -488,13 +508,13 @@ static int write_event_desc(struct feat_fd *ff, /* * size of perf_event_attr struct */ - sz = (u32)sizeof(evsel->attr); + sz = (u32)sizeof(evsel->core.attr); ret = do_write(ff, &sz, sizeof(sz)); if (ret < 0) return ret; evlist__for_each_entry(evlist, evsel) { - ret = do_write(ff, &evsel->attr, sz); + ret = do_write(ff, &evsel->core.attr, sz); if (ret < 0) return ret; /* @@ -526,7 +546,7 @@ static int write_event_desc(struct feat_fd *ff, } static int write_cmdline(struct feat_fd *ff, - struct perf_evlist *evlist __maybe_unused) + struct evlist *evlist __maybe_unused) { char pbuf[MAXPATHLEN], *buf; int i, ret, n; @@ -555,7 +575,7 @@ static int write_cmdline(struct feat_fd *ff, static int write_cpu_topology(struct feat_fd *ff, - struct perf_evlist *evlist __maybe_unused) + struct evlist *evlist __maybe_unused) { struct cpu_topology *tp; u32 i; @@ -627,7 +647,7 @@ done: static int write_total_mem(struct feat_fd *ff, - struct perf_evlist *evlist __maybe_unused) + struct evlist *evlist __maybe_unused) { char *buf = NULL; FILE *fp; @@ -656,7 +676,7 @@ static int write_total_mem(struct feat_fd *ff, } static int write_numa_topology(struct feat_fd *ff, - struct perf_evlist *evlist __maybe_unused) + struct evlist *evlist __maybe_unused) { struct numa_topology *tp; int ret = -1; @@ -710,7 +730,7 @@ err: */ static int write_pmu_mappings(struct feat_fd *ff, - struct perf_evlist *evlist __maybe_unused) + struct evlist *evlist __maybe_unused) { struct perf_pmu *pmu = NULL; u32 pmu_num = 0; @@ -759,10 +779,10 @@ static int write_pmu_mappings(struct feat_fd *ff, * }; */ static int write_group_desc(struct feat_fd *ff, - struct perf_evlist *evlist) + struct evlist *evlist) { u32 nr_groups = evlist->nr_groups; - struct perf_evsel *evsel; + struct evsel *evsel; int ret; ret = do_write(ff, &nr_groups, sizeof(nr_groups)); @@ -771,10 +791,10 @@ static int write_group_desc(struct feat_fd *ff, evlist__for_each_entry(evlist, evsel) { if (perf_evsel__is_group_leader(evsel) && - evsel->nr_members > 1) { + evsel->core.nr_members > 1) { const char *name = evsel->group_name ?: "{anon_group}"; u32 leader_idx = evsel->idx; - u32 nr_members = evsel->nr_members; + u32 nr_members = evsel->core.nr_members; ret = do_write_string(ff, name); if (ret < 0) @@ -841,7 +861,7 @@ int __weak get_cpuid(char *buffer __maybe_unused, size_t sz __maybe_unused) } static int write_cpuid(struct feat_fd *ff, - struct perf_evlist *evlist __maybe_unused) + struct evlist *evlist __maybe_unused) { char buffer[64]; int ret; @@ -854,13 +874,13 @@ static int write_cpuid(struct feat_fd *ff, } static int write_branch_stack(struct feat_fd *ff __maybe_unused, - struct perf_evlist *evlist __maybe_unused) + struct evlist *evlist __maybe_unused) { return 0; } static int write_auxtrace(struct feat_fd *ff, - struct perf_evlist *evlist __maybe_unused) + struct evlist *evlist __maybe_unused) { struct perf_session *session; int err; @@ -877,14 +897,14 @@ static int write_auxtrace(struct feat_fd *ff, } static int write_clockid(struct feat_fd *ff, - struct perf_evlist *evlist __maybe_unused) + struct evlist *evlist __maybe_unused) { return do_write(ff, &ff->ph->env.clockid_res_ns, sizeof(ff->ph->env.clockid_res_ns)); } static int write_dir_format(struct feat_fd *ff, - struct perf_evlist *evlist __maybe_unused) + struct evlist *evlist __maybe_unused) { struct perf_session *session; struct perf_data *data; @@ -900,7 +920,7 @@ static int write_dir_format(struct feat_fd *ff, #ifdef HAVE_LIBBPF_SUPPORT static int write_bpf_prog_info(struct feat_fd *ff, - struct perf_evlist *evlist __maybe_unused) + struct evlist *evlist __maybe_unused) { struct perf_env *env = &ff->ph->env; struct rb_root *root; @@ -942,14 +962,14 @@ out: } #else // HAVE_LIBBPF_SUPPORT static int write_bpf_prog_info(struct feat_fd *ff __maybe_unused, - struct perf_evlist *evlist __maybe_unused) + struct evlist *evlist __maybe_unused) { return 0; } #endif // HAVE_LIBBPF_SUPPORT static int write_bpf_btf(struct feat_fd *ff, - struct perf_evlist *evlist __maybe_unused) + struct evlist *evlist __maybe_unused) { struct perf_env *env = &ff->ph->env; struct rb_root *root; @@ -1120,16 +1140,17 @@ static int build_caches(struct cpu_cache_level caches[], u32 size, u32 *cntp) return 0; } -#define MAX_CACHES (MAX_NR_CPUS * 4) +#define MAX_CACHE_LVL 4 static int write_cache(struct feat_fd *ff, - struct perf_evlist *evlist __maybe_unused) + struct evlist *evlist __maybe_unused) { - struct cpu_cache_level caches[MAX_CACHES]; + u32 max_caches = cpu__max_cpu() * MAX_CACHE_LVL; + struct cpu_cache_level caches[max_caches]; u32 cnt = 0, i, version = 1; int ret; - ret = build_caches(caches, MAX_CACHES, &cnt); + ret = build_caches(caches, max_caches, &cnt); if (ret) goto out; @@ -1175,13 +1196,13 @@ out: } static int write_stat(struct feat_fd *ff __maybe_unused, - struct perf_evlist *evlist __maybe_unused) + struct evlist *evlist __maybe_unused) { return 0; } static int write_sample_time(struct feat_fd *ff, - struct perf_evlist *evlist) + struct evlist *evlist) { int ret; @@ -1315,7 +1336,7 @@ static int build_mem_topology(struct memory_node *nodes, u64 size, u64 *cntp) * 48 - bitmap | bitmap of memory indexes that belongs to node */ static int write_mem_topology(struct feat_fd *ff __maybe_unused, - struct perf_evlist *evlist __maybe_unused) + struct evlist *evlist __maybe_unused) { static struct memory_node nodes[MAX_MEMORY_NODES]; u64 bsize, version = 1, i, nr; @@ -1365,7 +1386,7 @@ out: } static int write_compressed(struct feat_fd *ff __maybe_unused, - struct perf_evlist *evlist __maybe_unused) + struct evlist *evlist __maybe_unused) { int ret; @@ -1568,14 +1589,14 @@ static void print_bpf_btf(struct feat_fd *ff, FILE *fp) up_read(&env->bpf_progs.lock); } -static void free_event_desc(struct perf_evsel *events) +static void free_event_desc(struct evsel *events) { - struct perf_evsel *evsel; + struct evsel *evsel; if (!events) return; - for (evsel = events; evsel->attr.size; evsel++) { + for (evsel = events; evsel->core.attr.size; evsel++) { zfree(&evsel->name); zfree(&evsel->id); } @@ -1583,9 +1604,9 @@ static void free_event_desc(struct perf_evsel *events) free(events); } -static struct perf_evsel *read_event_desc(struct feat_fd *ff) +static struct evsel *read_event_desc(struct feat_fd *ff) { - struct perf_evsel *evsel, *events = NULL; + struct evsel *evsel, *events = NULL; u64 *id; void *buf = NULL; u32 nre, sz, nr, i, j; @@ -1603,12 +1624,12 @@ static struct perf_evsel *read_event_desc(struct feat_fd *ff) if (!buf) goto error; - /* the last event terminates with evsel->attr.size == 0: */ + /* the last event terminates with evsel->core.attr.size == 0: */ events = calloc(nre + 1, sizeof(*events)); if (!events) goto error; - msz = sizeof(evsel->attr); + msz = sizeof(evsel->core.attr); if (sz < msz) msz = sz; @@ -1625,7 +1646,7 @@ static struct perf_evsel *read_event_desc(struct feat_fd *ff) if (ff->ph->needs_swap) perf_event__attr_swap(buf); - memcpy(&evsel->attr, buf, msz); + memcpy(&evsel->core.attr, buf, msz); if (do_read_u32(ff, &nr)) goto error; @@ -1669,7 +1690,7 @@ static int __desc_attr__fprintf(FILE *fp, const char *name, const char *val, static void print_event_desc(struct feat_fd *ff, FILE *fp) { - struct perf_evsel *evsel, *events; + struct evsel *evsel, *events; u32 j; u64 *id; @@ -1683,7 +1704,7 @@ static void print_event_desc(struct feat_fd *ff, FILE *fp) return; } - for (evsel = events; evsel->attr.size; evsel++) { + for (evsel = events; evsel->core.attr.size; evsel++) { fprintf(fp, "# event : name = %s, ", evsel->name); if (evsel->ids) { @@ -1696,7 +1717,7 @@ static void print_event_desc(struct feat_fd *ff, FILE *fp) fprintf(fp, " }"); } - perf_event_attr__fprintf(fp, &evsel->attr, __desc_attr__fprintf, NULL); + perf_event_attr__fprintf(fp, &evsel->core.attr, __desc_attr__fprintf, NULL); fputc('\n', fp); } @@ -1804,18 +1825,18 @@ error: static void print_group_desc(struct feat_fd *ff, FILE *fp) { struct perf_session *session; - struct perf_evsel *evsel; + struct evsel *evsel; u32 nr = 0; session = container_of(ff->ph, struct perf_session, header); evlist__for_each_entry(session->evlist, evsel) { if (perf_evsel__is_group_leader(evsel) && - evsel->nr_members > 1) { + evsel->core.nr_members > 1) { fprintf(fp, "# group: %s{%s", evsel->group_name ?: "", perf_evsel__name(evsel)); - nr = evsel->nr_members - 1; + nr = evsel->core.nr_members - 1; } else if (nr) { fprintf(fp, ",%s", perf_evsel__name(evsel)); @@ -1876,7 +1897,7 @@ static void print_mem_topology(struct feat_fd *ff, FILE *fp) } } -static int __event_process_build_id(struct build_id_event *bev, +static int __event_process_build_id(struct perf_record_header_build_id *bev, char *filename, struct perf_session *session) { @@ -1945,7 +1966,7 @@ static int perf_header__read_build_ids_abi_quirk(struct perf_header *header, u8 build_id[PERF_ALIGN(BUILD_ID_SIZE, sizeof(u64))]; char filename[0]; } old_bev; - struct build_id_event bev; + struct perf_record_header_build_id bev; char filename[PATH_MAX]; u64 limit = offset + size; @@ -1986,7 +2007,7 @@ static int perf_header__read_build_ids(struct perf_header *header, int input, u64 offset, u64 size) { struct perf_session *session = container_of(header, struct perf_session, header); - struct build_id_event bev; + struct perf_record_header_build_id bev; char filename[PATH_MAX]; u64 limit = offset + size, orig_offset = offset; int err = -1; @@ -2008,7 +2029,7 @@ static int perf_header__read_build_ids(struct perf_header *header, * * "perf: 'perf kvm' tool for monitoring guest performance from host" * - * Added a field to struct build_id_event that broke the file + * Added a field to struct perf_record_header_build_id that broke the file * format. * * Since the kernel build-id is the first entry, process the @@ -2089,10 +2110,10 @@ static int process_total_mem(struct feat_fd *ff, void *data __maybe_unused) return 0; } -static struct perf_evsel * -perf_evlist__find_by_index(struct perf_evlist *evlist, int idx) +static struct evsel * +perf_evlist__find_by_index(struct evlist *evlist, int idx) { - struct perf_evsel *evsel; + struct evsel *evsel; evlist__for_each_entry(evlist, evsel) { if (evsel->idx == idx) @@ -2103,10 +2124,10 @@ perf_evlist__find_by_index(struct perf_evlist *evlist, int idx) } static void -perf_evlist__set_event_name(struct perf_evlist *evlist, - struct perf_evsel *event) +perf_evlist__set_event_name(struct evlist *evlist, + struct evsel *event) { - struct perf_evsel *evsel; + struct evsel *evsel; if (!event->name) return; @@ -2125,7 +2146,7 @@ static int process_event_desc(struct feat_fd *ff, void *data __maybe_unused) { struct perf_session *session; - struct perf_evsel *evsel, *events = read_event_desc(ff); + struct evsel *evsel, *events = read_event_desc(ff); if (!events) return 0; @@ -2138,7 +2159,7 @@ process_event_desc(struct feat_fd *ff, void *data __maybe_unused) ff->events = events; } - for (evsel = events; evsel->attr.size; evsel++) + for (evsel = events; evsel->core.attr.size; evsel++) perf_evlist__set_event_name(session->evlist, evsel); if (!session->data->is_pipe) @@ -2251,8 +2272,10 @@ static int process_cpu_topology(struct feat_fd *ff, void *data __maybe_unused) /* On s390 the socket_id number is not related to the numbers of cpus. * The socket_id number might be higher than the numbers of cpus. * This depends on the configuration. + * AArch64 is the same. */ - if (ph->env.arch && !strncmp(ph->env.arch, "s390", 4)) + if (ph->env.arch && (!strncmp(ph->env.arch, "s390", 4) + || !strncmp(ph->env.arch, "aarch64", 7))) do_core_id_test = false; for (i = 0; i < (u32)cpu_nr; i++) { @@ -2348,7 +2371,7 @@ static int process_numa_topology(struct feat_fd *ff, void *data __maybe_unused) if (!str) goto error; - n->map = cpu_map__new(str); + n->map = perf_cpu_map__new(str); if (!n->map) goto error; @@ -2415,7 +2438,7 @@ static int process_group_desc(struct feat_fd *ff, void *data __maybe_unused) size_t ret = -1; u32 i, nr, nr_groups; struct perf_session *session; - struct perf_evsel *evsel, *leader = NULL; + struct evsel *evsel, *leader = NULL; struct group_desc { char *name; u32 leader_idx; @@ -2462,7 +2485,7 @@ static int process_group_desc(struct feat_fd *ff, void *data __maybe_unused) evsel->group_name = desc[i].name; desc[i].name = NULL; } - evsel->nr_members = desc[i].nr_members; + evsel->core.nr_members = desc[i].nr_members; if (i >= nr_groups || nr > 0) { pr_debug("invalid group desc\n"); @@ -2470,7 +2493,7 @@ static int process_group_desc(struct feat_fd *ff, void *data __maybe_unused) } leader = evsel; - nr = evsel->nr_members - 1; + nr = evsel->core.nr_members - 1; i++; } else if (nr) { /* This is a group member */ @@ -2801,7 +2824,7 @@ static int process_compressed(struct feat_fd *ff, } struct feature_ops { - int (*write)(struct feat_fd *ff, struct perf_evlist *evlist); + int (*write)(struct feat_fd *ff, struct evlist *evlist); void (*print)(struct feat_fd *ff, FILE *fp); int (*process)(struct feat_fd *ff, void *data); const char *name; @@ -2946,7 +2969,7 @@ int perf_header__fprintf_info(struct perf_session *session, FILE *fp, bool full) static int do_write_feat(struct feat_fd *ff, int type, struct perf_file_section **p, - struct perf_evlist *evlist) + struct evlist *evlist) { int err; int ret = 0; @@ -2976,7 +2999,7 @@ static int do_write_feat(struct feat_fd *ff, int type, } static int perf_header__adds_write(struct perf_header *header, - struct perf_evlist *evlist, int fd) + struct evlist *evlist, int fd) { int nr_sections; struct feat_fd ff; @@ -3044,13 +3067,13 @@ int perf_header__write_pipe(int fd) } int perf_session__write_header(struct perf_session *session, - struct perf_evlist *evlist, + struct evlist *evlist, int fd, bool at_exit) { struct perf_file_header f_header; struct perf_file_attr f_attr; struct perf_header *header = &session->header; - struct perf_evsel *evsel; + struct evsel *evsel; struct feat_fd ff; u64 attr_offset; int err; @@ -3071,7 +3094,7 @@ int perf_session__write_header(struct perf_session *session, evlist__for_each_entry(evlist, evsel) { f_attr = (struct perf_file_attr){ - .attr = evsel->attr, + .attr = evsel->core.attr, .ids = { .offset = evsel->id_offset, .size = evsel->ids * sizeof(u64), @@ -3100,7 +3123,7 @@ int perf_session__write_header(struct perf_session *session, .attr_size = sizeof(f_attr), .attrs = { .offset = attr_offset, - .size = evlist->nr_entries * sizeof(f_attr), + .size = evlist->core.nr_entries * sizeof(f_attr), }, .data = { .offset = header->data_offset, @@ -3479,7 +3502,7 @@ static int read_attr(int fd, struct perf_header *ph, return ret <= 0 ? -1 : 0; } -static int perf_evsel__prepare_tracepoint_event(struct perf_evsel *evsel, +static int perf_evsel__prepare_tracepoint_event(struct evsel *evsel, struct tep_handle *pevent) { struct tep_event *event; @@ -3494,9 +3517,9 @@ static int perf_evsel__prepare_tracepoint_event(struct perf_evsel *evsel, return -1; } - event = tep_find_event(pevent, evsel->attr.config); + event = tep_find_event(pevent, evsel->core.attr.config); if (event == NULL) { - pr_debug("cannot find event format for %d\n", (int)evsel->attr.config); + pr_debug("cannot find event format for %d\n", (int)evsel->core.attr.config); return -1; } @@ -3511,13 +3534,13 @@ static int perf_evsel__prepare_tracepoint_event(struct perf_evsel *evsel, return 0; } -static int perf_evlist__prepare_tracepoint_events(struct perf_evlist *evlist, +static int perf_evlist__prepare_tracepoint_events(struct evlist *evlist, struct tep_handle *pevent) { - struct perf_evsel *pos; + struct evsel *pos; evlist__for_each_entry(evlist, pos) { - if (pos->attr.type == PERF_TYPE_TRACEPOINT && + if (pos->core.attr.type == PERF_TYPE_TRACEPOINT && perf_evsel__prepare_tracepoint_event(pos, pevent)) return -1; } @@ -3535,7 +3558,7 @@ int perf_session__read_header(struct perf_session *session) int nr_attrs, nr_ids, i, j; int fd = perf_data__fd(data); - session->evlist = perf_evlist__new(); + session->evlist = evlist__new(); if (session->evlist == NULL) return -ENOMEM; @@ -3570,7 +3593,7 @@ int perf_session__read_header(struct perf_session *session) lseek(fd, f_header.attrs.offset, SEEK_SET); for (i = 0; i < nr_attrs; i++) { - struct perf_evsel *evsel; + struct evsel *evsel; off_t tmp; if (read_attr(fd, header, &f_attr) < 0) @@ -3583,7 +3606,7 @@ int perf_session__read_header(struct perf_session *session) } tmp = lseek(fd, 0, SEEK_CUR); - evsel = perf_evsel__new(&f_attr.attr); + evsel = evsel__new(&f_attr.attr); if (evsel == NULL) goto out_delete_evlist; @@ -3591,9 +3614,9 @@ int perf_session__read_header(struct perf_session *session) evsel->needs_swap = header->needs_swap; /* * Do it before so that if perf_evsel__alloc_id fails, this - * entry gets purged too at perf_evlist__delete(). + * entry gets purged too at evlist__delete(). */ - perf_evlist__add(session->evlist, evsel); + evlist__add(session->evlist, evsel); nr_ids = f_attr.ids.size / sizeof(u64); /* @@ -3628,7 +3651,7 @@ out_errno: return -errno; out_delete_evlist: - perf_evlist__delete(session->evlist); + evlist__delete(session->evlist); session->evlist = NULL; return -ENOMEM; } @@ -3669,12 +3692,12 @@ int perf_event__synthesize_attr(struct perf_tool *tool, int perf_event__synthesize_features(struct perf_tool *tool, struct perf_session *session, - struct perf_evlist *evlist, + struct evlist *evlist, perf_event__handler_t process) { struct perf_header *header = &session->header; struct feat_fd ff; - struct feature_event *fe; + struct perf_record_header_feature *fe; size_t sz, sz_hdr; int feat, ret; @@ -3737,7 +3760,7 @@ int perf_event__process_feature(struct perf_session *session, { struct perf_tool *tool = session->tool; struct feat_fd ff = { .fd = 0 }; - struct feature_event *fe = (struct feature_event *)event; + struct perf_record_header_feature *fe = (struct perf_record_header_feature *)event; int type = fe->header.type; u64 feat = fe->feat_id; @@ -3774,10 +3797,10 @@ int perf_event__process_feature(struct perf_session *session, return 0; } -static struct event_update_event * +static struct perf_record_event_update * event_update_event__new(size_t size, u64 type, u64 id) { - struct event_update_event *ev; + struct perf_record_event_update *ev; size += sizeof(*ev); size = PERF_ALIGN(size, sizeof(u64)); @@ -3794,10 +3817,10 @@ event_update_event__new(size_t size, u64 type, u64 id) int perf_event__synthesize_event_update_unit(struct perf_tool *tool, - struct perf_evsel *evsel, + struct evsel *evsel, perf_event__handler_t process) { - struct event_update_event *ev; + struct perf_record_event_update *ev; size_t size = strlen(evsel->unit); int err; @@ -3813,18 +3836,18 @@ perf_event__synthesize_event_update_unit(struct perf_tool *tool, int perf_event__synthesize_event_update_scale(struct perf_tool *tool, - struct perf_evsel *evsel, + struct evsel *evsel, perf_event__handler_t process) { - struct event_update_event *ev; - struct event_update_event_scale *ev_data; + struct perf_record_event_update *ev; + struct perf_record_event_update_scale *ev_data; int err; ev = event_update_event__new(sizeof(*ev_data), PERF_EVENT_UPDATE__SCALE, evsel->id[0]); if (ev == NULL) return -ENOMEM; - ev_data = (struct event_update_event_scale *) ev->data; + ev_data = (struct perf_record_event_update_scale *)ev->data; ev_data->scale = evsel->scale; err = process(tool, (union perf_event*) ev, NULL, NULL); free(ev); @@ -3833,10 +3856,10 @@ perf_event__synthesize_event_update_scale(struct perf_tool *tool, int perf_event__synthesize_event_update_name(struct perf_tool *tool, - struct perf_evsel *evsel, + struct evsel *evsel, perf_event__handler_t process) { - struct event_update_event *ev; + struct perf_record_event_update *ev; size_t len = strlen(evsel->name); int err; @@ -3852,18 +3875,18 @@ perf_event__synthesize_event_update_name(struct perf_tool *tool, int perf_event__synthesize_event_update_cpus(struct perf_tool *tool, - struct perf_evsel *evsel, + struct evsel *evsel, perf_event__handler_t process) { - size_t size = sizeof(struct event_update_event); - struct event_update_event *ev; + size_t size = sizeof(struct perf_record_event_update); + struct perf_record_event_update *ev; int max, err; u16 type; - if (!evsel->own_cpus) + if (!evsel->core.own_cpus) return 0; - ev = cpu_map_data__alloc(evsel->own_cpus, &size, &type, &max); + ev = cpu_map_data__alloc(evsel->core.own_cpus, &size, &type, &max); if (!ev) return -ENOMEM; @@ -3872,8 +3895,8 @@ perf_event__synthesize_event_update_cpus(struct perf_tool *tool, ev->type = PERF_EVENT_UPDATE__CPUS; ev->id = evsel->id[0]; - cpu_map_data__synthesize((struct cpu_map_data *) ev->data, - evsel->own_cpus, + cpu_map_data__synthesize((struct perf_record_cpu_map_data *)ev->data, + evsel->core.own_cpus, type, max); err = process(tool, (union perf_event*) ev, NULL, NULL); @@ -3883,17 +3906,17 @@ perf_event__synthesize_event_update_cpus(struct perf_tool *tool, size_t perf_event__fprintf_event_update(union perf_event *event, FILE *fp) { - struct event_update_event *ev = &event->event_update; - struct event_update_event_scale *ev_scale; - struct event_update_event_cpus *ev_cpus; - struct cpu_map *map; + struct perf_record_event_update *ev = &event->event_update; + struct perf_record_event_update_scale *ev_scale; + struct perf_record_event_update_cpus *ev_cpus; + struct perf_cpu_map *map; size_t ret; - ret = fprintf(fp, "\n... id: %" PRIu64 "\n", ev->id); + ret = fprintf(fp, "\n... id: %" PRI_lu64 "\n", ev->id); switch (ev->type) { case PERF_EVENT_UPDATE__SCALE: - ev_scale = (struct event_update_event_scale *) ev->data; + ev_scale = (struct perf_record_event_update_scale *)ev->data; ret += fprintf(fp, "... scale: %f\n", ev_scale->scale); break; case PERF_EVENT_UPDATE__UNIT: @@ -3903,7 +3926,7 @@ size_t perf_event__fprintf_event_update(union perf_event *event, FILE *fp) ret += fprintf(fp, "... name: %s\n", ev->data); break; case PERF_EVENT_UPDATE__CPUS: - ev_cpus = (struct event_update_event_cpus *) ev->data; + ev_cpus = (struct perf_record_event_update_cpus *)ev->data; ret += fprintf(fp, "... "); map = cpu_map__new_data(&ev_cpus->cpus); @@ -3921,14 +3944,14 @@ size_t perf_event__fprintf_event_update(union perf_event *event, FILE *fp) } int perf_event__synthesize_attrs(struct perf_tool *tool, - struct perf_evlist *evlist, + struct evlist *evlist, perf_event__handler_t process) { - struct perf_evsel *evsel; + struct evsel *evsel; int err = 0; evlist__for_each_entry(evlist, evsel) { - err = perf_event__synthesize_attr(tool, &evsel->attr, evsel->ids, + err = perf_event__synthesize_attr(tool, &evsel->core.attr, evsel->ids, evsel->id, process); if (err) { pr_debug("failed to create perf header attribute\n"); @@ -3939,22 +3962,22 @@ int perf_event__synthesize_attrs(struct perf_tool *tool, return err; } -static bool has_unit(struct perf_evsel *counter) +static bool has_unit(struct evsel *counter) { return counter->unit && *counter->unit; } -static bool has_scale(struct perf_evsel *counter) +static bool has_scale(struct evsel *counter) { return counter->scale != 1; } int perf_event__synthesize_extra_attr(struct perf_tool *tool, - struct perf_evlist *evsel_list, + struct evlist *evsel_list, perf_event__handler_t process, bool is_pipe) { - struct perf_evsel *counter; + struct evsel *counter; int err; /* @@ -3984,7 +4007,7 @@ int perf_event__synthesize_extra_attr(struct perf_tool *tool, } } - if (counter->own_cpus) { + if (counter->core.own_cpus) { err = perf_event__synthesize_event_update_cpus(tool, counter, process); if (err < 0) { pr_err("Couldn't synthesize evsel cpus.\n"); @@ -4009,23 +4032,23 @@ int perf_event__synthesize_extra_attr(struct perf_tool *tool, int perf_event__process_attr(struct perf_tool *tool __maybe_unused, union perf_event *event, - struct perf_evlist **pevlist) + struct evlist **pevlist) { u32 i, ids, n_ids; - struct perf_evsel *evsel; - struct perf_evlist *evlist = *pevlist; + struct evsel *evsel; + struct evlist *evlist = *pevlist; if (evlist == NULL) { - *pevlist = evlist = perf_evlist__new(); + *pevlist = evlist = evlist__new(); if (evlist == NULL) return -ENOMEM; } - evsel = perf_evsel__new(&event->attr.attr); + evsel = evsel__new(&event->attr.attr); if (evsel == NULL) return -ENOMEM; - perf_evlist__add(evlist, evsel); + evlist__add(evlist, evsel); ids = event->header.size; ids -= (void *)&event->attr.id - (void *)event; @@ -4047,14 +4070,14 @@ int perf_event__process_attr(struct perf_tool *tool __maybe_unused, int perf_event__process_event_update(struct perf_tool *tool __maybe_unused, union perf_event *event, - struct perf_evlist **pevlist) + struct evlist **pevlist) { - struct event_update_event *ev = &event->event_update; - struct event_update_event_scale *ev_scale; - struct event_update_event_cpus *ev_cpus; - struct perf_evlist *evlist; - struct perf_evsel *evsel; - struct cpu_map *map; + struct perf_record_event_update *ev = &event->event_update; + struct perf_record_event_update_scale *ev_scale; + struct perf_record_event_update_cpus *ev_cpus; + struct evlist *evlist; + struct evsel *evsel; + struct perf_cpu_map *map; if (!pevlist || *pevlist == NULL) return -EINVAL; @@ -4073,15 +4096,15 @@ int perf_event__process_event_update(struct perf_tool *tool __maybe_unused, evsel->name = strdup(ev->data); break; case PERF_EVENT_UPDATE__SCALE: - ev_scale = (struct event_update_event_scale *) ev->data; + ev_scale = (struct perf_record_event_update_scale *)ev->data; evsel->scale = ev_scale->scale; break; case PERF_EVENT_UPDATE__CPUS: - ev_cpus = (struct event_update_event_cpus *) ev->data; + ev_cpus = (struct perf_record_event_update_cpus *)ev->data; map = cpu_map__new_data(&ev_cpus->cpus); if (map) - evsel->own_cpus = map; + evsel->core.own_cpus = map; else pr_err("failed to get event_update cpus\n"); default: @@ -4092,7 +4115,7 @@ int perf_event__process_event_update(struct perf_tool *tool __maybe_unused, } int perf_event__synthesize_tracing_data(struct perf_tool *tool, int fd, - struct perf_evlist *evlist, + struct evlist *evlist, perf_event__handler_t process) { union perf_event ev; @@ -4112,7 +4135,7 @@ int perf_event__synthesize_tracing_data(struct perf_tool *tool, int fd, * - write the tracing data from the temp file * to the pipe */ - tdata = tracing_data_get(&evlist->entries, fd, true); + tdata = tracing_data_get(&evlist->core.entries, fd, true); if (!tdata) return -1; @@ -4149,7 +4172,7 @@ int perf_event__process_tracing_data(struct perf_session *session, char buf[BUFSIZ]; /* setup for reading amidst mmap */ - lseek(fd, offset + sizeof(struct tracing_data_event), + lseek(fd, offset + sizeof(struct perf_record_header_tracing_data), SEEK_SET); size_read = trace_report(fd, &session->tevent, diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h index 5b3abe4172e2..3e48ae3c49b1 100644 --- a/tools/perf/util/header.h +++ b/tools/perf/util/header.h @@ -92,12 +92,12 @@ struct perf_header { struct perf_env env; }; -struct perf_evlist; +struct evlist; struct perf_session; int perf_session__read_header(struct perf_session *session); int perf_session__write_header(struct perf_session *session, - struct perf_evlist *evlist, + struct evlist *evlist, int fd, bool at_exit); int perf_header__write_pipe(int fd); @@ -117,11 +117,11 @@ int perf_header__fprintf_info(struct perf_session *s, FILE *fp, bool full); int perf_event__synthesize_features(struct perf_tool *tool, struct perf_session *session, - struct perf_evlist *evlist, + struct evlist *evlist, perf_event__handler_t process); int perf_event__synthesize_extra_attr(struct perf_tool *tool, - struct perf_evlist *evsel_list, + struct evlist *evsel_list, perf_event__handler_t process, bool is_pipe); @@ -132,29 +132,29 @@ int perf_event__synthesize_attr(struct perf_tool *tool, struct perf_event_attr *attr, u32 ids, u64 *id, perf_event__handler_t process); int perf_event__synthesize_attrs(struct perf_tool *tool, - struct perf_evlist *evlist, + struct evlist *evlist, perf_event__handler_t process); int perf_event__synthesize_event_update_unit(struct perf_tool *tool, - struct perf_evsel *evsel, + struct evsel *evsel, perf_event__handler_t process); int perf_event__synthesize_event_update_scale(struct perf_tool *tool, - struct perf_evsel *evsel, + struct evsel *evsel, perf_event__handler_t process); int perf_event__synthesize_event_update_name(struct perf_tool *tool, - struct perf_evsel *evsel, + struct evsel *evsel, perf_event__handler_t process); int perf_event__synthesize_event_update_cpus(struct perf_tool *tool, - struct perf_evsel *evsel, + struct evsel *evsel, perf_event__handler_t process); int perf_event__process_attr(struct perf_tool *tool, union perf_event *event, - struct perf_evlist **pevlist); + struct evlist **pevlist); int perf_event__process_event_update(struct perf_tool *tool, union perf_event *event, - struct perf_evlist **pevlist); + struct evlist **pevlist); size_t perf_event__fprintf_event_update(union perf_event *event, FILE *fp); int perf_event__synthesize_tracing_data(struct perf_tool *tool, - int fd, struct perf_evlist *evlist, + int fd, struct evlist *evlist, perf_event__handler_t process); int perf_event__process_tracing_data(struct perf_session *session, union perf_event *event); diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index f24fd1954f6c..679a1d75090c 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -1,8 +1,13 @@ // SPDX-License-Identifier: GPL-2.0 #include "callchain.h" +#include "debug.h" +#include "dso.h" #include "build-id.h" #include "hist.h" #include "map.h" +#include "map_symbol.h" +#include "branch.h" +#include "mem-events.h" #include "session.h" #include "namespaces.h" #include "sort.h" @@ -18,6 +23,8 @@ #include <math.h> #include <inttypes.h> #include <sys/param.h> +#include <linux/rbtree.h> +#include <linux/string.h> #include <linux/time64.h> #include <linux/zalloc.h> @@ -193,7 +200,10 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h) hists__new_col_len(hists, HISTC_MEM_LVL, 21 + 3); hists__new_col_len(hists, HISTC_LOCAL_WEIGHT, 12); hists__new_col_len(hists, HISTC_GLOBAL_WEIGHT, 12); - hists__new_col_len(hists, HISTC_TIME, 12); + if (symbol_conf.nanosecs) + hists__new_col_len(hists, HISTC_TIME, 16); + else + hists__new_col_len(hists, HISTC_TIME, 12); if (h->srcline) { len = MAX(strlen(h->srcline), strlen(sort_srcline.se_header)); @@ -816,7 +826,7 @@ static int iter_finish_mem_entry(struct hist_entry_iter *iter, struct addr_location *al __maybe_unused) { - struct perf_evsel *evsel = iter->evsel; + struct evsel *evsel = iter->evsel; struct hists *hists = evsel__hists(evsel); struct hist_entry *he = iter->he; int err = -EINVAL; @@ -886,7 +896,7 @@ static int iter_add_next_branch_entry(struct hist_entry_iter *iter, struct addr_location *al) { struct branch_info *bi; - struct perf_evsel *evsel = iter->evsel; + struct evsel *evsel = iter->evsel; struct hists *hists = evsel__hists(evsel); struct perf_sample *sample = iter->sample; struct hist_entry *he = NULL; @@ -938,7 +948,7 @@ iter_prepare_normal_entry(struct hist_entry_iter *iter __maybe_unused, static int iter_add_single_normal_entry(struct hist_entry_iter *iter, struct addr_location *al) { - struct perf_evsel *evsel = iter->evsel; + struct evsel *evsel = iter->evsel; struct perf_sample *sample = iter->sample; struct hist_entry *he; @@ -956,7 +966,7 @@ iter_finish_normal_entry(struct hist_entry_iter *iter, struct addr_location *al __maybe_unused) { struct hist_entry *he = iter->he; - struct perf_evsel *evsel = iter->evsel; + struct evsel *evsel = iter->evsel; struct perf_sample *sample = iter->sample; if (he == NULL) @@ -996,7 +1006,7 @@ static int iter_add_single_cumulative_entry(struct hist_entry_iter *iter, struct addr_location *al) { - struct perf_evsel *evsel = iter->evsel; + struct evsel *evsel = iter->evsel; struct hists *hists = evsel__hists(evsel); struct perf_sample *sample = iter->sample; struct hist_entry **he_cache = iter->priv; @@ -1041,7 +1051,7 @@ static int iter_add_next_cumulative_entry(struct hist_entry_iter *iter, struct addr_location *al) { - struct perf_evsel *evsel = iter->evsel; + struct evsel *evsel = iter->evsel; struct perf_sample *sample = iter->sample; struct hist_entry **he_cache = iter->priv; struct hist_entry *he; @@ -1873,7 +1883,7 @@ static void output_resort(struct hists *hists, struct ui_progress *prog, } } -void perf_evsel__output_resort_cb(struct perf_evsel *evsel, struct ui_progress *prog, +void perf_evsel__output_resort_cb(struct evsel *evsel, struct ui_progress *prog, hists__resort_cb_t cb, void *cb_arg) { bool use_callchain; @@ -1888,7 +1898,7 @@ void perf_evsel__output_resort_cb(struct perf_evsel *evsel, struct ui_progress * output_resort(evsel__hists(evsel), prog, use_callchain, cb, cb_arg); } -void perf_evsel__output_resort(struct perf_evsel *evsel, struct ui_progress *prog) +void perf_evsel__output_resort(struct evsel *evsel, struct ui_progress *prog) { return perf_evsel__output_resort_cb(evsel, prog, NULL, NULL); } @@ -2539,6 +2549,25 @@ int hists__link(struct hists *leader, struct hists *other) return 0; } +int hists__unlink(struct hists *hists) +{ + struct rb_root_cached *root; + struct rb_node *nd; + struct hist_entry *pos; + + if (hists__has(hists, need_collapse)) + root = &hists->entries_collapsed; + else + root = hists->entries_in; + + for (nd = rb_first_cached(root); nd; nd = rb_next(nd)) { + pos = rb_entry(nd, struct hist_entry, rb_node_in); + list_del_init(&pos->pairs.node); + } + + return 0; +} + void hist__account_cycles(struct branch_stack *bs, struct addr_location *al, struct perf_sample *sample, bool nonany_branch_mode) { @@ -2573,9 +2602,9 @@ void hist__account_cycles(struct branch_stack *bs, struct addr_location *al, } } -size_t perf_evlist__fprintf_nr_events(struct perf_evlist *evlist, FILE *fp) +size_t perf_evlist__fprintf_nr_events(struct evlist *evlist, FILE *fp) { - struct perf_evsel *pos; + struct evsel *pos; size_t ret = 0; evlist__for_each_entry(evlist, pos) { @@ -2602,7 +2631,7 @@ int __hists__scnprintf_title(struct hists *hists, char *bf, size_t size, bool sh int socket_id = hists->socket_filter; unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE]; u64 nr_events = hists->stats.total_period; - struct perf_evsel *evsel = hists_to_evsel(hists); + struct evsel *evsel = hists_to_evsel(hists); const char *ev_name = perf_evsel__name(evsel); char buf[512], sample_freq_str[64] = ""; size_t buflen = sizeof(buf); @@ -2615,7 +2644,7 @@ int __hists__scnprintf_title(struct hists *hists, char *bf, size_t size, bool sh } if (perf_evsel__is_group_event(evsel)) { - struct perf_evsel *pos; + struct evsel *pos; perf_evsel__group_desc(evsel, buf, buflen); ev_name = buf; @@ -2638,12 +2667,12 @@ int __hists__scnprintf_title(struct hists *hists, char *bf, size_t size, bool sh enable_ref = true; if (show_freq) - scnprintf(sample_freq_str, sizeof(sample_freq_str), " %d Hz,", evsel->attr.sample_freq); + scnprintf(sample_freq_str, sizeof(sample_freq_str), " %d Hz,", evsel->core.attr.sample_freq); nr_samples = convert_unit(nr_samples, &unit); printed = scnprintf(bf, size, "Samples: %lu%c of event%s '%s',%s%sEvent count (approx.): %" PRIu64, - nr_samples, unit, evsel->nr_members > 1 ? "s" : "", + nr_samples, unit, evsel->core.nr_members > 1 ? "s" : "", ev_name, sample_freq_str, enable_ref ? ref : " ", nr_events); @@ -2731,7 +2760,7 @@ static void hists__delete_all_entries(struct hists *hists) hists__delete_remaining_entries(&hists->entries_collapsed); } -static void hists_evsel__exit(struct perf_evsel *evsel) +static void hists_evsel__exit(struct evsel *evsel) { struct hists *hists = evsel__hists(evsel); struct perf_hpp_fmt *fmt, *pos; @@ -2749,7 +2778,7 @@ static void hists_evsel__exit(struct perf_evsel *evsel) } } -static int hists_evsel__init(struct perf_evsel *evsel) +static int hists_evsel__init(struct evsel *evsel) { struct hists *hists = evsel__hists(evsel); diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index 24635f36148d..34803e33dc80 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h @@ -6,9 +6,8 @@ #include <linux/types.h> #include <pthread.h> #include "evsel.h" -#include "header.h" #include "color.h" -#include "ui/progress.h" +#include "events_stats.h" struct hist_entry; struct hist_entry_ops; @@ -18,6 +17,7 @@ struct mem_info; struct branch_info; struct block_info; struct symbol; +struct ui_progress; enum hist_filter { HIST_FILTER__DSO, @@ -116,7 +116,7 @@ struct hist_entry_iter { bool hide_unresolved; - struct perf_evsel *evsel; + struct evsel *evsel; struct perf_sample *sample; struct hist_entry *he; struct symbol *parent; @@ -171,9 +171,9 @@ void hist_entry__delete(struct hist_entry *he); typedef int (*hists__resort_cb_t)(struct hist_entry *he, void *arg); -void perf_evsel__output_resort_cb(struct perf_evsel *evsel, struct ui_progress *prog, +void perf_evsel__output_resort_cb(struct evsel *evsel, struct ui_progress *prog, hists__resort_cb_t cb, void *cb_arg); -void perf_evsel__output_resort(struct perf_evsel *evsel, struct ui_progress *prog); +void perf_evsel__output_resort(struct evsel *evsel, struct ui_progress *prog); void hists__output_resort(struct hists *hists, struct ui_progress *prog); void hists__output_resort_cb(struct hists *hists, struct ui_progress *prog, hists__resort_cb_t cb); @@ -190,13 +190,11 @@ void hists__reset_stats(struct hists *hists); void hists__inc_stats(struct hists *hists, struct hist_entry *h); void hists__inc_nr_events(struct hists *hists, u32 type); void hists__inc_nr_samples(struct hists *hists, bool filtered); -void events_stats__inc(struct events_stats *stats, u32 type); -size_t events_stats__fprintf(struct events_stats *stats, FILE *fp); size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, int max_cols, float min_pcnt, FILE *fp, bool ignore_callchains); -size_t perf_evlist__fprintf_nr_events(struct perf_evlist *evlist, FILE *fp); +size_t perf_evlist__fprintf_nr_events(struct evlist *evlist, FILE *fp); void hists__filter_by_dso(struct hists *hists); void hists__filter_by_thread(struct hists *hists); @@ -217,19 +215,20 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *he); void hists__match(struct hists *leader, struct hists *other); int hists__link(struct hists *leader, struct hists *other); +int hists__unlink(struct hists *hists); struct hists_evsel { - struct perf_evsel evsel; + struct evsel evsel; struct hists hists; }; -static inline struct perf_evsel *hists_to_evsel(struct hists *hists) +static inline struct evsel *hists_to_evsel(struct hists *hists) { struct hists_evsel *hevsel = container_of(hists, struct hists_evsel, hists); return &hevsel->evsel; } -static inline struct hists *evsel__hists(struct perf_evsel *evsel) +static inline struct hists *evsel__hists(struct evsel *evsel) { struct hists_evsel *hevsel = (struct hists_evsel *)evsel; return &hevsel->hists; @@ -367,7 +366,7 @@ void perf_hpp__setup_output_field(struct perf_hpp_list *list); void perf_hpp__reset_output_field(struct perf_hpp_list *list); void perf_hpp__append_sort_keys(struct perf_hpp_list *list); int perf_hpp__setup_hists_formats(struct perf_hpp_list *list, - struct perf_evlist *evlist); + struct evlist *evlist); bool perf_hpp__is_sort_entry(struct perf_hpp_fmt *format); @@ -432,7 +431,7 @@ static inline size_t perf_hpp__color_overhead(void) : 0; } -struct perf_evlist; +struct evlist; struct hist_browser_timer { void (*timer)(void *arg); @@ -453,30 +452,30 @@ enum rstype { #include "../ui/keysyms.h" void attr_to_script(char *buf, struct perf_event_attr *attr); -int map_symbol__tui_annotate(struct map_symbol *ms, struct perf_evsel *evsel, +int map_symbol__tui_annotate(struct map_symbol *ms, struct evsel *evsel, struct hist_browser_timer *hbt, struct annotation_options *annotation_opts); -int hist_entry__tui_annotate(struct hist_entry *he, struct perf_evsel *evsel, +int hist_entry__tui_annotate(struct hist_entry *he, struct evsel *evsel, struct hist_browser_timer *hbt, struct annotation_options *annotation_opts); -int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help, +int perf_evlist__tui_browse_hists(struct evlist *evlist, const char *help, struct hist_browser_timer *hbt, float min_pcnt, struct perf_env *env, bool warn_lost_event, struct annotation_options *annotation_options); -int script_browse(const char *script_opt, struct perf_evsel *evsel); +int script_browse(const char *script_opt, struct evsel *evsel); void run_script(char *cmd); int res_sample_browse(struct res_sample *res_samples, int num_res, - struct perf_evsel *evsel, enum rstype rstype); + struct evsel *evsel, enum rstype rstype); void res_sample_init(void); #else static inline -int perf_evlist__tui_browse_hists(struct perf_evlist *evlist __maybe_unused, +int perf_evlist__tui_browse_hists(struct evlist *evlist __maybe_unused, const char *help __maybe_unused, struct hist_browser_timer *hbt __maybe_unused, float min_pcnt __maybe_unused, @@ -487,7 +486,7 @@ int perf_evlist__tui_browse_hists(struct perf_evlist *evlist __maybe_unused, return 0; } static inline int map_symbol__tui_annotate(struct map_symbol *ms __maybe_unused, - struct perf_evsel *evsel __maybe_unused, + struct evsel *evsel __maybe_unused, struct hist_browser_timer *hbt __maybe_unused, struct annotation_options *annotation_options __maybe_unused) { @@ -495,7 +494,7 @@ static inline int map_symbol__tui_annotate(struct map_symbol *ms __maybe_unused, } static inline int hist_entry__tui_annotate(struct hist_entry *he __maybe_unused, - struct perf_evsel *evsel __maybe_unused, + struct evsel *evsel __maybe_unused, struct hist_browser_timer *hbt __maybe_unused, struct annotation_options *annotation_opts __maybe_unused) { @@ -503,14 +502,14 @@ static inline int hist_entry__tui_annotate(struct hist_entry *he __maybe_unused, } static inline int script_browse(const char *script_opt __maybe_unused, - struct perf_evsel *evsel __maybe_unused) + struct evsel *evsel __maybe_unused) { return 0; } static inline int res_sample_browse(struct res_sample *res_samples __maybe_unused, int num_res __maybe_unused, - struct perf_evsel *evsel __maybe_unused, + struct evsel *evsel __maybe_unused, enum rstype rstype __maybe_unused) { return 0; diff --git a/tools/perf/util/intel-bts.c b/tools/perf/util/intel-bts.c index 5560e95afdda..aacffa2b0362 100644 --- a/tools/perf/util/intel-bts.c +++ b/tools/perf/util/intel-bts.c @@ -19,9 +19,9 @@ #include "evsel.h" #include "evlist.h" #include "machine.h" -#include "map.h" #include "symbol.h" #include "session.h" +#include "tool.h" #include "thread.h" #include "thread-stack.h" #include "debug.h" @@ -760,15 +760,15 @@ static int intel_bts_synth_event(struct perf_session *session, static int intel_bts_synth_events(struct intel_bts *bts, struct perf_session *session) { - struct perf_evlist *evlist = session->evlist; - struct perf_evsel *evsel; + struct evlist *evlist = session->evlist; + struct evsel *evsel; struct perf_event_attr attr; bool found = false; u64 id; int err; evlist__for_each_entry(evlist, evsel) { - if (evsel->attr.type == bts->pmu_type && evsel->ids) { + if (evsel->core.attr.type == bts->pmu_type && evsel->ids) { found = true; break; } @@ -782,18 +782,18 @@ static int intel_bts_synth_events(struct intel_bts *bts, memset(&attr, 0, sizeof(struct perf_event_attr)); attr.size = sizeof(struct perf_event_attr); attr.type = PERF_TYPE_HARDWARE; - attr.sample_type = evsel->attr.sample_type & PERF_SAMPLE_MASK; + attr.sample_type = evsel->core.attr.sample_type & PERF_SAMPLE_MASK; attr.sample_type |= PERF_SAMPLE_IP | PERF_SAMPLE_TID | PERF_SAMPLE_PERIOD; attr.sample_type &= ~(u64)PERF_SAMPLE_TIME; attr.sample_type &= ~(u64)PERF_SAMPLE_CPU; - attr.exclude_user = evsel->attr.exclude_user; - attr.exclude_kernel = evsel->attr.exclude_kernel; - attr.exclude_hv = evsel->attr.exclude_hv; - attr.exclude_host = evsel->attr.exclude_host; - attr.exclude_guest = evsel->attr.exclude_guest; - attr.sample_id_all = evsel->attr.sample_id_all; - attr.read_format = evsel->attr.read_format; + attr.exclude_user = evsel->core.attr.exclude_user; + attr.exclude_kernel = evsel->core.attr.exclude_kernel; + attr.exclude_hv = evsel->core.attr.exclude_hv; + attr.exclude_host = evsel->core.attr.exclude_host; + attr.exclude_guest = evsel->core.attr.exclude_guest; + attr.sample_id_all = evsel->core.attr.sample_id_all; + attr.read_format = evsel->core.attr.read_format; id = evsel->id[0] + 1000000000; if (!id) @@ -818,7 +818,7 @@ static int intel_bts_synth_events(struct intel_bts *bts, * We only use sample types from PERF_SAMPLE_MASK so we can use * __perf_evsel__sample_size() here. */ - bts->branches_event_size = sizeof(struct sample_event) + + bts->branches_event_size = sizeof(struct perf_record_sample) + __perf_evsel__sample_size(attr.sample_type); } @@ -834,7 +834,7 @@ static const char * const intel_bts_info_fmts[] = { [INTEL_BTS_SNAPSHOT_MODE] = " Snapshot mode %"PRId64"\n", }; -static void intel_bts_print_info(u64 *arr, int start, int finish) +static void intel_bts_print_info(__u64 *arr, int start, int finish) { int i; @@ -848,12 +848,12 @@ static void intel_bts_print_info(u64 *arr, int start, int finish) int intel_bts_process_auxtrace_info(union perf_event *event, struct perf_session *session) { - struct auxtrace_info_event *auxtrace_info = &event->auxtrace_info; + struct perf_record_auxtrace_info *auxtrace_info = &event->auxtrace_info; size_t min_sz = sizeof(u64) * INTEL_BTS_SNAPSHOT_MODE; struct intel_bts *bts; int err; - if (auxtrace_info->header.size < sizeof(struct auxtrace_info_event) + + if (auxtrace_info->header.size < sizeof(struct perf_record_auxtrace_info) + min_sz) return -EINVAL; diff --git a/tools/perf/util/intel-pt-decoder/Build b/tools/perf/util/intel-pt-decoder/Build index 23bf788f84b9..bc629359826f 100644 --- a/tools/perf/util/intel-pt-decoder/Build +++ b/tools/perf/util/intel-pt-decoder/Build @@ -1,7 +1,7 @@ perf-$(CONFIG_AUXTRACE) += intel-pt-pkt-decoder.o intel-pt-insn-decoder.o intel-pt-log.o intel-pt-decoder.o -inat_tables_script = util/intel-pt-decoder/gen-insn-attr-x86.awk -inat_tables_maps = util/intel-pt-decoder/x86-opcode-map.txt +inat_tables_script = $(srctree)/tools/arch/x86/tools/gen-insn-attr-x86.awk +inat_tables_maps = $(srctree)/tools/arch/x86/lib/x86-opcode-map.txt $(OUTPUT)util/intel-pt-decoder/inat-tables.c: $(inat_tables_script) $(inat_tables_maps) $(call rule_mkdir) @@ -9,23 +9,7 @@ $(OUTPUT)util/intel-pt-decoder/inat-tables.c: $(inat_tables_script) $(inat_table # Busybox's diff doesn't have -I, avoid warning in the case -$(OUTPUT)util/intel-pt-decoder/intel-pt-insn-decoder.o: util/intel-pt-decoder/intel-pt-insn-decoder.c util/intel-pt-decoder/inat.c $(OUTPUT)util/intel-pt-decoder/inat-tables.c - @(diff -I 2>&1 | grep -q 'option requires an argument' && \ - test -d ../../kernel -a -d ../../tools -a -d ../perf && ( \ - ((diff -B -I'^#include' util/intel-pt-decoder/insn.c ../../arch/x86/lib/insn.c >/dev/null) || \ - (echo "Warning: Intel PT: x86 instruction decoder C file at 'tools/perf/util/intel-pt-decoder/insn.c' differs from latest version at 'arch/x86/lib/insn.c'" >&2)) && \ - ((diff -B -I'^#include' util/intel-pt-decoder/inat.c ../../arch/x86/lib/inat.c >/dev/null) || \ - (echo "Warning: Intel PT: x86 instruction decoder C file at 'tools/perf/util/intel-pt-decoder/inat.c' differs from latest version at 'arch/x86/lib/inat.c'" >&2)) && \ - ((diff -B util/intel-pt-decoder/x86-opcode-map.txt ../../arch/x86/lib/x86-opcode-map.txt >/dev/null) || \ - (echo "Warning: Intel PT: x86 instruction decoder map file at 'tools/perf/util/intel-pt-decoder/x86-opcode-map.txt' differs from latest version at 'arch/x86/lib/x86-opcode-map.txt'" >&2)) && \ - ((diff -B util/intel-pt-decoder/gen-insn-attr-x86.awk ../../arch/x86/tools/gen-insn-attr-x86.awk >/dev/null) || \ - (echo "Warning: Intel PT: x86 instruction decoder script at 'tools/perf/util/intel-pt-decoder/gen-insn-attr-x86.awk' differs from latest version at 'arch/x86/tools/gen-insn-attr-x86.awk'" >&2)) && \ - ((diff -B -I'^#include' util/intel-pt-decoder/insn.h ../../arch/x86/include/asm/insn.h >/dev/null) || \ - (echo "Warning: Intel PT: x86 instruction decoder header at 'tools/perf/util/intel-pt-decoder/insn.h' differs from latest version at 'arch/x86/include/asm/insn.h'" >&2)) && \ - ((diff -B -I'^#include' util/intel-pt-decoder/inat.h ../../arch/x86/include/asm/inat.h >/dev/null) || \ - (echo "Warning: Intel PT: x86 instruction decoder header at 'tools/perf/util/intel-pt-decoder/inat.h' differs from latest version at 'arch/x86/include/asm/inat.h'" >&2)) && \ - ((diff -B -I'^#include' util/intel-pt-decoder/inat_types.h ../../arch/x86/include/asm/inat_types.h >/dev/null) || \ - (echo "Warning: Intel PT: x86 instruction decoder header at 'tools/perf/util/intel-pt-decoder/inat_types.h' differs from latest version at 'arch/x86/include/asm/inat_types.h'" >&2)))) || true +$(OUTPUT)util/intel-pt-decoder/intel-pt-insn-decoder.o: util/intel-pt-decoder/intel-pt-insn-decoder.c $(OUTPUT)util/intel-pt-decoder/inat-tables.c $(call rule_mkdir) $(call if_changed_dep,cc_o_c) diff --git a/tools/perf/util/intel-pt-decoder/gen-insn-attr-x86.awk b/tools/perf/util/intel-pt-decoder/gen-insn-attr-x86.awk deleted file mode 100644 index ddd5c4c21129..000000000000 --- a/tools/perf/util/intel-pt-decoder/gen-insn-attr-x86.awk +++ /dev/null @@ -1,392 +0,0 @@ -#!/bin/awk -f -# SPDX-License-Identifier: GPL-2.0 -# gen-insn-attr-x86.awk: Instruction attribute table generator -# Written by Masami Hiramatsu <mhiramat@redhat.com> -# -# Usage: awk -f gen-insn-attr-x86.awk x86-opcode-map.txt > inat-tables.c - -# Awk implementation sanity check -function check_awk_implement() { - if (sprintf("%x", 0) != "0") - return "Your awk has a printf-format problem." - return "" -} - -# Clear working vars -function clear_vars() { - delete table - delete lptable2 - delete lptable1 - delete lptable3 - eid = -1 # escape id - gid = -1 # group id - aid = -1 # AVX id - tname = "" -} - -BEGIN { - # Implementation error checking - awkchecked = check_awk_implement() - if (awkchecked != "") { - print "Error: " awkchecked > "/dev/stderr" - print "Please try to use gawk." > "/dev/stderr" - exit 1 - } - - # Setup generating tables - print "/* x86 opcode map generated from x86-opcode-map.txt */" - print "/* Do not change this code. */\n" - ggid = 1 - geid = 1 - gaid = 0 - delete etable - delete gtable - delete atable - - opnd_expr = "^[A-Za-z/]" - ext_expr = "^\\(" - sep_expr = "^\\|$" - group_expr = "^Grp[0-9A-Za-z]+" - - imm_expr = "^[IJAOL][a-z]" - imm_flag["Ib"] = "INAT_MAKE_IMM(INAT_IMM_BYTE)" - imm_flag["Jb"] = "INAT_MAKE_IMM(INAT_IMM_BYTE)" - imm_flag["Iw"] = "INAT_MAKE_IMM(INAT_IMM_WORD)" - imm_flag["Id"] = "INAT_MAKE_IMM(INAT_IMM_DWORD)" - imm_flag["Iq"] = "INAT_MAKE_IMM(INAT_IMM_QWORD)" - imm_flag["Ap"] = "INAT_MAKE_IMM(INAT_IMM_PTR)" - imm_flag["Iz"] = "INAT_MAKE_IMM(INAT_IMM_VWORD32)" - imm_flag["Jz"] = "INAT_MAKE_IMM(INAT_IMM_VWORD32)" - imm_flag["Iv"] = "INAT_MAKE_IMM(INAT_IMM_VWORD)" - imm_flag["Ob"] = "INAT_MOFFSET" - imm_flag["Ov"] = "INAT_MOFFSET" - imm_flag["Lx"] = "INAT_MAKE_IMM(INAT_IMM_BYTE)" - - modrm_expr = "^([CDEGMNPQRSUVW/][a-z]+|NTA|T[012])" - force64_expr = "\\([df]64\\)" - rex_expr = "^REX(\\.[XRWB]+)*" - fpu_expr = "^ESC" # TODO - - lprefix1_expr = "\\((66|!F3)\\)" - lprefix2_expr = "\\(F3\\)" - lprefix3_expr = "\\((F2|!F3|66\\&F2)\\)" - lprefix_expr = "\\((66|F2|F3)\\)" - max_lprefix = 4 - - # All opcodes starting with lower-case 'v', 'k' or with (v1) superscript - # accepts VEX prefix - vexok_opcode_expr = "^[vk].*" - vexok_expr = "\\(v1\\)" - # All opcodes with (v) superscript supports *only* VEX prefix - vexonly_expr = "\\(v\\)" - # All opcodes with (ev) superscript supports *only* EVEX prefix - evexonly_expr = "\\(ev\\)" - - prefix_expr = "\\(Prefix\\)" - prefix_num["Operand-Size"] = "INAT_PFX_OPNDSZ" - prefix_num["REPNE"] = "INAT_PFX_REPNE" - prefix_num["REP/REPE"] = "INAT_PFX_REPE" - prefix_num["XACQUIRE"] = "INAT_PFX_REPNE" - prefix_num["XRELEASE"] = "INAT_PFX_REPE" - prefix_num["LOCK"] = "INAT_PFX_LOCK" - prefix_num["SEG=CS"] = "INAT_PFX_CS" - prefix_num["SEG=DS"] = "INAT_PFX_DS" - prefix_num["SEG=ES"] = "INAT_PFX_ES" - prefix_num["SEG=FS"] = "INAT_PFX_FS" - prefix_num["SEG=GS"] = "INAT_PFX_GS" - prefix_num["SEG=SS"] = "INAT_PFX_SS" - prefix_num["Address-Size"] = "INAT_PFX_ADDRSZ" - prefix_num["VEX+1byte"] = "INAT_PFX_VEX2" - prefix_num["VEX+2byte"] = "INAT_PFX_VEX3" - prefix_num["EVEX"] = "INAT_PFX_EVEX" - - clear_vars() -} - -function semantic_error(msg) { - print "Semantic error at " NR ": " msg > "/dev/stderr" - exit 1 -} - -function debug(msg) { - print "DEBUG: " msg -} - -function array_size(arr, i,c) { - c = 0 - for (i in arr) - c++ - return c -} - -/^Table:/ { - print "/* " $0 " */" - if (tname != "") - semantic_error("Hit Table: before EndTable:."); -} - -/^Referrer:/ { - if (NF != 1) { - # escape opcode table - ref = "" - for (i = 2; i <= NF; i++) - ref = ref $i - eid = escape[ref] - tname = sprintf("inat_escape_table_%d", eid) - } -} - -/^AVXcode:/ { - if (NF != 1) { - # AVX/escape opcode table - aid = $2 - if (gaid <= aid) - gaid = aid + 1 - if (tname == "") # AVX only opcode table - tname = sprintf("inat_avx_table_%d", $2) - } - if (aid == -1 && eid == -1) # primary opcode table - tname = "inat_primary_table" -} - -/^GrpTable:/ { - print "/* " $0 " */" - if (!($2 in group)) - semantic_error("No group: " $2 ) - gid = group[$2] - tname = "inat_group_table_" gid -} - -function print_table(tbl,name,fmt,n) -{ - print "const insn_attr_t " name " = {" - for (i = 0; i < n; i++) { - id = sprintf(fmt, i) - if (tbl[id]) - print " [" id "] = " tbl[id] "," - } - print "};" -} - -/^EndTable/ { - if (gid != -1) { - # print group tables - if (array_size(table) != 0) { - print_table(table, tname "[INAT_GROUP_TABLE_SIZE]", - "0x%x", 8) - gtable[gid,0] = tname - } - if (array_size(lptable1) != 0) { - print_table(lptable1, tname "_1[INAT_GROUP_TABLE_SIZE]", - "0x%x", 8) - gtable[gid,1] = tname "_1" - } - if (array_size(lptable2) != 0) { - print_table(lptable2, tname "_2[INAT_GROUP_TABLE_SIZE]", - "0x%x", 8) - gtable[gid,2] = tname "_2" - } - if (array_size(lptable3) != 0) { - print_table(lptable3, tname "_3[INAT_GROUP_TABLE_SIZE]", - "0x%x", 8) - gtable[gid,3] = tname "_3" - } - } else { - # print primary/escaped tables - if (array_size(table) != 0) { - print_table(table, tname "[INAT_OPCODE_TABLE_SIZE]", - "0x%02x", 256) - etable[eid,0] = tname - if (aid >= 0) - atable[aid,0] = tname - } - if (array_size(lptable1) != 0) { - print_table(lptable1,tname "_1[INAT_OPCODE_TABLE_SIZE]", - "0x%02x", 256) - etable[eid,1] = tname "_1" - if (aid >= 0) - atable[aid,1] = tname "_1" - } - if (array_size(lptable2) != 0) { - print_table(lptable2,tname "_2[INAT_OPCODE_TABLE_SIZE]", - "0x%02x", 256) - etable[eid,2] = tname "_2" - if (aid >= 0) - atable[aid,2] = tname "_2" - } - if (array_size(lptable3) != 0) { - print_table(lptable3,tname "_3[INAT_OPCODE_TABLE_SIZE]", - "0x%02x", 256) - etable[eid,3] = tname "_3" - if (aid >= 0) - atable[aid,3] = tname "_3" - } - } - print "" - clear_vars() -} - -function add_flags(old,new) { - if (old && new) - return old " | " new - else if (old) - return old - else - return new -} - -# convert operands to flags. -function convert_operands(count,opnd, i,j,imm,mod) -{ - imm = null - mod = null - for (j = 1; j <= count; j++) { - i = opnd[j] - if (match(i, imm_expr) == 1) { - if (!imm_flag[i]) - semantic_error("Unknown imm opnd: " i) - if (imm) { - if (i != "Ib") - semantic_error("Second IMM error") - imm = add_flags(imm, "INAT_SCNDIMM") - } else - imm = imm_flag[i] - } else if (match(i, modrm_expr)) - mod = "INAT_MODRM" - } - return add_flags(imm, mod) -} - -/^[0-9a-f]+\:/ { - if (NR == 1) - next - # get index - idx = "0x" substr($1, 1, index($1,":") - 1) - if (idx in table) - semantic_error("Redefine " idx " in " tname) - - # check if escaped opcode - if ("escape" == $2) { - if ($3 != "#") - semantic_error("No escaped name") - ref = "" - for (i = 4; i <= NF; i++) - ref = ref $i - if (ref in escape) - semantic_error("Redefine escape (" ref ")") - escape[ref] = geid - geid++ - table[idx] = "INAT_MAKE_ESCAPE(" escape[ref] ")" - next - } - - variant = null - # converts - i = 2 - while (i <= NF) { - opcode = $(i++) - delete opnds - ext = null - flags = null - opnd = null - # parse one opcode - if (match($i, opnd_expr)) { - opnd = $i - count = split($(i++), opnds, ",") - flags = convert_operands(count, opnds) - } - if (match($i, ext_expr)) - ext = $(i++) - if (match($i, sep_expr)) - i++ - else if (i < NF) - semantic_error($i " is not a separator") - - # check if group opcode - if (match(opcode, group_expr)) { - if (!(opcode in group)) { - group[opcode] = ggid - ggid++ - } - flags = add_flags(flags, "INAT_MAKE_GROUP(" group[opcode] ")") - } - # check force(or default) 64bit - if (match(ext, force64_expr)) - flags = add_flags(flags, "INAT_FORCE64") - - # check REX prefix - if (match(opcode, rex_expr)) - flags = add_flags(flags, "INAT_MAKE_PREFIX(INAT_PFX_REX)") - - # check coprocessor escape : TODO - if (match(opcode, fpu_expr)) - flags = add_flags(flags, "INAT_MODRM") - - # check VEX codes - if (match(ext, evexonly_expr)) - flags = add_flags(flags, "INAT_VEXOK | INAT_EVEXONLY") - else if (match(ext, vexonly_expr)) - flags = add_flags(flags, "INAT_VEXOK | INAT_VEXONLY") - else if (match(ext, vexok_expr) || match(opcode, vexok_opcode_expr)) - flags = add_flags(flags, "INAT_VEXOK") - - # check prefixes - if (match(ext, prefix_expr)) { - if (!prefix_num[opcode]) - semantic_error("Unknown prefix: " opcode) - flags = add_flags(flags, "INAT_MAKE_PREFIX(" prefix_num[opcode] ")") - } - if (length(flags) == 0) - continue - # check if last prefix - if (match(ext, lprefix1_expr)) { - lptable1[idx] = add_flags(lptable1[idx],flags) - variant = "INAT_VARIANT" - } - if (match(ext, lprefix2_expr)) { - lptable2[idx] = add_flags(lptable2[idx],flags) - variant = "INAT_VARIANT" - } - if (match(ext, lprefix3_expr)) { - lptable3[idx] = add_flags(lptable3[idx],flags) - variant = "INAT_VARIANT" - } - if (!match(ext, lprefix_expr)){ - table[idx] = add_flags(table[idx],flags) - } - } - if (variant) - table[idx] = add_flags(table[idx],variant) -} - -END { - if (awkchecked != "") - exit 1 - # print escape opcode map's array - print "/* Escape opcode map array */" - print "const insn_attr_t * const inat_escape_tables[INAT_ESC_MAX + 1]" \ - "[INAT_LSTPFX_MAX + 1] = {" - for (i = 0; i < geid; i++) - for (j = 0; j < max_lprefix; j++) - if (etable[i,j]) - print " ["i"]["j"] = "etable[i,j]"," - print "};\n" - # print group opcode map's array - print "/* Group opcode map array */" - print "const insn_attr_t * const inat_group_tables[INAT_GRP_MAX + 1]"\ - "[INAT_LSTPFX_MAX + 1] = {" - for (i = 0; i < ggid; i++) - for (j = 0; j < max_lprefix; j++) - if (gtable[i,j]) - print " ["i"]["j"] = "gtable[i,j]"," - print "};\n" - # print AVX opcode map's array - print "/* AVX opcode map array */" - print "const insn_attr_t * const inat_avx_tables[X86_VEX_M_MAX + 1]"\ - "[INAT_LSTPFX_MAX + 1] = {" - for (i = 0; i < gaid; i++) - for (j = 0; j < max_lprefix; j++) - if (atable[i,j]) - print " ["i"]["j"] = "atable[i,j]"," - print "};" -} diff --git a/tools/perf/util/intel-pt-decoder/inat.c b/tools/perf/util/intel-pt-decoder/inat.c deleted file mode 100644 index 446c0413a27c..000000000000 --- a/tools/perf/util/intel-pt-decoder/inat.c +++ /dev/null @@ -1,82 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * x86 instruction attribute tables - * - * Written by Masami Hiramatsu <mhiramat@redhat.com> - */ -#include "insn.h" - -/* Attribute tables are generated from opcode map */ -#include "inat-tables.c" - -/* Attribute search APIs */ -insn_attr_t inat_get_opcode_attribute(insn_byte_t opcode) -{ - return inat_primary_table[opcode]; -} - -int inat_get_last_prefix_id(insn_byte_t last_pfx) -{ - insn_attr_t lpfx_attr; - - lpfx_attr = inat_get_opcode_attribute(last_pfx); - return inat_last_prefix_id(lpfx_attr); -} - -insn_attr_t inat_get_escape_attribute(insn_byte_t opcode, int lpfx_id, - insn_attr_t esc_attr) -{ - const insn_attr_t *table; - int n; - - n = inat_escape_id(esc_attr); - - table = inat_escape_tables[n][0]; - if (!table) - return 0; - if (inat_has_variant(table[opcode]) && lpfx_id) { - table = inat_escape_tables[n][lpfx_id]; - if (!table) - return 0; - } - return table[opcode]; -} - -insn_attr_t inat_get_group_attribute(insn_byte_t modrm, int lpfx_id, - insn_attr_t grp_attr) -{ - const insn_attr_t *table; - int n; - - n = inat_group_id(grp_attr); - - table = inat_group_tables[n][0]; - if (!table) - return inat_group_common_attribute(grp_attr); - if (inat_has_variant(table[X86_MODRM_REG(modrm)]) && lpfx_id) { - table = inat_group_tables[n][lpfx_id]; - if (!table) - return inat_group_common_attribute(grp_attr); - } - return table[X86_MODRM_REG(modrm)] | - inat_group_common_attribute(grp_attr); -} - -insn_attr_t inat_get_avx_attribute(insn_byte_t opcode, insn_byte_t vex_m, - insn_byte_t vex_p) -{ - const insn_attr_t *table; - if (vex_m > X86_VEX_M_MAX || vex_p > INAT_LSTPFX_MAX) - return 0; - /* At first, this checks the master table */ - table = inat_avx_tables[vex_m][0]; - if (!table) - return 0; - if (!inat_is_group(table[opcode]) && vex_p) { - /* If this is not a group, get attribute directly */ - table = inat_avx_tables[vex_m][vex_p]; - if (!table) - return 0; - } - return table[opcode]; -} diff --git a/tools/perf/util/intel-pt-decoder/inat.h b/tools/perf/util/intel-pt-decoder/inat.h deleted file mode 100644 index 877827b7c2c3..000000000000 --- a/tools/perf/util/intel-pt-decoder/inat.h +++ /dev/null @@ -1,230 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -#ifndef _ASM_X86_INAT_H -#define _ASM_X86_INAT_H -/* - * x86 instruction attributes - * - * Written by Masami Hiramatsu <mhiramat@redhat.com> - */ -#include "inat_types.h" - -/* - * Internal bits. Don't use bitmasks directly, because these bits are - * unstable. You should use checking functions. - */ - -#define INAT_OPCODE_TABLE_SIZE 256 -#define INAT_GROUP_TABLE_SIZE 8 - -/* Legacy last prefixes */ -#define INAT_PFX_OPNDSZ 1 /* 0x66 */ /* LPFX1 */ -#define INAT_PFX_REPE 2 /* 0xF3 */ /* LPFX2 */ -#define INAT_PFX_REPNE 3 /* 0xF2 */ /* LPFX3 */ -/* Other Legacy prefixes */ -#define INAT_PFX_LOCK 4 /* 0xF0 */ -#define INAT_PFX_CS 5 /* 0x2E */ -#define INAT_PFX_DS 6 /* 0x3E */ -#define INAT_PFX_ES 7 /* 0x26 */ -#define INAT_PFX_FS 8 /* 0x64 */ -#define INAT_PFX_GS 9 /* 0x65 */ -#define INAT_PFX_SS 10 /* 0x36 */ -#define INAT_PFX_ADDRSZ 11 /* 0x67 */ -/* x86-64 REX prefix */ -#define INAT_PFX_REX 12 /* 0x4X */ -/* AVX VEX prefixes */ -#define INAT_PFX_VEX2 13 /* 2-bytes VEX prefix */ -#define INAT_PFX_VEX3 14 /* 3-bytes VEX prefix */ -#define INAT_PFX_EVEX 15 /* EVEX prefix */ - -#define INAT_LSTPFX_MAX 3 -#define INAT_LGCPFX_MAX 11 - -/* Immediate size */ -#define INAT_IMM_BYTE 1 -#define INAT_IMM_WORD 2 -#define INAT_IMM_DWORD 3 -#define INAT_IMM_QWORD 4 -#define INAT_IMM_PTR 5 -#define INAT_IMM_VWORD32 6 -#define INAT_IMM_VWORD 7 - -/* Legacy prefix */ -#define INAT_PFX_OFFS 0 -#define INAT_PFX_BITS 4 -#define INAT_PFX_MAX ((1 << INAT_PFX_BITS) - 1) -#define INAT_PFX_MASK (INAT_PFX_MAX << INAT_PFX_OFFS) -/* Escape opcodes */ -#define INAT_ESC_OFFS (INAT_PFX_OFFS + INAT_PFX_BITS) -#define INAT_ESC_BITS 2 -#define INAT_ESC_MAX ((1 << INAT_ESC_BITS) - 1) -#define INAT_ESC_MASK (INAT_ESC_MAX << INAT_ESC_OFFS) -/* Group opcodes (1-16) */ -#define INAT_GRP_OFFS (INAT_ESC_OFFS + INAT_ESC_BITS) -#define INAT_GRP_BITS 5 -#define INAT_GRP_MAX ((1 << INAT_GRP_BITS) - 1) -#define INAT_GRP_MASK (INAT_GRP_MAX << INAT_GRP_OFFS) -/* Immediates */ -#define INAT_IMM_OFFS (INAT_GRP_OFFS + INAT_GRP_BITS) -#define INAT_IMM_BITS 3 -#define INAT_IMM_MASK (((1 << INAT_IMM_BITS) - 1) << INAT_IMM_OFFS) -/* Flags */ -#define INAT_FLAG_OFFS (INAT_IMM_OFFS + INAT_IMM_BITS) -#define INAT_MODRM (1 << (INAT_FLAG_OFFS)) -#define INAT_FORCE64 (1 << (INAT_FLAG_OFFS + 1)) -#define INAT_SCNDIMM (1 << (INAT_FLAG_OFFS + 2)) -#define INAT_MOFFSET (1 << (INAT_FLAG_OFFS + 3)) -#define INAT_VARIANT (1 << (INAT_FLAG_OFFS + 4)) -#define INAT_VEXOK (1 << (INAT_FLAG_OFFS + 5)) -#define INAT_VEXONLY (1 << (INAT_FLAG_OFFS + 6)) -#define INAT_EVEXONLY (1 << (INAT_FLAG_OFFS + 7)) -/* Attribute making macros for attribute tables */ -#define INAT_MAKE_PREFIX(pfx) (pfx << INAT_PFX_OFFS) -#define INAT_MAKE_ESCAPE(esc) (esc << INAT_ESC_OFFS) -#define INAT_MAKE_GROUP(grp) ((grp << INAT_GRP_OFFS) | INAT_MODRM) -#define INAT_MAKE_IMM(imm) (imm << INAT_IMM_OFFS) - -/* Identifiers for segment registers */ -#define INAT_SEG_REG_IGNORE 0 -#define INAT_SEG_REG_DEFAULT 1 -#define INAT_SEG_REG_CS 2 -#define INAT_SEG_REG_SS 3 -#define INAT_SEG_REG_DS 4 -#define INAT_SEG_REG_ES 5 -#define INAT_SEG_REG_FS 6 -#define INAT_SEG_REG_GS 7 - -/* Attribute search APIs */ -extern insn_attr_t inat_get_opcode_attribute(insn_byte_t opcode); -extern int inat_get_last_prefix_id(insn_byte_t last_pfx); -extern insn_attr_t inat_get_escape_attribute(insn_byte_t opcode, - int lpfx_id, - insn_attr_t esc_attr); -extern insn_attr_t inat_get_group_attribute(insn_byte_t modrm, - int lpfx_id, - insn_attr_t esc_attr); -extern insn_attr_t inat_get_avx_attribute(insn_byte_t opcode, - insn_byte_t vex_m, - insn_byte_t vex_pp); - -/* Attribute checking functions */ -static inline int inat_is_legacy_prefix(insn_attr_t attr) -{ - attr &= INAT_PFX_MASK; - return attr && attr <= INAT_LGCPFX_MAX; -} - -static inline int inat_is_address_size_prefix(insn_attr_t attr) -{ - return (attr & INAT_PFX_MASK) == INAT_PFX_ADDRSZ; -} - -static inline int inat_is_operand_size_prefix(insn_attr_t attr) -{ - return (attr & INAT_PFX_MASK) == INAT_PFX_OPNDSZ; -} - -static inline int inat_is_rex_prefix(insn_attr_t attr) -{ - return (attr & INAT_PFX_MASK) == INAT_PFX_REX; -} - -static inline int inat_last_prefix_id(insn_attr_t attr) -{ - if ((attr & INAT_PFX_MASK) > INAT_LSTPFX_MAX) - return 0; - else - return attr & INAT_PFX_MASK; -} - -static inline int inat_is_vex_prefix(insn_attr_t attr) -{ - attr &= INAT_PFX_MASK; - return attr == INAT_PFX_VEX2 || attr == INAT_PFX_VEX3 || - attr == INAT_PFX_EVEX; -} - -static inline int inat_is_evex_prefix(insn_attr_t attr) -{ - return (attr & INAT_PFX_MASK) == INAT_PFX_EVEX; -} - -static inline int inat_is_vex3_prefix(insn_attr_t attr) -{ - return (attr & INAT_PFX_MASK) == INAT_PFX_VEX3; -} - -static inline int inat_is_escape(insn_attr_t attr) -{ - return attr & INAT_ESC_MASK; -} - -static inline int inat_escape_id(insn_attr_t attr) -{ - return (attr & INAT_ESC_MASK) >> INAT_ESC_OFFS; -} - -static inline int inat_is_group(insn_attr_t attr) -{ - return attr & INAT_GRP_MASK; -} - -static inline int inat_group_id(insn_attr_t attr) -{ - return (attr & INAT_GRP_MASK) >> INAT_GRP_OFFS; -} - -static inline int inat_group_common_attribute(insn_attr_t attr) -{ - return attr & ~INAT_GRP_MASK; -} - -static inline int inat_has_immediate(insn_attr_t attr) -{ - return attr & INAT_IMM_MASK; -} - -static inline int inat_immediate_size(insn_attr_t attr) -{ - return (attr & INAT_IMM_MASK) >> INAT_IMM_OFFS; -} - -static inline int inat_has_modrm(insn_attr_t attr) -{ - return attr & INAT_MODRM; -} - -static inline int inat_is_force64(insn_attr_t attr) -{ - return attr & INAT_FORCE64; -} - -static inline int inat_has_second_immediate(insn_attr_t attr) -{ - return attr & INAT_SCNDIMM; -} - -static inline int inat_has_moffset(insn_attr_t attr) -{ - return attr & INAT_MOFFSET; -} - -static inline int inat_has_variant(insn_attr_t attr) -{ - return attr & INAT_VARIANT; -} - -static inline int inat_accept_vex(insn_attr_t attr) -{ - return attr & INAT_VEXOK; -} - -static inline int inat_must_vex(insn_attr_t attr) -{ - return attr & (INAT_VEXONLY | INAT_EVEXONLY); -} - -static inline int inat_must_evex(insn_attr_t attr) -{ - return attr & INAT_EVEXONLY; -} -#endif diff --git a/tools/perf/util/intel-pt-decoder/inat_types.h b/tools/perf/util/intel-pt-decoder/inat_types.h deleted file mode 100644 index b047efa9ddc2..000000000000 --- a/tools/perf/util/intel-pt-decoder/inat_types.h +++ /dev/null @@ -1,15 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -#ifndef _ASM_X86_INAT_TYPES_H -#define _ASM_X86_INAT_TYPES_H -/* - * x86 instruction attributes - * - * Written by Masami Hiramatsu <mhiramat@redhat.com> - */ - -/* Instruction attributes */ -typedef unsigned int insn_attr_t; -typedef unsigned char insn_byte_t; -typedef signed int insn_value_t; - -#endif diff --git a/tools/perf/util/intel-pt-decoder/insn.c b/tools/perf/util/intel-pt-decoder/insn.c deleted file mode 100644 index 82783bf43b74..000000000000 --- a/tools/perf/util/intel-pt-decoder/insn.c +++ /dev/null @@ -1,593 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * x86 instruction analysis - * - * Copyright (C) IBM Corporation, 2002, 2004, 2009 - */ - -#ifdef __KERNEL__ -#include <linux/string.h> -#else -#include <string.h> -#endif -#include "inat.h" -#include "insn.h" - -/* Verify next sizeof(t) bytes can be on the same instruction */ -#define validate_next(t, insn, n) \ - ((insn)->next_byte + sizeof(t) + n <= (insn)->end_kaddr) - -#define __get_next(t, insn) \ - ({ t r = *(t*)insn->next_byte; insn->next_byte += sizeof(t); r; }) - -#define __peek_nbyte_next(t, insn, n) \ - ({ t r = *(t*)((insn)->next_byte + n); r; }) - -#define get_next(t, insn) \ - ({ if (unlikely(!validate_next(t, insn, 0))) goto err_out; __get_next(t, insn); }) - -#define peek_nbyte_next(t, insn, n) \ - ({ if (unlikely(!validate_next(t, insn, n))) goto err_out; __peek_nbyte_next(t, insn, n); }) - -#define peek_next(t, insn) peek_nbyte_next(t, insn, 0) - -/** - * insn_init() - initialize struct insn - * @insn: &struct insn to be initialized - * @kaddr: address (in kernel memory) of instruction (or copy thereof) - * @x86_64: !0 for 64-bit kernel or 64-bit app - */ -void insn_init(struct insn *insn, const void *kaddr, int buf_len, int x86_64) -{ - /* - * Instructions longer than MAX_INSN_SIZE (15 bytes) are invalid - * even if the input buffer is long enough to hold them. - */ - if (buf_len > MAX_INSN_SIZE) - buf_len = MAX_INSN_SIZE; - - memset(insn, 0, sizeof(*insn)); - insn->kaddr = kaddr; - insn->end_kaddr = kaddr + buf_len; - insn->next_byte = kaddr; - insn->x86_64 = x86_64 ? 1 : 0; - insn->opnd_bytes = 4; - if (x86_64) - insn->addr_bytes = 8; - else - insn->addr_bytes = 4; -} - -/** - * insn_get_prefixes - scan x86 instruction prefix bytes - * @insn: &struct insn containing instruction - * - * Populates the @insn->prefixes bitmap, and updates @insn->next_byte - * to point to the (first) opcode. No effect if @insn->prefixes.got - * is already set. - */ -void insn_get_prefixes(struct insn *insn) -{ - struct insn_field *prefixes = &insn->prefixes; - insn_attr_t attr; - insn_byte_t b, lb; - int i, nb; - - if (prefixes->got) - return; - - nb = 0; - lb = 0; - b = peek_next(insn_byte_t, insn); - attr = inat_get_opcode_attribute(b); - while (inat_is_legacy_prefix(attr)) { - /* Skip if same prefix */ - for (i = 0; i < nb; i++) - if (prefixes->bytes[i] == b) - goto found; - if (nb == 4) - /* Invalid instruction */ - break; - prefixes->bytes[nb++] = b; - if (inat_is_address_size_prefix(attr)) { - /* address size switches 2/4 or 4/8 */ - if (insn->x86_64) - insn->addr_bytes ^= 12; - else - insn->addr_bytes ^= 6; - } else if (inat_is_operand_size_prefix(attr)) { - /* oprand size switches 2/4 */ - insn->opnd_bytes ^= 6; - } -found: - prefixes->nbytes++; - insn->next_byte++; - lb = b; - b = peek_next(insn_byte_t, insn); - attr = inat_get_opcode_attribute(b); - } - /* Set the last prefix */ - if (lb && lb != insn->prefixes.bytes[3]) { - if (unlikely(insn->prefixes.bytes[3])) { - /* Swap the last prefix */ - b = insn->prefixes.bytes[3]; - for (i = 0; i < nb; i++) - if (prefixes->bytes[i] == lb) - prefixes->bytes[i] = b; - } - insn->prefixes.bytes[3] = lb; - } - - /* Decode REX prefix */ - if (insn->x86_64) { - b = peek_next(insn_byte_t, insn); - attr = inat_get_opcode_attribute(b); - if (inat_is_rex_prefix(attr)) { - insn->rex_prefix.value = b; - insn->rex_prefix.nbytes = 1; - insn->next_byte++; - if (X86_REX_W(b)) - /* REX.W overrides opnd_size */ - insn->opnd_bytes = 8; - } - } - insn->rex_prefix.got = 1; - - /* Decode VEX prefix */ - b = peek_next(insn_byte_t, insn); - attr = inat_get_opcode_attribute(b); - if (inat_is_vex_prefix(attr)) { - insn_byte_t b2 = peek_nbyte_next(insn_byte_t, insn, 1); - if (!insn->x86_64) { - /* - * In 32-bits mode, if the [7:6] bits (mod bits of - * ModRM) on the second byte are not 11b, it is - * LDS or LES or BOUND. - */ - if (X86_MODRM_MOD(b2) != 3) - goto vex_end; - } - insn->vex_prefix.bytes[0] = b; - insn->vex_prefix.bytes[1] = b2; - if (inat_is_evex_prefix(attr)) { - b2 = peek_nbyte_next(insn_byte_t, insn, 2); - insn->vex_prefix.bytes[2] = b2; - b2 = peek_nbyte_next(insn_byte_t, insn, 3); - insn->vex_prefix.bytes[3] = b2; - insn->vex_prefix.nbytes = 4; - insn->next_byte += 4; - if (insn->x86_64 && X86_VEX_W(b2)) - /* VEX.W overrides opnd_size */ - insn->opnd_bytes = 8; - } else if (inat_is_vex3_prefix(attr)) { - b2 = peek_nbyte_next(insn_byte_t, insn, 2); - insn->vex_prefix.bytes[2] = b2; - insn->vex_prefix.nbytes = 3; - insn->next_byte += 3; - if (insn->x86_64 && X86_VEX_W(b2)) - /* VEX.W overrides opnd_size */ - insn->opnd_bytes = 8; - } else { - /* - * For VEX2, fake VEX3-like byte#2. - * Makes it easier to decode vex.W, vex.vvvv, - * vex.L and vex.pp. Masking with 0x7f sets vex.W == 0. - */ - insn->vex_prefix.bytes[2] = b2 & 0x7f; - insn->vex_prefix.nbytes = 2; - insn->next_byte += 2; - } - } -vex_end: - insn->vex_prefix.got = 1; - - prefixes->got = 1; - -err_out: - return; -} - -/** - * insn_get_opcode - collect opcode(s) - * @insn: &struct insn containing instruction - * - * Populates @insn->opcode, updates @insn->next_byte to point past the - * opcode byte(s), and set @insn->attr (except for groups). - * If necessary, first collects any preceding (prefix) bytes. - * Sets @insn->opcode.value = opcode1. No effect if @insn->opcode.got - * is already 1. - */ -void insn_get_opcode(struct insn *insn) -{ - struct insn_field *opcode = &insn->opcode; - insn_byte_t op; - int pfx_id; - if (opcode->got) - return; - if (!insn->prefixes.got) - insn_get_prefixes(insn); - - /* Get first opcode */ - op = get_next(insn_byte_t, insn); - opcode->bytes[0] = op; - opcode->nbytes = 1; - - /* Check if there is VEX prefix or not */ - if (insn_is_avx(insn)) { - insn_byte_t m, p; - m = insn_vex_m_bits(insn); - p = insn_vex_p_bits(insn); - insn->attr = inat_get_avx_attribute(op, m, p); - if ((inat_must_evex(insn->attr) && !insn_is_evex(insn)) || - (!inat_accept_vex(insn->attr) && - !inat_is_group(insn->attr))) - insn->attr = 0; /* This instruction is bad */ - goto end; /* VEX has only 1 byte for opcode */ - } - - insn->attr = inat_get_opcode_attribute(op); - while (inat_is_escape(insn->attr)) { - /* Get escaped opcode */ - op = get_next(insn_byte_t, insn); - opcode->bytes[opcode->nbytes++] = op; - pfx_id = insn_last_prefix_id(insn); - insn->attr = inat_get_escape_attribute(op, pfx_id, insn->attr); - } - if (inat_must_vex(insn->attr)) - insn->attr = 0; /* This instruction is bad */ -end: - opcode->got = 1; - -err_out: - return; -} - -/** - * insn_get_modrm - collect ModRM byte, if any - * @insn: &struct insn containing instruction - * - * Populates @insn->modrm and updates @insn->next_byte to point past the - * ModRM byte, if any. If necessary, first collects the preceding bytes - * (prefixes and opcode(s)). No effect if @insn->modrm.got is already 1. - */ -void insn_get_modrm(struct insn *insn) -{ - struct insn_field *modrm = &insn->modrm; - insn_byte_t pfx_id, mod; - if (modrm->got) - return; - if (!insn->opcode.got) - insn_get_opcode(insn); - - if (inat_has_modrm(insn->attr)) { - mod = get_next(insn_byte_t, insn); - modrm->value = mod; - modrm->nbytes = 1; - if (inat_is_group(insn->attr)) { - pfx_id = insn_last_prefix_id(insn); - insn->attr = inat_get_group_attribute(mod, pfx_id, - insn->attr); - if (insn_is_avx(insn) && !inat_accept_vex(insn->attr)) - insn->attr = 0; /* This is bad */ - } - } - - if (insn->x86_64 && inat_is_force64(insn->attr)) - insn->opnd_bytes = 8; - modrm->got = 1; - -err_out: - return; -} - - -/** - * insn_rip_relative() - Does instruction use RIP-relative addressing mode? - * @insn: &struct insn containing instruction - * - * If necessary, first collects the instruction up to and including the - * ModRM byte. No effect if @insn->x86_64 is 0. - */ -int insn_rip_relative(struct insn *insn) -{ - struct insn_field *modrm = &insn->modrm; - - if (!insn->x86_64) - return 0; - if (!modrm->got) - insn_get_modrm(insn); - /* - * For rip-relative instructions, the mod field (top 2 bits) - * is zero and the r/m field (bottom 3 bits) is 0x5. - */ - return (modrm->nbytes && (modrm->value & 0xc7) == 0x5); -} - -/** - * insn_get_sib() - Get the SIB byte of instruction - * @insn: &struct insn containing instruction - * - * If necessary, first collects the instruction up to and including the - * ModRM byte. - */ -void insn_get_sib(struct insn *insn) -{ - insn_byte_t modrm; - - if (insn->sib.got) - return; - if (!insn->modrm.got) - insn_get_modrm(insn); - if (insn->modrm.nbytes) { - modrm = (insn_byte_t)insn->modrm.value; - if (insn->addr_bytes != 2 && - X86_MODRM_MOD(modrm) != 3 && X86_MODRM_RM(modrm) == 4) { - insn->sib.value = get_next(insn_byte_t, insn); - insn->sib.nbytes = 1; - } - } - insn->sib.got = 1; - -err_out: - return; -} - - -/** - * insn_get_displacement() - Get the displacement of instruction - * @insn: &struct insn containing instruction - * - * If necessary, first collects the instruction up to and including the - * SIB byte. - * Displacement value is sign-expanded. - */ -void insn_get_displacement(struct insn *insn) -{ - insn_byte_t mod, rm, base; - - if (insn->displacement.got) - return; - if (!insn->sib.got) - insn_get_sib(insn); - if (insn->modrm.nbytes) { - /* - * Interpreting the modrm byte: - * mod = 00 - no displacement fields (exceptions below) - * mod = 01 - 1-byte displacement field - * mod = 10 - displacement field is 4 bytes, or 2 bytes if - * address size = 2 (0x67 prefix in 32-bit mode) - * mod = 11 - no memory operand - * - * If address size = 2... - * mod = 00, r/m = 110 - displacement field is 2 bytes - * - * If address size != 2... - * mod != 11, r/m = 100 - SIB byte exists - * mod = 00, SIB base = 101 - displacement field is 4 bytes - * mod = 00, r/m = 101 - rip-relative addressing, displacement - * field is 4 bytes - */ - mod = X86_MODRM_MOD(insn->modrm.value); - rm = X86_MODRM_RM(insn->modrm.value); - base = X86_SIB_BASE(insn->sib.value); - if (mod == 3) - goto out; - if (mod == 1) { - insn->displacement.value = get_next(signed char, insn); - insn->displacement.nbytes = 1; - } else if (insn->addr_bytes == 2) { - if ((mod == 0 && rm == 6) || mod == 2) { - insn->displacement.value = - get_next(short, insn); - insn->displacement.nbytes = 2; - } - } else { - if ((mod == 0 && rm == 5) || mod == 2 || - (mod == 0 && base == 5)) { - insn->displacement.value = get_next(int, insn); - insn->displacement.nbytes = 4; - } - } - } -out: - insn->displacement.got = 1; - -err_out: - return; -} - -/* Decode moffset16/32/64. Return 0 if failed */ -static int __get_moffset(struct insn *insn) -{ - switch (insn->addr_bytes) { - case 2: - insn->moffset1.value = get_next(short, insn); - insn->moffset1.nbytes = 2; - break; - case 4: - insn->moffset1.value = get_next(int, insn); - insn->moffset1.nbytes = 4; - break; - case 8: - insn->moffset1.value = get_next(int, insn); - insn->moffset1.nbytes = 4; - insn->moffset2.value = get_next(int, insn); - insn->moffset2.nbytes = 4; - break; - default: /* opnd_bytes must be modified manually */ - goto err_out; - } - insn->moffset1.got = insn->moffset2.got = 1; - - return 1; - -err_out: - return 0; -} - -/* Decode imm v32(Iz). Return 0 if failed */ -static int __get_immv32(struct insn *insn) -{ - switch (insn->opnd_bytes) { - case 2: - insn->immediate.value = get_next(short, insn); - insn->immediate.nbytes = 2; - break; - case 4: - case 8: - insn->immediate.value = get_next(int, insn); - insn->immediate.nbytes = 4; - break; - default: /* opnd_bytes must be modified manually */ - goto err_out; - } - - return 1; - -err_out: - return 0; -} - -/* Decode imm v64(Iv/Ov), Return 0 if failed */ -static int __get_immv(struct insn *insn) -{ - switch (insn->opnd_bytes) { - case 2: - insn->immediate1.value = get_next(short, insn); - insn->immediate1.nbytes = 2; - break; - case 4: - insn->immediate1.value = get_next(int, insn); - insn->immediate1.nbytes = 4; - break; - case 8: - insn->immediate1.value = get_next(int, insn); - insn->immediate1.nbytes = 4; - insn->immediate2.value = get_next(int, insn); - insn->immediate2.nbytes = 4; - break; - default: /* opnd_bytes must be modified manually */ - goto err_out; - } - insn->immediate1.got = insn->immediate2.got = 1; - - return 1; -err_out: - return 0; -} - -/* Decode ptr16:16/32(Ap) */ -static int __get_immptr(struct insn *insn) -{ - switch (insn->opnd_bytes) { - case 2: - insn->immediate1.value = get_next(short, insn); - insn->immediate1.nbytes = 2; - break; - case 4: - insn->immediate1.value = get_next(int, insn); - insn->immediate1.nbytes = 4; - break; - case 8: - /* ptr16:64 is not exist (no segment) */ - return 0; - default: /* opnd_bytes must be modified manually */ - goto err_out; - } - insn->immediate2.value = get_next(unsigned short, insn); - insn->immediate2.nbytes = 2; - insn->immediate1.got = insn->immediate2.got = 1; - - return 1; -err_out: - return 0; -} - -/** - * insn_get_immediate() - Get the immediates of instruction - * @insn: &struct insn containing instruction - * - * If necessary, first collects the instruction up to and including the - * displacement bytes. - * Basically, most of immediates are sign-expanded. Unsigned-value can be - * get by bit masking with ((1 << (nbytes * 8)) - 1) - */ -void insn_get_immediate(struct insn *insn) -{ - if (insn->immediate.got) - return; - if (!insn->displacement.got) - insn_get_displacement(insn); - - if (inat_has_moffset(insn->attr)) { - if (!__get_moffset(insn)) - goto err_out; - goto done; - } - - if (!inat_has_immediate(insn->attr)) - /* no immediates */ - goto done; - - switch (inat_immediate_size(insn->attr)) { - case INAT_IMM_BYTE: - insn->immediate.value = get_next(signed char, insn); - insn->immediate.nbytes = 1; - break; - case INAT_IMM_WORD: - insn->immediate.value = get_next(short, insn); - insn->immediate.nbytes = 2; - break; - case INAT_IMM_DWORD: - insn->immediate.value = get_next(int, insn); - insn->immediate.nbytes = 4; - break; - case INAT_IMM_QWORD: - insn->immediate1.value = get_next(int, insn); - insn->immediate1.nbytes = 4; - insn->immediate2.value = get_next(int, insn); - insn->immediate2.nbytes = 4; - break; - case INAT_IMM_PTR: - if (!__get_immptr(insn)) - goto err_out; - break; - case INAT_IMM_VWORD32: - if (!__get_immv32(insn)) - goto err_out; - break; - case INAT_IMM_VWORD: - if (!__get_immv(insn)) - goto err_out; - break; - default: - /* Here, insn must have an immediate, but failed */ - goto err_out; - } - if (inat_has_second_immediate(insn->attr)) { - insn->immediate2.value = get_next(signed char, insn); - insn->immediate2.nbytes = 1; - } -done: - insn->immediate.got = 1; - -err_out: - return; -} - -/** - * insn_get_length() - Get the length of instruction - * @insn: &struct insn containing instruction - * - * If necessary, first collects the instruction up to and including the - * immediates bytes. - */ -void insn_get_length(struct insn *insn) -{ - if (insn->length) - return; - if (!insn->immediate.got) - insn_get_immediate(insn); - insn->length = (unsigned char)((unsigned long)insn->next_byte - - (unsigned long)insn->kaddr); -} diff --git a/tools/perf/util/intel-pt-decoder/insn.h b/tools/perf/util/intel-pt-decoder/insn.h deleted file mode 100644 index 37a4c390750b..000000000000 --- a/tools/perf/util/intel-pt-decoder/insn.h +++ /dev/null @@ -1,216 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -#ifndef _ASM_X86_INSN_H -#define _ASM_X86_INSN_H -/* - * x86 instruction analysis - * - * Copyright (C) IBM Corporation, 2009 - */ - -/* insn_attr_t is defined in inat.h */ -#include "inat.h" - -struct insn_field { - union { - insn_value_t value; - insn_byte_t bytes[4]; - }; - /* !0 if we've run insn_get_xxx() for this field */ - unsigned char got; - unsigned char nbytes; -}; - -struct insn { - struct insn_field prefixes; /* - * Prefixes - * prefixes.bytes[3]: last prefix - */ - struct insn_field rex_prefix; /* REX prefix */ - struct insn_field vex_prefix; /* VEX prefix */ - struct insn_field opcode; /* - * opcode.bytes[0]: opcode1 - * opcode.bytes[1]: opcode2 - * opcode.bytes[2]: opcode3 - */ - struct insn_field modrm; - struct insn_field sib; - struct insn_field displacement; - union { - struct insn_field immediate; - struct insn_field moffset1; /* for 64bit MOV */ - struct insn_field immediate1; /* for 64bit imm or off16/32 */ - }; - union { - struct insn_field moffset2; /* for 64bit MOV */ - struct insn_field immediate2; /* for 64bit imm or seg16 */ - }; - - insn_attr_t attr; - unsigned char opnd_bytes; - unsigned char addr_bytes; - unsigned char length; - unsigned char x86_64; - - const insn_byte_t *kaddr; /* kernel address of insn to analyze */ - const insn_byte_t *end_kaddr; /* kernel address of last insn in buffer */ - const insn_byte_t *next_byte; -}; - -#define MAX_INSN_SIZE 15 - -#define X86_MODRM_MOD(modrm) (((modrm) & 0xc0) >> 6) -#define X86_MODRM_REG(modrm) (((modrm) & 0x38) >> 3) -#define X86_MODRM_RM(modrm) ((modrm) & 0x07) - -#define X86_SIB_SCALE(sib) (((sib) & 0xc0) >> 6) -#define X86_SIB_INDEX(sib) (((sib) & 0x38) >> 3) -#define X86_SIB_BASE(sib) ((sib) & 0x07) - -#define X86_REX_W(rex) ((rex) & 8) -#define X86_REX_R(rex) ((rex) & 4) -#define X86_REX_X(rex) ((rex) & 2) -#define X86_REX_B(rex) ((rex) & 1) - -/* VEX bit flags */ -#define X86_VEX_W(vex) ((vex) & 0x80) /* VEX3 Byte2 */ -#define X86_VEX_R(vex) ((vex) & 0x80) /* VEX2/3 Byte1 */ -#define X86_VEX_X(vex) ((vex) & 0x40) /* VEX3 Byte1 */ -#define X86_VEX_B(vex) ((vex) & 0x20) /* VEX3 Byte1 */ -#define X86_VEX_L(vex) ((vex) & 0x04) /* VEX3 Byte2, VEX2 Byte1 */ -/* VEX bit fields */ -#define X86_EVEX_M(vex) ((vex) & 0x03) /* EVEX Byte1 */ -#define X86_VEX3_M(vex) ((vex) & 0x1f) /* VEX3 Byte1 */ -#define X86_VEX2_M 1 /* VEX2.M always 1 */ -#define X86_VEX_V(vex) (((vex) & 0x78) >> 3) /* VEX3 Byte2, VEX2 Byte1 */ -#define X86_VEX_P(vex) ((vex) & 0x03) /* VEX3 Byte2, VEX2 Byte1 */ -#define X86_VEX_M_MAX 0x1f /* VEX3.M Maximum value */ - -extern void insn_init(struct insn *insn, const void *kaddr, int buf_len, int x86_64); -extern void insn_get_prefixes(struct insn *insn); -extern void insn_get_opcode(struct insn *insn); -extern void insn_get_modrm(struct insn *insn); -extern void insn_get_sib(struct insn *insn); -extern void insn_get_displacement(struct insn *insn); -extern void insn_get_immediate(struct insn *insn); -extern void insn_get_length(struct insn *insn); - -/* Attribute will be determined after getting ModRM (for opcode groups) */ -static inline void insn_get_attribute(struct insn *insn) -{ - insn_get_modrm(insn); -} - -/* Instruction uses RIP-relative addressing */ -extern int insn_rip_relative(struct insn *insn); - -/* Init insn for kernel text */ -static inline void kernel_insn_init(struct insn *insn, - const void *kaddr, int buf_len) -{ -#ifdef CONFIG_X86_64 - insn_init(insn, kaddr, buf_len, 1); -#else /* CONFIG_X86_32 */ - insn_init(insn, kaddr, buf_len, 0); -#endif -} - -static inline int insn_is_avx(struct insn *insn) -{ - if (!insn->prefixes.got) - insn_get_prefixes(insn); - return (insn->vex_prefix.value != 0); -} - -static inline int insn_is_evex(struct insn *insn) -{ - if (!insn->prefixes.got) - insn_get_prefixes(insn); - return (insn->vex_prefix.nbytes == 4); -} - -/* Ensure this instruction is decoded completely */ -static inline int insn_complete(struct insn *insn) -{ - return insn->opcode.got && insn->modrm.got && insn->sib.got && - insn->displacement.got && insn->immediate.got; -} - -static inline insn_byte_t insn_vex_m_bits(struct insn *insn) -{ - if (insn->vex_prefix.nbytes == 2) /* 2 bytes VEX */ - return X86_VEX2_M; - else if (insn->vex_prefix.nbytes == 3) /* 3 bytes VEX */ - return X86_VEX3_M(insn->vex_prefix.bytes[1]); - else /* EVEX */ - return X86_EVEX_M(insn->vex_prefix.bytes[1]); -} - -static inline insn_byte_t insn_vex_p_bits(struct insn *insn) -{ - if (insn->vex_prefix.nbytes == 2) /* 2 bytes VEX */ - return X86_VEX_P(insn->vex_prefix.bytes[1]); - else - return X86_VEX_P(insn->vex_prefix.bytes[2]); -} - -/* Get the last prefix id from last prefix or VEX prefix */ -static inline int insn_last_prefix_id(struct insn *insn) -{ - if (insn_is_avx(insn)) - return insn_vex_p_bits(insn); /* VEX_p is a SIMD prefix id */ - - if (insn->prefixes.bytes[3]) - return inat_get_last_prefix_id(insn->prefixes.bytes[3]); - - return 0; -} - -/* Offset of each field from kaddr */ -static inline int insn_offset_rex_prefix(struct insn *insn) -{ - return insn->prefixes.nbytes; -} -static inline int insn_offset_vex_prefix(struct insn *insn) -{ - return insn_offset_rex_prefix(insn) + insn->rex_prefix.nbytes; -} -static inline int insn_offset_opcode(struct insn *insn) -{ - return insn_offset_vex_prefix(insn) + insn->vex_prefix.nbytes; -} -static inline int insn_offset_modrm(struct insn *insn) -{ - return insn_offset_opcode(insn) + insn->opcode.nbytes; -} -static inline int insn_offset_sib(struct insn *insn) -{ - return insn_offset_modrm(insn) + insn->modrm.nbytes; -} -static inline int insn_offset_displacement(struct insn *insn) -{ - return insn_offset_sib(insn) + insn->sib.nbytes; -} -static inline int insn_offset_immediate(struct insn *insn) -{ - return insn_offset_displacement(insn) + insn->displacement.nbytes; -} - -#define POP_SS_OPCODE 0x1f -#define MOV_SREG_OPCODE 0x8e - -/* - * Intel SDM Vol.3A 6.8.3 states; - * "Any single-step trap that would be delivered following the MOV to SS - * instruction or POP to SS instruction (because EFLAGS.TF is 1) is - * suppressed." - * This function returns true if @insn is MOV SS or POP SS. On these - * instructions, single stepping is suppressed. - */ -static inline int insn_masking_exception(struct insn *insn) -{ - return insn->opcode.bytes[0] == POP_SS_OPCODE || - (insn->opcode.bytes[0] == MOV_SREG_OPCODE && - X86_MODRM_REG(insn->modrm.bytes[0]) == 2); -} - -#endif /* _ASM_X86_INSN_H */ diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c index 3bfdf2b7a96a..f8ccfd6be0ee 100644 --- a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c +++ b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c @@ -14,9 +14,9 @@ #include <stdint.h> #include <inttypes.h> #include <linux/compiler.h> +#include <linux/string.h> #include <linux/zalloc.h> -#include "../cache.h" #include "../auxtrace.h" #include "intel-pt-insn-decoder.h" diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-insn-decoder.c b/tools/perf/util/intel-pt-decoder/intel-pt-insn-decoder.c index 598f56be9f17..fb8a3558d3d5 100644 --- a/tools/perf/util/intel-pt-decoder/intel-pt-insn-decoder.c +++ b/tools/perf/util/intel-pt-decoder/intel-pt-insn-decoder.c @@ -4,17 +4,17 @@ * Copyright (c) 2013-2014, Intel Corporation. */ +#include <linux/kernel.h> #include <stdio.h> #include <string.h> #include <endian.h> #include <byteswap.h> +#include "../../../arch/x86/include/asm/insn.h" -#include "event.h" - -#include "insn.h" +#include "../../../arch/x86/lib/inat.c" +#include "../../../arch/x86/lib/insn.c" -#include "inat.c" -#include "insn.c" +#include "event.h" #include "intel-pt-insn-decoder.h" #include "dump-insn.h" diff --git a/tools/perf/util/intel-pt-decoder/x86-opcode-map.txt b/tools/perf/util/intel-pt-decoder/x86-opcode-map.txt deleted file mode 100644 index e0b85930dd77..000000000000 --- a/tools/perf/util/intel-pt-decoder/x86-opcode-map.txt +++ /dev/null @@ -1,1072 +0,0 @@ -# x86 Opcode Maps -# -# This is (mostly) based on following documentations. -# - Intel(R) 64 and IA-32 Architectures Software Developer's Manual Vol.2C -# (#326018-047US, June 2013) -# -#<Opcode maps> -# Table: table-name -# Referrer: escaped-name -# AVXcode: avx-code -# opcode: mnemonic|GrpXXX [operand1[,operand2...]] [(extra1)[,(extra2)...] [| 2nd-mnemonic ...] -# (or) -# opcode: escape # escaped-name -# EndTable -# -# mnemonics that begin with lowercase 'v' accept a VEX or EVEX prefix -# mnemonics that begin with lowercase 'k' accept a VEX prefix -# -#<group maps> -# GrpTable: GrpXXX -# reg: mnemonic [operand1[,operand2...]] [(extra1)[,(extra2)...] [| 2nd-mnemonic ...] -# EndTable -# -# AVX Superscripts -# (ev): this opcode requires EVEX prefix. -# (evo): this opcode is changed by EVEX prefix (EVEX opcode) -# (v): this opcode requires VEX prefix. -# (v1): this opcode only supports 128bit VEX. -# -# Last Prefix Superscripts -# - (66): the last prefix is 0x66 -# - (F3): the last prefix is 0xF3 -# - (F2): the last prefix is 0xF2 -# - (!F3) : the last prefix is not 0xF3 (including non-last prefix case) -# - (66&F2): Both 0x66 and 0xF2 prefixes are specified. - -Table: one byte opcode -Referrer: -AVXcode: -# 0x00 - 0x0f -00: ADD Eb,Gb -01: ADD Ev,Gv -02: ADD Gb,Eb -03: ADD Gv,Ev -04: ADD AL,Ib -05: ADD rAX,Iz -06: PUSH ES (i64) -07: POP ES (i64) -08: OR Eb,Gb -09: OR Ev,Gv -0a: OR Gb,Eb -0b: OR Gv,Ev -0c: OR AL,Ib -0d: OR rAX,Iz -0e: PUSH CS (i64) -0f: escape # 2-byte escape -# 0x10 - 0x1f -10: ADC Eb,Gb -11: ADC Ev,Gv -12: ADC Gb,Eb -13: ADC Gv,Ev -14: ADC AL,Ib -15: ADC rAX,Iz -16: PUSH SS (i64) -17: POP SS (i64) -18: SBB Eb,Gb -19: SBB Ev,Gv -1a: SBB Gb,Eb -1b: SBB Gv,Ev -1c: SBB AL,Ib -1d: SBB rAX,Iz -1e: PUSH DS (i64) -1f: POP DS (i64) -# 0x20 - 0x2f -20: AND Eb,Gb -21: AND Ev,Gv -22: AND Gb,Eb -23: AND Gv,Ev -24: AND AL,Ib -25: AND rAx,Iz -26: SEG=ES (Prefix) -27: DAA (i64) -28: SUB Eb,Gb -29: SUB Ev,Gv -2a: SUB Gb,Eb -2b: SUB Gv,Ev -2c: SUB AL,Ib -2d: SUB rAX,Iz -2e: SEG=CS (Prefix) -2f: DAS (i64) -# 0x30 - 0x3f -30: XOR Eb,Gb -31: XOR Ev,Gv -32: XOR Gb,Eb -33: XOR Gv,Ev -34: XOR AL,Ib -35: XOR rAX,Iz -36: SEG=SS (Prefix) -37: AAA (i64) -38: CMP Eb,Gb -39: CMP Ev,Gv -3a: CMP Gb,Eb -3b: CMP Gv,Ev -3c: CMP AL,Ib -3d: CMP rAX,Iz -3e: SEG=DS (Prefix) -3f: AAS (i64) -# 0x40 - 0x4f -40: INC eAX (i64) | REX (o64) -41: INC eCX (i64) | REX.B (o64) -42: INC eDX (i64) | REX.X (o64) -43: INC eBX (i64) | REX.XB (o64) -44: INC eSP (i64) | REX.R (o64) -45: INC eBP (i64) | REX.RB (o64) -46: INC eSI (i64) | REX.RX (o64) -47: INC eDI (i64) | REX.RXB (o64) -48: DEC eAX (i64) | REX.W (o64) -49: DEC eCX (i64) | REX.WB (o64) -4a: DEC eDX (i64) | REX.WX (o64) -4b: DEC eBX (i64) | REX.WXB (o64) -4c: DEC eSP (i64) | REX.WR (o64) -4d: DEC eBP (i64) | REX.WRB (o64) -4e: DEC eSI (i64) | REX.WRX (o64) -4f: DEC eDI (i64) | REX.WRXB (o64) -# 0x50 - 0x5f -50: PUSH rAX/r8 (d64) -51: PUSH rCX/r9 (d64) -52: PUSH rDX/r10 (d64) -53: PUSH rBX/r11 (d64) -54: PUSH rSP/r12 (d64) -55: PUSH rBP/r13 (d64) -56: PUSH rSI/r14 (d64) -57: PUSH rDI/r15 (d64) -58: POP rAX/r8 (d64) -59: POP rCX/r9 (d64) -5a: POP rDX/r10 (d64) -5b: POP rBX/r11 (d64) -5c: POP rSP/r12 (d64) -5d: POP rBP/r13 (d64) -5e: POP rSI/r14 (d64) -5f: POP rDI/r15 (d64) -# 0x60 - 0x6f -60: PUSHA/PUSHAD (i64) -61: POPA/POPAD (i64) -62: BOUND Gv,Ma (i64) | EVEX (Prefix) -63: ARPL Ew,Gw (i64) | MOVSXD Gv,Ev (o64) -64: SEG=FS (Prefix) -65: SEG=GS (Prefix) -66: Operand-Size (Prefix) -67: Address-Size (Prefix) -68: PUSH Iz (d64) -69: IMUL Gv,Ev,Iz -6a: PUSH Ib (d64) -6b: IMUL Gv,Ev,Ib -6c: INS/INSB Yb,DX -6d: INS/INSW/INSD Yz,DX -6e: OUTS/OUTSB DX,Xb -6f: OUTS/OUTSW/OUTSD DX,Xz -# 0x70 - 0x7f -70: JO Jb -71: JNO Jb -72: JB/JNAE/JC Jb -73: JNB/JAE/JNC Jb -74: JZ/JE Jb -75: JNZ/JNE Jb -76: JBE/JNA Jb -77: JNBE/JA Jb -78: JS Jb -79: JNS Jb -7a: JP/JPE Jb -7b: JNP/JPO Jb -7c: JL/JNGE Jb -7d: JNL/JGE Jb -7e: JLE/JNG Jb -7f: JNLE/JG Jb -# 0x80 - 0x8f -80: Grp1 Eb,Ib (1A) -81: Grp1 Ev,Iz (1A) -82: Grp1 Eb,Ib (1A),(i64) -83: Grp1 Ev,Ib (1A) -84: TEST Eb,Gb -85: TEST Ev,Gv -86: XCHG Eb,Gb -87: XCHG Ev,Gv -88: MOV Eb,Gb -89: MOV Ev,Gv -8a: MOV Gb,Eb -8b: MOV Gv,Ev -8c: MOV Ev,Sw -8d: LEA Gv,M -8e: MOV Sw,Ew -8f: Grp1A (1A) | POP Ev (d64) -# 0x90 - 0x9f -90: NOP | PAUSE (F3) | XCHG r8,rAX -91: XCHG rCX/r9,rAX -92: XCHG rDX/r10,rAX -93: XCHG rBX/r11,rAX -94: XCHG rSP/r12,rAX -95: XCHG rBP/r13,rAX -96: XCHG rSI/r14,rAX -97: XCHG rDI/r15,rAX -98: CBW/CWDE/CDQE -99: CWD/CDQ/CQO -9a: CALLF Ap (i64) -9b: FWAIT/WAIT -9c: PUSHF/D/Q Fv (d64) -9d: POPF/D/Q Fv (d64) -9e: SAHF -9f: LAHF -# 0xa0 - 0xaf -a0: MOV AL,Ob -a1: MOV rAX,Ov -a2: MOV Ob,AL -a3: MOV Ov,rAX -a4: MOVS/B Yb,Xb -a5: MOVS/W/D/Q Yv,Xv -a6: CMPS/B Xb,Yb -a7: CMPS/W/D Xv,Yv -a8: TEST AL,Ib -a9: TEST rAX,Iz -aa: STOS/B Yb,AL -ab: STOS/W/D/Q Yv,rAX -ac: LODS/B AL,Xb -ad: LODS/W/D/Q rAX,Xv -ae: SCAS/B AL,Yb -# Note: The May 2011 Intel manual shows Xv for the second parameter of the -# next instruction but Yv is correct -af: SCAS/W/D/Q rAX,Yv -# 0xb0 - 0xbf -b0: MOV AL/R8L,Ib -b1: MOV CL/R9L,Ib -b2: MOV DL/R10L,Ib -b3: MOV BL/R11L,Ib -b4: MOV AH/R12L,Ib -b5: MOV CH/R13L,Ib -b6: MOV DH/R14L,Ib -b7: MOV BH/R15L,Ib -b8: MOV rAX/r8,Iv -b9: MOV rCX/r9,Iv -ba: MOV rDX/r10,Iv -bb: MOV rBX/r11,Iv -bc: MOV rSP/r12,Iv -bd: MOV rBP/r13,Iv -be: MOV rSI/r14,Iv -bf: MOV rDI/r15,Iv -# 0xc0 - 0xcf -c0: Grp2 Eb,Ib (1A) -c1: Grp2 Ev,Ib (1A) -c2: RETN Iw (f64) -c3: RETN -c4: LES Gz,Mp (i64) | VEX+2byte (Prefix) -c5: LDS Gz,Mp (i64) | VEX+1byte (Prefix) -c6: Grp11A Eb,Ib (1A) -c7: Grp11B Ev,Iz (1A) -c8: ENTER Iw,Ib -c9: LEAVE (d64) -ca: RETF Iw -cb: RETF -cc: INT3 -cd: INT Ib -ce: INTO (i64) -cf: IRET/D/Q -# 0xd0 - 0xdf -d0: Grp2 Eb,1 (1A) -d1: Grp2 Ev,1 (1A) -d2: Grp2 Eb,CL (1A) -d3: Grp2 Ev,CL (1A) -d4: AAM Ib (i64) -d5: AAD Ib (i64) -d6: -d7: XLAT/XLATB -d8: ESC -d9: ESC -da: ESC -db: ESC -dc: ESC -dd: ESC -de: ESC -df: ESC -# 0xe0 - 0xef -# Note: "forced64" is Intel CPU behavior: they ignore 0x66 prefix -# in 64-bit mode. AMD CPUs accept 0x66 prefix, it causes RIP truncation -# to 16 bits. In 32-bit mode, 0x66 is accepted by both Intel and AMD. -e0: LOOPNE/LOOPNZ Jb (f64) -e1: LOOPE/LOOPZ Jb (f64) -e2: LOOP Jb (f64) -e3: JrCXZ Jb (f64) -e4: IN AL,Ib -e5: IN eAX,Ib -e6: OUT Ib,AL -e7: OUT Ib,eAX -# With 0x66 prefix in 64-bit mode, for AMD CPUs immediate offset -# in "near" jumps and calls is 16-bit. For CALL, -# push of return address is 16-bit wide, RSP is decremented by 2 -# but is not truncated to 16 bits, unlike RIP. -e8: CALL Jz (f64) -e9: JMP-near Jz (f64) -ea: JMP-far Ap (i64) -eb: JMP-short Jb (f64) -ec: IN AL,DX -ed: IN eAX,DX -ee: OUT DX,AL -ef: OUT DX,eAX -# 0xf0 - 0xff -f0: LOCK (Prefix) -f1: -f2: REPNE (Prefix) | XACQUIRE (Prefix) -f3: REP/REPE (Prefix) | XRELEASE (Prefix) -f4: HLT -f5: CMC -f6: Grp3_1 Eb (1A) -f7: Grp3_2 Ev (1A) -f8: CLC -f9: STC -fa: CLI -fb: STI -fc: CLD -fd: STD -fe: Grp4 (1A) -ff: Grp5 (1A) -EndTable - -Table: 2-byte opcode (0x0f) -Referrer: 2-byte escape -AVXcode: 1 -# 0x0f 0x00-0x0f -00: Grp6 (1A) -01: Grp7 (1A) -02: LAR Gv,Ew -03: LSL Gv,Ew -04: -05: SYSCALL (o64) -06: CLTS -07: SYSRET (o64) -08: INVD -09: WBINVD -0a: -0b: UD2 (1B) -0c: -# AMD's prefetch group. Intel supports prefetchw(/1) only. -0d: GrpP -0e: FEMMS -# 3DNow! uses the last imm byte as opcode extension. -0f: 3DNow! Pq,Qq,Ib -# 0x0f 0x10-0x1f -# NOTE: According to Intel SDM opcode map, vmovups and vmovupd has no operands -# but it actually has operands. And also, vmovss and vmovsd only accept 128bit. -# MOVSS/MOVSD has too many forms(3) on SDM. This map just shows a typical form. -# Many AVX instructions lack v1 superscript, according to Intel AVX-Prgramming -# Reference A.1 -10: vmovups Vps,Wps | vmovupd Vpd,Wpd (66) | vmovss Vx,Hx,Wss (F3),(v1) | vmovsd Vx,Hx,Wsd (F2),(v1) -11: vmovups Wps,Vps | vmovupd Wpd,Vpd (66) | vmovss Wss,Hx,Vss (F3),(v1) | vmovsd Wsd,Hx,Vsd (F2),(v1) -12: vmovlps Vq,Hq,Mq (v1) | vmovhlps Vq,Hq,Uq (v1) | vmovlpd Vq,Hq,Mq (66),(v1) | vmovsldup Vx,Wx (F3) | vmovddup Vx,Wx (F2) -13: vmovlps Mq,Vq (v1) | vmovlpd Mq,Vq (66),(v1) -14: vunpcklps Vx,Hx,Wx | vunpcklpd Vx,Hx,Wx (66) -15: vunpckhps Vx,Hx,Wx | vunpckhpd Vx,Hx,Wx (66) -16: vmovhps Vdq,Hq,Mq (v1) | vmovlhps Vdq,Hq,Uq (v1) | vmovhpd Vdq,Hq,Mq (66),(v1) | vmovshdup Vx,Wx (F3) -17: vmovhps Mq,Vq (v1) | vmovhpd Mq,Vq (66),(v1) -18: Grp16 (1A) -19: -# Intel SDM opcode map does not list MPX instructions. For now using Gv for -# bnd registers and Ev for everything else is OK because the instruction -# decoder does not use the information except as an indication that there is -# a ModR/M byte. -1a: BNDCL Gv,Ev (F3) | BNDCU Gv,Ev (F2) | BNDMOV Gv,Ev (66) | BNDLDX Gv,Ev -1b: BNDCN Gv,Ev (F2) | BNDMOV Ev,Gv (66) | BNDMK Gv,Ev (F3) | BNDSTX Ev,Gv -1c: -1d: -1e: -1f: NOP Ev -# 0x0f 0x20-0x2f -20: MOV Rd,Cd -21: MOV Rd,Dd -22: MOV Cd,Rd -23: MOV Dd,Rd -24: -25: -26: -27: -28: vmovaps Vps,Wps | vmovapd Vpd,Wpd (66) -29: vmovaps Wps,Vps | vmovapd Wpd,Vpd (66) -2a: cvtpi2ps Vps,Qpi | cvtpi2pd Vpd,Qpi (66) | vcvtsi2ss Vss,Hss,Ey (F3),(v1) | vcvtsi2sd Vsd,Hsd,Ey (F2),(v1) -2b: vmovntps Mps,Vps | vmovntpd Mpd,Vpd (66) -2c: cvttps2pi Ppi,Wps | cvttpd2pi Ppi,Wpd (66) | vcvttss2si Gy,Wss (F3),(v1) | vcvttsd2si Gy,Wsd (F2),(v1) -2d: cvtps2pi Ppi,Wps | cvtpd2pi Qpi,Wpd (66) | vcvtss2si Gy,Wss (F3),(v1) | vcvtsd2si Gy,Wsd (F2),(v1) -2e: vucomiss Vss,Wss (v1) | vucomisd Vsd,Wsd (66),(v1) -2f: vcomiss Vss,Wss (v1) | vcomisd Vsd,Wsd (66),(v1) -# 0x0f 0x30-0x3f -30: WRMSR -31: RDTSC -32: RDMSR -33: RDPMC -34: SYSENTER -35: SYSEXIT -36: -37: GETSEC -38: escape # 3-byte escape 1 -39: -3a: escape # 3-byte escape 2 -3b: -3c: -3d: -3e: -3f: -# 0x0f 0x40-0x4f -40: CMOVO Gv,Ev -41: CMOVNO Gv,Ev | kandw/q Vk,Hk,Uk | kandb/d Vk,Hk,Uk (66) -42: CMOVB/C/NAE Gv,Ev | kandnw/q Vk,Hk,Uk | kandnb/d Vk,Hk,Uk (66) -43: CMOVAE/NB/NC Gv,Ev -44: CMOVE/Z Gv,Ev | knotw/q Vk,Uk | knotb/d Vk,Uk (66) -45: CMOVNE/NZ Gv,Ev | korw/q Vk,Hk,Uk | korb/d Vk,Hk,Uk (66) -46: CMOVBE/NA Gv,Ev | kxnorw/q Vk,Hk,Uk | kxnorb/d Vk,Hk,Uk (66) -47: CMOVA/NBE Gv,Ev | kxorw/q Vk,Hk,Uk | kxorb/d Vk,Hk,Uk (66) -48: CMOVS Gv,Ev -49: CMOVNS Gv,Ev -4a: CMOVP/PE Gv,Ev | kaddw/q Vk,Hk,Uk | kaddb/d Vk,Hk,Uk (66) -4b: CMOVNP/PO Gv,Ev | kunpckbw Vk,Hk,Uk (66) | kunpckwd/dq Vk,Hk,Uk -4c: CMOVL/NGE Gv,Ev -4d: CMOVNL/GE Gv,Ev -4e: CMOVLE/NG Gv,Ev -4f: CMOVNLE/G Gv,Ev -# 0x0f 0x50-0x5f -50: vmovmskps Gy,Ups | vmovmskpd Gy,Upd (66) -51: vsqrtps Vps,Wps | vsqrtpd Vpd,Wpd (66) | vsqrtss Vss,Hss,Wss (F3),(v1) | vsqrtsd Vsd,Hsd,Wsd (F2),(v1) -52: vrsqrtps Vps,Wps | vrsqrtss Vss,Hss,Wss (F3),(v1) -53: vrcpps Vps,Wps | vrcpss Vss,Hss,Wss (F3),(v1) -54: vandps Vps,Hps,Wps | vandpd Vpd,Hpd,Wpd (66) -55: vandnps Vps,Hps,Wps | vandnpd Vpd,Hpd,Wpd (66) -56: vorps Vps,Hps,Wps | vorpd Vpd,Hpd,Wpd (66) -57: vxorps Vps,Hps,Wps | vxorpd Vpd,Hpd,Wpd (66) -58: vaddps Vps,Hps,Wps | vaddpd Vpd,Hpd,Wpd (66) | vaddss Vss,Hss,Wss (F3),(v1) | vaddsd Vsd,Hsd,Wsd (F2),(v1) -59: vmulps Vps,Hps,Wps | vmulpd Vpd,Hpd,Wpd (66) | vmulss Vss,Hss,Wss (F3),(v1) | vmulsd Vsd,Hsd,Wsd (F2),(v1) -5a: vcvtps2pd Vpd,Wps | vcvtpd2ps Vps,Wpd (66) | vcvtss2sd Vsd,Hx,Wss (F3),(v1) | vcvtsd2ss Vss,Hx,Wsd (F2),(v1) -5b: vcvtdq2ps Vps,Wdq | vcvtqq2ps Vps,Wqq (evo) | vcvtps2dq Vdq,Wps (66) | vcvttps2dq Vdq,Wps (F3) -5c: vsubps Vps,Hps,Wps | vsubpd Vpd,Hpd,Wpd (66) | vsubss Vss,Hss,Wss (F3),(v1) | vsubsd Vsd,Hsd,Wsd (F2),(v1) -5d: vminps Vps,Hps,Wps | vminpd Vpd,Hpd,Wpd (66) | vminss Vss,Hss,Wss (F3),(v1) | vminsd Vsd,Hsd,Wsd (F2),(v1) -5e: vdivps Vps,Hps,Wps | vdivpd Vpd,Hpd,Wpd (66) | vdivss Vss,Hss,Wss (F3),(v1) | vdivsd Vsd,Hsd,Wsd (F2),(v1) -5f: vmaxps Vps,Hps,Wps | vmaxpd Vpd,Hpd,Wpd (66) | vmaxss Vss,Hss,Wss (F3),(v1) | vmaxsd Vsd,Hsd,Wsd (F2),(v1) -# 0x0f 0x60-0x6f -60: punpcklbw Pq,Qd | vpunpcklbw Vx,Hx,Wx (66),(v1) -61: punpcklwd Pq,Qd | vpunpcklwd Vx,Hx,Wx (66),(v1) -62: punpckldq Pq,Qd | vpunpckldq Vx,Hx,Wx (66),(v1) -63: packsswb Pq,Qq | vpacksswb Vx,Hx,Wx (66),(v1) -64: pcmpgtb Pq,Qq | vpcmpgtb Vx,Hx,Wx (66),(v1) -65: pcmpgtw Pq,Qq | vpcmpgtw Vx,Hx,Wx (66),(v1) -66: pcmpgtd Pq,Qq | vpcmpgtd Vx,Hx,Wx (66),(v1) -67: packuswb Pq,Qq | vpackuswb Vx,Hx,Wx (66),(v1) -68: punpckhbw Pq,Qd | vpunpckhbw Vx,Hx,Wx (66),(v1) -69: punpckhwd Pq,Qd | vpunpckhwd Vx,Hx,Wx (66),(v1) -6a: punpckhdq Pq,Qd | vpunpckhdq Vx,Hx,Wx (66),(v1) -6b: packssdw Pq,Qd | vpackssdw Vx,Hx,Wx (66),(v1) -6c: vpunpcklqdq Vx,Hx,Wx (66),(v1) -6d: vpunpckhqdq Vx,Hx,Wx (66),(v1) -6e: movd/q Pd,Ey | vmovd/q Vy,Ey (66),(v1) -6f: movq Pq,Qq | vmovdqa Vx,Wx (66) | vmovdqa32/64 Vx,Wx (66),(evo) | vmovdqu Vx,Wx (F3) | vmovdqu32/64 Vx,Wx (F3),(evo) | vmovdqu8/16 Vx,Wx (F2),(ev) -# 0x0f 0x70-0x7f -70: pshufw Pq,Qq,Ib | vpshufd Vx,Wx,Ib (66),(v1) | vpshufhw Vx,Wx,Ib (F3),(v1) | vpshuflw Vx,Wx,Ib (F2),(v1) -71: Grp12 (1A) -72: Grp13 (1A) -73: Grp14 (1A) -74: pcmpeqb Pq,Qq | vpcmpeqb Vx,Hx,Wx (66),(v1) -75: pcmpeqw Pq,Qq | vpcmpeqw Vx,Hx,Wx (66),(v1) -76: pcmpeqd Pq,Qq | vpcmpeqd Vx,Hx,Wx (66),(v1) -# Note: Remove (v), because vzeroall and vzeroupper becomes emms without VEX. -77: emms | vzeroupper | vzeroall -78: VMREAD Ey,Gy | vcvttps2udq/pd2udq Vx,Wpd (evo) | vcvttsd2usi Gv,Wx (F2),(ev) | vcvttss2usi Gv,Wx (F3),(ev) | vcvttps2uqq/pd2uqq Vx,Wx (66),(ev) -79: VMWRITE Gy,Ey | vcvtps2udq/pd2udq Vx,Wpd (evo) | vcvtsd2usi Gv,Wx (F2),(ev) | vcvtss2usi Gv,Wx (F3),(ev) | vcvtps2uqq/pd2uqq Vx,Wx (66),(ev) -7a: vcvtudq2pd/uqq2pd Vpd,Wx (F3),(ev) | vcvtudq2ps/uqq2ps Vpd,Wx (F2),(ev) | vcvttps2qq/pd2qq Vx,Wx (66),(ev) -7b: vcvtusi2sd Vpd,Hpd,Ev (F2),(ev) | vcvtusi2ss Vps,Hps,Ev (F3),(ev) | vcvtps2qq/pd2qq Vx,Wx (66),(ev) -7c: vhaddpd Vpd,Hpd,Wpd (66) | vhaddps Vps,Hps,Wps (F2) -7d: vhsubpd Vpd,Hpd,Wpd (66) | vhsubps Vps,Hps,Wps (F2) -7e: movd/q Ey,Pd | vmovd/q Ey,Vy (66),(v1) | vmovq Vq,Wq (F3),(v1) -7f: movq Qq,Pq | vmovdqa Wx,Vx (66) | vmovdqa32/64 Wx,Vx (66),(evo) | vmovdqu Wx,Vx (F3) | vmovdqu32/64 Wx,Vx (F3),(evo) | vmovdqu8/16 Wx,Vx (F2),(ev) -# 0x0f 0x80-0x8f -# Note: "forced64" is Intel CPU behavior (see comment about CALL insn). -80: JO Jz (f64) -81: JNO Jz (f64) -82: JB/JC/JNAE Jz (f64) -83: JAE/JNB/JNC Jz (f64) -84: JE/JZ Jz (f64) -85: JNE/JNZ Jz (f64) -86: JBE/JNA Jz (f64) -87: JA/JNBE Jz (f64) -88: JS Jz (f64) -89: JNS Jz (f64) -8a: JP/JPE Jz (f64) -8b: JNP/JPO Jz (f64) -8c: JL/JNGE Jz (f64) -8d: JNL/JGE Jz (f64) -8e: JLE/JNG Jz (f64) -8f: JNLE/JG Jz (f64) -# 0x0f 0x90-0x9f -90: SETO Eb | kmovw/q Vk,Wk | kmovb/d Vk,Wk (66) -91: SETNO Eb | kmovw/q Mv,Vk | kmovb/d Mv,Vk (66) -92: SETB/C/NAE Eb | kmovw Vk,Rv | kmovb Vk,Rv (66) | kmovq/d Vk,Rv (F2) -93: SETAE/NB/NC Eb | kmovw Gv,Uk | kmovb Gv,Uk (66) | kmovq/d Gv,Uk (F2) -94: SETE/Z Eb -95: SETNE/NZ Eb -96: SETBE/NA Eb -97: SETA/NBE Eb -98: SETS Eb | kortestw/q Vk,Uk | kortestb/d Vk,Uk (66) -99: SETNS Eb | ktestw/q Vk,Uk | ktestb/d Vk,Uk (66) -9a: SETP/PE Eb -9b: SETNP/PO Eb -9c: SETL/NGE Eb -9d: SETNL/GE Eb -9e: SETLE/NG Eb -9f: SETNLE/G Eb -# 0x0f 0xa0-0xaf -a0: PUSH FS (d64) -a1: POP FS (d64) -a2: CPUID -a3: BT Ev,Gv -a4: SHLD Ev,Gv,Ib -a5: SHLD Ev,Gv,CL -a6: GrpPDLK -a7: GrpRNG -a8: PUSH GS (d64) -a9: POP GS (d64) -aa: RSM -ab: BTS Ev,Gv -ac: SHRD Ev,Gv,Ib -ad: SHRD Ev,Gv,CL -ae: Grp15 (1A),(1C) -af: IMUL Gv,Ev -# 0x0f 0xb0-0xbf -b0: CMPXCHG Eb,Gb -b1: CMPXCHG Ev,Gv -b2: LSS Gv,Mp -b3: BTR Ev,Gv -b4: LFS Gv,Mp -b5: LGS Gv,Mp -b6: MOVZX Gv,Eb -b7: MOVZX Gv,Ew -b8: JMPE (!F3) | POPCNT Gv,Ev (F3) -b9: Grp10 (1A) -ba: Grp8 Ev,Ib (1A) -bb: BTC Ev,Gv -bc: BSF Gv,Ev (!F3) | TZCNT Gv,Ev (F3) -bd: BSR Gv,Ev (!F3) | LZCNT Gv,Ev (F3) -be: MOVSX Gv,Eb -bf: MOVSX Gv,Ew -# 0x0f 0xc0-0xcf -c0: XADD Eb,Gb -c1: XADD Ev,Gv -c2: vcmpps Vps,Hps,Wps,Ib | vcmppd Vpd,Hpd,Wpd,Ib (66) | vcmpss Vss,Hss,Wss,Ib (F3),(v1) | vcmpsd Vsd,Hsd,Wsd,Ib (F2),(v1) -c3: movnti My,Gy -c4: pinsrw Pq,Ry/Mw,Ib | vpinsrw Vdq,Hdq,Ry/Mw,Ib (66),(v1) -c5: pextrw Gd,Nq,Ib | vpextrw Gd,Udq,Ib (66),(v1) -c6: vshufps Vps,Hps,Wps,Ib | vshufpd Vpd,Hpd,Wpd,Ib (66) -c7: Grp9 (1A) -c8: BSWAP RAX/EAX/R8/R8D -c9: BSWAP RCX/ECX/R9/R9D -ca: BSWAP RDX/EDX/R10/R10D -cb: BSWAP RBX/EBX/R11/R11D -cc: BSWAP RSP/ESP/R12/R12D -cd: BSWAP RBP/EBP/R13/R13D -ce: BSWAP RSI/ESI/R14/R14D -cf: BSWAP RDI/EDI/R15/R15D -# 0x0f 0xd0-0xdf -d0: vaddsubpd Vpd,Hpd,Wpd (66) | vaddsubps Vps,Hps,Wps (F2) -d1: psrlw Pq,Qq | vpsrlw Vx,Hx,Wx (66),(v1) -d2: psrld Pq,Qq | vpsrld Vx,Hx,Wx (66),(v1) -d3: psrlq Pq,Qq | vpsrlq Vx,Hx,Wx (66),(v1) -d4: paddq Pq,Qq | vpaddq Vx,Hx,Wx (66),(v1) -d5: pmullw Pq,Qq | vpmullw Vx,Hx,Wx (66),(v1) -d6: vmovq Wq,Vq (66),(v1) | movq2dq Vdq,Nq (F3) | movdq2q Pq,Uq (F2) -d7: pmovmskb Gd,Nq | vpmovmskb Gd,Ux (66),(v1) -d8: psubusb Pq,Qq | vpsubusb Vx,Hx,Wx (66),(v1) -d9: psubusw Pq,Qq | vpsubusw Vx,Hx,Wx (66),(v1) -da: pminub Pq,Qq | vpminub Vx,Hx,Wx (66),(v1) -db: pand Pq,Qq | vpand Vx,Hx,Wx (66),(v1) | vpandd/q Vx,Hx,Wx (66),(evo) -dc: paddusb Pq,Qq | vpaddusb Vx,Hx,Wx (66),(v1) -dd: paddusw Pq,Qq | vpaddusw Vx,Hx,Wx (66),(v1) -de: pmaxub Pq,Qq | vpmaxub Vx,Hx,Wx (66),(v1) -df: pandn Pq,Qq | vpandn Vx,Hx,Wx (66),(v1) | vpandnd/q Vx,Hx,Wx (66),(evo) -# 0x0f 0xe0-0xef -e0: pavgb Pq,Qq | vpavgb Vx,Hx,Wx (66),(v1) -e1: psraw Pq,Qq | vpsraw Vx,Hx,Wx (66),(v1) -e2: psrad Pq,Qq | vpsrad Vx,Hx,Wx (66),(v1) -e3: pavgw Pq,Qq | vpavgw Vx,Hx,Wx (66),(v1) -e4: pmulhuw Pq,Qq | vpmulhuw Vx,Hx,Wx (66),(v1) -e5: pmulhw Pq,Qq | vpmulhw Vx,Hx,Wx (66),(v1) -e6: vcvttpd2dq Vx,Wpd (66) | vcvtdq2pd Vx,Wdq (F3) | vcvtdq2pd/qq2pd Vx,Wdq (F3),(evo) | vcvtpd2dq Vx,Wpd (F2) -e7: movntq Mq,Pq | vmovntdq Mx,Vx (66) -e8: psubsb Pq,Qq | vpsubsb Vx,Hx,Wx (66),(v1) -e9: psubsw Pq,Qq | vpsubsw Vx,Hx,Wx (66),(v1) -ea: pminsw Pq,Qq | vpminsw Vx,Hx,Wx (66),(v1) -eb: por Pq,Qq | vpor Vx,Hx,Wx (66),(v1) | vpord/q Vx,Hx,Wx (66),(evo) -ec: paddsb Pq,Qq | vpaddsb Vx,Hx,Wx (66),(v1) -ed: paddsw Pq,Qq | vpaddsw Vx,Hx,Wx (66),(v1) -ee: pmaxsw Pq,Qq | vpmaxsw Vx,Hx,Wx (66),(v1) -ef: pxor Pq,Qq | vpxor Vx,Hx,Wx (66),(v1) | vpxord/q Vx,Hx,Wx (66),(evo) -# 0x0f 0xf0-0xff -f0: vlddqu Vx,Mx (F2) -f1: psllw Pq,Qq | vpsllw Vx,Hx,Wx (66),(v1) -f2: pslld Pq,Qq | vpslld Vx,Hx,Wx (66),(v1) -f3: psllq Pq,Qq | vpsllq Vx,Hx,Wx (66),(v1) -f4: pmuludq Pq,Qq | vpmuludq Vx,Hx,Wx (66),(v1) -f5: pmaddwd Pq,Qq | vpmaddwd Vx,Hx,Wx (66),(v1) -f6: psadbw Pq,Qq | vpsadbw Vx,Hx,Wx (66),(v1) -f7: maskmovq Pq,Nq | vmaskmovdqu Vx,Ux (66),(v1) -f8: psubb Pq,Qq | vpsubb Vx,Hx,Wx (66),(v1) -f9: psubw Pq,Qq | vpsubw Vx,Hx,Wx (66),(v1) -fa: psubd Pq,Qq | vpsubd Vx,Hx,Wx (66),(v1) -fb: psubq Pq,Qq | vpsubq Vx,Hx,Wx (66),(v1) -fc: paddb Pq,Qq | vpaddb Vx,Hx,Wx (66),(v1) -fd: paddw Pq,Qq | vpaddw Vx,Hx,Wx (66),(v1) -fe: paddd Pq,Qq | vpaddd Vx,Hx,Wx (66),(v1) -ff: UD0 -EndTable - -Table: 3-byte opcode 1 (0x0f 0x38) -Referrer: 3-byte escape 1 -AVXcode: 2 -# 0x0f 0x38 0x00-0x0f -00: pshufb Pq,Qq | vpshufb Vx,Hx,Wx (66),(v1) -01: phaddw Pq,Qq | vphaddw Vx,Hx,Wx (66),(v1) -02: phaddd Pq,Qq | vphaddd Vx,Hx,Wx (66),(v1) -03: phaddsw Pq,Qq | vphaddsw Vx,Hx,Wx (66),(v1) -04: pmaddubsw Pq,Qq | vpmaddubsw Vx,Hx,Wx (66),(v1) -05: phsubw Pq,Qq | vphsubw Vx,Hx,Wx (66),(v1) -06: phsubd Pq,Qq | vphsubd Vx,Hx,Wx (66),(v1) -07: phsubsw Pq,Qq | vphsubsw Vx,Hx,Wx (66),(v1) -08: psignb Pq,Qq | vpsignb Vx,Hx,Wx (66),(v1) -09: psignw Pq,Qq | vpsignw Vx,Hx,Wx (66),(v1) -0a: psignd Pq,Qq | vpsignd Vx,Hx,Wx (66),(v1) -0b: pmulhrsw Pq,Qq | vpmulhrsw Vx,Hx,Wx (66),(v1) -0c: vpermilps Vx,Hx,Wx (66),(v) -0d: vpermilpd Vx,Hx,Wx (66),(v) -0e: vtestps Vx,Wx (66),(v) -0f: vtestpd Vx,Wx (66),(v) -# 0x0f 0x38 0x10-0x1f -10: pblendvb Vdq,Wdq (66) | vpsrlvw Vx,Hx,Wx (66),(evo) | vpmovuswb Wx,Vx (F3),(ev) -11: vpmovusdb Wx,Vd (F3),(ev) | vpsravw Vx,Hx,Wx (66),(ev) -12: vpmovusqb Wx,Vq (F3),(ev) | vpsllvw Vx,Hx,Wx (66),(ev) -13: vcvtph2ps Vx,Wx (66),(v) | vpmovusdw Wx,Vd (F3),(ev) -14: blendvps Vdq,Wdq (66) | vpmovusqw Wx,Vq (F3),(ev) | vprorvd/q Vx,Hx,Wx (66),(evo) -15: blendvpd Vdq,Wdq (66) | vpmovusqd Wx,Vq (F3),(ev) | vprolvd/q Vx,Hx,Wx (66),(evo) -16: vpermps Vqq,Hqq,Wqq (66),(v) | vpermps/d Vqq,Hqq,Wqq (66),(evo) -17: vptest Vx,Wx (66) -18: vbroadcastss Vx,Wd (66),(v) -19: vbroadcastsd Vqq,Wq (66),(v) | vbroadcastf32x2 Vqq,Wq (66),(evo) -1a: vbroadcastf128 Vqq,Mdq (66),(v) | vbroadcastf32x4/64x2 Vqq,Wq (66),(evo) -1b: vbroadcastf32x8/64x4 Vqq,Mdq (66),(ev) -1c: pabsb Pq,Qq | vpabsb Vx,Wx (66),(v1) -1d: pabsw Pq,Qq | vpabsw Vx,Wx (66),(v1) -1e: pabsd Pq,Qq | vpabsd Vx,Wx (66),(v1) -1f: vpabsq Vx,Wx (66),(ev) -# 0x0f 0x38 0x20-0x2f -20: vpmovsxbw Vx,Ux/Mq (66),(v1) | vpmovswb Wx,Vx (F3),(ev) -21: vpmovsxbd Vx,Ux/Md (66),(v1) | vpmovsdb Wx,Vd (F3),(ev) -22: vpmovsxbq Vx,Ux/Mw (66),(v1) | vpmovsqb Wx,Vq (F3),(ev) -23: vpmovsxwd Vx,Ux/Mq (66),(v1) | vpmovsdw Wx,Vd (F3),(ev) -24: vpmovsxwq Vx,Ux/Md (66),(v1) | vpmovsqw Wx,Vq (F3),(ev) -25: vpmovsxdq Vx,Ux/Mq (66),(v1) | vpmovsqd Wx,Vq (F3),(ev) -26: vptestmb/w Vk,Hx,Wx (66),(ev) | vptestnmb/w Vk,Hx,Wx (F3),(ev) -27: vptestmd/q Vk,Hx,Wx (66),(ev) | vptestnmd/q Vk,Hx,Wx (F3),(ev) -28: vpmuldq Vx,Hx,Wx (66),(v1) | vpmovm2b/w Vx,Uk (F3),(ev) -29: vpcmpeqq Vx,Hx,Wx (66),(v1) | vpmovb2m/w2m Vk,Ux (F3),(ev) -2a: vmovntdqa Vx,Mx (66),(v1) | vpbroadcastmb2q Vx,Uk (F3),(ev) -2b: vpackusdw Vx,Hx,Wx (66),(v1) -2c: vmaskmovps Vx,Hx,Mx (66),(v) | vscalefps/d Vx,Hx,Wx (66),(evo) -2d: vmaskmovpd Vx,Hx,Mx (66),(v) | vscalefss/d Vx,Hx,Wx (66),(evo) -2e: vmaskmovps Mx,Hx,Vx (66),(v) -2f: vmaskmovpd Mx,Hx,Vx (66),(v) -# 0x0f 0x38 0x30-0x3f -30: vpmovzxbw Vx,Ux/Mq (66),(v1) | vpmovwb Wx,Vx (F3),(ev) -31: vpmovzxbd Vx,Ux/Md (66),(v1) | vpmovdb Wx,Vd (F3),(ev) -32: vpmovzxbq Vx,Ux/Mw (66),(v1) | vpmovqb Wx,Vq (F3),(ev) -33: vpmovzxwd Vx,Ux/Mq (66),(v1) | vpmovdw Wx,Vd (F3),(ev) -34: vpmovzxwq Vx,Ux/Md (66),(v1) | vpmovqw Wx,Vq (F3),(ev) -35: vpmovzxdq Vx,Ux/Mq (66),(v1) | vpmovqd Wx,Vq (F3),(ev) -36: vpermd Vqq,Hqq,Wqq (66),(v) | vpermd/q Vqq,Hqq,Wqq (66),(evo) -37: vpcmpgtq Vx,Hx,Wx (66),(v1) -38: vpminsb Vx,Hx,Wx (66),(v1) | vpmovm2d/q Vx,Uk (F3),(ev) -39: vpminsd Vx,Hx,Wx (66),(v1) | vpminsd/q Vx,Hx,Wx (66),(evo) | vpmovd2m/q2m Vk,Ux (F3),(ev) -3a: vpminuw Vx,Hx,Wx (66),(v1) | vpbroadcastmw2d Vx,Uk (F3),(ev) -3b: vpminud Vx,Hx,Wx (66),(v1) | vpminud/q Vx,Hx,Wx (66),(evo) -3c: vpmaxsb Vx,Hx,Wx (66),(v1) -3d: vpmaxsd Vx,Hx,Wx (66),(v1) | vpmaxsd/q Vx,Hx,Wx (66),(evo) -3e: vpmaxuw Vx,Hx,Wx (66),(v1) -3f: vpmaxud Vx,Hx,Wx (66),(v1) | vpmaxud/q Vx,Hx,Wx (66),(evo) -# 0x0f 0x38 0x40-0x8f -40: vpmulld Vx,Hx,Wx (66),(v1) | vpmulld/q Vx,Hx,Wx (66),(evo) -41: vphminposuw Vdq,Wdq (66),(v1) -42: vgetexpps/d Vx,Wx (66),(ev) -43: vgetexpss/d Vx,Hx,Wx (66),(ev) -44: vplzcntd/q Vx,Wx (66),(ev) -45: vpsrlvd/q Vx,Hx,Wx (66),(v) -46: vpsravd Vx,Hx,Wx (66),(v) | vpsravd/q Vx,Hx,Wx (66),(evo) -47: vpsllvd/q Vx,Hx,Wx (66),(v) -# Skip 0x48-0x4b -4c: vrcp14ps/d Vpd,Wpd (66),(ev) -4d: vrcp14ss/d Vsd,Hpd,Wsd (66),(ev) -4e: vrsqrt14ps/d Vpd,Wpd (66),(ev) -4f: vrsqrt14ss/d Vsd,Hsd,Wsd (66),(ev) -# Skip 0x50-0x57 -58: vpbroadcastd Vx,Wx (66),(v) -59: vpbroadcastq Vx,Wx (66),(v) | vbroadcasti32x2 Vx,Wx (66),(evo) -5a: vbroadcasti128 Vqq,Mdq (66),(v) | vbroadcasti32x4/64x2 Vx,Wx (66),(evo) -5b: vbroadcasti32x8/64x4 Vqq,Mdq (66),(ev) -# Skip 0x5c-0x63 -64: vpblendmd/q Vx,Hx,Wx (66),(ev) -65: vblendmps/d Vx,Hx,Wx (66),(ev) -66: vpblendmb/w Vx,Hx,Wx (66),(ev) -# Skip 0x67-0x74 -75: vpermi2b/w Vx,Hx,Wx (66),(ev) -76: vpermi2d/q Vx,Hx,Wx (66),(ev) -77: vpermi2ps/d Vx,Hx,Wx (66),(ev) -78: vpbroadcastb Vx,Wx (66),(v) -79: vpbroadcastw Vx,Wx (66),(v) -7a: vpbroadcastb Vx,Rv (66),(ev) -7b: vpbroadcastw Vx,Rv (66),(ev) -7c: vpbroadcastd/q Vx,Rv (66),(ev) -7d: vpermt2b/w Vx,Hx,Wx (66),(ev) -7e: vpermt2d/q Vx,Hx,Wx (66),(ev) -7f: vpermt2ps/d Vx,Hx,Wx (66),(ev) -80: INVEPT Gy,Mdq (66) -81: INVVPID Gy,Mdq (66) -82: INVPCID Gy,Mdq (66) -83: vpmultishiftqb Vx,Hx,Wx (66),(ev) -88: vexpandps/d Vpd,Wpd (66),(ev) -89: vpexpandd/q Vx,Wx (66),(ev) -8a: vcompressps/d Wx,Vx (66),(ev) -8b: vpcompressd/q Wx,Vx (66),(ev) -8c: vpmaskmovd/q Vx,Hx,Mx (66),(v) -8d: vpermb/w Vx,Hx,Wx (66),(ev) -8e: vpmaskmovd/q Mx,Vx,Hx (66),(v) -# 0x0f 0x38 0x90-0xbf (FMA) -90: vgatherdd/q Vx,Hx,Wx (66),(v) | vpgatherdd/q Vx,Wx (66),(evo) -91: vgatherqd/q Vx,Hx,Wx (66),(v) | vpgatherqd/q Vx,Wx (66),(evo) -92: vgatherdps/d Vx,Hx,Wx (66),(v) -93: vgatherqps/d Vx,Hx,Wx (66),(v) -94: -95: -96: vfmaddsub132ps/d Vx,Hx,Wx (66),(v) -97: vfmsubadd132ps/d Vx,Hx,Wx (66),(v) -98: vfmadd132ps/d Vx,Hx,Wx (66),(v) -99: vfmadd132ss/d Vx,Hx,Wx (66),(v),(v1) -9a: vfmsub132ps/d Vx,Hx,Wx (66),(v) -9b: vfmsub132ss/d Vx,Hx,Wx (66),(v),(v1) -9c: vfnmadd132ps/d Vx,Hx,Wx (66),(v) -9d: vfnmadd132ss/d Vx,Hx,Wx (66),(v),(v1) -9e: vfnmsub132ps/d Vx,Hx,Wx (66),(v) -9f: vfnmsub132ss/d Vx,Hx,Wx (66),(v),(v1) -a0: vpscatterdd/q Wx,Vx (66),(ev) -a1: vpscatterqd/q Wx,Vx (66),(ev) -a2: vscatterdps/d Wx,Vx (66),(ev) -a3: vscatterqps/d Wx,Vx (66),(ev) -a6: vfmaddsub213ps/d Vx,Hx,Wx (66),(v) -a7: vfmsubadd213ps/d Vx,Hx,Wx (66),(v) -a8: vfmadd213ps/d Vx,Hx,Wx (66),(v) -a9: vfmadd213ss/d Vx,Hx,Wx (66),(v),(v1) -aa: vfmsub213ps/d Vx,Hx,Wx (66),(v) -ab: vfmsub213ss/d Vx,Hx,Wx (66),(v),(v1) -ac: vfnmadd213ps/d Vx,Hx,Wx (66),(v) -ad: vfnmadd213ss/d Vx,Hx,Wx (66),(v),(v1) -ae: vfnmsub213ps/d Vx,Hx,Wx (66),(v) -af: vfnmsub213ss/d Vx,Hx,Wx (66),(v),(v1) -b4: vpmadd52luq Vx,Hx,Wx (66),(ev) -b5: vpmadd52huq Vx,Hx,Wx (66),(ev) -b6: vfmaddsub231ps/d Vx,Hx,Wx (66),(v) -b7: vfmsubadd231ps/d Vx,Hx,Wx (66),(v) -b8: vfmadd231ps/d Vx,Hx,Wx (66),(v) -b9: vfmadd231ss/d Vx,Hx,Wx (66),(v),(v1) -ba: vfmsub231ps/d Vx,Hx,Wx (66),(v) -bb: vfmsub231ss/d Vx,Hx,Wx (66),(v),(v1) -bc: vfnmadd231ps/d Vx,Hx,Wx (66),(v) -bd: vfnmadd231ss/d Vx,Hx,Wx (66),(v),(v1) -be: vfnmsub231ps/d Vx,Hx,Wx (66),(v) -bf: vfnmsub231ss/d Vx,Hx,Wx (66),(v),(v1) -# 0x0f 0x38 0xc0-0xff -c4: vpconflictd/q Vx,Wx (66),(ev) -c6: Grp18 (1A) -c7: Grp19 (1A) -c8: sha1nexte Vdq,Wdq | vexp2ps/d Vx,Wx (66),(ev) -c9: sha1msg1 Vdq,Wdq -ca: sha1msg2 Vdq,Wdq | vrcp28ps/d Vx,Wx (66),(ev) -cb: sha256rnds2 Vdq,Wdq | vrcp28ss/d Vx,Hx,Wx (66),(ev) -cc: sha256msg1 Vdq,Wdq | vrsqrt28ps/d Vx,Wx (66),(ev) -cd: sha256msg2 Vdq,Wdq | vrsqrt28ss/d Vx,Hx,Wx (66),(ev) -db: VAESIMC Vdq,Wdq (66),(v1) -dc: VAESENC Vdq,Hdq,Wdq (66),(v1) -dd: VAESENCLAST Vdq,Hdq,Wdq (66),(v1) -de: VAESDEC Vdq,Hdq,Wdq (66),(v1) -df: VAESDECLAST Vdq,Hdq,Wdq (66),(v1) -f0: MOVBE Gy,My | MOVBE Gw,Mw (66) | CRC32 Gd,Eb (F2) | CRC32 Gd,Eb (66&F2) -f1: MOVBE My,Gy | MOVBE Mw,Gw (66) | CRC32 Gd,Ey (F2) | CRC32 Gd,Ew (66&F2) -f2: ANDN Gy,By,Ey (v) -f3: Grp17 (1A) -f5: BZHI Gy,Ey,By (v) | PEXT Gy,By,Ey (F3),(v) | PDEP Gy,By,Ey (F2),(v) -f6: ADCX Gy,Ey (66) | ADOX Gy,Ey (F3) | MULX By,Gy,rDX,Ey (F2),(v) -f7: BEXTR Gy,Ey,By (v) | SHLX Gy,Ey,By (66),(v) | SARX Gy,Ey,By (F3),(v) | SHRX Gy,Ey,By (F2),(v) -EndTable - -Table: 3-byte opcode 2 (0x0f 0x3a) -Referrer: 3-byte escape 2 -AVXcode: 3 -# 0x0f 0x3a 0x00-0xff -00: vpermq Vqq,Wqq,Ib (66),(v) -01: vpermpd Vqq,Wqq,Ib (66),(v) -02: vpblendd Vx,Hx,Wx,Ib (66),(v) -03: valignd/q Vx,Hx,Wx,Ib (66),(ev) -04: vpermilps Vx,Wx,Ib (66),(v) -05: vpermilpd Vx,Wx,Ib (66),(v) -06: vperm2f128 Vqq,Hqq,Wqq,Ib (66),(v) -07: -08: vroundps Vx,Wx,Ib (66) | vrndscaleps Vx,Wx,Ib (66),(evo) -09: vroundpd Vx,Wx,Ib (66) | vrndscalepd Vx,Wx,Ib (66),(evo) -0a: vroundss Vss,Wss,Ib (66),(v1) | vrndscaless Vx,Hx,Wx,Ib (66),(evo) -0b: vroundsd Vsd,Wsd,Ib (66),(v1) | vrndscalesd Vx,Hx,Wx,Ib (66),(evo) -0c: vblendps Vx,Hx,Wx,Ib (66) -0d: vblendpd Vx,Hx,Wx,Ib (66) -0e: vpblendw Vx,Hx,Wx,Ib (66),(v1) -0f: palignr Pq,Qq,Ib | vpalignr Vx,Hx,Wx,Ib (66),(v1) -14: vpextrb Rd/Mb,Vdq,Ib (66),(v1) -15: vpextrw Rd/Mw,Vdq,Ib (66),(v1) -16: vpextrd/q Ey,Vdq,Ib (66),(v1) -17: vextractps Ed,Vdq,Ib (66),(v1) -18: vinsertf128 Vqq,Hqq,Wqq,Ib (66),(v) | vinsertf32x4/64x2 Vqq,Hqq,Wqq,Ib (66),(evo) -19: vextractf128 Wdq,Vqq,Ib (66),(v) | vextractf32x4/64x2 Wdq,Vqq,Ib (66),(evo) -1a: vinsertf32x8/64x4 Vqq,Hqq,Wqq,Ib (66),(ev) -1b: vextractf32x8/64x4 Wdq,Vqq,Ib (66),(ev) -1d: vcvtps2ph Wx,Vx,Ib (66),(v) -1e: vpcmpud/q Vk,Hd,Wd,Ib (66),(ev) -1f: vpcmpd/q Vk,Hd,Wd,Ib (66),(ev) -20: vpinsrb Vdq,Hdq,Ry/Mb,Ib (66),(v1) -21: vinsertps Vdq,Hdq,Udq/Md,Ib (66),(v1) -22: vpinsrd/q Vdq,Hdq,Ey,Ib (66),(v1) -23: vshuff32x4/64x2 Vx,Hx,Wx,Ib (66),(ev) -25: vpternlogd/q Vx,Hx,Wx,Ib (66),(ev) -26: vgetmantps/d Vx,Wx,Ib (66),(ev) -27: vgetmantss/d Vx,Hx,Wx,Ib (66),(ev) -30: kshiftrb/w Vk,Uk,Ib (66),(v) -31: kshiftrd/q Vk,Uk,Ib (66),(v) -32: kshiftlb/w Vk,Uk,Ib (66),(v) -33: kshiftld/q Vk,Uk,Ib (66),(v) -38: vinserti128 Vqq,Hqq,Wqq,Ib (66),(v) | vinserti32x4/64x2 Vqq,Hqq,Wqq,Ib (66),(evo) -39: vextracti128 Wdq,Vqq,Ib (66),(v) | vextracti32x4/64x2 Wdq,Vqq,Ib (66),(evo) -3a: vinserti32x8/64x4 Vqq,Hqq,Wqq,Ib (66),(ev) -3b: vextracti32x8/64x4 Wdq,Vqq,Ib (66),(ev) -3e: vpcmpub/w Vk,Hk,Wx,Ib (66),(ev) -3f: vpcmpb/w Vk,Hk,Wx,Ib (66),(ev) -40: vdpps Vx,Hx,Wx,Ib (66) -41: vdppd Vdq,Hdq,Wdq,Ib (66),(v1) -42: vmpsadbw Vx,Hx,Wx,Ib (66),(v1) | vdbpsadbw Vx,Hx,Wx,Ib (66),(evo) -43: vshufi32x4/64x2 Vx,Hx,Wx,Ib (66),(ev) -44: vpclmulqdq Vdq,Hdq,Wdq,Ib (66),(v1) -46: vperm2i128 Vqq,Hqq,Wqq,Ib (66),(v) -4a: vblendvps Vx,Hx,Wx,Lx (66),(v) -4b: vblendvpd Vx,Hx,Wx,Lx (66),(v) -4c: vpblendvb Vx,Hx,Wx,Lx (66),(v1) -50: vrangeps/d Vx,Hx,Wx,Ib (66),(ev) -51: vrangess/d Vx,Hx,Wx,Ib (66),(ev) -54: vfixupimmps/d Vx,Hx,Wx,Ib (66),(ev) -55: vfixupimmss/d Vx,Hx,Wx,Ib (66),(ev) -56: vreduceps/d Vx,Wx,Ib (66),(ev) -57: vreducess/d Vx,Hx,Wx,Ib (66),(ev) -60: vpcmpestrm Vdq,Wdq,Ib (66),(v1) -61: vpcmpestri Vdq,Wdq,Ib (66),(v1) -62: vpcmpistrm Vdq,Wdq,Ib (66),(v1) -63: vpcmpistri Vdq,Wdq,Ib (66),(v1) -66: vfpclassps/d Vk,Wx,Ib (66),(ev) -67: vfpclassss/d Vk,Wx,Ib (66),(ev) -cc: sha1rnds4 Vdq,Wdq,Ib -df: VAESKEYGEN Vdq,Wdq,Ib (66),(v1) -f0: RORX Gy,Ey,Ib (F2),(v) -EndTable - -GrpTable: Grp1 -0: ADD -1: OR -2: ADC -3: SBB -4: AND -5: SUB -6: XOR -7: CMP -EndTable - -GrpTable: Grp1A -0: POP -EndTable - -GrpTable: Grp2 -0: ROL -1: ROR -2: RCL -3: RCR -4: SHL/SAL -5: SHR -6: -7: SAR -EndTable - -GrpTable: Grp3_1 -0: TEST Eb,Ib -1: TEST Eb,Ib -2: NOT Eb -3: NEG Eb -4: MUL AL,Eb -5: IMUL AL,Eb -6: DIV AL,Eb -7: IDIV AL,Eb -EndTable - -GrpTable: Grp3_2 -0: TEST Ev,Iz -1: -2: NOT Ev -3: NEG Ev -4: MUL rAX,Ev -5: IMUL rAX,Ev -6: DIV rAX,Ev -7: IDIV rAX,Ev -EndTable - -GrpTable: Grp4 -0: INC Eb -1: DEC Eb -EndTable - -GrpTable: Grp5 -0: INC Ev -1: DEC Ev -# Note: "forced64" is Intel CPU behavior (see comment about CALL insn). -2: CALLN Ev (f64) -3: CALLF Ep -4: JMPN Ev (f64) -5: JMPF Mp -6: PUSH Ev (d64) -7: -EndTable - -GrpTable: Grp6 -0: SLDT Rv/Mw -1: STR Rv/Mw -2: LLDT Ew -3: LTR Ew -4: VERR Ew -5: VERW Ew -EndTable - -GrpTable: Grp7 -0: SGDT Ms | VMCALL (001),(11B) | VMLAUNCH (010),(11B) | VMRESUME (011),(11B) | VMXOFF (100),(11B) -1: SIDT Ms | MONITOR (000),(11B) | MWAIT (001),(11B) | CLAC (010),(11B) | STAC (011),(11B) -2: LGDT Ms | XGETBV (000),(11B) | XSETBV (001),(11B) | VMFUNC (100),(11B) | XEND (101)(11B) | XTEST (110)(11B) -3: LIDT Ms -4: SMSW Mw/Rv -5: rdpkru (110),(11B) | wrpkru (111),(11B) -6: LMSW Ew -7: INVLPG Mb | SWAPGS (o64),(000),(11B) | RDTSCP (001),(11B) -EndTable - -GrpTable: Grp8 -4: BT -5: BTS -6: BTR -7: BTC -EndTable - -GrpTable: Grp9 -1: CMPXCHG8B/16B Mq/Mdq -3: xrstors -4: xsavec -5: xsaves -6: VMPTRLD Mq | VMCLEAR Mq (66) | VMXON Mq (F3) | RDRAND Rv (11B) -7: VMPTRST Mq | VMPTRST Mq (F3) | RDSEED Rv (11B) -EndTable - -GrpTable: Grp10 -# all are UD1 -0: UD1 -1: UD1 -2: UD1 -3: UD1 -4: UD1 -5: UD1 -6: UD1 -7: UD1 -EndTable - -# Grp11A and Grp11B are expressed as Grp11 in Intel SDM -GrpTable: Grp11A -0: MOV Eb,Ib -7: XABORT Ib (000),(11B) -EndTable - -GrpTable: Grp11B -0: MOV Eb,Iz -7: XBEGIN Jz (000),(11B) -EndTable - -GrpTable: Grp12 -2: psrlw Nq,Ib (11B) | vpsrlw Hx,Ux,Ib (66),(11B),(v1) -4: psraw Nq,Ib (11B) | vpsraw Hx,Ux,Ib (66),(11B),(v1) -6: psllw Nq,Ib (11B) | vpsllw Hx,Ux,Ib (66),(11B),(v1) -EndTable - -GrpTable: Grp13 -0: vprord/q Hx,Wx,Ib (66),(ev) -1: vprold/q Hx,Wx,Ib (66),(ev) -2: psrld Nq,Ib (11B) | vpsrld Hx,Ux,Ib (66),(11B),(v1) -4: psrad Nq,Ib (11B) | vpsrad Hx,Ux,Ib (66),(11B),(v1) | vpsrad/q Hx,Ux,Ib (66),(evo) -6: pslld Nq,Ib (11B) | vpslld Hx,Ux,Ib (66),(11B),(v1) -EndTable - -GrpTable: Grp14 -2: psrlq Nq,Ib (11B) | vpsrlq Hx,Ux,Ib (66),(11B),(v1) -3: vpsrldq Hx,Ux,Ib (66),(11B),(v1) -6: psllq Nq,Ib (11B) | vpsllq Hx,Ux,Ib (66),(11B),(v1) -7: vpslldq Hx,Ux,Ib (66),(11B),(v1) -EndTable - -GrpTable: Grp15 -0: fxsave | RDFSBASE Ry (F3),(11B) -1: fxstor | RDGSBASE Ry (F3),(11B) -2: vldmxcsr Md (v1) | WRFSBASE Ry (F3),(11B) -3: vstmxcsr Md (v1) | WRGSBASE Ry (F3),(11B) -4: XSAVE | ptwrite Ey (F3),(11B) -5: XRSTOR | lfence (11B) -6: XSAVEOPT | clwb (66) | mfence (11B) -7: clflush | clflushopt (66) | sfence (11B) -EndTable - -GrpTable: Grp16 -0: prefetch NTA -1: prefetch T0 -2: prefetch T1 -3: prefetch T2 -EndTable - -GrpTable: Grp17 -1: BLSR By,Ey (v) -2: BLSMSK By,Ey (v) -3: BLSI By,Ey (v) -EndTable - -GrpTable: Grp18 -1: vgatherpf0dps/d Wx (66),(ev) -2: vgatherpf1dps/d Wx (66),(ev) -5: vscatterpf0dps/d Wx (66),(ev) -6: vscatterpf1dps/d Wx (66),(ev) -EndTable - -GrpTable: Grp19 -1: vgatherpf0qps/d Wx (66),(ev) -2: vgatherpf1qps/d Wx (66),(ev) -5: vscatterpf0qps/d Wx (66),(ev) -6: vscatterpf1qps/d Wx (66),(ev) -EndTable - -# AMD's Prefetch Group -GrpTable: GrpP -0: PREFETCH -1: PREFETCHW -EndTable - -GrpTable: GrpPDLK -0: MONTMUL -1: XSHA1 -2: XSHA2 -EndTable - -GrpTable: GrpRNG -0: xstore-rng -1: xcrypt-ecb -2: xcrypt-cbc -4: xcrypt-cfb -5: xcrypt-ofb -EndTable diff --git a/tools/perf/util/intel-pt.c b/tools/perf/util/intel-pt.c index df061599fef4..9b56fb74bedf 100644 --- a/tools/perf/util/intel-pt.c +++ b/tools/perf/util/intel-pt.c @@ -9,10 +9,10 @@ #include <stdbool.h> #include <errno.h> #include <linux/kernel.h> +#include <linux/string.h> #include <linux/types.h> #include <linux/zalloc.h> -#include "../perf.h" #include "session.h" #include "machine.h" #include "memswap.h" @@ -56,7 +56,7 @@ struct intel_pt { u32 auxtrace_type; struct perf_session *session; struct machine *machine; - struct perf_evsel *switch_evsel; + struct evsel *switch_evsel; struct thread *unknown_thread; bool timeless_decoding; bool sampling_mode; @@ -104,7 +104,7 @@ struct intel_pt { u64 cbr_id; bool sample_pebs; - struct perf_evsel *pebs_evsel; + struct evsel *pebs_evsel; u64 tsc_bit; u64 mtc_bit; @@ -723,11 +723,11 @@ static bool intel_pt_get_config(struct intel_pt *pt, static bool intel_pt_exclude_kernel(struct intel_pt *pt) { - struct perf_evsel *evsel; + struct evsel *evsel; evlist__for_each_entry(pt->session->evlist, evsel) { - if (intel_pt_get_config(pt, &evsel->attr, NULL) && - !evsel->attr.exclude_kernel) + if (intel_pt_get_config(pt, &evsel->core.attr, NULL) && + !evsel->core.attr.exclude_kernel) return false; } return true; @@ -735,14 +735,14 @@ static bool intel_pt_exclude_kernel(struct intel_pt *pt) static bool intel_pt_return_compression(struct intel_pt *pt) { - struct perf_evsel *evsel; + struct evsel *evsel; u64 config; if (!pt->noretcomp_bit) return true; evlist__for_each_entry(pt->session->evlist, evsel) { - if (intel_pt_get_config(pt, &evsel->attr, &config) && + if (intel_pt_get_config(pt, &evsel->core.attr, &config) && (config & pt->noretcomp_bit)) return false; } @@ -751,11 +751,11 @@ static bool intel_pt_return_compression(struct intel_pt *pt) static bool intel_pt_branch_enable(struct intel_pt *pt) { - struct perf_evsel *evsel; + struct evsel *evsel; u64 config; evlist__for_each_entry(pt->session->evlist, evsel) { - if (intel_pt_get_config(pt, &evsel->attr, &config) && + if (intel_pt_get_config(pt, &evsel->core.attr, &config) && (config & 1) && !(config & 0x2000)) return false; } @@ -764,7 +764,7 @@ static bool intel_pt_branch_enable(struct intel_pt *pt) static unsigned int intel_pt_mtc_period(struct intel_pt *pt) { - struct perf_evsel *evsel; + struct evsel *evsel; unsigned int shift; u64 config; @@ -775,7 +775,7 @@ static unsigned int intel_pt_mtc_period(struct intel_pt *pt) config >>= 1; evlist__for_each_entry(pt->session->evlist, evsel) { - if (intel_pt_get_config(pt, &evsel->attr, &config)) + if (intel_pt_get_config(pt, &evsel->core.attr, &config)) return (config & pt->mtc_freq_bits) >> shift; } return 0; @@ -783,7 +783,7 @@ static unsigned int intel_pt_mtc_period(struct intel_pt *pt) static bool intel_pt_timeless_decoding(struct intel_pt *pt) { - struct perf_evsel *evsel; + struct evsel *evsel; bool timeless_decoding = true; u64 config; @@ -791,9 +791,9 @@ static bool intel_pt_timeless_decoding(struct intel_pt *pt) return true; evlist__for_each_entry(pt->session->evlist, evsel) { - if (!(evsel->attr.sample_type & PERF_SAMPLE_TIME)) + if (!(evsel->core.attr.sample_type & PERF_SAMPLE_TIME)) return true; - if (intel_pt_get_config(pt, &evsel->attr, &config)) { + if (intel_pt_get_config(pt, &evsel->core.attr, &config)) { if (config & pt->tsc_bit) timeless_decoding = false; else @@ -805,11 +805,11 @@ static bool intel_pt_timeless_decoding(struct intel_pt *pt) static bool intel_pt_tracing_kernel(struct intel_pt *pt) { - struct perf_evsel *evsel; + struct evsel *evsel; evlist__for_each_entry(pt->session->evlist, evsel) { - if (intel_pt_get_config(pt, &evsel->attr, NULL) && - !evsel->attr.exclude_kernel) + if (intel_pt_get_config(pt, &evsel->core.attr, NULL) && + !evsel->core.attr.exclude_kernel) return true; } return false; @@ -817,7 +817,7 @@ static bool intel_pt_tracing_kernel(struct intel_pt *pt) static bool intel_pt_have_tsc(struct intel_pt *pt) { - struct perf_evsel *evsel; + struct evsel *evsel; bool have_tsc = false; u64 config; @@ -825,7 +825,7 @@ static bool intel_pt_have_tsc(struct intel_pt *pt) return false; evlist__for_each_entry(pt->session->evlist, evsel) { - if (intel_pt_get_config(pt, &evsel->attr, &config)) { + if (intel_pt_get_config(pt, &evsel->core.attr, &config)) { if (config & pt->tsc_bit) have_tsc = true; else @@ -1702,8 +1702,8 @@ static int intel_pt_synth_pebs_sample(struct intel_pt_queue *ptq) struct perf_sample sample = { .ip = 0, }; union perf_event *event = ptq->event_buf; struct intel_pt *pt = ptq->pt; - struct perf_evsel *evsel = pt->pebs_evsel; - u64 sample_type = evsel->attr.sample_type; + struct evsel *evsel = pt->pebs_evsel; + u64 sample_type = evsel->core.attr.sample_type; u64 id = evsel->id[0]; u8 cpumode; @@ -1715,8 +1715,8 @@ static int intel_pt_synth_pebs_sample(struct intel_pt_queue *ptq) sample.id = id; sample.stream_id = id; - if (!evsel->attr.freq) - sample.period = evsel->attr.sample_period; + if (!evsel->core.attr.freq) + sample.period = evsel->core.attr.sample_period; /* No support for non-zero CS base */ if (items->has_ip) @@ -1757,7 +1757,7 @@ static int intel_pt_synth_pebs_sample(struct intel_pt_queue *ptq) if (sample_type & PERF_SAMPLE_REGS_INTR && items->mask[INTEL_PT_GP_REGS_POS]) { u64 regs[sizeof(sample.intr_regs.mask)]; - u64 regs_mask = evsel->attr.sample_regs_intr; + u64 regs_mask = evsel->core.attr.sample_regs_intr; u64 *pos; sample.intr_regs.abi = items->is_32_bit ? @@ -2401,7 +2401,7 @@ static int intel_pt_sync_switch(struct intel_pt *pt, int cpu, pid_t tid, static int intel_pt_process_switch(struct intel_pt *pt, struct perf_sample *sample) { - struct perf_evsel *evsel; + struct evsel *evsel; pid_t tid; int cpu, ret; @@ -2713,10 +2713,10 @@ static int intel_pt_synth_event(struct perf_session *session, const char *name, return err; } -static void intel_pt_set_event_name(struct perf_evlist *evlist, u64 id, +static void intel_pt_set_event_name(struct evlist *evlist, u64 id, const char *name) { - struct perf_evsel *evsel; + struct evsel *evsel; evlist__for_each_entry(evlist, evsel) { if (evsel->id && evsel->id[0] == id) { @@ -2728,13 +2728,13 @@ static void intel_pt_set_event_name(struct perf_evlist *evlist, u64 id, } } -static struct perf_evsel *intel_pt_evsel(struct intel_pt *pt, - struct perf_evlist *evlist) +static struct evsel *intel_pt_evsel(struct intel_pt *pt, + struct evlist *evlist) { - struct perf_evsel *evsel; + struct evsel *evsel; evlist__for_each_entry(evlist, evsel) { - if (evsel->attr.type == pt->pmu_type && evsel->ids) + if (evsel->core.attr.type == pt->pmu_type && evsel->ids) return evsel; } @@ -2744,8 +2744,8 @@ static struct perf_evsel *intel_pt_evsel(struct intel_pt *pt, static int intel_pt_synth_events(struct intel_pt *pt, struct perf_session *session) { - struct perf_evlist *evlist = session->evlist; - struct perf_evsel *evsel = intel_pt_evsel(pt, evlist); + struct evlist *evlist = session->evlist; + struct evsel *evsel = intel_pt_evsel(pt, evlist); struct perf_event_attr attr; u64 id; int err; @@ -2758,7 +2758,7 @@ static int intel_pt_synth_events(struct intel_pt *pt, memset(&attr, 0, sizeof(struct perf_event_attr)); attr.size = sizeof(struct perf_event_attr); attr.type = PERF_TYPE_HARDWARE; - attr.sample_type = evsel->attr.sample_type & PERF_SAMPLE_MASK; + attr.sample_type = evsel->core.attr.sample_type & PERF_SAMPLE_MASK; attr.sample_type |= PERF_SAMPLE_IP | PERF_SAMPLE_TID | PERF_SAMPLE_PERIOD; if (pt->timeless_decoding) @@ -2767,13 +2767,13 @@ static int intel_pt_synth_events(struct intel_pt *pt, attr.sample_type |= PERF_SAMPLE_TIME; if (!pt->per_cpu_mmaps) attr.sample_type &= ~(u64)PERF_SAMPLE_CPU; - attr.exclude_user = evsel->attr.exclude_user; - attr.exclude_kernel = evsel->attr.exclude_kernel; - attr.exclude_hv = evsel->attr.exclude_hv; - attr.exclude_host = evsel->attr.exclude_host; - attr.exclude_guest = evsel->attr.exclude_guest; - attr.sample_id_all = evsel->attr.sample_id_all; - attr.read_format = evsel->attr.read_format; + attr.exclude_user = evsel->core.attr.exclude_user; + attr.exclude_kernel = evsel->core.attr.exclude_kernel; + attr.exclude_hv = evsel->core.attr.exclude_hv; + attr.exclude_host = evsel->core.attr.exclude_host; + attr.exclude_guest = evsel->core.attr.exclude_guest; + attr.sample_id_all = evsel->core.attr.sample_id_all; + attr.read_format = evsel->core.attr.read_format; id = evsel->id[0] + 1000000000; if (!id) @@ -2857,7 +2857,7 @@ static int intel_pt_synth_events(struct intel_pt *pt, id += 1; } - if (pt->synth_opts.pwr_events && (evsel->attr.config & 0x10)) { + if (pt->synth_opts.pwr_events && (evsel->core.attr.config & 0x10)) { attr.config = PERF_SYNTH_INTEL_MWAIT; err = intel_pt_synth_event(session, "mwait", &attr, id); if (err) @@ -2894,9 +2894,25 @@ static int intel_pt_synth_events(struct intel_pt *pt, return 0; } -static struct perf_evsel *intel_pt_find_sched_switch(struct perf_evlist *evlist) +static void intel_pt_setup_pebs_events(struct intel_pt *pt) { - struct perf_evsel *evsel; + struct evsel *evsel; + + if (!pt->synth_opts.other_events) + return; + + evlist__for_each_entry(pt->session->evlist, evsel) { + if (evsel->core.attr.aux_output && evsel->id) { + pt->sample_pebs = true; + pt->pebs_evsel = evsel; + return; + } + } +} + +static struct evsel *intel_pt_find_sched_switch(struct evlist *evlist) +{ + struct evsel *evsel; evlist__for_each_entry_reverse(evlist, evsel) { const char *name = perf_evsel__name(evsel); @@ -2908,12 +2924,12 @@ static struct perf_evsel *intel_pt_find_sched_switch(struct perf_evlist *evlist) return NULL; } -static bool intel_pt_find_switch(struct perf_evlist *evlist) +static bool intel_pt_find_switch(struct evlist *evlist) { - struct perf_evsel *evsel; + struct evsel *evsel; evlist__for_each_entry(evlist, evsel) { - if (evsel->attr.context_switch) + if (evsel->core.attr.context_switch) return true; } @@ -3028,7 +3044,7 @@ static const char * const intel_pt_info_fmts[] = { [INTEL_PT_FILTER_STR_LEN] = " Filter string len. %"PRIu64"\n", }; -static void intel_pt_print_info(u64 *arr, int start, int finish) +static void intel_pt_print_info(__u64 *arr, int start, int finish) { int i; @@ -3047,23 +3063,23 @@ static void intel_pt_print_info_str(const char *name, const char *str) fprintf(stdout, " %-20s%s\n", name, str ? str : ""); } -static bool intel_pt_has(struct auxtrace_info_event *auxtrace_info, int pos) +static bool intel_pt_has(struct perf_record_auxtrace_info *auxtrace_info, int pos) { return auxtrace_info->header.size >= - sizeof(struct auxtrace_info_event) + (sizeof(u64) * (pos + 1)); + sizeof(struct perf_record_auxtrace_info) + (sizeof(u64) * (pos + 1)); } int intel_pt_process_auxtrace_info(union perf_event *event, struct perf_session *session) { - struct auxtrace_info_event *auxtrace_info = &event->auxtrace_info; + struct perf_record_auxtrace_info *auxtrace_info = &event->auxtrace_info; size_t min_sz = sizeof(u64) * INTEL_PT_PER_CPU_MMAPS; struct intel_pt *pt; void *info_end; - u64 *info; + __u64 *info; int err; - if (auxtrace_info->header.size < sizeof(struct auxtrace_info_event) + + if (auxtrace_info->header.size < sizeof(struct perf_record_auxtrace_info) + min_sz) return -EINVAL; @@ -3263,6 +3279,8 @@ int intel_pt_process_auxtrace_info(union perf_event *event, if (err) goto err_delete_thread; + intel_pt_setup_pebs_events(pt); + err = auxtrace_queues__process_index(&pt->queues, session); if (err) goto err_delete_thread; diff --git a/tools/perf/util/jitdump.c b/tools/perf/util/jitdump.c index 18c34f0c1966..b80f29bfc7bb 100644 --- a/tools/perf/util/jitdump.c +++ b/tools/perf/util/jitdump.c @@ -14,6 +14,7 @@ #include <sys/mman.h> #include <linux/stringify.h> +#include "build-id.h" #include "util.h" #include "event.h" #include "debug.h" @@ -118,13 +119,13 @@ jit_close(struct jit_buf_desc *jd) static int jit_validate_events(struct perf_session *session) { - struct perf_evsel *evsel; + struct evsel *evsel; /* * check that all events use CLOCK_MONOTONIC */ evlist__for_each_entry(session->evlist, evsel) { - if (evsel->attr.use_clockid == 0 || evsel->attr.clockid != CLOCK_MONOTONIC) + if (evsel->core.attr.use_clockid == 0 || evsel->core.attr.clockid != CLOCK_MONOTONIC) return -1; } return 0; @@ -758,7 +759,7 @@ jit_process(struct perf_session *session, pid_t pid, u64 *nbytes) { - struct perf_evsel *first; + struct evsel *first; struct jit_buf_desc jd; int ret; @@ -779,7 +780,7 @@ jit_process(struct perf_session *session, * perf sets the same sample type to all events as of now */ first = perf_evlist__first(session->evlist); - jd.sample_type = first->attr.sample_type; + jd.sample_type = first->core.attr.sample_type; *nbytes = 0; diff --git a/tools/perf/util/kvm-stat.h b/tools/perf/util/kvm-stat.h index 1403dec189b4..46913637085b 100644 --- a/tools/perf/util/kvm-stat.h +++ b/tools/perf/util/kvm-stat.h @@ -2,12 +2,12 @@ #ifndef __PERF_KVM_STAT_H #define __PERF_KVM_STAT_H -#include "../perf.h" #include "tool.h" #include "stat.h" +#include "record.h" -struct perf_evsel; -struct perf_evlist; +struct evsel; +struct evlist; struct perf_session; struct event_key { @@ -45,17 +45,17 @@ struct kvm_event_key { struct perf_kvm_stat; struct child_event_ops { - void (*get_key)(struct perf_evsel *evsel, + void (*get_key)(struct evsel *evsel, struct perf_sample *sample, struct event_key *key); const char *name; }; struct kvm_events_ops { - bool (*is_begin_event)(struct perf_evsel *evsel, + bool (*is_begin_event)(struct evsel *evsel, struct perf_sample *sample, struct event_key *key); - bool (*is_end_event)(struct perf_evsel *evsel, + bool (*is_end_event)(struct evsel *evsel, struct perf_sample *sample, struct event_key *key); struct child_event_ops *child_ops; void (*decode_key)(struct perf_kvm_stat *kvm, struct event_key *key, @@ -74,7 +74,7 @@ struct exit_reasons_table { struct perf_kvm_stat { struct perf_tool tool; struct record_opts opts; - struct perf_evlist *evlist; + struct evlist *evlist; struct perf_session *session; const char *file_name; @@ -109,21 +109,21 @@ struct kvm_reg_events_ops { struct kvm_events_ops *ops; }; -void exit_event_get_key(struct perf_evsel *evsel, +void exit_event_get_key(struct evsel *evsel, struct perf_sample *sample, struct event_key *key); -bool exit_event_begin(struct perf_evsel *evsel, +bool exit_event_begin(struct evsel *evsel, struct perf_sample *sample, struct event_key *key); -bool exit_event_end(struct perf_evsel *evsel, +bool exit_event_end(struct evsel *evsel, struct perf_sample *sample, struct event_key *key); void exit_event_decode_key(struct perf_kvm_stat *kvm, struct event_key *key, char *decode); -bool kvm_exit_event(struct perf_evsel *evsel); -bool kvm_entry_event(struct perf_evsel *evsel); +bool kvm_exit_event(struct evsel *evsel); +bool kvm_entry_event(struct evsel *evsel); int setup_kvm_events_tp(struct perf_kvm_stat *kvm); #define define_exit_reasons_table(name, symbols) \ diff --git a/tools/perf/util/llvm-utils.c b/tools/perf/util/llvm-utils.c index 9f0470ecbca9..55fb4b3b1157 100644 --- a/tools/perf/util/llvm-utils.c +++ b/tools/perf/util/llvm-utils.c @@ -9,6 +9,7 @@ #include <stdio.h> #include <stdlib.h> #include <linux/err.h> +#include <linux/string.h> #include <linux/zalloc.h> #include "debug.h" #include "llvm-utils.h" diff --git a/tools/perf/util/llvm-utils.h b/tools/perf/util/llvm-utils.h index bf3f3f4c4fe2..7878a0e3fa98 100644 --- a/tools/perf/util/llvm-utils.h +++ b/tools/perf/util/llvm-utils.h @@ -6,7 +6,7 @@ #ifndef __LLVM_UTILS_H #define __LLVM_UTILS_H -#include "debug.h" +#include <stdbool.h> struct llvm_param { /* Path of clang executable */ diff --git a/tools/perf/util/lzma.c b/tools/perf/util/lzma.c index b1dd29a9d915..397447066033 100644 --- a/tools/perf/util/lzma.c +++ b/tools/perf/util/lzma.c @@ -9,6 +9,7 @@ #include "compress.h" #include "util.h" #include "debug.h" +#include <string.h> #include <unistd.h> #define BUFSIZE 8192 diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index 83b2fbbeeb90..b4749d3eed08 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c @@ -3,17 +3,26 @@ #include <errno.h> #include <inttypes.h> #include <regex.h> +#include <stdlib.h> #include "callchain.h" #include "debug.h" +#include "dso.h" +#include "env.h" #include "event.h" #include "evsel.h" #include "hist.h" #include "machine.h" #include "map.h" +#include "map_symbol.h" +#include "branch.h" +#include "mem-events.h" +#include "srcline.h" #include "symbol.h" #include "sort.h" #include "strlist.h" +#include "target.h" #include "thread.h" +#include "util.h" #include "vdso.h" #include <stdbool.h> #include <sys/types.h> @@ -27,6 +36,7 @@ #include <linux/ctype.h> #include <symbol/kallsyms.h> #include <linux/mman.h> +#include <linux/string.h> #include <linux/zalloc.h> static void __machine__remove_thread(struct machine *machine, struct thread *th, bool lock); @@ -642,7 +652,7 @@ int machine__process_namespaces_event(struct machine *machine __maybe_unused, int machine__process_lost_event(struct machine *machine __maybe_unused, union perf_event *event, struct perf_sample *sample __maybe_unused) { - dump_printf(": id:%" PRIu64 ": lost:%" PRIu64 "\n", + dump_printf(": id:%" PRI_lu64 ": lost:%" PRI_lu64 "\n", event->lost.id, event->lost.lost); return 0; } @@ -650,7 +660,7 @@ int machine__process_lost_event(struct machine *machine __maybe_unused, int machine__process_lost_samples_event(struct machine *machine __maybe_unused, union perf_event *event, struct perf_sample *sample) { - dump_printf(": id:%" PRIu64 ": lost samples :%" PRIu64 "\n", + dump_printf(": id:%" PRIu64 ": lost samples :%" PRI_lu64 "\n", sample->id, event->lost_samples.lost); return 0; } @@ -710,20 +720,20 @@ static int machine__process_ksymbol_register(struct machine *machine, struct symbol *sym; struct map *map; - map = map_groups__find(&machine->kmaps, event->ksymbol_event.addr); + map = map_groups__find(&machine->kmaps, event->ksymbol.addr); if (!map) { - map = dso__new_map(event->ksymbol_event.name); + map = dso__new_map(event->ksymbol.name); if (!map) return -ENOMEM; - map->start = event->ksymbol_event.addr; - map->end = map->start + event->ksymbol_event.len; + map->start = event->ksymbol.addr; + map->end = map->start + event->ksymbol.len; map_groups__insert(&machine->kmaps, map); } sym = symbol__new(map->map_ip(map, map->start), - event->ksymbol_event.len, - 0, 0, event->ksymbol_event.name); + event->ksymbol.len, + 0, 0, event->ksymbol.name); if (!sym) return -ENOMEM; dso__insert_symbol(map->dso, sym); @@ -736,7 +746,7 @@ static int machine__process_ksymbol_unregister(struct machine *machine, { struct map *map; - map = map_groups__find(&machine->kmaps, event->ksymbol_event.addr); + map = map_groups__find(&machine->kmaps, event->ksymbol.addr); if (map) map_groups__remove(&machine->kmaps, map); @@ -750,7 +760,7 @@ int machine__process_ksymbol(struct machine *machine __maybe_unused, if (dump_trace) perf_event__fprintf_ksymbol(event, stdout); - if (event->ksymbol_event.flags & PERF_RECORD_KSYMBOL_FLAGS_UNREGISTER) + if (event->ksymbol.flags & PERF_RECORD_KSYMBOL_FLAGS_UNREGISTER) return machine__process_ksymbol_unregister(machine, event, sample); return machine__process_ksymbol_register(machine, event, sample); @@ -1919,7 +1929,7 @@ int machine__process_event(struct machine *machine, union perf_event *event, case PERF_RECORD_KSYMBOL: ret = machine__process_ksymbol(machine, event, sample); break; case PERF_RECORD_BPF_EVENT: - ret = machine__process_bpf_event(machine, event, sample); break; + ret = machine__process_bpf(machine, event, sample); break; default: ret = -1; break; @@ -2288,7 +2298,7 @@ static int find_prev_cpumode(struct ip_callchain *chain, struct thread *thread, static int thread__resolve_callchain_sample(struct thread *thread, struct callchain_cursor *cursor, - struct perf_evsel *evsel, + struct evsel *evsel, struct perf_sample *sample, struct symbol **parent, struct addr_location *root_al, @@ -2494,13 +2504,13 @@ static int unwind_entry(struct unwind_entry *entry, void *arg) static int thread__resolve_callchain_unwind(struct thread *thread, struct callchain_cursor *cursor, - struct perf_evsel *evsel, + struct evsel *evsel, struct perf_sample *sample, int max_stack) { /* Can we do dwarf post unwind? */ - if (!((evsel->attr.sample_type & PERF_SAMPLE_REGS_USER) && - (evsel->attr.sample_type & PERF_SAMPLE_STACK_USER))) + if (!((evsel->core.attr.sample_type & PERF_SAMPLE_REGS_USER) && + (evsel->core.attr.sample_type & PERF_SAMPLE_STACK_USER))) return 0; /* Bail out if nothing was captured. */ @@ -2514,7 +2524,7 @@ static int thread__resolve_callchain_unwind(struct thread *thread, int thread__resolve_callchain(struct thread *thread, struct callchain_cursor *cursor, - struct perf_evsel *evsel, + struct evsel *evsel, struct perf_sample *sample, struct symbol **parent, struct addr_location *root_al, @@ -2600,7 +2610,7 @@ int machines__for_each_thread(struct machines *machines, } int __machine__synthesize_threads(struct machine *machine, struct perf_tool *tool, - struct target *target, struct thread_map *threads, + struct target *target, struct perf_thread_map *threads, perf_event__handler_t process, bool data_mmap, unsigned int nr_threads_synthesize) { @@ -2616,7 +2626,9 @@ int __machine__synthesize_threads(struct machine *machine, struct perf_tool *too pid_t machine__get_current_tid(struct machine *machine, int cpu) { - if (cpu < 0 || cpu >= MAX_NR_CPUS || !machine->current_tid) + int nr_cpus = min(machine->env->nr_cpus_online, MAX_NR_CPUS); + + if (cpu < 0 || cpu >= nr_cpus || !machine->current_tid) return -1; return machine->current_tid[cpu]; @@ -2626,6 +2638,7 @@ int machine__set_current_tid(struct machine *machine, int cpu, pid_t pid, pid_t tid) { struct thread *thread; + int nr_cpus = min(machine->env->nr_cpus_online, MAX_NR_CPUS); if (cpu < 0) return -EINVAL; @@ -2633,14 +2646,14 @@ int machine__set_current_tid(struct machine *machine, int cpu, pid_t pid, if (!machine->current_tid) { int i; - machine->current_tid = calloc(MAX_NR_CPUS, sizeof(pid_t)); + machine->current_tid = calloc(nr_cpus, sizeof(pid_t)); if (!machine->current_tid) return -ENOMEM; - for (i = 0; i < MAX_NR_CPUS; i++) + for (i = 0; i < nr_cpus; i++) machine->current_tid[i] = -1; } - if (cpu >= MAX_NR_CPUS) { + if (cpu >= nr_cpus) { pr_err("Requested CPU %d too large. ", cpu); pr_err("Consider raising MAX_NR_CPUS\n"); return -EINVAL; diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h index 7aa38da26427..ffd391a925a6 100644 --- a/tools/perf/util/machine.h +++ b/tools/perf/util/machine.h @@ -5,15 +5,17 @@ #include <sys/types.h> #include <linux/rbtree.h> #include "map_groups.h" -#include "dso.h" +#include "dsos.h" #include "event.h" #include "rwsem.h" struct addr_location; struct branch_stack; -struct perf_evsel; +struct dso; +struct evsel; struct perf_sample; struct symbol; +struct target; struct thread; union perf_event; @@ -175,7 +177,7 @@ struct callchain_cursor; int thread__resolve_callchain(struct thread *thread, struct callchain_cursor *cursor, - struct perf_evsel *evsel, + struct evsel *evsel, struct perf_sample *sample, struct symbol **parent, struct addr_location *root_al, @@ -251,12 +253,12 @@ int machines__for_each_thread(struct machines *machines, void *priv); int __machine__synthesize_threads(struct machine *machine, struct perf_tool *tool, - struct target *target, struct thread_map *threads, + struct target *target, struct perf_thread_map *threads, perf_event__handler_t process, bool data_mmap, unsigned int nr_threads_synthesize); static inline int machine__synthesize_threads(struct machine *machine, struct target *target, - struct thread_map *threads, bool data_mmap, + struct perf_thread_map *threads, bool data_mmap, unsigned int nr_threads_synthesize) { return __machine__synthesize_threads(machine, NULL, target, threads, diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c index 668410b1d426..5b83ed1ebbd6 100644 --- a/tools/perf/util/map.c +++ b/tools/perf/util/map.c @@ -8,7 +8,9 @@ #include <stdio.h> #include <unistd.h> #include <uapi/linux/mman.h> /* To get things like MAP_HUGETLB even on older libc headers */ +#include "dso.h" #include "map.h" +#include "map_symbol.h" #include "thread.h" #include "vdso.h" #include "build-id.h" @@ -20,6 +22,7 @@ #include "namespaces.h" #include "unwind.h" #include "srccode.h" +#include "ui/ui.h" static void __maps__insert(struct maps *maps, struct map *map); static void __maps__insert_name(struct maps *maps, struct map *map); @@ -636,7 +639,7 @@ bool map_groups__empty(struct map_groups *mg) struct map_groups *map_groups__new(struct machine *machine) { - struct map_groups *mg = malloc(sizeof(*mg)); + struct map_groups *mg = zalloc(sizeof(*mg)); if (mg != NULL) map_groups__init(mg, machine); @@ -647,6 +650,7 @@ struct map_groups *map_groups__new(struct machine *machine) void map_groups__delete(struct map_groups *mg) { map_groups__exit(mg); + unwind__finish_access(mg); free(mg); } @@ -887,7 +891,7 @@ int map_groups__clone(struct thread *thread, struct map_groups *parent) if (new == NULL) goto out_unlock; - err = unwind__prepare_access(thread, new, NULL); + err = unwind__prepare_access(mg, new, NULL); if (err) goto out_unlock; diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h index dc93787c74f0..c3614195ddc7 100644 --- a/tools/perf/util/map.h +++ b/tools/perf/util/map.h @@ -16,7 +16,7 @@ struct ip_callchain; struct ref_reloc_sym; struct map_groups; struct machine; -struct perf_evsel; +struct evsel; struct map { union { diff --git a/tools/perf/util/map_groups.h b/tools/perf/util/map_groups.h index 5f25efa6d6bc..77252e14008f 100644 --- a/tools/perf/util/map_groups.h +++ b/tools/perf/util/map_groups.h @@ -31,6 +31,10 @@ struct map_groups { struct maps maps; struct machine *machine; refcount_t refcnt; +#ifdef HAVE_LIBUNWIND_SUPPORT + void *addr_space; + struct unwind_libunwind_ops *unwind_libunwind_ops; +#endif }; #define KMAP_NAME_LEN 256 diff --git a/tools/perf/util/mem-events.c b/tools/perf/util/mem-events.c index 42c3e5a229d2..3d391583f2ae 100644 --- a/tools/perf/util/mem-events.c +++ b/tools/perf/util/mem-events.c @@ -8,10 +8,10 @@ #include <unistd.h> #include <api/fs/fs.h> #include <linux/kernel.h> +#include "map_symbol.h" #include "mem-events.h" #include "debug.h" #include "symbol.h" -#include "sort.h" unsigned int perf_mem_events__loads_ldlat = 30; diff --git a/tools/perf/util/mem-events.h b/tools/perf/util/mem-events.h index a889ec2fa9f5..f1389bdae7bf 100644 --- a/tools/perf/util/mem-events.h +++ b/tools/perf/util/mem-events.h @@ -6,6 +6,8 @@ #include <stdint.h> #include <stdio.h> #include <linux/types.h> +#include <linux/refcount.h> +#include <linux/perf_event.h> #include "stat.h" struct perf_mem_event { @@ -16,6 +18,13 @@ struct perf_mem_event { const char *sysfs_name; }; +struct mem_info { + struct addr_map_symbol iaddr; + struct addr_map_symbol daddr; + union perf_mem_data_src data_src; + refcount_t refcnt; +}; + enum { PERF_MEM_EVENTS__LOAD, PERF_MEM_EVENTS__STORE, diff --git a/tools/perf/util/mem2node.c b/tools/perf/util/mem2node.c index cacc2fc4dcbd..797d86a1ab09 100644 --- a/tools/perf/util/mem2node.c +++ b/tools/perf/util/mem2node.c @@ -1,7 +1,10 @@ #include <errno.h> #include <inttypes.h> #include <linux/bitmap.h> +#include <linux/kernel.h> #include <linux/zalloc.h> +#include "debug.h" +#include "env.h" #include "mem2node.h" struct phys_entry { diff --git a/tools/perf/util/mem2node.h b/tools/perf/util/mem2node.h index 59c4752a2181..8dfa2b58d0cd 100644 --- a/tools/perf/util/mem2node.h +++ b/tools/perf/util/mem2node.h @@ -2,8 +2,9 @@ #define __MEM2NODE_H #include <linux/rbtree.h> -#include "env.h" +#include <linux/types.h> +struct perf_env; struct phys_entry; struct mem2node { diff --git a/tools/perf/util/metricgroup.c b/tools/perf/util/metricgroup.c index 416a9015405e..a7c0424dbda3 100644 --- a/tools/perf/util/metricgroup.c +++ b/tools/perf/util/metricgroup.c @@ -6,22 +6,25 @@ /* Manage metrics and groups of metrics from JSON files */ #include "metricgroup.h" +#include "debug.h" #include "evlist.h" +#include "evsel.h" #include "strbuf.h" #include "pmu.h" #include "expr.h" #include "rblist.h" #include <string.h> -#include <stdbool.h> #include <errno.h> #include "pmu-events/pmu-events.h" #include "strlist.h" #include <assert.h> #include <linux/ctype.h> +#include <linux/string.h> #include <linux/zalloc.h> +#include <subcmd/parse-options.h> struct metric_event *metricgroup__lookup(struct rblist *metric_events, - struct perf_evsel *evsel, + struct evsel *evsel, bool create) { struct rb_node *nd; @@ -84,63 +87,68 @@ struct egroup { const char **ids; const char *metric_name; const char *metric_expr; + const char *metric_unit; }; -static bool record_evsel(int *ind, struct perf_evsel **start, - int idnum, - struct perf_evsel **metric_events, - struct perf_evsel *ev) +static struct evsel *find_evsel_group(struct evlist *perf_evlist, + const char **ids, + int idnum, + struct evsel **metric_events) { - metric_events[*ind] = ev; - if (*ind == 0) - *start = ev; - if (++*ind == idnum) { - metric_events[*ind] = NULL; - return true; - } - return false; -} - -static struct perf_evsel *find_evsel_group(struct perf_evlist *perf_evlist, - const char **ids, - int idnum, - struct perf_evsel **metric_events) -{ - struct perf_evsel *ev, *start = NULL; - int ind = 0; + struct evsel *ev; + int i = 0; + bool leader_found; evlist__for_each_entry (perf_evlist, ev) { - if (ev->collect_stat) - continue; - if (!strcmp(ev->name, ids[ind])) { - if (record_evsel(&ind, &start, idnum, - metric_events, ev)) - return start; + if (!strcmp(ev->name, ids[i])) { + if (!metric_events[i]) + metric_events[i] = ev; } else { - /* - * We saw some other event that is not - * in our list of events. Discard - * the whole match and start again. - */ - ind = 0; - start = NULL; - if (!strcmp(ev->name, ids[ind])) { - if (record_evsel(&ind, &start, idnum, - metric_events, ev)) - return start; + if (++i == idnum) { + /* Discard the whole match and start again */ + i = 0; + memset(metric_events, 0, + sizeof(struct evsel *) * idnum); + continue; + } + + if (!strcmp(ev->name, ids[i])) + metric_events[i] = ev; + else { + /* Discard the whole match and start again */ + i = 0; + memset(metric_events, 0, + sizeof(struct evsel *) * idnum); + continue; } } } - /* - * This can happen when an alias expands to multiple - * events, like for uncore events. - * We don't support this case for now. - */ - return NULL; + + if (i != idnum - 1) { + /* Not whole match */ + return NULL; + } + + metric_events[idnum] = NULL; + + for (i = 0; i < idnum; i++) { + leader_found = false; + evlist__for_each_entry(perf_evlist, ev) { + if (!leader_found && (ev == metric_events[i])) + leader_found = true; + + if (leader_found && + !strcmp(ev->name, metric_events[i]->name)) { + ev->metric_leader = metric_events[i]; + } + } + } + + return metric_events[0]; } static int metricgroup__setup_events(struct list_head *groups, - struct perf_evlist *perf_evlist, + struct evlist *perf_evlist, struct rblist *metric_events_list) { struct metric_event *me; @@ -148,10 +156,10 @@ static int metricgroup__setup_events(struct list_head *groups, int i = 0; int ret = 0; struct egroup *eg; - struct perf_evsel *evsel; + struct evsel *evsel; list_for_each_entry (eg, groups, nd) { - struct perf_evsel **metric_events; + struct evsel **metric_events; metric_events = calloc(sizeof(void *), eg->idnum + 1); if (!metric_events) { @@ -179,6 +187,7 @@ static int metricgroup__setup_events(struct list_head *groups, } expr->metric_expr = eg->metric_expr; expr->metric_name = eg->metric_name; + expr->metric_unit = eg->metric_unit; expr->metric_events = metric_events; list_add(&expr->nd, &me->head); } @@ -450,6 +459,7 @@ static int metricgroup__add_metric(const char *metric, struct strbuf *events, eg->idnum = idnum; eg->metric_name = pe->metric_name; eg->metric_expr = pe->metric_expr; + eg->metric_unit = pe->unit; list_add_tail(&eg->nd, group_list); ret = 0; } @@ -502,7 +512,7 @@ int metricgroup__parse_groups(const struct option *opt, struct rblist *metric_events) { struct parse_events_error parse_error; - struct perf_evlist *perf_evlist = *(struct perf_evlist **)opt->value; + struct evlist *perf_evlist = *(struct evlist **)opt->value; struct strbuf extra_events; LIST_HEAD(group_list); int ret; diff --git a/tools/perf/util/metricgroup.h b/tools/perf/util/metricgroup.h index 5c52097a5c63..475c7f912864 100644 --- a/tools/perf/util/metricgroup.h +++ b/tools/perf/util/metricgroup.h @@ -1,15 +1,18 @@ +// SPDX-License-Identifier: GPL-2.0-only #ifndef METRICGROUP_H #define METRICGROUP_H 1 -#include "linux/list.h" -#include "rblist.h" -#include <subcmd/parse-options.h> -#include "evlist.h" -#include "strbuf.h" +#include <linux/list.h> +#include <linux/rbtree.h> +#include <stdbool.h> + +struct evsel; +struct option; +struct rblist; struct metric_event { struct rb_node nd; - struct perf_evsel *evsel; + struct evsel *evsel; struct list_head head; /* list of metric_expr */ }; @@ -17,11 +20,12 @@ struct metric_expr { struct list_head nd; const char *metric_expr; const char *metric_name; - struct perf_evsel **metric_events; + const char *metric_unit; + struct evsel **metric_events; }; struct metric_event *metricgroup__lookup(struct rblist *metric_events, - struct perf_evsel *evsel, + struct evsel *evsel, bool create); int metricgroup__parse_groups(const struct option *opt, const char *str, diff --git a/tools/perf/util/mmap.c b/tools/perf/util/mmap.c index 9f0b6391af33..33c5b5495482 100644 --- a/tools/perf/util/mmap.c +++ b/tools/perf/util/mmap.c @@ -10,12 +10,16 @@ #include <inttypes.h> #include <asm/bug.h> #include <linux/zalloc.h> +#include <stdlib.h> +#include <string.h> #ifdef HAVE_LIBNUMA_SUPPORT #include <numaif.h> #endif +#include "cpumap.h" #include "debug.h" #include "event.h" #include "mmap.h" +#include "../perf.h" #include "util.h" /* page_size */ size_t perf_mmap__mmap_len(struct perf_mmap *map) @@ -150,7 +154,7 @@ void __weak auxtrace_mmap_params__init(struct auxtrace_mmap_params *mp __maybe_u } void __weak auxtrace_mmap_params__set_idx(struct auxtrace_mmap_params *mp __maybe_unused, - struct perf_evlist *evlist __maybe_unused, + struct evlist *evlist __maybe_unused, int idx __maybe_unused, bool per_cpu __maybe_unused) { @@ -325,13 +329,13 @@ void perf_mmap__munmap(struct perf_mmap *map) static void build_node_mask(int node, cpu_set_t *mask) { int c, cpu, nr_cpus; - const struct cpu_map *cpu_map = NULL; + const struct perf_cpu_map *cpu_map = NULL; cpu_map = cpu_map__online(); if (!cpu_map) return; - nr_cpus = cpu_map__nr(cpu_map); + nr_cpus = perf_cpu_map__nr(cpu_map); 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) diff --git a/tools/perf/util/mmap.h b/tools/perf/util/mmap.h index 274ce389cd84..3857a49e8f96 100644 --- a/tools/perf/util/mmap.h +++ b/tools/perf/util/mmap.h @@ -6,6 +6,7 @@ #include <linux/types.h> #include <linux/ring_buffer.h> #include <stdbool.h> +#include <pthread.h> // for cpu_set_t #ifdef HAVE_AIO_SUPPORT #include <aio.h> #endif diff --git a/tools/perf/util/namespaces.c b/tools/perf/util/namespaces.c index 46d3a7754897..99be15dd2b6b 100644 --- a/tools/perf/util/namespaces.c +++ b/tools/perf/util/namespaces.c @@ -19,7 +19,7 @@ #include <asm/bug.h> #include <linux/zalloc.h> -struct namespaces *namespaces__new(struct namespaces_event *event) +struct namespaces *namespaces__new(struct perf_record_namespaces *event) { struct namespaces *namespaces; u64 link_info_size = ((event ? event->nr_namespaces : NR_NAMESPACES) * diff --git a/tools/perf/util/namespaces.h b/tools/perf/util/namespaces.h index 004430c0de93..40edef56cb52 100644 --- a/tools/perf/util/namespaces.h +++ b/tools/perf/util/namespaces.h @@ -17,7 +17,7 @@ int setns(int fd, int nstype); #endif -struct namespaces_event; +struct perf_record_namespaces; struct namespaces { struct list_head list; @@ -25,7 +25,7 @@ struct namespaces { struct perf_ns_link_info link_info[]; }; -struct namespaces *namespaces__new(struct namespaces_event *event); +struct namespaces *namespaces__new(struct perf_record_namespaces *event); void namespaces__free(struct namespaces *namespaces); struct nsinfo { diff --git a/tools/perf/util/ordered-events.c b/tools/perf/util/ordered-events.c index bb5f34b7ab44..359db2b1fcef 100644 --- a/tools/perf/util/ordered-events.c +++ b/tools/perf/util/ordered-events.c @@ -8,6 +8,7 @@ #include "session.h" #include "asm/bug.h" #include "debug.h" +#include "ui/progress.h" #define pr_N(n, fmt, ...) \ eprintf(n, debug_ordered_events, fmt, ##__VA_ARGS__) diff --git a/tools/perf/util/parse-branch-options.c b/tools/perf/util/parse-branch-options.c index 726e8d9e8c54..bb4aa88c50a8 100644 --- a/tools/perf/util/parse-branch-options.c +++ b/tools/perf/util/parse-branch-options.c @@ -1,9 +1,10 @@ // SPDX-License-Identifier: GPL-2.0 -#include "perf.h" #include "util/debug.h" +#include "util/event.h" #include <subcmd/parse-options.h> #include "util/parse-branch-options.h" #include <stdlib.h> +#include <string.h> #define BRANCH_OPT(n, m) \ { .name = n, .mode = (m) } @@ -30,6 +31,7 @@ static const struct branch_mode branch_modes[] = { BRANCH_OPT("ind_jmp", PERF_SAMPLE_BRANCH_IND_JUMP), BRANCH_OPT("call", PERF_SAMPLE_BRANCH_CALL), BRANCH_OPT("save_type", PERF_SAMPLE_BRANCH_TYPE_SAVE), + BRANCH_OPT("stack", PERF_SAMPLE_BRANCH_CALL_STACK), BRANCH_END }; diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 371ff3aee769..5ec21d21113c 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -10,20 +10,21 @@ #include <fcntl.h> #include <sys/param.h> #include "term.h" -#include "../perf.h" +#include "build-id.h" #include "evlist.h" #include "evsel.h" +#include <subcmd/pager.h> #include <subcmd/parse-options.h> #include "parse-events.h" #include <subcmd/exec-cmd.h> #include "string2.h" #include "strlist.h" #include "symbol.h" -#include "cache.h" #include "header.h" #include "bpf-loader.h" #include "debug.h" #include <api/fs/tracing_path.h> +#include <perf/cpumap.h> #include "parse-events-bison.h" #define YY_EXTRA_TYPE int #include "parse-events-flex.h" @@ -314,16 +315,16 @@ static char *get_config_name(struct list_head *head_terms) return NULL; } -static struct perf_evsel * +static struct evsel * __add_event(struct list_head *list, int *idx, struct perf_event_attr *attr, char *name, struct perf_pmu *pmu, struct list_head *config_terms, bool auto_merge_stats, const char *cpu_list) { - struct perf_evsel *evsel; - struct cpu_map *cpus = pmu ? pmu->cpus : - cpu_list ? cpu_map__new(cpu_list) : NULL; + struct evsel *evsel; + struct perf_cpu_map *cpus = pmu ? pmu->cpus : + cpu_list ? perf_cpu_map__new(cpu_list) : NULL; event_attr_init(attr); @@ -332,8 +333,8 @@ __add_event(struct list_head *list, int *idx, return NULL; (*idx)++; - evsel->cpus = cpu_map__get(cpus); - evsel->own_cpus = cpu_map__get(cpus); + evsel->core.cpus = perf_cpu_map__get(cpus); + evsel->core.own_cpus = perf_cpu_map__get(cpus); evsel->system_wide = pmu ? pmu->is_uncore : false; evsel->auto_merge_stats = auto_merge_stats; @@ -343,7 +344,7 @@ __add_event(struct list_head *list, int *idx, if (config_terms) list_splice(config_terms, &evsel->config_terms); - list_add_tail(&evsel->node, list); + list_add_tail(&evsel->core.node, list); return evsel; } @@ -357,7 +358,7 @@ static int add_event(struct list_head *list, int *idx, static int add_event_tool(struct list_head *list, int *idx, enum perf_tool_event tool_event) { - struct perf_evsel *evsel; + struct evsel *evsel; struct perf_event_attr attr = { .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_DUMMY, @@ -510,7 +511,7 @@ static int add_tracepoint(struct list_head *list, int *idx, struct parse_events_error *err, struct list_head *head_config) { - struct perf_evsel *evsel; + struct evsel *evsel; evsel = perf_evsel__newtp_idx(sys_name, evt_name, (*idx)++); if (IS_ERR(evsel)) { @@ -526,7 +527,7 @@ static int add_tracepoint(struct list_head *list, int *idx, list_splice(&config_terms, &evsel->config_terms); } - list_add_tail(&evsel->node, list); + list_add_tail(&evsel->core.node, list); return 0; } @@ -630,15 +631,24 @@ struct __add_bpf_event_param { struct list_head *head_config; }; -static int add_bpf_event(const char *group, const char *event, int fd, +static int add_bpf_event(const char *group, const char *event, int fd, struct bpf_object *obj, void *_param) { LIST_HEAD(new_evsels); struct __add_bpf_event_param *param = _param; struct parse_events_state *parse_state = param->parse_state; struct list_head *list = param->list; - struct perf_evsel *pos; + struct evsel *pos; int err; + /* + * Check if we should add the event, i.e. if it is a TP but starts with a '!', + * then don't add the tracepoint, this will be used for something else, like + * adding to a BPF_MAP_TYPE_PROG_ARRAY. + * + * See tools/perf/examples/bpf/augmented_raw_syscalls.c + */ + if (group[0] == '!') + return 0; pr_debug("add bpf event %s:%s and attach bpf program %d\n", group, event, fd); @@ -647,22 +657,23 @@ static int add_bpf_event(const char *group, const char *event, int fd, event, parse_state->error, param->head_config); if (err) { - struct perf_evsel *evsel, *tmp; + struct evsel *evsel, *tmp; pr_debug("Failed to add BPF event %s:%s\n", group, event); - list_for_each_entry_safe(evsel, tmp, &new_evsels, node) { - list_del_init(&evsel->node); - perf_evsel__delete(evsel); + list_for_each_entry_safe(evsel, tmp, &new_evsels, core.node) { + list_del_init(&evsel->core.node); + evsel__delete(evsel); } return err; } pr_debug("adding %s:%s\n", group, event); - list_for_each_entry(pos, &new_evsels, node) { + list_for_each_entry(pos, &new_evsels, core.node) { pr_debug("adding %s:%s to %p\n", group, event, pos); pos->bpf_fd = fd; + pos->bpf_obj = obj; } list_splice(&new_evsels, list); return 0; @@ -952,6 +963,7 @@ static const char *config_term_names[__PARSE_EVENTS__TERM_TYPE_NR] = { [PARSE_EVENTS__TERM_TYPE_NOOVERWRITE] = "no-overwrite", [PARSE_EVENTS__TERM_TYPE_DRV_CFG] = "driver-config", [PARSE_EVENTS__TERM_TYPE_PERCORE] = "percore", + [PARSE_EVENTS__TERM_TYPE_AUX_OUTPUT] = "aux-output", }; static bool config_term_shrinked; @@ -1072,6 +1084,9 @@ do { \ return -EINVAL; } break; + case PARSE_EVENTS__TERM_TYPE_AUX_OUTPUT: + CHECK_TYPE_VAL(NUM); + break; default: err->str = strdup("unknown term"); err->idx = term->err_term; @@ -1122,6 +1137,7 @@ static int config_term_tracepoint(struct perf_event_attr *attr, case PARSE_EVENTS__TERM_TYPE_MAX_EVENTS: case PARSE_EVENTS__TERM_TYPE_OVERWRITE: case PARSE_EVENTS__TERM_TYPE_NOOVERWRITE: + case PARSE_EVENTS__TERM_TYPE_AUX_OUTPUT: return config_term_common(attr, term, err); default: if (err) { @@ -1214,6 +1230,9 @@ do { \ ADD_CONFIG_TERM(PERCORE, percore, term->val.num ? true : false); break; + case PARSE_EVENTS__TERM_TYPE_AUX_OUTPUT: + ADD_CONFIG_TERM(AUX_OUTPUT, aux_output, term->val.num ? 1 : 0); + break; default: break; } @@ -1296,7 +1315,7 @@ int parse_events_add_pmu(struct parse_events_state *parse_state, struct perf_event_attr attr; struct perf_pmu_info info; struct perf_pmu *pmu; - struct perf_evsel *evsel; + struct evsel *evsel; struct parse_events_error *err = parse_state->error; bool use_uncore_alias; LIST_HEAD(config_terms); @@ -1443,13 +1462,13 @@ static int parse_events__set_leader_for_uncore_aliase(char *name, struct list_head *list, struct parse_events_state *parse_state) { - struct perf_evsel *evsel, *leader; + struct evsel *evsel, *leader; uintptr_t *leaders; bool is_leader = true; int i, nr_pmu = 0, total_members, ret = 0; - leader = list_first_entry(list, struct perf_evsel, node); - evsel = list_last_entry(list, struct perf_evsel, node); + leader = list_first_entry(list, struct evsel, core.node); + evsel = list_last_entry(list, struct evsel, core.node); total_members = evsel->idx - leader->idx + 1; leaders = calloc(total_members, sizeof(uintptr_t)); @@ -1511,13 +1530,13 @@ parse_events__set_leader_for_uncore_aliase(char *name, struct list_head *list, __evlist__for_each_entry(list, evsel) { if (i >= nr_pmu) i = 0; - evsel->leader = (struct perf_evsel *) leaders[i++]; + evsel->leader = (struct evsel *) leaders[i++]; } /* The number of members and group name are same for each group */ for (i = 0; i < nr_pmu; i++) { - evsel = (struct perf_evsel *) leaders[i]; - evsel->nr_members = total_members / nr_pmu; + evsel = (struct evsel *) leaders[i]; + evsel->core.nr_members = total_members / nr_pmu; evsel->group_name = name ? strdup(name) : NULL; } @@ -1534,7 +1553,7 @@ out: void parse_events__set_leader(char *name, struct list_head *list, struct parse_events_state *parse_state) { - struct perf_evsel *leader; + struct evsel *leader; if (list_empty(list)) { WARN_ONCE(true, "WARNING: failed to set leader: empty list"); @@ -1545,7 +1564,7 @@ void parse_events__set_leader(char *name, struct list_head *list, return; __perf_evlist__set_leader(list); - leader = list_entry(list->next, struct perf_evsel, node); + leader = list_entry(list->next, struct evsel, core.node); leader->group_name = name ? strdup(name) : NULL; } @@ -1578,18 +1597,18 @@ struct event_modifier { }; static int get_event_modifier(struct event_modifier *mod, char *str, - struct perf_evsel *evsel) -{ - int eu = evsel ? evsel->attr.exclude_user : 0; - int ek = evsel ? evsel->attr.exclude_kernel : 0; - int eh = evsel ? evsel->attr.exclude_hv : 0; - int eH = evsel ? evsel->attr.exclude_host : 0; - int eG = evsel ? evsel->attr.exclude_guest : 0; - int eI = evsel ? evsel->attr.exclude_idle : 0; - int precise = evsel ? evsel->attr.precise_ip : 0; + struct evsel *evsel) +{ + int eu = evsel ? evsel->core.attr.exclude_user : 0; + int ek = evsel ? evsel->core.attr.exclude_kernel : 0; + int eh = evsel ? evsel->core.attr.exclude_hv : 0; + int eH = evsel ? evsel->core.attr.exclude_host : 0; + int eG = evsel ? evsel->core.attr.exclude_guest : 0; + int eI = evsel ? evsel->core.attr.exclude_idle : 0; + int precise = evsel ? evsel->core.attr.precise_ip : 0; int precise_max = 0; int sample_read = 0; - int pinned = evsel ? evsel->attr.pinned : 0; + int pinned = evsel ? evsel->core.attr.pinned : 0; int exclude = eu | ek | eh; int exclude_GH = evsel ? evsel->exclude_GH : 0; @@ -1691,7 +1710,7 @@ static int check_modifier(char *str) int parse_events__modifier_event(struct list_head *list, char *str, bool add) { - struct perf_evsel *evsel; + struct evsel *evsel; struct event_modifier mod; if (str == NULL) @@ -1707,20 +1726,20 @@ int parse_events__modifier_event(struct list_head *list, char *str, bool add) if (add && get_event_modifier(&mod, str, evsel)) return -EINVAL; - evsel->attr.exclude_user = mod.eu; - evsel->attr.exclude_kernel = mod.ek; - evsel->attr.exclude_hv = mod.eh; - evsel->attr.precise_ip = mod.precise; - evsel->attr.exclude_host = mod.eH; - evsel->attr.exclude_guest = mod.eG; - evsel->attr.exclude_idle = mod.eI; + evsel->core.attr.exclude_user = mod.eu; + evsel->core.attr.exclude_kernel = mod.ek; + evsel->core.attr.exclude_hv = mod.eh; + evsel->core.attr.precise_ip = mod.precise; + evsel->core.attr.exclude_host = mod.eH; + evsel->core.attr.exclude_guest = mod.eG; + evsel->core.attr.exclude_idle = mod.eI; evsel->exclude_GH = mod.exclude_GH; evsel->sample_read = mod.sample_read; evsel->precise_max = mod.precise_max; evsel->weak_group = mod.weak; if (perf_evsel__is_group_leader(evsel)) - evsel->attr.pinned = mod.pinned; + evsel->core.attr.pinned = mod.pinned; } return 0; @@ -1728,7 +1747,7 @@ int parse_events__modifier_event(struct list_head *list, char *str, bool add) int parse_events_name(struct list_head *list, char *name) { - struct perf_evsel *evsel; + struct evsel *evsel; __evlist__for_each_entry(list, evsel) { if (!evsel->name) @@ -1894,12 +1913,12 @@ int parse_events_terms(struct list_head *terms, const char *str) return ret; } -int parse_events(struct perf_evlist *evlist, const char *str, +int parse_events(struct evlist *evlist, const char *str, struct parse_events_error *err) { struct parse_events_state parse_state = { .list = LIST_HEAD_INIT(parse_state.list), - .idx = evlist->nr_entries, + .idx = evlist->core.nr_entries, .error = err, .evlist = evlist, }; @@ -1908,7 +1927,7 @@ int parse_events(struct perf_evlist *evlist, const char *str, ret = parse_events__scanner(str, &parse_state, PE_START_EVENTS); perf_pmu__parse_cleanup(); if (!ret) { - struct perf_evsel *last; + struct evsel *last; if (list_empty(&parse_state.list)) { WARN_ONCE(true, "WARNING: event parser found nothing\n"); @@ -1925,7 +1944,7 @@ int parse_events(struct perf_evlist *evlist, const char *str, /* * There are 2 users - builtin-record and builtin-test objects. - * Both call perf_evlist__delete in case of error, so we dont + * Both call evlist__delete in case of error, so we dont * need to bother. */ return ret; @@ -2003,7 +2022,7 @@ void parse_events_print_error(struct parse_events_error *err, int parse_events_option(const struct option *opt, const char *str, int unset __maybe_unused) { - struct perf_evlist *evlist = *(struct perf_evlist **)opt->value; + struct evlist *evlist = *(struct evlist **)opt->value; struct parse_events_error err = { .idx = 0, }; int ret = parse_events(evlist, str, &err); @@ -2016,12 +2035,12 @@ int parse_events_option(const struct option *opt, const char *str, } static int -foreach_evsel_in_last_glob(struct perf_evlist *evlist, - int (*func)(struct perf_evsel *evsel, +foreach_evsel_in_last_glob(struct evlist *evlist, + int (*func)(struct evsel *evsel, const void *arg), const void *arg) { - struct perf_evsel *last = NULL; + struct evsel *last = NULL; int err; /* @@ -2030,7 +2049,7 @@ foreach_evsel_in_last_glob(struct perf_evlist *evlist, * * So no need to WARN here, let *func do this. */ - if (evlist->nr_entries > 0) + if (evlist->core.nr_entries > 0) last = perf_evlist__last(evlist); do { @@ -2040,15 +2059,15 @@ foreach_evsel_in_last_glob(struct perf_evlist *evlist, if (!last) return 0; - if (last->node.prev == &evlist->entries) + if (last->core.node.prev == &evlist->core.entries) return 0; - last = list_entry(last->node.prev, struct perf_evsel, node); + last = list_entry(last->core.node.prev, struct evsel, core.node); } while (!last->cmdline_group_boundary); return 0; } -static int set_filter(struct perf_evsel *evsel, const void *arg) +static int set_filter(struct evsel *evsel, const void *arg) { const char *str = arg; bool found = false; @@ -2061,7 +2080,7 @@ static int set_filter(struct perf_evsel *evsel, const void *arg) return -1; } - if (evsel->attr.type == PERF_TYPE_TRACEPOINT) { + if (evsel->core.attr.type == PERF_TYPE_TRACEPOINT) { if (perf_evsel__append_tp_filter(evsel, str) < 0) { fprintf(stderr, "not enough memory to hold filter string\n"); @@ -2072,7 +2091,7 @@ static int set_filter(struct perf_evsel *evsel, const void *arg) } while ((pmu = perf_pmu__scan(pmu)) != NULL) - if (pmu->type == evsel->attr.type) { + if (pmu->type == evsel->core.attr.type) { found = true; break; } @@ -2099,18 +2118,18 @@ static int set_filter(struct perf_evsel *evsel, const void *arg) int parse_filter(const struct option *opt, const char *str, int unset __maybe_unused) { - struct perf_evlist *evlist = *(struct perf_evlist **)opt->value; + struct evlist *evlist = *(struct evlist **)opt->value; return foreach_evsel_in_last_glob(evlist, set_filter, (const void *)str); } -static int add_exclude_perf_filter(struct perf_evsel *evsel, +static int add_exclude_perf_filter(struct evsel *evsel, const void *arg __maybe_unused) { char new_filter[64]; - if (evsel == NULL || evsel->attr.type != PERF_TYPE_TRACEPOINT) { + if (evsel == NULL || evsel->core.attr.type != PERF_TYPE_TRACEPOINT) { fprintf(stderr, "--exclude-perf option should follow a -e tracepoint option\n"); return -1; @@ -2131,7 +2150,7 @@ int exclude_perf(const struct option *opt, const char *arg __maybe_unused, int unset __maybe_unused) { - struct perf_evlist *evlist = *(struct perf_evlist **)opt->value; + struct evlist *evlist = *(struct evlist **)opt->value; return foreach_evsel_in_last_glob(evlist, add_exclude_perf_filter, NULL); @@ -2297,20 +2316,20 @@ static bool is_event_supported(u8 type, unsigned config) { bool ret = true; int open_return; - struct perf_evsel *evsel; + struct evsel *evsel; struct perf_event_attr attr = { .type = type, .config = config, .disabled = 1, }; - struct thread_map *tmap = thread_map__new_by_tid(0); + struct perf_thread_map *tmap = thread_map__new_by_tid(0); if (tmap == NULL) return false; - evsel = perf_evsel__new(&attr); + evsel = evsel__new(&attr); if (evsel) { - open_return = perf_evsel__open(evsel, NULL, tmap); + open_return = evsel__open(evsel, NULL, tmap); ret = open_return >= 0; if (open_return == -EACCES) { @@ -2321,13 +2340,13 @@ static bool is_event_supported(u8 type, unsigned config) * by default as some ARM machines do not support it. * */ - evsel->attr.exclude_kernel = 1; - ret = perf_evsel__open(evsel, NULL, tmap) >= 0; + evsel->core.attr.exclude_kernel = 1; + ret = evsel__open(evsel, NULL, tmap) >= 0; } - perf_evsel__delete(evsel); + evsel__delete(evsel); } - thread_map__put(tmap); + perf_thread_map__put(tmap); return ret; } diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index f7139e1a2fd3..616ca1eda0eb 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h @@ -12,8 +12,8 @@ #include <string.h> struct list_head; -struct perf_evsel; -struct perf_evlist; +struct evsel; +struct evlist; struct parse_events_error; struct option; @@ -31,7 +31,7 @@ bool have_tracepoints(struct list_head *evlist); const char *event_type(int type); int parse_events_option(const struct option *opt, const char *str, int unset); -int parse_events(struct perf_evlist *evlist, const char *str, +int parse_events(struct evlist *evlist, const char *str, struct parse_events_error *error); int parse_events_terms(struct list_head *terms, const char *str); int parse_filter(const struct option *opt, const char *str, int unset); @@ -76,6 +76,7 @@ enum { PARSE_EVENTS__TERM_TYPE_OVERWRITE, PARSE_EVENTS__TERM_TYPE_DRV_CFG, PARSE_EVENTS__TERM_TYPE_PERCORE, + PARSE_EVENTS__TERM_TYPE_AUX_OUTPUT, __PARSE_EVENTS__TERM_TYPE_NR, }; @@ -119,7 +120,7 @@ struct parse_events_state { int idx; int nr_groups; struct parse_events_error *error; - struct perf_evlist *evlist; + struct evlist *evlist; struct list_head *terms; }; diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l index ca6098874fe2..7469497cd28e 100644 --- a/tools/perf/util/parse-events.l +++ b/tools/perf/util/parse-events.l @@ -284,6 +284,7 @@ no-inherit { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_NOINHERIT); } overwrite { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_OVERWRITE); } no-overwrite { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_NOOVERWRITE); } percore { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_PERCORE); } +aux-output { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_AUX_OUTPUT); } , { return ','; } "/" { BEGIN(INITIAL); return '/'; } {name_minus} { return str(yyscanner, PE_NAME); } diff --git a/tools/perf/util/path.c b/tools/perf/util/path.c index ca56ba2dd3da..caed0336429f 100644 --- a/tools/perf/util/path.c +++ b/tools/perf/util/path.c @@ -11,11 +11,12 @@ * * which is what it's designed for. */ -#include "cache.h" #include "path.h" +#include "cache.h" #include <linux/kernel.h> #include <limits.h> #include <stdio.h> +#include <string.h> #include <sys/types.h> #include <sys/stat.h> #include <dirent.h> diff --git a/tools/perf/util/path.h b/tools/perf/util/path.h index f014f905df50..083429b7efa3 100644 --- a/tools/perf/util/path.h +++ b/tools/perf/util/path.h @@ -2,6 +2,9 @@ #ifndef _PERF_PATH_H #define _PERF_PATH_H +#include <stddef.h> +#include <stdbool.h> + struct dirent; int path__join(char *bf, size_t size, const char *path1, const char *path2); diff --git a/tools/perf/util/perf-hooks.c b/tools/perf/util/perf-hooks.c index 4f3aa8d99ef4..e635c594f773 100644 --- a/tools/perf/util/perf-hooks.c +++ b/tools/perf/util/perf-hooks.c @@ -8,6 +8,7 @@ #include <errno.h> #include <stdlib.h> +#include <string.h> #include <setjmp.h> #include <linux/err.h> #include <linux/kernel.h> diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index f32b710347db..fb597fa94234 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c @@ -3,6 +3,7 @@ #include <linux/compiler.h> #include <linux/string.h> #include <linux/zalloc.h> +#include <subcmd/pager.h> #include <sys/types.h> #include <errno.h> #include <fcntl.h> @@ -15,13 +16,15 @@ #include <api/fs/fs.h> #include <locale.h> #include <regex.h> +#include <perf/cpumap.h> +#include "debug.h" #include "pmu.h" #include "parse-events.h" #include "cpumap.h" #include "header.h" #include "pmu-events/pmu-events.h" -#include "cache.h" #include "string2.h" +#include "strbuf.h" struct perf_pmu_format { char *name; @@ -99,7 +102,7 @@ static int pmu_format(const char *name, struct list_head *format) return 0; } -static int convert_scale(const char *scale, char **end, double *sval) +int perf_pmu__convert_scale(const char *scale, char **end, double *sval) { char *lc; int ret = 0; @@ -162,7 +165,7 @@ static int perf_pmu__parse_scale(struct perf_pmu_alias *alias, char *dir, char * else scale[sret] = '\0'; - ret = convert_scale(scale, NULL, &alias->scale); + ret = perf_pmu__convert_scale(scale, NULL, &alias->scale); error: close(fd); return ret; @@ -370,7 +373,7 @@ static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name, desc ? strdup(desc) : NULL; alias->topic = topic ? strdup(topic) : NULL; if (unit) { - if (convert_scale(unit, &unit, &alias->scale) < 0) + if (perf_pmu__convert_scale(unit, &unit, &alias->scale) < 0) return -1; snprintf(alias->unit, sizeof(alias->unit), "%s", unit); } @@ -572,16 +575,16 @@ static void pmu_read_sysfs(void) closedir(dir); } -static struct cpu_map *__pmu_cpumask(const char *path) +static struct perf_cpu_map *__pmu_cpumask(const char *path) { FILE *file; - struct cpu_map *cpus; + struct perf_cpu_map *cpus; file = fopen(path, "r"); if (!file) return NULL; - cpus = cpu_map__read(file); + cpus = perf_cpu_map__read(file); fclose(file); return cpus; } @@ -593,10 +596,10 @@ static struct cpu_map *__pmu_cpumask(const char *path) #define CPUS_TEMPLATE_UNCORE "%s/bus/event_source/devices/%s/cpumask" #define CPUS_TEMPLATE_CPU "%s/bus/event_source/devices/%s/cpus" -static struct cpu_map *pmu_cpumask(const char *name) +static struct perf_cpu_map *pmu_cpumask(const char *name) { char path[PATH_MAX]; - struct cpu_map *cpus; + struct perf_cpu_map *cpus; const char *sysfs = sysfs__mountpoint(); const char *templates[] = { CPUS_TEMPLATE_UNCORE, @@ -621,12 +624,12 @@ static struct cpu_map *pmu_cpumask(const char *name) static bool pmu_is_uncore(const char *name) { char path[PATH_MAX]; - struct cpu_map *cpus; + struct perf_cpu_map *cpus; const char *sysfs = sysfs__mountpoint(); snprintf(path, PATH_MAX, CPUS_TEMPLATE_UNCORE, sysfs, name); cpus = __pmu_cpumask(path); - cpu_map__put(cpus); + perf_cpu_map__put(cpus); return !!cpus; } diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h index bd9ec2704a57..f36ade6df76d 100644 --- a/tools/perf/util/pmu.h +++ b/tools/perf/util/pmu.h @@ -28,7 +28,7 @@ struct perf_pmu { bool is_uncore; int max_precise; struct perf_event_attr *default_config; - struct cpu_map *cpus; + struct perf_cpu_map *cpus; struct list_head format; /* HEAD struct perf_pmu_format -> list */ struct list_head aliases; /* HEAD struct perf_pmu_alias -> list */ struct list_head list; /* ELEM */ @@ -96,4 +96,6 @@ struct perf_event_attr *perf_pmu__get_default_config(struct perf_pmu *pmu); struct pmu_events_map *perf_pmu__find_map(struct perf_pmu *pmu); +int perf_pmu__convert_scale(const char *scale, char **end, double *sval); + #endif /* __PMU_H */ diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 8394d48f8b32..b8e0967c5c21 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -19,17 +19,17 @@ #include <limits.h> #include <elf.h> +#include "build-id.h" #include "event.h" #include "namespaces.h" #include "strlist.h" #include "strfilter.h" #include "debug.h" -#include "cache.h" +#include "dso.h" #include "color.h" #include "map.h" #include "map_groups.h" #include "symbol.h" -#include "thread.h" #include <api/fs/fs.h> #include "trace-event.h" /* For __maybe_unused */ #include "probe-event.h" @@ -37,7 +37,9 @@ #include "probe-file.h" #include "session.h" #include "string2.h" +#include "strbuf.h" +#include <subcmd/pager.h> #include <linux/ctype.h> #include <linux/zalloc.h> diff --git a/tools/perf/util/probe-file.c b/tools/perf/util/probe-file.c index 5b4d49382932..d13db55a2feb 100644 --- a/tools/perf/util/probe-file.c +++ b/tools/perf/util/probe-file.c @@ -16,10 +16,10 @@ #include "strlist.h" #include "strfilter.h" #include "debug.h" -#include "cache.h" +#include "dso.h" #include "color.h" #include "symbol.h" -#include "thread.h" +#include "strbuf.h" #include <api/fs/tracing_path.h> #include "probe-event.h" #include "probe-file.h" diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index 025fc4491993..505905fc21c5 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c @@ -24,6 +24,7 @@ #include "dso.h" #include "debug.h" #include "intlist.h" +#include "strbuf.h" #include "strlist.h" #include "symbol.h" #include "probe-finder.h" diff --git a/tools/perf/util/pstack.c b/tools/perf/util/pstack.c index 28de8a4c2ce8..80ff41fc45be 100644 --- a/tools/perf/util/pstack.c +++ b/tools/perf/util/pstack.c @@ -10,6 +10,7 @@ #include <linux/kernel.h> #include <linux/zalloc.h> #include <stdlib.h> +#include <string.h> struct pstack { unsigned short top; diff --git a/tools/perf/util/python-ext-sources b/tools/perf/util/python-ext-sources index ceb8afdf9a89..c6dd478956f1 100644 --- a/tools/perf/util/python-ext-sources +++ b/tools/perf/util/python-ext-sources @@ -7,6 +7,7 @@ util/python.c ../lib/ctype.c +util/cap.c util/evlist.c util/evsel.c util/cpumap.c @@ -18,10 +19,8 @@ util/namespaces.c ../lib/hweight.c ../lib/string.c ../lib/vsprintf.c -../lib/zalloc.c util/thread_map.c util/util.c -util/xyarray.c util/cgroup.c util/parse-branch-options.c util/rblist.c diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c index 1e5b6718dcea..07ca4535e6f7 100644 --- a/tools/perf/util/python.c +++ b/tools/perf/util/python.c @@ -4,6 +4,9 @@ #include <inttypes.h> #include <poll.h> #include <linux/err.h> +#include <perf/cpumap.h> +#include <traceevent/event-parse.h> +#include "debug.h" #include "evlist.h" #include "callchain.h" #include "evsel.h" @@ -11,8 +14,10 @@ #include "cpumap.h" #include "print_binary.h" #include "thread_map.h" +#include "trace-event.h" #include "mmap.h" #include "util.h" +#include "../perf-sys.h" #if PY_MAJOR_VERSION < 3 #define _PyUnicode_FromString(arg) \ @@ -93,7 +98,7 @@ PyMODINIT_FUNC PyInit_perf(void); struct pyrf_event { PyObject_HEAD - struct perf_evsel *evsel; + struct evsel *evsel; struct perf_sample sample; union perf_event event; }; @@ -115,12 +120,12 @@ static PyMemberDef pyrf_mmap_event__members[] = { sample_members member_def(perf_event_header, type, T_UINT, "event type"), member_def(perf_event_header, misc, T_UINT, "event misc"), - member_def(mmap_event, pid, T_UINT, "event pid"), - member_def(mmap_event, tid, T_UINT, "event tid"), - member_def(mmap_event, start, T_ULONGLONG, "start of the map"), - member_def(mmap_event, len, T_ULONGLONG, "map length"), - member_def(mmap_event, pgoff, T_ULONGLONG, "page offset"), - member_def(mmap_event, filename, T_STRING_INPLACE, "backing store"), + member_def(perf_record_mmap, pid, T_UINT, "event pid"), + member_def(perf_record_mmap, tid, T_UINT, "event tid"), + member_def(perf_record_mmap, start, T_ULONGLONG, "start of the map"), + member_def(perf_record_mmap, len, T_ULONGLONG, "map length"), + member_def(perf_record_mmap, pgoff, T_ULONGLONG, "page offset"), + member_def(perf_record_mmap, filename, T_STRING_INPLACE, "backing store"), { .name = NULL, }, }; @@ -129,8 +134,8 @@ static PyObject *pyrf_mmap_event__repr(struct pyrf_event *pevent) PyObject *ret; char *s; - if (asprintf(&s, "{ type: mmap, pid: %u, tid: %u, start: %#" PRIx64 ", " - "length: %#" PRIx64 ", offset: %#" PRIx64 ", " + if (asprintf(&s, "{ type: mmap, pid: %u, tid: %u, start: %#" PRI_lx64 ", " + "length: %#" PRI_lx64 ", offset: %#" PRI_lx64 ", " "filename: %s }", pevent->event.mmap.pid, pevent->event.mmap.tid, pevent->event.mmap.start, pevent->event.mmap.len, @@ -158,18 +163,18 @@ static char pyrf_task_event__doc[] = PyDoc_STR("perf task (fork/exit) event obje static PyMemberDef pyrf_task_event__members[] = { sample_members member_def(perf_event_header, type, T_UINT, "event type"), - member_def(fork_event, pid, T_UINT, "event pid"), - member_def(fork_event, ppid, T_UINT, "event ppid"), - member_def(fork_event, tid, T_UINT, "event tid"), - member_def(fork_event, ptid, T_UINT, "event ptid"), - member_def(fork_event, time, T_ULONGLONG, "timestamp"), + member_def(perf_record_fork, pid, T_UINT, "event pid"), + member_def(perf_record_fork, ppid, T_UINT, "event ppid"), + member_def(perf_record_fork, tid, T_UINT, "event tid"), + member_def(perf_record_fork, ptid, T_UINT, "event ptid"), + member_def(perf_record_fork, time, T_ULONGLONG, "timestamp"), { .name = NULL, }, }; static PyObject *pyrf_task_event__repr(struct pyrf_event *pevent) { return _PyUnicode_FromFormat("{ type: %s, pid: %u, ppid: %u, tid: %u, " - "ptid: %u, time: %" PRIu64 "}", + "ptid: %u, time: %" PRI_lu64 "}", pevent->event.header.type == PERF_RECORD_FORK ? "fork" : "exit", pevent->event.fork.pid, pevent->event.fork.ppid, @@ -193,9 +198,9 @@ static char pyrf_comm_event__doc[] = PyDoc_STR("perf comm event object."); static PyMemberDef pyrf_comm_event__members[] = { sample_members member_def(perf_event_header, type, T_UINT, "event type"), - member_def(comm_event, pid, T_UINT, "event pid"), - member_def(comm_event, tid, T_UINT, "event tid"), - member_def(comm_event, comm, T_STRING_INPLACE, "process name"), + member_def(perf_record_comm, pid, T_UINT, "event pid"), + member_def(perf_record_comm, tid, T_UINT, "event tid"), + member_def(perf_record_comm, comm, T_STRING_INPLACE, "process name"), { .name = NULL, }, }; @@ -222,18 +227,18 @@ static char pyrf_throttle_event__doc[] = PyDoc_STR("perf throttle event object." static PyMemberDef pyrf_throttle_event__members[] = { sample_members member_def(perf_event_header, type, T_UINT, "event type"), - member_def(throttle_event, time, T_ULONGLONG, "timestamp"), - member_def(throttle_event, id, T_ULONGLONG, "event id"), - member_def(throttle_event, stream_id, T_ULONGLONG, "event stream id"), + member_def(perf_record_throttle, time, T_ULONGLONG, "timestamp"), + member_def(perf_record_throttle, id, T_ULONGLONG, "event id"), + member_def(perf_record_throttle, stream_id, T_ULONGLONG, "event stream id"), { .name = NULL, }, }; static PyObject *pyrf_throttle_event__repr(struct pyrf_event *pevent) { - struct throttle_event *te = (struct throttle_event *)(&pevent->event.header + 1); + struct perf_record_throttle *te = (struct perf_record_throttle *)(&pevent->event.header + 1); - return _PyUnicode_FromFormat("{ type: %sthrottle, time: %" PRIu64 ", id: %" PRIu64 - ", stream_id: %" PRIu64 " }", + return _PyUnicode_FromFormat("{ type: %sthrottle, time: %" PRI_lu64 ", id: %" PRI_lu64 + ", stream_id: %" PRI_lu64 " }", pevent->event.header.type == PERF_RECORD_THROTTLE ? "" : "un", te->time, te->id, te->stream_id); } @@ -252,8 +257,8 @@ static char pyrf_lost_event__doc[] = PyDoc_STR("perf lost event object."); static PyMemberDef pyrf_lost_event__members[] = { sample_members - member_def(lost_event, id, T_ULONGLONG, "event id"), - member_def(lost_event, lost, T_ULONGLONG, "number of lost events"), + member_def(perf_record_lost, id, T_ULONGLONG, "event id"), + member_def(perf_record_lost, lost, T_ULONGLONG, "number of lost events"), { .name = NULL, }, }; @@ -262,8 +267,8 @@ static PyObject *pyrf_lost_event__repr(struct pyrf_event *pevent) PyObject *ret; char *s; - if (asprintf(&s, "{ type: lost, id: %#" PRIx64 ", " - "lost: %#" PRIx64 " }", + if (asprintf(&s, "{ type: lost, id: %#" PRI_lx64 ", " + "lost: %#" PRI_lx64 " }", pevent->event.lost.id, pevent->event.lost.lost) < 0) { ret = PyErr_NoMemory(); } else { @@ -287,8 +292,8 @@ static char pyrf_read_event__doc[] = PyDoc_STR("perf read event object."); static PyMemberDef pyrf_read_event__members[] = { sample_members - member_def(read_event, pid, T_UINT, "event pid"), - member_def(read_event, tid, T_UINT, "event tid"), + member_def(perf_record_read, pid, T_UINT, "event pid"), + member_def(perf_record_read, tid, T_UINT, "event tid"), { .name = NULL, }, }; @@ -337,7 +342,7 @@ static PyObject *pyrf_sample_event__repr(struct pyrf_event *pevent) static bool is_tracepoint(struct pyrf_event *pevent) { - return pevent->evsel->attr.type == PERF_TYPE_TRACEPOINT; + return pevent->evsel->core.attr.type == PERF_TYPE_TRACEPOINT; } static PyObject* @@ -383,13 +388,13 @@ static PyObject* get_tracepoint_field(struct pyrf_event *pevent, PyObject *attr_name) { const char *str = _PyUnicode_AsString(PyObject_Str(attr_name)); - struct perf_evsel *evsel = pevent->evsel; + struct evsel *evsel = pevent->evsel; struct tep_format_field *field; if (!evsel->tp_format) { struct tep_event *tp_format; - tp_format = trace_event__tp_format_id(evsel->attr.config); + tp_format = trace_event__tp_format_id(evsel->core.attr.config); if (!tp_format) return NULL; @@ -430,8 +435,8 @@ static char pyrf_context_switch_event__doc[] = PyDoc_STR("perf context_switch ev static PyMemberDef pyrf_context_switch_event__members[] = { sample_members member_def(perf_event_header, type, T_UINT, "event type"), - member_def(context_switch_event, next_prev_pid, T_UINT, "next/prev pid"), - member_def(context_switch_event, next_prev_tid, T_UINT, "next/prev tid"), + member_def(perf_record_switch, next_prev_pid, T_UINT, "next/prev pid"), + member_def(perf_record_switch, next_prev_tid, T_UINT, "next/prev tid"), { .name = NULL, }, }; @@ -536,7 +541,7 @@ static PyObject *pyrf_event__new(union perf_event *event) struct pyrf_cpu_map { PyObject_HEAD - struct cpu_map *cpus; + struct perf_cpu_map *cpus; }; static int pyrf_cpu_map__init(struct pyrf_cpu_map *pcpus, @@ -549,7 +554,7 @@ static int pyrf_cpu_map__init(struct pyrf_cpu_map *pcpus, kwlist, &cpustr)) return -1; - pcpus->cpus = cpu_map__new(cpustr); + pcpus->cpus = perf_cpu_map__new(cpustr); if (pcpus->cpus == NULL) return -1; return 0; @@ -557,7 +562,7 @@ static int pyrf_cpu_map__init(struct pyrf_cpu_map *pcpus, static void pyrf_cpu_map__delete(struct pyrf_cpu_map *pcpus) { - cpu_map__put(pcpus->cpus); + perf_cpu_map__put(pcpus->cpus); Py_TYPE(pcpus)->tp_free((PyObject*)pcpus); } @@ -605,7 +610,7 @@ static int pyrf_cpu_map__setup_types(void) struct pyrf_thread_map { PyObject_HEAD - struct thread_map *threads; + struct perf_thread_map *threads; }; static int pyrf_thread_map__init(struct pyrf_thread_map *pthreads, @@ -626,7 +631,7 @@ static int pyrf_thread_map__init(struct pyrf_thread_map *pthreads, static void pyrf_thread_map__delete(struct pyrf_thread_map *pthreads) { - thread_map__put(pthreads->threads); + perf_thread_map__put(pthreads->threads); Py_TYPE(pthreads)->tp_free((PyObject*)pthreads); } @@ -674,7 +679,7 @@ static int pyrf_thread_map__setup_types(void) struct pyrf_evsel { PyObject_HEAD - struct perf_evsel evsel; + struct evsel evsel; }; static int pyrf_evsel__init(struct pyrf_evsel *pevsel, @@ -782,7 +787,7 @@ static int pyrf_evsel__init(struct pyrf_evsel *pevsel, attr.sample_id_all = sample_id_all; attr.size = sizeof(attr); - perf_evsel__init(&pevsel->evsel, &attr, idx); + evsel__init(&pevsel->evsel, &attr, idx); return 0; } @@ -795,9 +800,9 @@ static void pyrf_evsel__delete(struct pyrf_evsel *pevsel) static PyObject *pyrf_evsel__open(struct pyrf_evsel *pevsel, PyObject *args, PyObject *kwargs) { - struct perf_evsel *evsel = &pevsel->evsel; - struct cpu_map *cpus = NULL; - struct thread_map *threads = NULL; + struct evsel *evsel = &pevsel->evsel; + struct perf_cpu_map *cpus = NULL; + struct perf_thread_map *threads = NULL; PyObject *pcpus = NULL, *pthreads = NULL; int group = 0, inherit = 0; static char *kwlist[] = { "cpus", "threads", "group", "inherit", NULL }; @@ -812,12 +817,12 @@ static PyObject *pyrf_evsel__open(struct pyrf_evsel *pevsel, if (pcpus != NULL) cpus = ((struct pyrf_cpu_map *)pcpus)->cpus; - evsel->attr.inherit = inherit; + evsel->core.attr.inherit = inherit; /* * This will group just the fds for this single evsel, to group * multiple events, use evlist.open(). */ - if (perf_evsel__open(evsel, cpus, threads) < 0) { + if (evsel__open(evsel, cpus, threads) < 0) { PyErr_SetFromErrno(PyExc_OSError); return NULL; } @@ -858,22 +863,22 @@ static int pyrf_evsel__setup_types(void) struct pyrf_evlist { PyObject_HEAD - struct perf_evlist evlist; + struct evlist evlist; }; static int pyrf_evlist__init(struct pyrf_evlist *pevlist, PyObject *args, PyObject *kwargs __maybe_unused) { PyObject *pcpus = NULL, *pthreads = NULL; - struct cpu_map *cpus; - struct thread_map *threads; + struct perf_cpu_map *cpus; + struct perf_thread_map *threads; if (!PyArg_ParseTuple(args, "OO", &pcpus, &pthreads)) return -1; threads = ((struct pyrf_thread_map *)pthreads)->threads; cpus = ((struct pyrf_cpu_map *)pcpus)->cpus; - perf_evlist__init(&pevlist->evlist, cpus, threads); + evlist__init(&pevlist->evlist, cpus, threads); return 0; } @@ -886,7 +891,7 @@ static void pyrf_evlist__delete(struct pyrf_evlist *pevlist) static PyObject *pyrf_evlist__mmap(struct pyrf_evlist *pevlist, PyObject *args, PyObject *kwargs) { - struct perf_evlist *evlist = &pevlist->evlist; + struct evlist *evlist = &pevlist->evlist; static char *kwlist[] = { "pages", "overwrite", NULL }; int pages = 128, overwrite = false; @@ -906,7 +911,7 @@ static PyObject *pyrf_evlist__mmap(struct pyrf_evlist *pevlist, static PyObject *pyrf_evlist__poll(struct pyrf_evlist *pevlist, PyObject *args, PyObject *kwargs) { - struct perf_evlist *evlist = &pevlist->evlist; + struct evlist *evlist = &pevlist->evlist; static char *kwlist[] = { "timeout", NULL }; int timeout = -1, n; @@ -926,7 +931,7 @@ static PyObject *pyrf_evlist__get_pollfd(struct pyrf_evlist *pevlist, PyObject *args __maybe_unused, PyObject *kwargs __maybe_unused) { - struct perf_evlist *evlist = &pevlist->evlist; + struct evlist *evlist = &pevlist->evlist; PyObject *list = PyList_New(0); int i; @@ -964,22 +969,22 @@ static PyObject *pyrf_evlist__add(struct pyrf_evlist *pevlist, PyObject *args, PyObject *kwargs __maybe_unused) { - struct perf_evlist *evlist = &pevlist->evlist; + struct evlist *evlist = &pevlist->evlist; PyObject *pevsel; - struct perf_evsel *evsel; + struct evsel *evsel; if (!PyArg_ParseTuple(args, "O", &pevsel)) return NULL; Py_INCREF(pevsel); evsel = &((struct pyrf_evsel *)pevsel)->evsel; - evsel->idx = evlist->nr_entries; - perf_evlist__add(evlist, evsel); + evsel->idx = evlist->core.nr_entries; + evlist__add(evlist, evsel); - return Py_BuildValue("i", evlist->nr_entries); + return Py_BuildValue("i", evlist->core.nr_entries); } -static struct perf_mmap *get_md(struct perf_evlist *evlist, int cpu) +static struct perf_mmap *get_md(struct evlist *evlist, int cpu) { int i; @@ -996,7 +1001,7 @@ static struct perf_mmap *get_md(struct perf_evlist *evlist, int cpu) static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist, PyObject *args, PyObject *kwargs) { - struct perf_evlist *evlist = &pevlist->evlist; + struct evlist *evlist = &pevlist->evlist; union perf_event *event; int sample_id_all = 1, cpu; static char *kwlist[] = { "cpu", "sample_id_all", NULL }; @@ -1018,7 +1023,7 @@ static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist, if (event != NULL) { PyObject *pyevent = pyrf_event__new(event); struct pyrf_event *pevent = (struct pyrf_event *)pyevent; - struct perf_evsel *evsel; + struct evsel *evsel; if (pyevent == NULL) return PyErr_NoMemory(); @@ -1049,7 +1054,7 @@ end: static PyObject *pyrf_evlist__open(struct pyrf_evlist *pevlist, PyObject *args, PyObject *kwargs) { - struct perf_evlist *evlist = &pevlist->evlist; + struct evlist *evlist = &pevlist->evlist; int group = 0; static char *kwlist[] = { "group", NULL }; @@ -1059,7 +1064,7 @@ static PyObject *pyrf_evlist__open(struct pyrf_evlist *pevlist, if (group) perf_evlist__set_leader(evlist); - if (perf_evlist__open(evlist) < 0) { + if (evlist__open(evlist) < 0) { PyErr_SetFromErrno(PyExc_OSError); return NULL; } @@ -1112,15 +1117,15 @@ static Py_ssize_t pyrf_evlist__length(PyObject *obj) { struct pyrf_evlist *pevlist = (void *)obj; - return pevlist->evlist.nr_entries; + return pevlist->evlist.core.nr_entries; } static PyObject *pyrf_evlist__item(PyObject *obj, Py_ssize_t i) { struct pyrf_evlist *pevlist = (void *)obj; - struct perf_evsel *pos; + struct evsel *pos; - if (i >= pevlist->evlist.nr_entries) + if (i >= pevlist->evlist.core.nr_entries) return NULL; evlist__for_each_entry(&pevlist->evlist, pos) { diff --git a/tools/perf/util/record.c b/tools/perf/util/record.c index 9cfc7bf16531..286fe816c0f3 100644 --- a/tools/perf/util/record.c +++ b/tools/perf/util/record.c @@ -1,25 +1,31 @@ // SPDX-License-Identifier: GPL-2.0 +#include "debug.h" #include "evlist.h" #include "evsel.h" #include "cpumap.h" #include "parse-events.h" #include <errno.h> +#include <limits.h> +#include <stdlib.h> #include <api/fs/fs.h> #include <subcmd/parse-options.h> +#include <perf/cpumap.h> #include "util.h" #include "cloexec.h" +#include "record.h" +#include "../perf-sys.h" -typedef void (*setup_probe_fn_t)(struct perf_evsel *evsel); +typedef void (*setup_probe_fn_t)(struct evsel *evsel); static int perf_do_probe_api(setup_probe_fn_t fn, int cpu, const char *str) { - struct perf_evlist *evlist; - struct perf_evsel *evsel; + struct evlist *evlist; + struct evsel *evsel; unsigned long flags = perf_event_open_cloexec_flag(); int err = -EAGAIN, fd; static pid_t pid = -1; - evlist = perf_evlist__new(); + evlist = evlist__new(); if (!evlist) return -ENOMEM; @@ -29,7 +35,7 @@ static int perf_do_probe_api(setup_probe_fn_t fn, int cpu, const char *str) evsel = perf_evlist__first(evlist); while (1) { - fd = sys_perf_event_open(&evsel->attr, pid, cpu, -1, flags); + fd = sys_perf_event_open(&evsel->core.attr, pid, cpu, -1, flags); if (fd < 0) { if (pid == -1 && errno == EACCES) { pid = 0; @@ -43,7 +49,7 @@ static int perf_do_probe_api(setup_probe_fn_t fn, int cpu, const char *str) fn(evsel); - fd = sys_perf_event_open(&evsel->attr, pid, cpu, -1, flags); + fd = sys_perf_event_open(&evsel->core.attr, pid, cpu, -1, flags); if (fd < 0) { if (errno == EINVAL) err = -EINVAL; @@ -53,21 +59,21 @@ static int perf_do_probe_api(setup_probe_fn_t fn, int cpu, const char *str) err = 0; out_delete: - perf_evlist__delete(evlist); + evlist__delete(evlist); return err; } static bool perf_probe_api(setup_probe_fn_t fn) { const char *try[] = {"cycles:u", "instructions:u", "cpu-clock:u", NULL}; - struct cpu_map *cpus; + struct perf_cpu_map *cpus; int cpu, ret, i = 0; - cpus = cpu_map__new(NULL); + cpus = perf_cpu_map__new(NULL); if (!cpus) return false; cpu = cpus->map[0]; - cpu_map__put(cpus); + perf_cpu_map__put(cpus); do { ret = perf_do_probe_api(fn, cpu, try[i++]); @@ -78,19 +84,19 @@ static bool perf_probe_api(setup_probe_fn_t fn) return false; } -static void perf_probe_sample_identifier(struct perf_evsel *evsel) +static void perf_probe_sample_identifier(struct evsel *evsel) { - evsel->attr.sample_type |= PERF_SAMPLE_IDENTIFIER; + evsel->core.attr.sample_type |= PERF_SAMPLE_IDENTIFIER; } -static void perf_probe_comm_exec(struct perf_evsel *evsel) +static void perf_probe_comm_exec(struct evsel *evsel) { - evsel->attr.comm_exec = 1; + evsel->core.attr.comm_exec = 1; } -static void perf_probe_context_switch(struct perf_evsel *evsel) +static void perf_probe_context_switch(struct evsel *evsel) { - evsel->attr.context_switch = 1; + evsel->core.attr.context_switch = 1; } bool perf_can_sample_identifier(void) @@ -115,14 +121,14 @@ bool perf_can_record_cpu_wide(void) .config = PERF_COUNT_SW_CPU_CLOCK, .exclude_kernel = 1, }; - struct cpu_map *cpus; + struct perf_cpu_map *cpus; int cpu, fd; - cpus = cpu_map__new(NULL); + cpus = perf_cpu_map__new(NULL); if (!cpus) return false; cpu = cpus->map[0]; - cpu_map__put(cpus); + perf_cpu_map__put(cpus); fd = sys_perf_event_open(&attr, -1, cpu, -1, 0); if (fd < 0) @@ -132,10 +138,10 @@ bool perf_can_record_cpu_wide(void) return true; } -void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts, +void perf_evlist__config(struct evlist *evlist, struct record_opts *opts, struct callchain_param *callchain) { - struct perf_evsel *evsel; + struct evsel *evsel; bool use_sample_identifier = false; bool use_comm_exec; bool sample_id = opts->sample_id; @@ -147,7 +153,7 @@ void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts, if (opts->group) perf_evlist__set_leader(evlist); - if (evlist->cpus->map[0] < 0) + if (evlist->core.cpus->map[0] < 0) opts->no_inherit = true; use_comm_exec = perf_can_comm_exec(); @@ -155,7 +161,7 @@ void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts, evlist__for_each_entry(evlist, evsel) { perf_evsel__config(evsel, opts, callchain); if (evsel->tracking && use_comm_exec) - evsel->attr.comm_exec = 1; + evsel->core.attr.comm_exec = 1; } if (opts->full_auxtrace) { @@ -166,11 +172,11 @@ void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts, */ use_sample_identifier = perf_can_sample_identifier(); sample_id = true; - } else if (evlist->nr_entries > 1) { - struct perf_evsel *first = perf_evlist__first(evlist); + } else if (evlist->core.nr_entries > 1) { + struct evsel *first = perf_evlist__first(evlist); evlist__for_each_entry(evlist, evsel) { - if (evsel->attr.sample_type == first->attr.sample_type) + if (evsel->core.attr.sample_type == first->core.attr.sample_type) continue; use_sample_identifier = perf_can_sample_identifier(); break; @@ -256,15 +262,15 @@ int record_opts__config(struct record_opts *opts) return record_opts__config_freq(opts); } -bool perf_evlist__can_select_event(struct perf_evlist *evlist, const char *str) +bool perf_evlist__can_select_event(struct evlist *evlist, const char *str) { - struct perf_evlist *temp_evlist; - struct perf_evsel *evsel; + struct evlist *temp_evlist; + struct evsel *evsel; int err, fd, cpu; bool ret = false; pid_t pid = -1; - temp_evlist = perf_evlist__new(); + temp_evlist = evlist__new(); if (!temp_evlist) return false; @@ -274,17 +280,17 @@ bool perf_evlist__can_select_event(struct perf_evlist *evlist, const char *str) evsel = perf_evlist__last(temp_evlist); - if (!evlist || cpu_map__empty(evlist->cpus)) { - struct cpu_map *cpus = cpu_map__new(NULL); + if (!evlist || perf_cpu_map__empty(evlist->core.cpus)) { + struct perf_cpu_map *cpus = perf_cpu_map__new(NULL); cpu = cpus ? cpus->map[0] : 0; - cpu_map__put(cpus); + perf_cpu_map__put(cpus); } else { - cpu = evlist->cpus->map[0]; + cpu = evlist->core.cpus->map[0]; } while (1) { - fd = sys_perf_event_open(&evsel->attr, pid, cpu, -1, + fd = sys_perf_event_open(&evsel->core.attr, pid, cpu, -1, perf_event_open_cloexec_flag()); if (fd < 0) { if (pid == -1 && errno == EACCES) { @@ -299,7 +305,7 @@ bool perf_evlist__can_select_event(struct perf_evlist *evlist, const char *str) ret = true; out_delete: - perf_evlist__delete(temp_evlist); + evlist__delete(temp_evlist); return ret; } diff --git a/tools/perf/util/record.h b/tools/perf/util/record.h new file mode 100644 index 000000000000..00275afc524d --- /dev/null +++ b/tools/perf/util/record.h @@ -0,0 +1,74 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _PERF_RECORD_H +#define _PERF_RECORD_H + +#include <time.h> +#include <stdbool.h> +#include <linux/types.h> +#include <linux/stddef.h> +#include <linux/perf_event.h> +#include "util/target.h" + +struct option; + +struct record_opts { + struct target target; + bool group; + bool inherit_stat; + bool no_buffering; + bool no_inherit; + bool no_inherit_set; + bool no_samples; + bool raw_samples; + bool sample_address; + bool sample_phys_addr; + bool sample_weight; + bool sample_time; + bool sample_time_set; + bool sample_cpu; + bool period; + bool period_set; + bool running_time; + bool full_auxtrace; + bool auxtrace_snapshot_mode; + bool auxtrace_snapshot_on_exit; + bool record_namespaces; + bool record_switch_events; + bool all_kernel; + bool all_user; + bool kernel_callchains; + bool user_callchains; + bool tail_synthesize; + bool overwrite; + bool ignore_missing_thread; + bool strict_freq; + bool sample_id; + bool no_bpf_event; + unsigned int freq; + unsigned int mmap_pages; + unsigned int auxtrace_mmap_pages; + unsigned int user_freq; + u64 branch_stack; + u64 sample_intr_regs; + u64 sample_user_regs; + u64 default_interval; + u64 user_interval; + size_t auxtrace_snapshot_size; + const char *auxtrace_snapshot_opts; + bool sample_transaction; + unsigned initial_delay; + bool use_clockid; + clockid_t clockid; + u64 clockid_res_ns; + int nr_cblocks; + int affinity; + int mmap_flush; + unsigned int comp_level; +}; + +extern const char * const *record_usage; +extern struct option *record_options; + +int record__parse_freq(const struct option *opt, const char *str, int unset); + +#endif // _PERF_RECORD_H diff --git a/tools/perf/util/s390-cpumsf.c b/tools/perf/util/s390-cpumsf.c index 83d2e149ef19..24a99909d8b3 100644 --- a/tools/perf/util/s390-cpumsf.c +++ b/tools/perf/util/s390-cpumsf.c @@ -157,7 +157,7 @@ #include "evlist.h" #include "machine.h" #include "session.h" -#include "thread.h" +#include "tool.h" #include "debug.h" #include "auxtrace.h" #include "s390-cpumsf.h" @@ -918,7 +918,7 @@ s390_cpumsf_process_event(struct perf_session *session, struct s390_cpumsf, auxtrace); u64 timestamp = sample->time; - struct perf_evsel *ev_bc000; + struct evsel *ev_bc000; int err = 0; @@ -935,7 +935,7 @@ s390_cpumsf_process_event(struct perf_session *session, /* Handle event with raw data */ ev_bc000 = perf_evlist__event2evsel(session->evlist, event); if (ev_bc000 && - ev_bc000->attr.config == PERF_EVENT_CPUM_CF_DIAG) + ev_bc000->core.attr.config == PERF_EVENT_CPUM_CF_DIAG) err = s390_cpumcf_dumpctr(sf, sample); return err; } @@ -1109,11 +1109,11 @@ static int s390_cpumsf__config(const char *var, const char *value, void *cb) int s390_cpumsf_process_auxtrace_info(union perf_event *event, struct perf_session *session) { - struct auxtrace_info_event *auxtrace_info = &event->auxtrace_info; + struct perf_record_auxtrace_info *auxtrace_info = &event->auxtrace_info; struct s390_cpumsf *sf; int err; - if (auxtrace_info->header.size < sizeof(struct auxtrace_info_event)) + if (auxtrace_info->header.size < sizeof(struct perf_record_auxtrace_info)) return -EINVAL; sf = zalloc(sizeof(struct s390_cpumsf)); diff --git a/tools/perf/util/s390-sample-raw.c b/tools/perf/util/s390-sample-raw.c index 6650f599ed9c..4d9593e331ea 100644 --- a/tools/perf/util/s390-sample-raw.c +++ b/tools/perf/util/s390-sample-raw.c @@ -23,10 +23,8 @@ #include "debug.h" #include "util.h" -#include "auxtrace.h" #include "session.h" #include "evlist.h" -#include "config.h" #include "color.h" #include "sample-raw.h" #include "s390-cpumcf-kernel.h" @@ -200,17 +198,17 @@ static void s390_cpumcfdg_dump(struct perf_sample *sample) * its raw data. * The function is only invoked when the dump flag -D is set. */ -void perf_evlist__s390_sample_raw(struct perf_evlist *evlist, union perf_event *event, +void perf_evlist__s390_sample_raw(struct evlist *evlist, union perf_event *event, struct perf_sample *sample) { - struct perf_evsel *ev_bc000; + struct evsel *ev_bc000; if (event->header.type != PERF_RECORD_SAMPLE) return; ev_bc000 = perf_evlist__event2evsel(evlist, event); if (ev_bc000 == NULL || - ev_bc000->attr.config != PERF_EVENT_CPUM_CF_DIAG) + ev_bc000->core.attr.config != PERF_EVENT_CPUM_CF_DIAG) return; /* Display raw data on screen */ diff --git a/tools/perf/util/sample-raw.c b/tools/perf/util/sample-raw.c index c21e1311fb0f..e84bbe0e441a 100644 --- a/tools/perf/util/sample-raw.c +++ b/tools/perf/util/sample-raw.c @@ -9,7 +9,7 @@ * Check platform the perf data file was created on and perform platform * specific interpretation. */ -void perf_evlist__init_trace_event_sample_raw(struct perf_evlist *evlist) +void perf_evlist__init_trace_event_sample_raw(struct evlist *evlist) { const char *arch_pf = perf_env__arch(evlist->env); diff --git a/tools/perf/util/sample-raw.h b/tools/perf/util/sample-raw.h index 95d445c87e93..afe1491a117e 100644 --- a/tools/perf/util/sample-raw.h +++ b/tools/perf/util/sample-raw.h @@ -2,13 +2,13 @@ #ifndef __SAMPLE_RAW_H #define __SAMPLE_RAW_H 1 -struct perf_evlist; +struct evlist; union perf_event; struct perf_sample; -void perf_evlist__s390_sample_raw(struct perf_evlist *evlist, +void perf_evlist__s390_sample_raw(struct evlist *evlist, union perf_event *event, struct perf_sample *sample); -void perf_evlist__init_trace_event_sample_raw(struct perf_evlist *evlist); +void perf_evlist__init_trace_event_sample_raw(struct evlist *evlist); #endif /* __PERF_EVLIST_H */ diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c index 61aa7f3df915..15961854ba67 100644 --- a/tools/perf/util/scripting-engines/trace-event-perl.c +++ b/tools/perf/util/scripting-engines/trace-event-perl.c @@ -34,8 +34,8 @@ #include <EXTERN.h> #include <perl.h> -#include "../../perf.h" #include "../callchain.h" +#include "../dso.h" #include "../machine.h" #include "../map.h" #include "../symbol.h" @@ -258,7 +258,7 @@ static void define_event_symbols(struct tep_event *event, } static SV *perl_process_callchain(struct perf_sample *sample, - struct perf_evsel *evsel, + struct evsel *evsel, struct addr_location *al) { AV *list; @@ -336,7 +336,7 @@ exit: } static void perl_process_tracepoint(struct perf_sample *sample, - struct perf_evsel *evsel, + struct evsel *evsel, struct addr_location *al) { struct thread *thread = al->thread; @@ -353,11 +353,11 @@ static void perl_process_tracepoint(struct perf_sample *sample, dSP; - if (evsel->attr.type != PERF_TYPE_TRACEPOINT) + if (evsel->core.attr.type != PERF_TYPE_TRACEPOINT) return; if (!event) { - pr_debug("ug! no event found for type %" PRIu64, (u64)evsel->attr.config); + pr_debug("ug! no event found for type %" PRIu64, (u64)evsel->core.attr.config); return; } @@ -431,7 +431,7 @@ static void perl_process_tracepoint(struct perf_sample *sample, static void perl_process_event_generic(union perf_event *event, struct perf_sample *sample, - struct perf_evsel *evsel) + struct evsel *evsel) { dSP; @@ -442,7 +442,7 @@ static void perl_process_event_generic(union perf_event *event, SAVETMPS; PUSHMARK(SP); XPUSHs(sv_2mortal(newSVpvn((const char *)event, event->header.size))); - XPUSHs(sv_2mortal(newSVpvn((const char *)&evsel->attr, sizeof(evsel->attr)))); + XPUSHs(sv_2mortal(newSVpvn((const char *)&evsel->core.attr, sizeof(evsel->core.attr)))); XPUSHs(sv_2mortal(newSVpvn((const char *)sample, sizeof(*sample)))); XPUSHs(sv_2mortal(newSVpvn((const char *)sample->raw_data, sample->raw_size))); PUTBACK; @@ -455,7 +455,7 @@ static void perl_process_event_generic(union perf_event *event, static void perl_process_event(union perf_event *event, struct perf_sample *sample, - struct perf_evsel *evsel, + struct evsel *evsel, struct addr_location *al) { perl_process_tracepoint(sample, evsel, al); diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index 25dc1d765553..666a56e88d8e 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c @@ -31,8 +31,10 @@ #include <linux/compiler.h> #include <linux/time64.h> -#include "../../perf.h" +#include "../build-id.h" +#include "../counts.h" #include "../debug.h" +#include "../dso.h" #include "../callchain.h" #include "../evsel.h" #include "../util.h" @@ -392,7 +394,7 @@ static const char *get_dsoname(struct map *map) } static PyObject *python_process_callchain(struct perf_sample *sample, - struct perf_evsel *evsel, + struct evsel *evsel, struct addr_location *al) { PyObject *pylist; @@ -634,9 +636,9 @@ static PyObject *get_sample_value_as_tuple(struct sample_read_value *value) static void set_sample_read_in_dict(PyObject *dict_sample, struct perf_sample *sample, - struct perf_evsel *evsel) + struct evsel *evsel) { - u64 read_format = evsel->attr.read_format; + u64 read_format = evsel->core.attr.read_format; PyObject *values; unsigned int i; @@ -705,9 +707,9 @@ static int regs_map(struct regs_dump *regs, uint64_t mask, char *bf, int size) static void set_regs_in_dict(PyObject *dict, struct perf_sample *sample, - struct perf_evsel *evsel) + struct evsel *evsel) { - struct perf_event_attr *attr = &evsel->attr; + struct perf_event_attr *attr = &evsel->core.attr; char bf[512]; regs_map(&sample->intr_regs, attr->sample_regs_intr, bf, sizeof(bf)); @@ -722,7 +724,7 @@ static void set_regs_in_dict(PyObject *dict, } static PyObject *get_perf_sample_dict(struct perf_sample *sample, - struct perf_evsel *evsel, + struct evsel *evsel, struct addr_location *al, PyObject *callchain) { @@ -737,7 +739,7 @@ static PyObject *get_perf_sample_dict(struct perf_sample *sample, Py_FatalError("couldn't create Python dictionary"); pydict_set_item_string_decref(dict, "ev_name", _PyUnicode_FromString(perf_evsel__name(evsel))); - pydict_set_item_string_decref(dict, "attr", _PyBytes_FromStringAndSize((const char *)&evsel->attr, sizeof(evsel->attr))); + pydict_set_item_string_decref(dict, "attr", _PyBytes_FromStringAndSize((const char *)&evsel->core.attr, sizeof(evsel->core.attr))); pydict_set_item_string_decref(dict_sample, "pid", _PyLong_FromLong(sample->pid)); @@ -790,7 +792,7 @@ static PyObject *get_perf_sample_dict(struct perf_sample *sample, } static void python_process_tracepoint(struct perf_sample *sample, - struct perf_evsel *evsel, + struct evsel *evsel, struct addr_location *al) { struct tep_event *event = evsel->tp_format; @@ -809,7 +811,7 @@ static void python_process_tracepoint(struct perf_sample *sample, if (!event) { snprintf(handler_name, sizeof(handler_name), - "ug! no event found for type %" PRIu64, (u64)evsel->attr.config); + "ug! no event found for type %" PRIu64, (u64)evsel->core.attr.config); Py_FatalError(handler_name); } @@ -955,7 +957,7 @@ static int tuple_set_bytes(PyObject *t, unsigned int pos, void *bytes, return PyTuple_SetItem(t, pos, _PyBytes_FromStringAndSize(bytes, sz)); } -static int python_export_evsel(struct db_export *dbe, struct perf_evsel *evsel) +static int python_export_evsel(struct db_export *dbe, struct evsel *evsel) { struct tables *tables = container_of(dbe, struct tables, dbe); PyObject *t; @@ -1163,7 +1165,7 @@ static void python_export_synth(struct db_export *dbe, struct export_sample *es) t = tuple_new(3); tuple_set_u64(t, 0, es->db_id); - tuple_set_u64(t, 1, es->evsel->attr.config); + tuple_set_u64(t, 1, es->evsel->core.attr.config); tuple_set_bytes(t, 2, es->sample->raw_data, es->sample->raw_size); call_object(tables->synth_handler, t, "synth_data"); @@ -1178,7 +1180,7 @@ static int python_export_sample(struct db_export *dbe, python_export_sample_table(dbe, es); - if (es->evsel->attr.type == PERF_TYPE_SYNTH && tables->synth_handler) + if (es->evsel->core.attr.type == PERF_TYPE_SYNTH && tables->synth_handler) python_export_synth(dbe, es); return 0; @@ -1275,7 +1277,7 @@ static int python_process_call_return(struct call_return *cr, u64 *parent_db_id, } static void python_process_general_event(struct perf_sample *sample, - struct perf_evsel *evsel, + struct evsel *evsel, struct addr_location *al) { PyObject *handler, *t, *dict, *callchain; @@ -1311,12 +1313,12 @@ static void python_process_general_event(struct perf_sample *sample, static void python_process_event(union perf_event *event, struct perf_sample *sample, - struct perf_evsel *evsel, + struct evsel *evsel, struct addr_location *al) { struct tables *tables = &tables_global; - switch (evsel->attr.type) { + switch (evsel->core.attr.type) { case PERF_TYPE_TRACEPOINT: python_process_tracepoint(sample, evsel, al); break; @@ -1340,7 +1342,7 @@ static void python_process_switch(union perf_event *event, } static void get_handler_name(char *str, size_t size, - struct perf_evsel *evsel) + struct evsel *evsel) { char *p = str; @@ -1353,7 +1355,7 @@ static void get_handler_name(char *str, size_t size, } static void -process_stat(struct perf_evsel *counter, int cpu, int thread, u64 tstamp, +process_stat(struct evsel *counter, int cpu, int thread, u64 tstamp, struct perf_counts_values *count) { PyObject *handler, *t; @@ -1390,10 +1392,10 @@ process_stat(struct perf_evsel *counter, int cpu, int thread, u64 tstamp, } static void python_process_stat(struct perf_stat_config *config, - struct perf_evsel *counter, u64 tstamp) + struct evsel *counter, u64 tstamp) { - struct thread_map *threads = counter->threads; - struct cpu_map *cpus = counter->cpus; + struct perf_thread_map *threads = counter->core.threads; + struct perf_cpu_map *cpus = counter->core.cpus; int cpu, thread; if (config->aggr_mode == AGGR_GLOBAL) { @@ -1405,7 +1407,7 @@ static void python_process_stat(struct perf_stat_config *config, for (thread = 0; thread < threads->nr; thread++) { for (cpu = 0; cpu < cpus->nr; cpu++) { process_stat(counter, cpus->map[cpu], - thread_map__pid(threads, thread), tstamp, + perf_thread_map__pid(threads, thread), tstamp, perf_counts(counter->counts, cpu, thread)); } } diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 37efa1f43d8b..e9e4a04f15db 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -1,16 +1,20 @@ // SPDX-License-Identifier: GPL-2.0 #include <errno.h> #include <inttypes.h> +#include <linux/err.h> #include <linux/kernel.h> #include <linux/zalloc.h> -#include <traceevent/event-parse.h> #include <api/fs/fs.h> #include <byteswap.h> #include <unistd.h> #include <sys/types.h> #include <sys/mman.h> +#include <perf/cpumap.h> +#include "map_symbol.h" +#include "branch.h" +#include "debug.h" #include "evlist.h" #include "evsel.h" #include "memswap.h" @@ -18,7 +22,6 @@ #include "symbol.h" #include "session.h" #include "tool.h" -#include "sort.h" #include "cpumap.h" #include "perf_regs.h" #include "asm/bug.h" @@ -27,6 +30,9 @@ #include "thread-stack.h" #include "sample-raw.h" #include "stat.h" +#include "util.h" +#include "ui/progress.h" +#include "../perf.h" #include "arch/common.h" #ifdef HAVE_ZSTD_SUPPORT @@ -61,8 +67,8 @@ static int perf_session__process_compressed_event(struct perf_session *session, decomp->size = decomp_last_rem; } - src = (void *)event + sizeof(struct compressed_event); - src_size = event->pack.header.size - sizeof(struct compressed_event); + src = (void *)event + sizeof(struct perf_record_compressed); + src_size = event->pack.header.size - sizeof(struct perf_record_compressed); decomp_size = zstd_decompress_stream(&(session->zstd_data), src, src_size, &(decomp->data[decomp_last_rem]), decomp_len - decomp_last_rem); @@ -151,10 +157,10 @@ static void perf_session__destroy_kernel_maps(struct perf_session *session) static bool perf_session__has_comm_exec(struct perf_session *session) { - struct perf_evsel *evsel; + struct evsel *evsel; evlist__for_each_entry(session->evlist, evsel) { - if (evsel->attr.comm_exec) + if (evsel->core.attr.comm_exec) return true; } @@ -300,7 +306,7 @@ static int process_event_synth_tracing_data_stub(struct perf_session *session static int process_event_synth_attr_stub(struct perf_tool *tool __maybe_unused, union perf_event *event __maybe_unused, - struct perf_evlist **pevlist + struct evlist **pevlist __maybe_unused) { dump_printf(": unhandled!\n"); @@ -309,7 +315,7 @@ static int process_event_synth_attr_stub(struct perf_tool *tool __maybe_unused, static int process_event_synth_event_update_stub(struct perf_tool *tool __maybe_unused, union perf_event *event __maybe_unused, - struct perf_evlist **pevlist + struct evlist **pevlist __maybe_unused) { if (dump_trace) @@ -322,7 +328,7 @@ static int process_event_synth_event_update_stub(struct perf_tool *tool __maybe_ static int process_event_sample_stub(struct perf_tool *tool __maybe_unused, union perf_event *event __maybe_unused, struct perf_sample *sample __maybe_unused, - struct perf_evsel *evsel __maybe_unused, + struct evsel *evsel __maybe_unused, struct machine *machine __maybe_unused) { dump_printf(": unhandled!\n"); @@ -471,8 +477,8 @@ void perf_tool__fill_defaults(struct perf_tool *tool) tool->context_switch = perf_event__process_switch; if (tool->ksymbol == NULL) tool->ksymbol = perf_event__process_ksymbol; - if (tool->bpf_event == NULL) - tool->bpf_event = perf_event__process_bpf_event; + if (tool->bpf == NULL) + tool->bpf = perf_event__process_bpf; if (tool->read == NULL) tool->read = process_event_sample_stub; if (tool->throttle == NULL) @@ -833,9 +839,9 @@ static void perf_event__thread_map_swap(union perf_event *event, static void perf_event__cpu_map_swap(union perf_event *event, bool sample_id_all __maybe_unused) { - struct cpu_map_data *data = &event->cpu_map.data; + struct perf_record_cpu_map_data *data = &event->cpu_map.data; struct cpu_map_entries *cpus; - struct cpu_map_mask *mask; + struct perf_record_record_cpu_map *mask; unsigned i; data->type = bswap_64(data->type); @@ -850,7 +856,7 @@ static void perf_event__cpu_map_swap(union perf_event *event, cpus->cpu[i] = bswap_16(cpus->cpu[i]); break; case PERF_CPU_MAP__MASK: - mask = (struct cpu_map_mask *) data->data; + mask = (struct perf_record_record_cpu_map *)data->data; mask->nr = bswap_16(mask->nr); mask->long_size = bswap_16(mask->long_size); @@ -1033,7 +1039,7 @@ static void callchain__lbr_callstack_printf(struct perf_sample *sample) } } -static void callchain__printf(struct perf_evsel *evsel, +static void callchain__printf(struct evsel *evsel, struct perf_sample *sample) { unsigned int i; @@ -1049,23 +1055,30 @@ static void callchain__printf(struct perf_evsel *evsel, i, callchain->ips[i]); } -static void branch_stack__printf(struct perf_sample *sample) +static void branch_stack__printf(struct perf_sample *sample, bool callstack) { uint64_t i; - printf("... branch stack: nr:%" PRIu64 "\n", sample->branch_stack->nr); + printf("%s: nr:%" PRIu64 "\n", + !callstack ? "... branch stack" : "... branch callstack", + sample->branch_stack->nr); for (i = 0; i < sample->branch_stack->nr; i++) { struct branch_entry *e = &sample->branch_stack->entries[i]; - printf("..... %2"PRIu64": %016" PRIx64 " -> %016" PRIx64 " %hu cycles %s%s%s%s %x\n", - i, e->from, e->to, - (unsigned short)e->flags.cycles, - e->flags.mispred ? "M" : " ", - e->flags.predicted ? "P" : " ", - e->flags.abort ? "A" : " ", - e->flags.in_tx ? "T" : " ", - (unsigned)e->flags.reserved); + if (!callstack) { + printf("..... %2"PRIu64": %016" PRIx64 " -> %016" PRIx64 " %hu cycles %s%s%s%s %x\n", + i, e->from, e->to, + (unsigned short)e->flags.cycles, + e->flags.mispred ? "M" : " ", + e->flags.predicted ? "P" : " ", + e->flags.abort ? "A" : " ", + e->flags.in_tx ? "T" : " ", + (unsigned)e->flags.reserved); + } else { + printf("..... %2"PRIu64": %016" PRIx64 "\n", + i, i > 0 ? e->from : e->to); + } } } @@ -1129,7 +1142,7 @@ static void stack_user__printf(struct stack_dump *dump) dump->size, dump->offset); } -static void perf_evlist__print_tstamp(struct perf_evlist *evlist, +static void perf_evlist__print_tstamp(struct evlist *evlist, union perf_event *event, struct perf_sample *sample) { @@ -1178,7 +1191,7 @@ static void sample_read__printf(struct perf_sample *sample, u64 read_format) sample->read.one.id, sample->read.one.value); } -static void dump_event(struct perf_evlist *evlist, union perf_event *event, +static void dump_event(struct evlist *evlist, union perf_event *event, u64 file_offset, struct perf_sample *sample) { if (!dump_trace) @@ -1198,7 +1211,7 @@ static void dump_event(struct perf_evlist *evlist, union perf_event *event, event->header.size, perf_event__name(event->header.type)); } -static void dump_sample(struct perf_evsel *evsel, union perf_event *event, +static void dump_sample(struct evsel *evsel, union perf_event *event, struct perf_sample *sample) { u64 sample_type; @@ -1210,13 +1223,13 @@ static void dump_sample(struct perf_evsel *evsel, union perf_event *event, event->header.misc, sample->pid, sample->tid, sample->ip, sample->period, sample->addr); - sample_type = evsel->attr.sample_type; + sample_type = evsel->core.attr.sample_type; if (evsel__has_callchain(evsel)) callchain__printf(evsel, sample); - if ((sample_type & PERF_SAMPLE_BRANCH_STACK) && !perf_evsel__has_branch_callstack(evsel)) - branch_stack__printf(sample); + if (sample_type & PERF_SAMPLE_BRANCH_STACK) + branch_stack__printf(sample, perf_evsel__has_branch_callstack(evsel)); if (sample_type & PERF_SAMPLE_REGS_USER) regs_user__printf(sample); @@ -1240,34 +1253,34 @@ static void dump_sample(struct perf_evsel *evsel, union perf_event *event, printf("... transaction: %" PRIx64 "\n", sample->transaction); if (sample_type & PERF_SAMPLE_READ) - sample_read__printf(sample, evsel->attr.read_format); + sample_read__printf(sample, evsel->core.attr.read_format); } -static void dump_read(struct perf_evsel *evsel, union perf_event *event) +static void dump_read(struct evsel *evsel, union perf_event *event) { - struct read_event *read_event = &event->read; + struct perf_record_read *read_event = &event->read; u64 read_format; if (!dump_trace) return; - printf(": %d %d %s %" PRIu64 "\n", event->read.pid, event->read.tid, + printf(": %d %d %s %" PRI_lu64 "\n", event->read.pid, event->read.tid, perf_evsel__name(evsel), event->read.value); if (!evsel) return; - read_format = evsel->attr.read_format; + read_format = evsel->core.attr.read_format; if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) - printf("... time enabled : %" PRIu64 "\n", read_event->time_enabled); + printf("... time enabled : %" PRI_lu64 "\n", read_event->time_enabled); if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) - printf("... time running : %" PRIu64 "\n", read_event->time_running); + printf("... time running : %" PRI_lu64 "\n", read_event->time_running); if (read_format & PERF_FORMAT_ID) - printf("... id : %" PRIu64 "\n", read_event->id); + printf("... id : %" PRI_lu64 "\n", read_event->id); } static struct machine *machines__find_for_cpumode(struct machines *machines, @@ -1296,7 +1309,7 @@ static struct machine *machines__find_for_cpumode(struct machines *machines, return &machines->host; } -static int deliver_sample_value(struct perf_evlist *evlist, +static int deliver_sample_value(struct evlist *evlist, struct perf_tool *tool, union perf_event *event, struct perf_sample *sample, @@ -1326,7 +1339,7 @@ static int deliver_sample_value(struct perf_evlist *evlist, return tool->sample(tool, event, sample, sid->evsel, machine); } -static int deliver_sample_group(struct perf_evlist *evlist, +static int deliver_sample_group(struct evlist *evlist, struct perf_tool *tool, union perf_event *event, struct perf_sample *sample, @@ -1347,16 +1360,16 @@ static int deliver_sample_group(struct perf_evlist *evlist, } static int - perf_evlist__deliver_sample(struct perf_evlist *evlist, + perf_evlist__deliver_sample(struct evlist *evlist, struct perf_tool *tool, union perf_event *event, struct perf_sample *sample, - struct perf_evsel *evsel, + struct evsel *evsel, struct machine *machine) { /* We know evsel != NULL. */ - u64 sample_type = evsel->attr.sample_type; - u64 read_format = evsel->attr.read_format; + u64 sample_type = evsel->core.attr.sample_type; + u64 read_format = evsel->core.attr.read_format; /* Standard sample delivery. */ if (!(sample_type & PERF_SAMPLE_READ)) @@ -1372,12 +1385,12 @@ static int } static int machines__deliver_event(struct machines *machines, - struct perf_evlist *evlist, + struct evlist *evlist, union perf_event *event, struct perf_sample *sample, struct perf_tool *tool, u64 file_offset) { - struct perf_evsel *evsel; + struct evsel *evsel; struct machine *machine; dump_event(evlist, event, file_offset, sample); @@ -1443,7 +1456,7 @@ static int machines__deliver_event(struct machines *machines, case PERF_RECORD_KSYMBOL: return tool->ksymbol(tool, event, sample, machine); case PERF_RECORD_BPF_EVENT: - return tool->bpf_event(tool, event, sample, machine); + return tool->bpf(tool, event, sample, machine); default: ++evlist->stats.nr_unknown_events; return -1; @@ -1553,7 +1566,7 @@ int perf_session__deliver_synth_event(struct perf_session *session, union perf_event *event, struct perf_sample *sample) { - struct perf_evlist *evlist = session->evlist; + struct evlist *evlist = session->evlist; struct perf_tool *tool = session->tool; events_stats__inc(&evlist->stats, event->header.type); @@ -1631,7 +1644,7 @@ out_parse_sample: static s64 perf_session__process_event(struct perf_session *session, union perf_event *event, u64 file_offset) { - struct perf_evlist *evlist = session->evlist; + struct evlist *evlist = session->evlist; struct perf_tool *tool = session->tool; int ret; @@ -1705,11 +1718,11 @@ static void perf_session__warn_order(const struct perf_session *session) { const struct ordered_events *oe = &session->ordered_events; - struct perf_evsel *evsel; + struct evsel *evsel; bool should_warn = true; evlist__for_each_entry(session->evlist, evsel) { - if (evsel->attr.write_backward) + if (evsel->core.attr.write_backward) should_warn = false; } @@ -1954,7 +1967,9 @@ fetch_mmaped_event(struct perf_session *session, /* We're not fetching the event so swap back again */ if (session->header.needs_swap) perf_event_header__bswap(&event->header); - return NULL; + pr_debug("%s: head=%#" PRIx64 " event->header_size=%#x, mmap_size=%#zx: fuzzed perf.data?\n", + __func__, head, event->header.size, mmap_size); + return ERR_PTR(-EINVAL); } return event; @@ -1972,6 +1987,9 @@ static int __perf_session__process_decomp_events(struct perf_session *session) while (decomp->head < decomp->size && !session_done()) { union perf_event *event = fetch_mmaped_event(session, decomp->head, decomp->size, decomp->data); + if (IS_ERR(event)) + return PTR_ERR(event); + if (!event) break; @@ -2071,6 +2089,9 @@ remap: more: event = fetch_mmaped_event(session, head, mmap_size, buf); + if (IS_ERR(event)) + return PTR_ERR(event); + if (!event) { if (mmaps[map_idx]) { munmap(mmaps[map_idx], mmap_size); @@ -2183,10 +2204,10 @@ int perf_session__process_events(struct perf_session *session) bool perf_session__has_traces(struct perf_session *session, const char *msg) { - struct perf_evsel *evsel; + struct evsel *evsel; evlist__for_each_entry(session->evlist, evsel) { - if (evsel->attr.type == PERF_TYPE_TRACEPOINT) + if (evsel->core.attr.type == PERF_TYPE_TRACEPOINT) return true; } @@ -2257,13 +2278,13 @@ size_t perf_session__fprintf(struct perf_session *session, FILE *fp) return machine__fprintf(&session->machines.host, fp); } -struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, +struct evsel *perf_session__find_first_evtype(struct perf_session *session, unsigned int type) { - struct perf_evsel *pos; + struct evsel *pos; evlist__for_each_entry(session->evlist, pos) { - if (pos->attr.type == type) + if (pos->core.attr.type == type) return pos; } return NULL; @@ -2273,23 +2294,24 @@ int perf_session__cpu_bitmap(struct perf_session *session, const char *cpu_list, unsigned long *cpu_bitmap) { int i, err = -1; - struct cpu_map *map; + struct perf_cpu_map *map; + int nr_cpus = min(session->header.env.nr_cpus_online, MAX_NR_CPUS); for (i = 0; i < PERF_TYPE_MAX; ++i) { - struct perf_evsel *evsel; + struct evsel *evsel; evsel = perf_session__find_first_evtype(session, i); if (!evsel) continue; - if (!(evsel->attr.sample_type & PERF_SAMPLE_CPU)) { + if (!(evsel->core.attr.sample_type & PERF_SAMPLE_CPU)) { pr_err("File does not contain CPU events. " "Remove -C option to proceed.\n"); return -1; } } - map = cpu_map__new(cpu_list); + map = perf_cpu_map__new(cpu_list); if (map == NULL) { pr_err("Invalid cpu_list\n"); return -1; @@ -2298,7 +2320,7 @@ int perf_session__cpu_bitmap(struct perf_session *session, for (i = 0; i < map->nr; i++) { int cpu = map->map[i]; - if (cpu >= MAX_NR_CPUS) { + if (cpu >= nr_cpus) { pr_err("Requested CPU %d too large. " "Consider raising MAX_NR_CPUS\n", cpu); goto out_delete_map; @@ -2310,7 +2332,7 @@ int perf_session__cpu_bitmap(struct perf_session *session, err = 0; out_delete_map: - cpu_map__put(map); + perf_cpu_map__put(map); return err; } @@ -2327,10 +2349,10 @@ void perf_session__fprintf_info(struct perf_session *session, FILE *fp, int __perf_session__set_tracepoints_handlers(struct perf_session *session, - const struct perf_evsel_str_handler *assocs, + const struct evsel_str_handler *assocs, size_t nr_assocs) { - struct perf_evsel *evsel; + struct evsel *evsel; size_t i; int err; @@ -2357,11 +2379,11 @@ out: int perf_event__process_id_index(struct perf_session *session, union perf_event *event) { - struct perf_evlist *evlist = session->evlist; - struct id_index_event *ie = &event->id_index; + struct evlist *evlist = session->evlist; + struct perf_record_id_index *ie = &event->id_index; size_t i, nr, max_nr; - max_nr = (ie->header.size - sizeof(struct id_index_event)) / + max_nr = (ie->header.size - sizeof(struct perf_record_id_index)) / sizeof(struct id_index_entry); nr = ie->nr; if (nr > max_nr) @@ -2375,10 +2397,10 @@ int perf_event__process_id_index(struct perf_session *session, struct perf_sample_id *sid; if (dump_trace) { - fprintf(stdout, " ... id: %"PRIu64, e->id); - fprintf(stdout, " idx: %"PRIu64, e->idx); - fprintf(stdout, " cpu: %"PRId64, e->cpu); - fprintf(stdout, " tid: %"PRId64"\n", e->tid); + fprintf(stdout, " ... id: %"PRI_lu64, e->id); + fprintf(stdout, " idx: %"PRI_lu64, e->idx); + fprintf(stdout, " cpu: %"PRI_ld64, e->cpu); + fprintf(stdout, " tid: %"PRI_ld64"\n", e->tid); } sid = perf_evlist__id2sid(evlist, e->id); @@ -2393,24 +2415,24 @@ int perf_event__process_id_index(struct perf_session *session, int perf_event__synthesize_id_index(struct perf_tool *tool, perf_event__handler_t process, - struct perf_evlist *evlist, + struct evlist *evlist, struct machine *machine) { union perf_event *ev; - struct perf_evsel *evsel; + struct evsel *evsel; size_t nr = 0, i = 0, sz, max_nr, n; int err; pr_debug2("Synthesizing id index\n"); - max_nr = (UINT16_MAX - sizeof(struct id_index_event)) / + max_nr = (UINT16_MAX - sizeof(struct perf_record_id_index)) / sizeof(struct id_index_entry); evlist__for_each_entry(evlist, evsel) nr += evsel->ids; n = nr > max_nr ? max_nr : nr; - sz = sizeof(struct id_index_event) + n * sizeof(struct id_index_entry); + sz = sizeof(struct perf_record_id_index) + n * sizeof(struct id_index_entry); ev = zalloc(sz); if (!ev) return -ENOMEM; @@ -2450,7 +2472,7 @@ int perf_event__synthesize_id_index(struct perf_tool *tool, } } - sz = sizeof(struct id_index_event) + nr * sizeof(struct id_index_entry); + sz = sizeof(struct perf_record_id_index) + nr * sizeof(struct id_index_entry); ev->id_index.header.size = sz; ev->id_index.nr = nr; diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index 863dbad87849..b7aa076ab6fd 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h @@ -23,12 +23,12 @@ struct itrace_synth_opts; struct perf_session { struct perf_header header; struct machines machines; - struct perf_evlist *evlist; + struct evlist *evlist; struct auxtrace *auxtrace; struct itrace_synth_opts *itrace_synth_opts; struct list_head auxtrace_index; struct trace_event tevent; - struct time_conv_event time_conv; + struct perf_record_time_conv time_conv; bool repipe; bool one_mmap; void *one_mmap_addr; @@ -73,7 +73,7 @@ int perf_session__queue_event(struct perf_session *s, union perf_event *event, void perf_tool__fill_defaults(struct perf_tool *tool); int perf_session__resolve_callchain(struct perf_session *session, - struct perf_evsel *evsel, + struct evsel *evsel, struct thread *thread, struct ip_callchain *chain, struct symbol **parent); @@ -110,7 +110,7 @@ size_t perf_session__fprintf_dsos_buildid(struct perf_session *session, FILE *fp size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp); -struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, +struct evsel *perf_session__find_first_evtype(struct perf_session *session, unsigned int type); int perf_session__cpu_bitmap(struct perf_session *session, @@ -118,10 +118,10 @@ int perf_session__cpu_bitmap(struct perf_session *session, void perf_session__fprintf_info(struct perf_session *s, FILE *fp, bool full); -struct perf_evsel_str_handler; +struct evsel_str_handler; int __perf_session__set_tracepoints_handlers(struct perf_session *session, - const struct perf_evsel_str_handler *assocs, + const struct evsel_str_handler *assocs, size_t nr_assocs); #define perf_session__set_tracepoints_handlers(session, array) \ @@ -140,7 +140,7 @@ int perf_event__process_id_index(struct perf_session *session, int perf_event__synthesize_id_index(struct perf_tool *tool, perf_event__handler_t process, - struct perf_evlist *evlist, + struct evlist *evlist, struct machine *machine); #endif /* __PERF_SESSION_H */ diff --git a/tools/perf/util/setup.py b/tools/perf/util/setup.py index a1a68a2fa917..aa344a163eaf 100644 --- a/tools/perf/util/setup.py +++ b/tools/perf/util/setup.py @@ -48,6 +48,7 @@ build_lib = getenv('PYTHON_EXTBUILD_LIB') build_tmp = getenv('PYTHON_EXTBUILD_TMP') libtraceevent = getenv('LIBTRACEEVENT') libapikfs = getenv('LIBAPI') +libperf = getenv('LIBPERF') ext_sources = [f.strip() for f in open('util/python-ext-sources') if len(f.strip()) > 0 and f[0] != '#'] @@ -58,13 +59,15 @@ ext_sources = list(map(lambda x: '%s/%s' % (src_perf, x) , ext_sources)) extra_libraries = [] if '-DHAVE_LIBNUMA_SUPPORT' in cflags: extra_libraries = [ 'numa' ] +if '-DHAVE_LIBCAP_SUPPORT' in cflags: + extra_libraries += [ 'cap' ] perf = Extension('perf', sources = ext_sources, include_dirs = ['util/include'], libraries = extra_libraries, extra_compile_args = cflags, - extra_objects = [libtraceevent, libapikfs], + extra_objects = [libtraceevent, libapikfs, libperf], ) setup(name='perf', diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index 5d2518e89fc4..a2308eb77681 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c @@ -2,16 +2,23 @@ #include <errno.h> #include <inttypes.h> #include <regex.h> +#include <stdlib.h> #include <linux/mman.h> #include <linux/time64.h> +#include "debug.h" +#include "dso.h" #include "sort.h" #include "hist.h" +#include "cacheline.h" #include "comm.h" #include "map.h" #include "symbol.h" +#include "map_symbol.h" +#include "branch.h" #include "thread.h" #include "evsel.h" #include "evlist.h" +#include "srcline.h" #include "strlist.h" #include "strbuf.h" #include <traceevent/event-parse.h> @@ -19,6 +26,7 @@ #include "annotate.h" #include "time-utils.h" #include <linux/kernel.h> +#include <linux/string.h> regex_t parent_regex; const char default_parent_pattern[] = "^sys_|^do_page_fault"; @@ -668,17 +676,11 @@ sort__time_cmp(struct hist_entry *left, struct hist_entry *right) static int hist_entry__time_snprintf(struct hist_entry *he, char *bf, size_t size, unsigned int width) { - unsigned long secs; - unsigned long long nsecs; char he_time[32]; - nsecs = he->time; - secs = nsecs / NSEC_PER_SEC; - nsecs -= secs * NSEC_PER_SEC; - if (symbol_conf.nanosecs) - snprintf(he_time, sizeof he_time, "%5lu.%09llu: ", - secs, nsecs); + timestamp__scnprintf_nsec(he->time, he_time, + sizeof(he_time)); else timestamp__scnprintf_usec(he->time, he_time, sizeof(he_time)); @@ -698,7 +700,7 @@ struct sort_entry sort_time = { static char *get_trace_output(struct hist_entry *he) { struct trace_seq seq; - struct perf_evsel *evsel; + struct evsel *evsel; struct tep_record rec = { .data = he->raw_data, .size = he->raw_size, @@ -711,7 +713,8 @@ static char *get_trace_output(struct hist_entry *he) tep_print_fields(&seq, he->raw_data, he->raw_size, evsel->tp_format); } else { - tep_event_info(&seq, evsel->tp_format, &rec); + tep_print_event(evsel->tp_format->tep, + &seq, &rec, "%s", TEP_PRINT_INFO); } /* * Trim the buffer, it starts at 4KB and we're not going to @@ -723,10 +726,10 @@ static char *get_trace_output(struct hist_entry *he) static int64_t sort__trace_cmp(struct hist_entry *left, struct hist_entry *right) { - struct perf_evsel *evsel; + struct evsel *evsel; evsel = hists_to_evsel(left->hists); - if (evsel->attr.type != PERF_TYPE_TRACEPOINT) + if (evsel->core.attr.type != PERF_TYPE_TRACEPOINT) return 0; if (left->trace_output == NULL) @@ -740,10 +743,10 @@ sort__trace_cmp(struct hist_entry *left, struct hist_entry *right) static int hist_entry__trace_snprintf(struct hist_entry *he, char *bf, size_t size, unsigned int width) { - struct perf_evsel *evsel; + struct evsel *evsel; evsel = hists_to_evsel(he->hists); - if (evsel->attr.type != PERF_TYPE_TRACEPOINT) + if (evsel->core.attr.type != PERF_TYPE_TRACEPOINT) return scnprintf(bf, size, "%-.*s", width, "N/A"); if (he->trace_output == NULL) @@ -1984,7 +1987,7 @@ static int __sort_dimension__add_hpp_output(struct sort_dimension *sd, struct hpp_dynamic_entry { struct perf_hpp_fmt hpp; - struct perf_evsel *evsel; + struct evsel *evsel; struct tep_format_field *field; unsigned dynamic_len; bool raw_trace; @@ -2218,7 +2221,7 @@ static void hde_free(struct perf_hpp_fmt *fmt) } static struct hpp_dynamic_entry * -__alloc_dynamic_entry(struct perf_evsel *evsel, struct tep_format_field *field, +__alloc_dynamic_entry(struct evsel *evsel, struct tep_format_field *field, int level) { struct hpp_dynamic_entry *hde; @@ -2313,17 +2316,17 @@ static int parse_field_name(char *str, char **event, char **field, char **opt) * 2. full event name (e.g. sched:sched_switch) * 3. partial event name (should not contain ':') */ -static struct perf_evsel *find_evsel(struct perf_evlist *evlist, char *event_name) +static struct evsel *find_evsel(struct evlist *evlist, char *event_name) { - struct perf_evsel *evsel = NULL; - struct perf_evsel *pos; + struct evsel *evsel = NULL; + struct evsel *pos; bool full_name; /* case 1 */ if (event_name[0] == '%') { int nr = strtol(event_name+1, NULL, 0); - if (nr > evlist->nr_entries) + if (nr > evlist->core.nr_entries) return NULL; evsel = perf_evlist__first(evlist); @@ -2352,7 +2355,7 @@ static struct perf_evsel *find_evsel(struct perf_evlist *evlist, char *event_nam return evsel; } -static int __dynamic_dimension__add(struct perf_evsel *evsel, +static int __dynamic_dimension__add(struct evsel *evsel, struct tep_format_field *field, bool raw_trace, int level) { @@ -2368,7 +2371,7 @@ static int __dynamic_dimension__add(struct perf_evsel *evsel, return 0; } -static int add_evsel_fields(struct perf_evsel *evsel, bool raw_trace, int level) +static int add_evsel_fields(struct evsel *evsel, bool raw_trace, int level) { int ret; struct tep_format_field *field; @@ -2384,14 +2387,14 @@ static int add_evsel_fields(struct perf_evsel *evsel, bool raw_trace, int level) return 0; } -static int add_all_dynamic_fields(struct perf_evlist *evlist, bool raw_trace, +static int add_all_dynamic_fields(struct evlist *evlist, bool raw_trace, int level) { int ret; - struct perf_evsel *evsel; + struct evsel *evsel; evlist__for_each_entry(evlist, evsel) { - if (evsel->attr.type != PERF_TYPE_TRACEPOINT) + if (evsel->core.attr.type != PERF_TYPE_TRACEPOINT) continue; ret = add_evsel_fields(evsel, raw_trace, level); @@ -2401,15 +2404,15 @@ static int add_all_dynamic_fields(struct perf_evlist *evlist, bool raw_trace, return 0; } -static int add_all_matching_fields(struct perf_evlist *evlist, +static int add_all_matching_fields(struct evlist *evlist, char *field_name, bool raw_trace, int level) { int ret = -ESRCH; - struct perf_evsel *evsel; + struct evsel *evsel; struct tep_format_field *field; evlist__for_each_entry(evlist, evsel) { - if (evsel->attr.type != PERF_TYPE_TRACEPOINT) + if (evsel->core.attr.type != PERF_TYPE_TRACEPOINT) continue; field = tep_find_any_field(evsel->tp_format, field_name); @@ -2423,11 +2426,11 @@ static int add_all_matching_fields(struct perf_evlist *evlist, return ret; } -static int add_dynamic_entry(struct perf_evlist *evlist, const char *tok, +static int add_dynamic_entry(struct evlist *evlist, const char *tok, int level) { char *str, *event_name, *field_name, *opt_name; - struct perf_evsel *evsel; + struct evsel *evsel; struct tep_format_field *field; bool raw_trace = symbol_conf.raw_trace; int ret = 0; @@ -2470,7 +2473,7 @@ static int add_dynamic_entry(struct perf_evlist *evlist, const char *tok, goto out; } - if (evsel->attr.type != PERF_TYPE_TRACEPOINT) { + if (evsel->core.attr.type != PERF_TYPE_TRACEPOINT) { pr_debug("%s is not a tracepoint event\n", event_name); ret = -EINVAL; goto out; @@ -2567,7 +2570,7 @@ int hpp_dimension__add_output(unsigned col) } int sort_dimension__add(struct perf_hpp_list *list, const char *tok, - struct perf_evlist *evlist, + struct evlist *evlist, int level) { unsigned int i; @@ -2663,7 +2666,7 @@ int sort_dimension__add(struct perf_hpp_list *list, const char *tok, } static int setup_sort_list(struct perf_hpp_list *list, char *str, - struct perf_evlist *evlist) + struct evlist *evlist) { char *tmp, *tok; int ret = 0; @@ -2709,7 +2712,7 @@ static int setup_sort_list(struct perf_hpp_list *list, char *str, return ret; } -static const char *get_default_sort_order(struct perf_evlist *evlist) +static const char *get_default_sort_order(struct evlist *evlist) { const char *default_sort_orders[] = { default_sort_order, @@ -2720,7 +2723,7 @@ static const char *get_default_sort_order(struct perf_evlist *evlist) default_tracepoint_sort_order, }; bool use_trace = true; - struct perf_evsel *evsel; + struct evsel *evsel; BUG_ON(sort__mode >= ARRAY_SIZE(default_sort_orders)); @@ -2728,7 +2731,7 @@ static const char *get_default_sort_order(struct perf_evlist *evlist) goto out_no_evlist; evlist__for_each_entry(evlist, evsel) { - if (evsel->attr.type != PERF_TYPE_TRACEPOINT) { + if (evsel->core.attr.type != PERF_TYPE_TRACEPOINT) { use_trace = false; break; } @@ -2743,7 +2746,7 @@ out_no_evlist: return default_sort_orders[sort__mode]; } -static int setup_sort_order(struct perf_evlist *evlist) +static int setup_sort_order(struct evlist *evlist) { char *new_sort_order; @@ -2804,7 +2807,7 @@ static char *setup_overhead(char *keys) return keys; } -static int __setup_sorting(struct perf_evlist *evlist) +static int __setup_sorting(struct evlist *evlist) { char *str; const char *sort_keys; @@ -3057,7 +3060,7 @@ out: return ret; } -int setup_sorting(struct perf_evlist *evlist) +int setup_sorting(struct evlist *evlist) { int err; diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h index a0f232151d6f..7b93f34ac1f4 100644 --- a/tools/perf/util/sort.h +++ b/tools/perf/util/sort.h @@ -1,29 +1,17 @@ /* SPDX-License-Identifier: GPL-2.0 */ #ifndef __PERF_SORT_H #define __PERF_SORT_H -#include "../builtin.h" - #include <regex.h> - -#include "color.h" +#include <stdbool.h> #include <linux/list.h> -#include "cache.h" #include <linux/rbtree.h> #include "map_symbol.h" #include "symbol_conf.h" -#include "string.h" #include "callchain.h" #include "values.h" - -#include "../perf.h" -#include "debug.h" -#include "header.h" - -#include <subcmd/parse-options.h> -#include "parse-events.h" #include "hist.h" -#include "srcline.h" +struct option; struct thread; extern regex_t parent_regex; @@ -204,18 +192,6 @@ static inline float hist_entry__get_percent_limit(struct hist_entry *he) return period * 100.0 / total_period; } -static inline u64 cl_address(u64 address) -{ - /* return the cacheline of the address */ - return (address & ~(cacheline_size() - 1)); -} - -static inline u64 cl_offset(u64 address) -{ - /* return the cacheline of the address */ - return (address & (cacheline_size() - 1)); -} - enum sort_mode { SORT_MODE__NORMAL, SORT_MODE__BRANCH, @@ -301,9 +277,9 @@ struct block_hist { extern struct sort_entry sort_thread; extern struct list_head hist_entry__sort_list; -struct perf_evlist; +struct evlist; struct tep_handle; -int setup_sorting(struct perf_evlist *evlist); +int setup_sorting(struct evlist *evlist); int setup_output_field(void); void reset_output_field(void); void sort__setup_elide(FILE *fp); @@ -318,7 +294,7 @@ bool is_strict_order(const char *order); int hpp_dimension__add_output(unsigned col); void reset_dimensions(void); int sort_dimension__add(struct perf_hpp_list *list, const char *tok, - struct perf_evlist *evlist, + struct evlist *evlist, int level); int output_field_add(struct perf_hpp_list *list, char *tok); int64_t diff --git a/tools/perf/util/stat-display.c b/tools/perf/util/stat-display.c index 58df6a0dbb9f..ed3b0ac2f785 100644 --- a/tools/perf/util/stat-display.c +++ b/tools/perf/util/stat-display.c @@ -1,9 +1,11 @@ +#include <stdlib.h> #include <stdio.h> #include <inttypes.h> #include <linux/string.h> #include <linux/time64.h> #include <math.h> #include "color.h" +#include "counts.h" #include "evlist.h" #include "evsel.h" #include "stat.h" @@ -13,7 +15,6 @@ #include "string2.h" #include <linux/ctype.h> #include "cgroup.h" -#include <math.h> #include <api/fs/fs.h> #define CNTR_NOT_SUPPORTED "<not supported>" @@ -45,7 +46,7 @@ static void print_noise_pct(struct perf_stat_config *config, } static void print_noise(struct perf_stat_config *config, - struct perf_evsel *evsel, double avg) + struct evsel *evsel, double avg) { struct perf_stat_evsel *ps; @@ -56,7 +57,7 @@ static void print_noise(struct perf_stat_config *config, print_noise_pct(config, stddev_stats(&ps->res_stats[0]), avg); } -static void print_cgroup(struct perf_stat_config *config, struct perf_evsel *evsel) +static void print_cgroup(struct perf_stat_config *config, struct evsel *evsel) { if (nr_cgroups) { const char *cgrp_name = evsel->cgrp ? evsel->cgrp->name : ""; @@ -66,7 +67,7 @@ static void print_cgroup(struct perf_stat_config *config, struct perf_evsel *evs static void aggr_printout(struct perf_stat_config *config, - struct perf_evsel *evsel, int id, int nr) + struct evsel *evsel, int id, int nr) { switch (config->aggr_mode) { case AGGR_CORE: @@ -109,16 +110,16 @@ static void aggr_printout(struct perf_stat_config *config, } else { fprintf(config->output, "CPU%*d%s ", config->csv_output ? 0 : -5, - perf_evsel__cpus(evsel)->map[id], + evsel__cpus(evsel)->map[id], config->csv_sep); } break; case AGGR_THREAD: fprintf(config->output, "%*s-%*d%s", config->csv_output ? 0 : 16, - thread_map__comm(evsel->threads, id), + perf_thread_map__comm(evsel->core.threads, id), config->csv_output ? 0 : -8, - thread_map__pid(evsel->threads, id), + perf_thread_map__pid(evsel->core.threads, id), config->csv_sep); break; case AGGR_GLOBAL: @@ -134,7 +135,7 @@ struct outstate { const char *prefix; int nfields; int id, nr; - struct perf_evsel *evsel; + struct evsel *evsel; }; #define METRIC_LEN 35 @@ -233,7 +234,7 @@ static bool valid_only_metric(const char *unit) return true; } -static const char *fixunit(char *buf, struct perf_evsel *evsel, +static const char *fixunit(char *buf, struct evsel *evsel, const char *unit) { if (!strncmp(unit, "of all", 6)) { @@ -310,9 +311,9 @@ static void print_metric_header(struct perf_stat_config *config, } static int first_shadow_cpu(struct perf_stat_config *config, - struct perf_evsel *evsel, int id) + struct evsel *evsel, int id) { - struct perf_evlist *evlist = evsel->evlist; + struct evlist *evlist = evsel->evlist; int i; if (!config->aggr_get_id) @@ -325,16 +326,16 @@ static int first_shadow_cpu(struct perf_stat_config *config, return 0; for (i = 0; i < perf_evsel__nr_cpus(evsel); i++) { - int cpu2 = perf_evsel__cpus(evsel)->map[i]; + int cpu2 = evsel__cpus(evsel)->map[i]; - if (config->aggr_get_id(config, evlist->cpus, cpu2) == id) + if (config->aggr_get_id(config, evlist->core.cpus, cpu2) == id) return cpu2; } return 0; } static void abs_printout(struct perf_stat_config *config, - int id, int nr, struct perf_evsel *evsel, double avg) + int id, int nr, struct evsel *evsel, double avg) { FILE *output = config->output; double sc = evsel->scale; @@ -363,24 +364,24 @@ static void abs_printout(struct perf_stat_config *config, print_cgroup(config, evsel); } -static bool is_mixed_hw_group(struct perf_evsel *counter) +static bool is_mixed_hw_group(struct evsel *counter) { - struct perf_evlist *evlist = counter->evlist; - u32 pmu_type = counter->attr.type; - struct perf_evsel *pos; + struct evlist *evlist = counter->evlist; + u32 pmu_type = counter->core.attr.type; + struct evsel *pos; - if (counter->nr_members < 2) + if (counter->core.nr_members < 2) return false; evlist__for_each_entry(evlist, pos) { /* software events can be part of any hardware group */ - if (pos->attr.type == PERF_TYPE_SOFTWARE) + if (pos->core.attr.type == PERF_TYPE_SOFTWARE) continue; if (pmu_type == PERF_TYPE_SOFTWARE) { - pmu_type = pos->attr.type; + pmu_type = pos->core.attr.type; continue; } - if (pmu_type != pos->attr.type) + if (pmu_type != pos->core.attr.type) return true; } @@ -388,7 +389,7 @@ static bool is_mixed_hw_group(struct perf_evsel *counter) } static void printout(struct perf_stat_config *config, int id, int nr, - struct perf_evsel *counter, double uval, + struct evsel *counter, double uval, char *prefix, u64 run, u64 ena, double noise, struct runtime_stat *st) { @@ -489,18 +490,18 @@ static void printout(struct perf_stat_config *config, int id, int nr, } static void aggr_update_shadow(struct perf_stat_config *config, - struct perf_evlist *evlist) + struct evlist *evlist) { int cpu, s2, id, s; u64 val; - struct perf_evsel *counter; + struct evsel *counter; for (s = 0; s < config->aggr_map->nr; s++) { id = config->aggr_map->map[s]; evlist__for_each_entry(evlist, counter) { val = 0; for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) { - s2 = config->aggr_get_id(config, evlist->cpus, cpu); + s2 = config->aggr_get_id(config, evlist->core.cpus, cpu); if (s2 != id) continue; val += perf_counts(counter->counts, cpu, 0)->val; @@ -512,7 +513,7 @@ static void aggr_update_shadow(struct perf_stat_config *config, } } -static void uniquify_event_name(struct perf_evsel *counter) +static void uniquify_event_name(struct evsel *counter) { char *new_name; char *config; @@ -540,16 +541,16 @@ static void uniquify_event_name(struct perf_evsel *counter) counter->uniquified_name = true; } -static void collect_all_aliases(struct perf_stat_config *config, struct perf_evsel *counter, - void (*cb)(struct perf_stat_config *config, struct perf_evsel *counter, void *data, +static void collect_all_aliases(struct perf_stat_config *config, struct evsel *counter, + void (*cb)(struct perf_stat_config *config, struct evsel *counter, void *data, bool first), void *data) { - struct perf_evlist *evlist = counter->evlist; - struct perf_evsel *alias; + struct evlist *evlist = counter->evlist; + struct evsel *alias; - alias = list_prepare_entry(counter, &(evlist->entries), node); - list_for_each_entry_continue (alias, &evlist->entries, node) { + alias = list_prepare_entry(counter, &(evlist->core.entries), core.node); + list_for_each_entry_continue (alias, &evlist->core.entries, core.node) { if (strcmp(perf_evsel__name(alias), perf_evsel__name(counter)) || alias->scale != counter->scale || alias->cgrp != counter->cgrp || @@ -562,8 +563,8 @@ static void collect_all_aliases(struct perf_stat_config *config, struct perf_evs } } -static bool collect_data(struct perf_stat_config *config, struct perf_evsel *counter, - void (*cb)(struct perf_stat_config *config, struct perf_evsel *counter, void *data, +static bool collect_data(struct perf_stat_config *config, struct evsel *counter, + void (*cb)(struct perf_stat_config *config, struct evsel *counter, void *data, bool first), void *data) { @@ -585,7 +586,7 @@ struct aggr_data { }; static void aggr_cb(struct perf_stat_config *config, - struct perf_evsel *counter, void *data, bool first) + struct evsel *counter, void *data, bool first) { struct aggr_data *ad = data; int cpu, s2; @@ -593,7 +594,7 @@ static void aggr_cb(struct perf_stat_config *config, for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) { struct perf_counts_values *counts; - s2 = config->aggr_get_id(config, perf_evsel__cpus(counter), cpu); + s2 = config->aggr_get_id(config, evsel__cpus(counter), cpu); if (s2 != ad->id) continue; if (first) @@ -616,7 +617,7 @@ static void aggr_cb(struct perf_stat_config *config, } static void print_counter_aggrdata(struct perf_stat_config *config, - struct perf_evsel *counter, int s, + struct evsel *counter, int s, char *prefix, bool metric_only, bool *first) { @@ -651,12 +652,12 @@ static void print_counter_aggrdata(struct perf_stat_config *config, } static void print_aggr(struct perf_stat_config *config, - struct perf_evlist *evlist, + struct evlist *evlist, char *prefix) { bool metric_only = config->metric_only; FILE *output = config->output; - struct perf_evsel *counter; + struct evsel *counter; int s; bool first; @@ -691,7 +692,7 @@ static int cmp_val(const void *a, const void *b) } static struct perf_aggr_thread_value *sort_aggr_thread( - struct perf_evsel *counter, + struct evsel *counter, int nthreads, int ncpus, int *ret, struct target *_target) @@ -741,11 +742,11 @@ static struct perf_aggr_thread_value *sort_aggr_thread( static void print_aggr_thread(struct perf_stat_config *config, struct target *_target, - struct perf_evsel *counter, char *prefix) + struct evsel *counter, char *prefix) { FILE *output = config->output; - int nthreads = thread_map__nr(counter->threads); - int ncpus = cpu_map__nr(counter->cpus); + int nthreads = perf_thread_map__nr(counter->core.threads); + int ncpus = perf_cpu_map__nr(counter->core.cpus); int thread, sorted_threads, id; struct perf_aggr_thread_value *buf; @@ -779,7 +780,7 @@ struct caggr_data { }; static void counter_aggr_cb(struct perf_stat_config *config __maybe_unused, - struct perf_evsel *counter, void *data, + struct evsel *counter, void *data, bool first __maybe_unused) { struct caggr_data *cd = data; @@ -795,7 +796,7 @@ static void counter_aggr_cb(struct perf_stat_config *config __maybe_unused, * aggregated counts in system-wide mode */ static void print_counter_aggr(struct perf_stat_config *config, - struct perf_evsel *counter, char *prefix) + struct evsel *counter, char *prefix) { bool metric_only = config->metric_only; FILE *output = config->output; @@ -816,7 +817,7 @@ static void print_counter_aggr(struct perf_stat_config *config, } static void counter_cb(struct perf_stat_config *config __maybe_unused, - struct perf_evsel *counter, void *data, + struct evsel *counter, void *data, bool first __maybe_unused) { struct aggr_data *ad = data; @@ -831,7 +832,7 @@ static void counter_cb(struct perf_stat_config *config __maybe_unused, * does not use aggregated count in system-wide */ static void print_counter(struct perf_stat_config *config, - struct perf_evsel *counter, char *prefix) + struct evsel *counter, char *prefix) { FILE *output = config->output; u64 ena, run, val; @@ -859,16 +860,16 @@ static void print_counter(struct perf_stat_config *config, } static void print_no_aggr_metric(struct perf_stat_config *config, - struct perf_evlist *evlist, + struct evlist *evlist, char *prefix) { int cpu; int nrcpus = 0; - struct perf_evsel *counter; + struct evsel *counter; u64 ena, run, val; double uval; - nrcpus = evlist->cpus->nr; + nrcpus = evlist->core.cpus->nr; for (cpu = 0; cpu < nrcpus; cpu++) { bool first = true; @@ -910,11 +911,11 @@ static const char *aggr_header_csv[] = { }; static void print_metric_headers(struct perf_stat_config *config, - struct perf_evlist *evlist, + struct evlist *evlist, const char *prefix, bool no_indent) { struct perf_stat_output_ctx out; - struct perf_evsel *counter; + struct evsel *counter; struct outstate os = { .fh = config->output }; @@ -949,7 +950,7 @@ static void print_metric_headers(struct perf_stat_config *config, } static void print_interval(struct perf_stat_config *config, - struct perf_evlist *evlist, + struct evlist *evlist, char *prefix, struct timespec *ts) { bool metric_only = config->metric_only; @@ -1132,7 +1133,7 @@ static void print_footer(struct perf_stat_config *config) } static void print_percore(struct perf_stat_config *config, - struct perf_evsel *counter, char *prefix) + struct evsel *counter, char *prefix) { bool metric_only = config->metric_only; FILE *output = config->output; @@ -1156,7 +1157,7 @@ static void print_percore(struct perf_stat_config *config, } void -perf_evlist__print_counters(struct perf_evlist *evlist, +perf_evlist__print_counters(struct evlist *evlist, struct perf_stat_config *config, struct target *_target, struct timespec *ts, @@ -1164,7 +1165,7 @@ perf_evlist__print_counters(struct perf_evlist *evlist, { bool metric_only = config->metric_only; int interval = config->interval; - struct perf_evsel *counter; + struct evsel *counter; char buf[64], *prefix = NULL; if (interval) diff --git a/tools/perf/util/stat-shadow.c b/tools/perf/util/stat-shadow.c index accb1bf1cfd8..70c87fdb2a43 100644 --- a/tools/perf/util/stat-shadow.c +++ b/tools/perf/util/stat-shadow.c @@ -25,12 +25,14 @@ struct stats walltime_nsecs_stats; struct saved_value { struct rb_node rb_node; - struct perf_evsel *evsel; + struct evsel *evsel; enum stat_type type; int ctx; int cpu; struct runtime_stat *stat; struct stats stats; + u64 metric_total; + int metric_other; }; static int saved_value_cmp(struct rb_node *rb_node, const void *entry) @@ -94,7 +96,7 @@ static void saved_value_delete(struct rblist *rblist __maybe_unused, free(v); } -static struct saved_value *saved_value_lookup(struct perf_evsel *evsel, +static struct saved_value *saved_value_lookup(struct evsel *evsel, int cpu, bool create, enum stat_type type, @@ -146,19 +148,19 @@ void perf_stat__init_shadow_stats(void) runtime_stat__init(&rt_stat); } -static int evsel_context(struct perf_evsel *evsel) +static int evsel_context(struct evsel *evsel) { int ctx = 0; - if (evsel->attr.exclude_kernel) + if (evsel->core.attr.exclude_kernel) ctx |= CTX_BIT_KERNEL; - if (evsel->attr.exclude_user) + if (evsel->core.attr.exclude_user) ctx |= CTX_BIT_USER; - if (evsel->attr.exclude_hv) + if (evsel->core.attr.exclude_hv) ctx |= CTX_BIT_HV; - if (evsel->attr.exclude_host) + if (evsel->core.attr.exclude_host) ctx |= CTX_BIT_HOST; - if (evsel->attr.exclude_idle) + if (evsel->core.attr.exclude_idle) ctx |= CTX_BIT_IDLE; return ctx; @@ -207,11 +209,12 @@ static void update_runtime_stat(struct runtime_stat *st, * more semantic information such as miss/hit ratios, * instruction rates, etc: */ -void perf_stat__update_shadow_stats(struct perf_evsel *counter, u64 count, +void perf_stat__update_shadow_stats(struct evsel *counter, u64 count, int cpu, struct runtime_stat *st) { int ctx = evsel_context(counter); u64 count_ns = count; + struct saved_value *v; count *= counter->scale; @@ -266,9 +269,15 @@ void perf_stat__update_shadow_stats(struct perf_evsel *counter, u64 count, update_runtime_stat(st, STAT_APERF, ctx, cpu, count); if (counter->collect_stat) { - struct saved_value *v = saved_value_lookup(counter, cpu, true, - STAT_NONE, 0, st); + v = saved_value_lookup(counter, cpu, true, STAT_NONE, 0, st); update_stats(&v->stats, count); + if (counter->metric_leader) + v->metric_total += count; + } else if (counter->metric_leader) { + v = saved_value_lookup(counter->metric_leader, + cpu, true, STAT_NONE, 0, st); + v->metric_total += count; + v->metric_other++; } } @@ -299,10 +308,10 @@ static const char *get_ratio_color(enum grc_type type, double ratio) return color; } -static struct perf_evsel *perf_stat__find_event(struct perf_evlist *evsel_list, +static struct evsel *perf_stat__find_event(struct evlist *evsel_list, const char *name) { - struct perf_evsel *c2; + struct evsel *c2; evlist__for_each_entry (evsel_list, c2) { if (!strcasecmp(c2->name, name) && !c2->collect_stat) @@ -312,9 +321,9 @@ static struct perf_evsel *perf_stat__find_event(struct perf_evlist *evsel_list, } /* Mark MetricExpr target events and link events using them to them. */ -void perf_stat__collect_metric_expr(struct perf_evlist *evsel_list) +void perf_stat__collect_metric_expr(struct evlist *evsel_list) { - struct perf_evsel *counter, *leader, **metric_events, *oc; + struct evsel *counter, *leader, **metric_events, *oc; bool found; const char **metric_names; int i; @@ -332,7 +341,7 @@ void perf_stat__collect_metric_expr(struct perf_evlist *evsel_list) &metric_names, &num_metric_names) < 0) continue; - metric_events = calloc(sizeof(struct perf_evsel *), + metric_events = calloc(sizeof(struct evsel *), num_metric_names + 1); if (!metric_events) return; @@ -415,7 +424,7 @@ static double runtime_stat_n(struct runtime_stat *st, static void print_stalled_cycles_frontend(struct perf_stat_config *config, int cpu, - struct perf_evsel *evsel, double avg, + struct evsel *evsel, double avg, struct perf_stat_output_ctx *out, struct runtime_stat *st) { @@ -439,7 +448,7 @@ static void print_stalled_cycles_frontend(struct perf_stat_config *config, static void print_stalled_cycles_backend(struct perf_stat_config *config, int cpu, - struct perf_evsel *evsel, double avg, + struct evsel *evsel, double avg, struct perf_stat_output_ctx *out, struct runtime_stat *st) { @@ -459,7 +468,7 @@ static void print_stalled_cycles_backend(struct perf_stat_config *config, static void print_branch_misses(struct perf_stat_config *config, int cpu, - struct perf_evsel *evsel, + struct evsel *evsel, double avg, struct perf_stat_output_ctx *out, struct runtime_stat *st) @@ -480,7 +489,7 @@ static void print_branch_misses(struct perf_stat_config *config, static void print_l1_dcache_misses(struct perf_stat_config *config, int cpu, - struct perf_evsel *evsel, + struct evsel *evsel, double avg, struct perf_stat_output_ctx *out, struct runtime_stat *st) @@ -502,7 +511,7 @@ static void print_l1_dcache_misses(struct perf_stat_config *config, static void print_l1_icache_misses(struct perf_stat_config *config, int cpu, - struct perf_evsel *evsel, + struct evsel *evsel, double avg, struct perf_stat_output_ctx *out, struct runtime_stat *st) @@ -523,7 +532,7 @@ static void print_l1_icache_misses(struct perf_stat_config *config, static void print_dtlb_cache_misses(struct perf_stat_config *config, int cpu, - struct perf_evsel *evsel, + struct evsel *evsel, double avg, struct perf_stat_output_ctx *out, struct runtime_stat *st) @@ -543,7 +552,7 @@ static void print_dtlb_cache_misses(struct perf_stat_config *config, static void print_itlb_cache_misses(struct perf_stat_config *config, int cpu, - struct perf_evsel *evsel, + struct evsel *evsel, double avg, struct perf_stat_output_ctx *out, struct runtime_stat *st) @@ -563,7 +572,7 @@ static void print_itlb_cache_misses(struct perf_stat_config *config, static void print_ll_cache_misses(struct perf_stat_config *config, int cpu, - struct perf_evsel *evsel, + struct evsel *evsel, double avg, struct perf_stat_output_ctx *out, struct runtime_stat *st) @@ -686,7 +695,7 @@ static double td_be_bound(int ctx, int cpu, struct runtime_stat *st) } static void print_smi_cost(struct perf_stat_config *config, - int cpu, struct perf_evsel *evsel, + int cpu, struct evsel *evsel, struct perf_stat_output_ctx *out, struct runtime_stat *st) { @@ -712,9 +721,10 @@ static void print_smi_cost(struct perf_stat_config *config, static void generic_metric(struct perf_stat_config *config, const char *metric_expr, - struct perf_evsel **metric_events, + struct evsel **metric_events, char *name, const char *metric_name, + const char *metric_unit, double avg, int cpu, struct perf_stat_output_ctx *out, @@ -722,17 +732,16 @@ static void generic_metric(struct perf_stat_config *config, { print_metric_t print_metric = out->print_metric; struct parse_ctx pctx; - double ratio; + double ratio, scale; int i; void *ctxp = out->ctx; char *n, *pn; expr__ctx_init(&pctx); - expr__add_id(&pctx, name, avg); for (i = 0; metric_events[i]; i++) { struct saved_value *v; struct stats *stats; - double scale; + u64 metric_total = 0; if (!strcmp(metric_events[i]->name, "duration_time")) { stats = &walltime_nsecs_stats; @@ -744,6 +753,9 @@ static void generic_metric(struct perf_stat_config *config, break; stats = &v->stats; scale = 1.0; + + if (v->metric_other) + metric_total = v->metric_total; } n = strdup(metric_events[i]->name); @@ -757,21 +769,44 @@ static void generic_metric(struct perf_stat_config *config, pn = strchr(n, ' '); if (pn) *pn = 0; - expr__add_id(&pctx, n, avg_stats(stats)*scale); + + if (metric_total) + expr__add_id(&pctx, n, metric_total); + else + expr__add_id(&pctx, n, avg_stats(stats)*scale); } + + expr__add_id(&pctx, name, avg); + if (!metric_events[i]) { const char *p = metric_expr; - if (expr__parse(&ratio, &pctx, &p) == 0) - print_metric(config, ctxp, NULL, "%8.1f", - metric_name ? - metric_name : - out->force_header ? name : "", - ratio); - else + if (expr__parse(&ratio, &pctx, &p) == 0) { + char *unit; + char metric_bf[64]; + + if (metric_unit && metric_name) { + if (perf_pmu__convert_scale(metric_unit, + &unit, &scale) >= 0) { + ratio *= scale; + } + + scnprintf(metric_bf, sizeof(metric_bf), + "%s %s", unit, metric_name); + print_metric(config, ctxp, NULL, "%8.1f", + metric_bf, ratio); + } else { + print_metric(config, ctxp, NULL, "%8.1f", + metric_name ? + metric_name : + out->force_header ? name : "", + ratio); + } + } else { print_metric(config, ctxp, NULL, NULL, out->force_header ? (metric_name ? metric_name : name) : "", 0); + } } else print_metric(config, ctxp, NULL, NULL, "", 0); @@ -780,7 +815,7 @@ static void generic_metric(struct perf_stat_config *config, } void perf_stat__print_shadow_stats(struct perf_stat_config *config, - struct perf_evsel *evsel, + struct evsel *evsel, double avg, int cpu, struct perf_stat_output_ctx *out, struct rblist *metric_events, @@ -829,8 +864,8 @@ void perf_stat__print_shadow_stats(struct perf_stat_config *config, else print_metric(config, ctxp, NULL, NULL, "of all branches", 0); } else if ( - evsel->attr.type == PERF_TYPE_HW_CACHE && - evsel->attr.config == ( PERF_COUNT_HW_CACHE_L1D | + evsel->core.attr.type == PERF_TYPE_HW_CACHE && + evsel->core.attr.config == ( PERF_COUNT_HW_CACHE_L1D | ((PERF_COUNT_HW_CACHE_OP_READ) << 8) | ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16))) { @@ -839,8 +874,8 @@ void perf_stat__print_shadow_stats(struct perf_stat_config *config, else print_metric(config, ctxp, NULL, NULL, "of all L1-dcache hits", 0); } else if ( - evsel->attr.type == PERF_TYPE_HW_CACHE && - evsel->attr.config == ( PERF_COUNT_HW_CACHE_L1I | + evsel->core.attr.type == PERF_TYPE_HW_CACHE && + evsel->core.attr.config == ( PERF_COUNT_HW_CACHE_L1I | ((PERF_COUNT_HW_CACHE_OP_READ) << 8) | ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16))) { @@ -849,8 +884,8 @@ void perf_stat__print_shadow_stats(struct perf_stat_config *config, else print_metric(config, ctxp, NULL, NULL, "of all L1-icache hits", 0); } else if ( - evsel->attr.type == PERF_TYPE_HW_CACHE && - evsel->attr.config == ( PERF_COUNT_HW_CACHE_DTLB | + evsel->core.attr.type == PERF_TYPE_HW_CACHE && + evsel->core.attr.config == ( PERF_COUNT_HW_CACHE_DTLB | ((PERF_COUNT_HW_CACHE_OP_READ) << 8) | ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16))) { @@ -859,8 +894,8 @@ void perf_stat__print_shadow_stats(struct perf_stat_config *config, else print_metric(config, ctxp, NULL, NULL, "of all dTLB cache hits", 0); } else if ( - evsel->attr.type == PERF_TYPE_HW_CACHE && - evsel->attr.config == ( PERF_COUNT_HW_CACHE_ITLB | + evsel->core.attr.type == PERF_TYPE_HW_CACHE && + evsel->core.attr.config == ( PERF_COUNT_HW_CACHE_ITLB | ((PERF_COUNT_HW_CACHE_OP_READ) << 8) | ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16))) { @@ -869,8 +904,8 @@ void perf_stat__print_shadow_stats(struct perf_stat_config *config, else print_metric(config, ctxp, NULL, NULL, "of all iTLB cache hits", 0); } else if ( - evsel->attr.type == PERF_TYPE_HW_CACHE && - evsel->attr.config == ( PERF_COUNT_HW_CACHE_LL | + evsel->core.attr.type == PERF_TYPE_HW_CACHE && + evsel->core.attr.config == ( PERF_COUNT_HW_CACHE_LL | ((PERF_COUNT_HW_CACHE_OP_READ) << 8) | ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16))) { @@ -992,7 +1027,7 @@ void perf_stat__print_shadow_stats(struct perf_stat_config *config, print_metric(config, ctxp, NULL, NULL, name, 0); } else if (evsel->metric_expr) { generic_metric(config, evsel->metric_expr, evsel->metric_events, evsel->name, - evsel->metric_name, avg, cpu, out, st); + evsel->metric_name, NULL, avg, cpu, out, st); } else if (runtime_stat_n(st, STAT_NSECS, 0, cpu) != 0) { char unit = 'M'; char unit_buf[10]; @@ -1021,7 +1056,7 @@ void perf_stat__print_shadow_stats(struct perf_stat_config *config, out->new_line(config, ctxp); generic_metric(config, mexp->metric_expr, mexp->metric_events, evsel->name, mexp->metric_name, - avg, cpu, out, st); + mexp->metric_unit, avg, cpu, out, st); } } if (num == 0) diff --git a/tools/perf/util/stat.c b/tools/perf/util/stat.c index db8a6cf336be..8f1ea27f976f 100644 --- a/tools/perf/util/stat.c +++ b/tools/perf/util/stat.c @@ -2,7 +2,13 @@ #include <errno.h> #include <inttypes.h> #include <math.h> +#include <string.h> +#include "counts.h" +#include "debug.h" +#include "header.h" #include "stat.h" +#include "session.h" +#include "target.h" #include "evlist.h" #include "evsel.h" #include "thread_map.h" @@ -68,7 +74,7 @@ double rel_stddev_stats(double stddev, double avg) return pct; } -bool __perf_evsel_stat__is(struct perf_evsel *evsel, +bool __perf_evsel_stat__is(struct evsel *evsel, enum perf_stat_evsel_id id) { struct perf_stat_evsel *ps = evsel->stats; @@ -93,7 +99,7 @@ static const char *id_str[PERF_STAT_EVSEL_ID__MAX] = { }; #undef ID -static void perf_stat_evsel_id_init(struct perf_evsel *evsel) +static void perf_stat_evsel_id_init(struct evsel *evsel) { struct perf_stat_evsel *ps = evsel->stats; int i; @@ -108,7 +114,7 @@ static void perf_stat_evsel_id_init(struct perf_evsel *evsel) } } -static void perf_evsel__reset_stat_priv(struct perf_evsel *evsel) +static void perf_evsel__reset_stat_priv(struct evsel *evsel) { int i; struct perf_stat_evsel *ps = evsel->stats; @@ -119,7 +125,7 @@ static void perf_evsel__reset_stat_priv(struct perf_evsel *evsel) perf_stat_evsel_id_init(evsel); } -static int perf_evsel__alloc_stat_priv(struct perf_evsel *evsel) +static int perf_evsel__alloc_stat_priv(struct evsel *evsel) { evsel->stats = zalloc(sizeof(struct perf_stat_evsel)); if (evsel->stats == NULL) @@ -128,7 +134,7 @@ static int perf_evsel__alloc_stat_priv(struct perf_evsel *evsel) return 0; } -static void perf_evsel__free_stat_priv(struct perf_evsel *evsel) +static void perf_evsel__free_stat_priv(struct evsel *evsel) { struct perf_stat_evsel *ps = evsel->stats; @@ -137,7 +143,7 @@ static void perf_evsel__free_stat_priv(struct perf_evsel *evsel) zfree(&evsel->stats); } -static int perf_evsel__alloc_prev_raw_counts(struct perf_evsel *evsel, +static int perf_evsel__alloc_prev_raw_counts(struct evsel *evsel, int ncpus, int nthreads) { struct perf_counts *counts; @@ -149,16 +155,16 @@ static int perf_evsel__alloc_prev_raw_counts(struct perf_evsel *evsel, return counts ? 0 : -ENOMEM; } -static void perf_evsel__free_prev_raw_counts(struct perf_evsel *evsel) +static void perf_evsel__free_prev_raw_counts(struct evsel *evsel) { perf_counts__delete(evsel->prev_raw_counts); evsel->prev_raw_counts = NULL; } -static int perf_evsel__alloc_stats(struct perf_evsel *evsel, bool alloc_raw) +static int perf_evsel__alloc_stats(struct evsel *evsel, bool alloc_raw) { int ncpus = perf_evsel__nr_cpus(evsel); - int nthreads = thread_map__nr(evsel->threads); + int nthreads = perf_thread_map__nr(evsel->core.threads); if (perf_evsel__alloc_stat_priv(evsel) < 0 || perf_evsel__alloc_counts(evsel, ncpus, nthreads) < 0 || @@ -168,9 +174,9 @@ static int perf_evsel__alloc_stats(struct perf_evsel *evsel, bool alloc_raw) return 0; } -int perf_evlist__alloc_stats(struct perf_evlist *evlist, bool alloc_raw) +int perf_evlist__alloc_stats(struct evlist *evlist, bool alloc_raw) { - struct perf_evsel *evsel; + struct evsel *evsel; evlist__for_each_entry(evlist, evsel) { if (perf_evsel__alloc_stats(evsel, alloc_raw)) @@ -184,9 +190,9 @@ out_free: return -1; } -void perf_evlist__free_stats(struct perf_evlist *evlist) +void perf_evlist__free_stats(struct evlist *evlist) { - struct perf_evsel *evsel; + struct evsel *evsel; evlist__for_each_entry(evlist, evsel) { perf_evsel__free_stat_priv(evsel); @@ -195,9 +201,9 @@ void perf_evlist__free_stats(struct perf_evlist *evlist) } } -void perf_evlist__reset_stats(struct perf_evlist *evlist) +void perf_evlist__reset_stats(struct evlist *evlist) { - struct perf_evsel *evsel; + struct evsel *evsel; evlist__for_each_entry(evlist, evsel) { perf_evsel__reset_stat_priv(evsel); @@ -205,17 +211,17 @@ void perf_evlist__reset_stats(struct perf_evlist *evlist) } } -static void zero_per_pkg(struct perf_evsel *counter) +static void zero_per_pkg(struct evsel *counter) { if (counter->per_pkg_mask) - memset(counter->per_pkg_mask, 0, MAX_NR_CPUS); + memset(counter->per_pkg_mask, 0, cpu__max_cpu()); } -static int check_per_pkg(struct perf_evsel *counter, +static int check_per_pkg(struct evsel *counter, struct perf_counts_values *vals, int cpu, bool *skip) { unsigned long *mask = counter->per_pkg_mask; - struct cpu_map *cpus = perf_evsel__cpus(counter); + struct perf_cpu_map *cpus = evsel__cpus(counter); int s; *skip = false; @@ -223,11 +229,11 @@ static int check_per_pkg(struct perf_evsel *counter, if (!counter->per_pkg) return 0; - if (cpu_map__empty(cpus)) + if (perf_cpu_map__empty(cpus)) return 0; if (!mask) { - mask = zalloc(MAX_NR_CPUS); + mask = zalloc(cpu__max_cpu()); if (!mask) return -ENOMEM; @@ -254,7 +260,7 @@ static int check_per_pkg(struct perf_evsel *counter, } static int -process_counter_values(struct perf_stat_config *config, struct perf_evsel *evsel, +process_counter_values(struct perf_stat_config *config, struct evsel *evsel, int cpu, int thread, struct perf_counts_values *count) { @@ -306,9 +312,9 @@ process_counter_values(struct perf_stat_config *config, struct perf_evsel *evsel } static int process_counter_maps(struct perf_stat_config *config, - struct perf_evsel *counter) + struct evsel *counter) { - int nthreads = thread_map__nr(counter->threads); + int nthreads = perf_thread_map__nr(counter->core.threads); int ncpus = perf_evsel__nr_cpus(counter); int cpu, thread; @@ -327,7 +333,7 @@ static int process_counter_maps(struct perf_stat_config *config, } int perf_stat_process_counter(struct perf_stat_config *config, - struct perf_evsel *counter) + struct evsel *counter) { struct perf_counts_values *aggr = &counter->counts->aggr; struct perf_stat_evsel *ps = counter->stats; @@ -380,8 +386,8 @@ int perf_event__process_stat_event(struct perf_session *session, union perf_event *event) { struct perf_counts_values count; - struct stat_event *st = &event->stat; - struct perf_evsel *counter; + struct perf_record_stat *st = &event->stat; + struct evsel *counter; count.val = st->val; count.ena = st->ena; @@ -400,12 +406,12 @@ int perf_event__process_stat_event(struct perf_session *session, size_t perf_event__fprintf_stat(union perf_event *event, FILE *fp) { - struct stat_event *st = (struct stat_event *) event; + struct perf_record_stat *st = (struct perf_record_stat *)event; size_t ret; - ret = fprintf(fp, "\n... id %" PRIu64 ", cpu %d, thread %d\n", + ret = fprintf(fp, "\n... id %" PRI_lu64 ", cpu %d, thread %d\n", st->id, st->cpu, st->thread); - ret += fprintf(fp, "... value %" PRIu64 ", enabled %" PRIu64 ", running %" PRIu64 "\n", + ret += fprintf(fp, "... value %" PRI_lu64 ", enabled %" PRI_lu64 ", running %" PRI_lu64 "\n", st->val, st->ena, st->run); return ret; @@ -413,10 +419,10 @@ size_t perf_event__fprintf_stat(union perf_event *event, FILE *fp) size_t perf_event__fprintf_stat_round(union perf_event *event, FILE *fp) { - struct stat_round_event *rd = (struct stat_round_event *)event; + struct perf_record_stat_round *rd = (struct perf_record_stat_round *)event; size_t ret; - ret = fprintf(fp, "\n... time %" PRIu64 ", type %s\n", rd->time, + ret = fprintf(fp, "\n... time %" PRI_lu64 ", type %s\n", rd->time, rd->type == PERF_STAT_ROUND_TYPE__FINAL ? "FINAL" : "INTERVAL"); return ret; @@ -437,12 +443,12 @@ size_t perf_event__fprintf_stat_config(union perf_event *event, FILE *fp) return ret; } -int create_perf_stat_counter(struct perf_evsel *evsel, +int create_perf_stat_counter(struct evsel *evsel, struct perf_stat_config *config, struct target *target) { - struct perf_event_attr *attr = &evsel->attr; - struct perf_evsel *leader = evsel->leader; + struct perf_event_attr *attr = &evsel->core.attr; + struct evsel *leader = evsel->leader; attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | PERF_FORMAT_TOTAL_TIME_RUNNING; @@ -452,7 +458,7 @@ int create_perf_stat_counter(struct perf_evsel *evsel, * the group read (for leader) and ID retrieval for all * members. */ - if (leader->nr_members > 1) + if (leader->core.nr_members > 1) attr->read_format |= PERF_FORMAT_ID|PERF_FORMAT_GROUP; attr->inherit = !config->no_inherit; @@ -483,14 +489,14 @@ int create_perf_stat_counter(struct perf_evsel *evsel, } if (target__has_cpu(target) && !target__has_per_thread(target)) - return perf_evsel__open_per_cpu(evsel, perf_evsel__cpus(evsel)); + return perf_evsel__open_per_cpu(evsel, evsel__cpus(evsel)); - return perf_evsel__open_per_thread(evsel, evsel->threads); + return perf_evsel__open_per_thread(evsel, evsel->core.threads); } int perf_stat_synthesize_config(struct perf_stat_config *config, struct perf_tool *tool, - struct perf_evlist *evlist, + struct evlist *evlist, perf_event__handler_t process, bool attrs) { @@ -507,14 +513,14 @@ int perf_stat_synthesize_config(struct perf_stat_config *config, err = perf_event__synthesize_extra_attr(tool, evlist, process, attrs); - err = perf_event__synthesize_thread_map2(tool, evlist->threads, + err = perf_event__synthesize_thread_map2(tool, evlist->core.threads, process, NULL); if (err < 0) { pr_err("Couldn't synthesize thread map.\n"); return err; } - err = perf_event__synthesize_cpu_map(tool, evlist->cpus, + err = perf_event__synthesize_cpu_map(tool, evlist->core.cpus, process, NULL); if (err < 0) { pr_err("Couldn't synthesize thread map.\n"); diff --git a/tools/perf/util/stat.h b/tools/perf/util/stat.h index 7032dd1eeac2..14fe3e548229 100644 --- a/tools/perf/util/stat.h +++ b/tools/perf/util/stat.h @@ -5,14 +5,12 @@ #include <linux/types.h> #include <stdio.h> #include <sys/types.h> -#include <sys/time.h> #include <sys/resource.h> -#include <sys/wait.h> -#include "xyarray.h" #include "rblist.h" -#include "perf.h" #include "event.h" +struct timespec; + struct stats { double n, mean, M2; u64 max, min; @@ -92,7 +90,7 @@ struct runtime_stat { }; typedef int (*aggr_get_id_t)(struct perf_stat_config *config, - struct cpu_map *m, int cpu); + struct perf_cpu_map *m, int cpu); struct perf_stat_config { enum aggr_mode aggr_mode; @@ -122,9 +120,9 @@ struct perf_stat_config { const char *csv_sep; struct stats *walltime_nsecs_stats; struct rusage ru_data; - struct cpu_map *aggr_map; + struct perf_cpu_map *aggr_map; aggr_get_id_t aggr_get_id; - struct cpu_map *cpus_aggr_map; + struct perf_cpu_map *cpus_aggr_map; u64 *walltime_run; struct rblist metric_events; }; @@ -143,11 +141,11 @@ static inline void init_stats(struct stats *stats) stats->max = 0; } -struct perf_evsel; -struct perf_evlist; +struct evsel; +struct evlist; struct perf_aggr_thread_value { - struct perf_evsel *counter; + struct evsel *counter; int id; double uval; u64 val; @@ -155,7 +153,7 @@ struct perf_aggr_thread_value { u64 ena; }; -bool __perf_evsel_stat__is(struct perf_evsel *evsel, +bool __perf_evsel_stat__is(struct evsel *evsel, enum perf_stat_evsel_id id); #define perf_stat_evsel__is(evsel, id) \ @@ -174,7 +172,7 @@ void runtime_stat__exit(struct runtime_stat *st); void perf_stat__init_shadow_stats(void); void perf_stat__reset_shadow_stats(void); void perf_stat__reset_shadow_per_stat(struct runtime_stat *st); -void perf_stat__update_shadow_stats(struct perf_evsel *counter, u64 count, +void perf_stat__update_shadow_stats(struct evsel *counter, u64 count, int cpu, struct runtime_stat *st); struct perf_stat_output_ctx { void *ctx; @@ -184,22 +182,24 @@ struct perf_stat_output_ctx { }; void perf_stat__print_shadow_stats(struct perf_stat_config *config, - struct perf_evsel *evsel, + struct evsel *evsel, double avg, int cpu, struct perf_stat_output_ctx *out, struct rblist *metric_events, struct runtime_stat *st); -void perf_stat__collect_metric_expr(struct perf_evlist *); +void perf_stat__collect_metric_expr(struct evlist *); -int perf_evlist__alloc_stats(struct perf_evlist *evlist, bool alloc_raw); -void perf_evlist__free_stats(struct perf_evlist *evlist); -void perf_evlist__reset_stats(struct perf_evlist *evlist); +int perf_evlist__alloc_stats(struct evlist *evlist, bool alloc_raw); +void perf_evlist__free_stats(struct evlist *evlist); +void perf_evlist__reset_stats(struct evlist *evlist); int perf_stat_process_counter(struct perf_stat_config *config, - struct perf_evsel *counter); + struct evsel *counter); struct perf_tool; union perf_event; struct perf_session; +struct target; + int perf_event__process_stat_event(struct perf_session *session, union perf_event *event); @@ -207,16 +207,16 @@ size_t perf_event__fprintf_stat(union perf_event *event, FILE *fp); size_t perf_event__fprintf_stat_round(union perf_event *event, FILE *fp); size_t perf_event__fprintf_stat_config(union perf_event *event, FILE *fp); -int create_perf_stat_counter(struct perf_evsel *evsel, +int create_perf_stat_counter(struct evsel *evsel, struct perf_stat_config *config, struct target *target); int perf_stat_synthesize_config(struct perf_stat_config *config, struct perf_tool *tool, - struct perf_evlist *evlist, + struct evlist *evlist, perf_event__handler_t process, bool attrs); void -perf_evlist__print_counters(struct perf_evlist *evlist, +perf_evlist__print_counters(struct evlist *evlist, struct perf_stat_config *config, struct target *_target, struct timespec *ts, diff --git a/tools/perf/util/strbuf.c b/tools/perf/util/strbuf.c index 2ce0dc887364..a64a37628f12 100644 --- a/tools/perf/util/strbuf.c +++ b/tools/perf/util/strbuf.c @@ -1,9 +1,14 @@ // SPDX-License-Identifier: GPL-2.0 +#include "cache.h" #include "debug.h" +#include "strbuf.h" #include <linux/kernel.h> +#include <linux/string.h> #include <linux/zalloc.h> #include <errno.h> +#include <stdio.h> #include <stdlib.h> +#include <unistd.h> /* * Used as the default ->buf value, so that people can always assume diff --git a/tools/perf/util/svghelper.c b/tools/perf/util/svghelper.c index 76cc54000483..582f4a69cd48 100644 --- a/tools/perf/util/svghelper.c +++ b/tools/perf/util/svghelper.c @@ -14,10 +14,12 @@ #include <unistd.h> #include <string.h> #include <linux/bitmap.h> +#include <linux/string.h> #include <linux/time64.h> #include <linux/zalloc.h> +#include <perf/cpumap.h> -#include "perf.h" +#include "env.h" #include "svghelper.h" #include "cpumap.h" @@ -694,7 +696,8 @@ struct topology { int sib_thr_nr; }; -static void scan_thread_topology(int *map, struct topology *t, int cpu, int *pos) +static void scan_thread_topology(int *map, struct topology *t, int cpu, + int *pos, int nr_cpus) { int i; int thr; @@ -703,41 +706,37 @@ static void scan_thread_topology(int *map, struct topology *t, int cpu, int *pos if (!test_bit(cpu, cpumask_bits(&t->sib_thr[i]))) continue; - for_each_set_bit(thr, - cpumask_bits(&t->sib_thr[i]), - MAX_NR_CPUS) + for_each_set_bit(thr, cpumask_bits(&t->sib_thr[i]), nr_cpus) if (map[thr] == -1) map[thr] = (*pos)++; } } -static void scan_core_topology(int *map, struct topology *t) +static void scan_core_topology(int *map, struct topology *t, int nr_cpus) { int pos = 0; int i; int cpu; for (i = 0; i < t->sib_core_nr; i++) - for_each_set_bit(cpu, - cpumask_bits(&t->sib_core[i]), - MAX_NR_CPUS) - scan_thread_topology(map, t, cpu, &pos); + for_each_set_bit(cpu, cpumask_bits(&t->sib_core[i]), nr_cpus) + scan_thread_topology(map, t, cpu, &pos, nr_cpus); } -static int str_to_bitmap(char *s, cpumask_t *b) +static int str_to_bitmap(char *s, cpumask_t *b, int nr_cpus) { int i; int ret = 0; - struct cpu_map *m; + struct perf_cpu_map *m; int c; - m = cpu_map__new(s); + m = perf_cpu_map__new(s); if (!m) return -1; for (i = 0; i < m->nr; i++) { c = m->map[i]; - if (c >= MAX_NR_CPUS) { + if (c >= nr_cpus) { ret = -1; break; } @@ -745,29 +744,34 @@ static int str_to_bitmap(char *s, cpumask_t *b) set_bit(c, cpumask_bits(b)); } - cpu_map__put(m); + perf_cpu_map__put(m); return ret; } -int svg_build_topology_map(char *sib_core, int sib_core_nr, - char *sib_thr, int sib_thr_nr) +int svg_build_topology_map(struct perf_env *env) { - int i; + int i, nr_cpus; struct topology t; + char *sib_core, *sib_thr; + + nr_cpus = min(env->nr_cpus_online, MAX_NR_CPUS); + + t.sib_core_nr = env->nr_sibling_cores; + t.sib_thr_nr = env->nr_sibling_threads; + t.sib_core = calloc(env->nr_sibling_cores, sizeof(cpumask_t)); + t.sib_thr = calloc(env->nr_sibling_threads, sizeof(cpumask_t)); - t.sib_core_nr = sib_core_nr; - t.sib_thr_nr = sib_thr_nr; - t.sib_core = calloc(sib_core_nr, sizeof(cpumask_t)); - t.sib_thr = calloc(sib_thr_nr, sizeof(cpumask_t)); + sib_core = env->sibling_cores; + sib_thr = env->sibling_threads; if (!t.sib_core || !t.sib_thr) { fprintf(stderr, "topology: no memory\n"); goto exit; } - for (i = 0; i < sib_core_nr; i++) { - if (str_to_bitmap(sib_core, &t.sib_core[i])) { + for (i = 0; i < env->nr_sibling_cores; i++) { + if (str_to_bitmap(sib_core, &t.sib_core[i], nr_cpus)) { fprintf(stderr, "topology: can't parse siblings map\n"); goto exit; } @@ -775,8 +779,8 @@ int svg_build_topology_map(char *sib_core, int sib_core_nr, sib_core += strlen(sib_core) + 1; } - for (i = 0; i < sib_thr_nr; i++) { - if (str_to_bitmap(sib_thr, &t.sib_thr[i])) { + for (i = 0; i < env->nr_sibling_threads; i++) { + if (str_to_bitmap(sib_thr, &t.sib_thr[i], nr_cpus)) { fprintf(stderr, "topology: can't parse siblings map\n"); goto exit; } @@ -784,16 +788,16 @@ int svg_build_topology_map(char *sib_core, int sib_core_nr, sib_thr += strlen(sib_thr) + 1; } - topology_map = malloc(sizeof(int) * MAX_NR_CPUS); + topology_map = malloc(sizeof(int) * nr_cpus); if (!topology_map) { fprintf(stderr, "topology: no memory\n"); goto exit; } - for (i = 0; i < MAX_NR_CPUS; i++) + for (i = 0; i < nr_cpus; i++) topology_map[i] = -1; - scan_core_topology(topology_map, &t); + scan_core_topology(topology_map, &t, nr_cpus); return 0; diff --git a/tools/perf/util/svghelper.h b/tools/perf/util/svghelper.h index e55338d5c3bd..81823e8bae3e 100644 --- a/tools/perf/util/svghelper.h +++ b/tools/perf/util/svghelper.h @@ -4,6 +4,8 @@ #include <linux/types.h> +struct perf_env; + void open_svg(const char *filename, int cpus, int rows, u64 start, u64 end); void svg_ubox(int Yslot, u64 start, u64 end, double height, const char *type, int fd, int err, int merges); void svg_lbox(int Yslot, u64 start, u64 end, double height, const char *type, int fd, int err, int merges); @@ -28,7 +30,7 @@ void svg_partial_wakeline(u64 start, int row1, char *desc1, int row2, char *desc void svg_interrupt(u64 start, int row, const char *backtrace); void svg_text(int Yslot, u64 start, const char *text); void svg_close(void); -int svg_build_topology_map(char *sib_core, int sib_core_nr, char *sib_thr, int sib_thr_nr); +int svg_build_topology_map(struct perf_env *env); extern int svg_page_width; extern u64 svg_highlight; diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c index 7d504dc22108..9428639872a6 100644 --- a/tools/perf/util/symbol-elf.c +++ b/tools/perf/util/symbol-elf.c @@ -10,6 +10,7 @@ #include "map.h" #include "map_groups.h" #include "symbol.h" +#include "symsrc.h" #include "demangle-java.h" #include "demangle-rust.h" #include "machine.h" @@ -40,6 +41,12 @@ typedef Elf64_Nhdr GElf_Nhdr; +#ifndef DMGL_PARAMS +#define DMGL_NO_OPTS 0 /* For readability... */ +#define DMGL_PARAMS (1 << 0) /* Include function args */ +#define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */ +#endif + #ifdef HAVE_CPLUS_DEMANGLE_SUPPORT extern char *cplus_demangle(const char *, int); diff --git a/tools/perf/util/symbol-minimal.c b/tools/perf/util/symbol-minimal.c index 3bc8b7e3300e..7e2813ec9498 100644 --- a/tools/perf/util/symbol-minimal.c +++ b/tools/perf/util/symbol-minimal.c @@ -1,5 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 +#include "dso.h" #include "symbol.h" +#include "symsrc.h" #include "util.h" #include <errno.h> diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 4efde7879474..765c75df2904 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -4,8 +4,10 @@ #include <stdlib.h> #include <stdio.h> #include <string.h> +#include <linux/capability.h> #include <linux/kernel.h> #include <linux/mman.h> +#include <linux/string.h> #include <linux/time64.h> #include <sys/types.h> #include <sys/stat.h> @@ -15,11 +17,17 @@ #include <inttypes.h> #include "annotate.h" #include "build-id.h" +#include "cap.h" +#include "dso.h" #include "util.h" #include "debug.h" +#include "event.h" #include "machine.h" #include "map.h" #include "symbol.h" +#include "map_symbol.h" +#include "mem-events.h" +#include "symsrc.h" #include "strlist.h" #include "intlist.h" #include "namespaces.h" @@ -2195,13 +2203,19 @@ static bool symbol__read_kptr_restrict(void) char line[8]; if (fgets(line, sizeof(line), fp) != NULL) - value = ((geteuid() != 0) || (getuid() != 0)) ? - (atoi(line) != 0) : - (atoi(line) == 2); + value = perf_cap__capable(CAP_SYSLOG) ? + (atoi(line) >= 2) : + (atoi(line) != 0); fclose(fp); } + /* Per kernel/kallsyms.c: + * we also restrict when perf_event_paranoid > 1 w/o CAP_SYSLOG + */ + if (perf_event_paranoid() > 1 && !perf_cap__capable(CAP_SYSLOG)) + value = true; + return value; } diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 183f630cb5f1..0b0c6b5b1899 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -3,13 +3,12 @@ #define __PERF_SYMBOL 1 #include <linux/types.h> +#include <linux/refcount.h> #include <stdbool.h> #include <stdint.h> #include <linux/list.h> #include <linux/rbtree.h> #include <stdio.h> -#include "map_symbol.h" -#include "branch.h" #include "path.h" #include "symbol_conf.h" @@ -19,8 +18,7 @@ #endif #include <elf.h> -#include "dso.h" - +struct dso; struct map; struct map_groups; struct option; @@ -40,15 +38,6 @@ Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep, GElf_Shdr *shp, const char *name, size_t *idx); #endif -#ifndef DMGL_PARAMS -#define DMGL_NO_OPTS 0 /* For readability... */ -#define DMGL_PARAMS (1 << 0) /* Include function args */ -#define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */ -#endif - -#define DSO__NAME_KALLSYMS "[kernel.kallsyms]" -#define DSO__NAME_KCORE "[kernel.kcore]" - /** struct symbol - symtab entry * * @ignore - resolvable but tools ignore it (e.g. idle routines) @@ -116,21 +105,6 @@ struct ref_reloc_sym { u64 unrelocated_addr; }; -struct branch_info { - struct addr_map_symbol from; - struct addr_map_symbol to; - struct branch_flags flags; - char *srcline_from; - char *srcline_to; -}; - -struct mem_info { - struct addr_map_symbol iaddr; - struct addr_map_symbol daddr; - union perf_mem_data_src data_src; - refcount_t refcnt; -}; - struct block_info { struct symbol *sym; u64 start; @@ -156,37 +130,6 @@ struct addr_location { s32 socket; }; -struct symsrc { - char *name; - int fd; - enum dso_binary_type type; - -#ifdef HAVE_LIBELF_SUPPORT - Elf *elf; - GElf_Ehdr ehdr; - - Elf_Scn *opdsec; - size_t opdidx; - GElf_Shdr opdshdr; - - Elf_Scn *symtab; - GElf_Shdr symshdr; - - Elf_Scn *dynsym; - size_t dynsym_idx; - GElf_Shdr dynshdr; - - bool adjust_symbols; - bool is_64_bit; -#endif -}; - -void symsrc__destroy(struct symsrc *ss); -int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name, - enum dso_binary_type type); -bool symsrc__has_symtab(struct symsrc *ss); -bool symsrc__possibly_runtime(struct symsrc *ss); - int dso__load(struct dso *dso, struct map *map); int dso__load_vmlinux(struct dso *dso, struct map *map, const char *vmlinux, bool vmlinux_allocated); @@ -240,6 +183,8 @@ bool symbol__restricted_filename(const char *filename, int symbol__config_symfs(const struct option *opt __maybe_unused, const char *dir, int unset __maybe_unused); +struct symsrc; + int dso__load_sym(struct dso *dso, struct map *map, struct symsrc *syms_ss, struct symsrc *runtime_ss, int kmodule); int dso__synthesize_plt_symbols(struct dso *dso, struct symsrc *ss); diff --git a/tools/perf/util/symbol_fprintf.c b/tools/perf/util/symbol_fprintf.c index 02e89b02c2ce..35c936ce33ef 100644 --- a/tools/perf/util/symbol_fprintf.c +++ b/tools/perf/util/symbol_fprintf.c @@ -3,6 +3,7 @@ #include <inttypes.h> #include <stdio.h> +#include "dso.h" #include "map.h" #include "symbol.h" diff --git a/tools/perf/util/symsrc.h b/tools/perf/util/symsrc.h new file mode 100644 index 000000000000..2665b4bde751 --- /dev/null +++ b/tools/perf/util/symsrc.h @@ -0,0 +1,46 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __PERF_SYMSRC_ +#define __PERF_SYMSRC_ 1 + +#include <stdbool.h> +#include <stddef.h> +#include "dso.h" + +#ifdef HAVE_LIBELF_SUPPORT +#include <libelf.h> +#include <gelf.h> +#endif +#include <elf.h> + +struct symsrc { + char *name; + int fd; + enum dso_binary_type type; + +#ifdef HAVE_LIBELF_SUPPORT + Elf *elf; + GElf_Ehdr ehdr; + + Elf_Scn *opdsec; + size_t opdidx; + GElf_Shdr opdshdr; + + Elf_Scn *symtab; + GElf_Shdr symshdr; + + Elf_Scn *dynsym; + size_t dynsym_idx; + GElf_Shdr dynshdr; + + bool adjust_symbols; + bool is_64_bit; +#endif +}; + +int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name, enum dso_binary_type type); +void symsrc__destroy(struct symsrc *ss); + +bool symsrc__has_symtab(struct symsrc *ss); +bool symsrc__possibly_runtime(struct symsrc *ss); + +#endif /* __PERF_SYMSRC_ */ diff --git a/tools/perf/util/syscalltbl.c b/tools/perf/util/syscalltbl.c index 022a9c670338..820fceeb19a9 100644 --- a/tools/perf/util/syscalltbl.c +++ b/tools/perf/util/syscalltbl.c @@ -79,6 +79,7 @@ static int syscalltbl__init_native(struct syscalltbl *tbl) qsort(tbl->syscalls.entries, nr_entries, sizeof(struct syscall), syscallcmp); tbl->syscalls.nr_entries = nr_entries; + tbl->syscalls.max_id = syscalltbl_native_max_id; return 0; } diff --git a/tools/perf/util/syscalltbl.h b/tools/perf/util/syscalltbl.h index c8e7e9ce0f01..9172613028d0 100644 --- a/tools/perf/util/syscalltbl.h +++ b/tools/perf/util/syscalltbl.h @@ -6,6 +6,7 @@ struct syscalltbl { union { int audit_machine; struct { + int max_id; int nr_entries; void *entries; } syscalls; diff --git a/tools/perf/util/target.c b/tools/perf/util/target.c index 3adc65480349..565f7aef7e6c 100644 --- a/tools/perf/util/target.c +++ b/tools/perf/util/target.c @@ -10,8 +10,11 @@ #include "debug.h" #include <pwd.h> +#include <stdio.h> #include <stdlib.h> #include <string.h> +#include <linux/kernel.h> +#include <linux/string.h> enum target_errno target__validate(struct target *target) { diff --git a/tools/perf/util/thread-stack.c b/tools/perf/util/thread-stack.c index 15134ac9b8f1..cd8a948d03ec 100644 --- a/tools/perf/util/thread-stack.c +++ b/tools/perf/util/thread-stack.c @@ -10,6 +10,7 @@ #include <linux/zalloc.h> #include <errno.h> #include <stdlib.h> +#include <string.h> #include "thread.h" #include "event.h" #include "machine.h" diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index 590793cc5142..b64e9e049636 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c @@ -1,11 +1,11 @@ // SPDX-License-Identifier: GPL-2.0 -#include "../perf.h" #include <errno.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #include <linux/kernel.h> #include <linux/zalloc.h> +#include "dso.h" #include "session.h" #include "thread.h" #include "thread-stack.h" @@ -105,7 +105,6 @@ void thread__delete(struct thread *thread) } up_write(&thread->comm_lock); - unwind__finish_access(thread); nsinfo__zput(thread->nsinfo); srccode_state_free(&thread->srccode_state); @@ -170,7 +169,7 @@ struct namespaces *thread__namespaces(struct thread *thread) } static int __thread__set_namespaces(struct thread *thread, u64 timestamp, - struct namespaces_event *event) + struct perf_record_namespaces *event) { struct namespaces *new, *curr = __thread__namespaces(thread); @@ -194,7 +193,7 @@ static int __thread__set_namespaces(struct thread *thread, u64 timestamp, } int thread__set_namespaces(struct thread *thread, u64 timestamp, - struct namespaces_event *event) + struct perf_record_namespaces *event) { int ret; @@ -252,7 +251,7 @@ static int ____thread__set_comm(struct thread *thread, const char *str, list_add(&new->list, &thread->comm_list); if (exec) - unwind__flush_access(thread); + unwind__flush_access(thread->mg); } thread->comm_set = true; @@ -332,7 +331,7 @@ int thread__insert_map(struct thread *thread, struct map *map) { int ret; - ret = unwind__prepare_access(thread, map, NULL); + ret = unwind__prepare_access(thread->mg, map, NULL); if (ret) return ret; @@ -352,7 +351,7 @@ static int __thread__prepare_access(struct thread *thread) down_read(&maps->lock); for (map = maps__first(maps); map; map = map__next(map)) { - err = unwind__prepare_access(thread, map, &initialized); + err = unwind__prepare_access(thread->mg, map, &initialized); if (err || initialized) break; } diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h index e97ef6977eb9..51bdb9a7af7f 100644 --- a/tools/perf/util/thread.h +++ b/tools/perf/util/thread.h @@ -16,7 +16,7 @@ struct addr_location; struct map; -struct namespaces_event; +struct perf_record_namespaces; struct thread_stack; struct unwind_libunwind_ops; @@ -44,10 +44,6 @@ struct thread { struct thread_stack *ts; struct nsinfo *nsinfo; struct srccode_state srccode_state; -#ifdef HAVE_LIBUNWIND_SUPPORT - void *addr_space; - struct unwind_libunwind_ops *unwind_libunwind_ops; -#endif bool filter; int filter_entry_depth; }; @@ -78,7 +74,7 @@ static inline void thread__exited(struct thread *thread) struct namespaces *thread__namespaces(struct thread *thread); int thread__set_namespaces(struct thread *thread, u64 timestamp, - struct namespaces_event *event); + struct perf_record_namespaces *event); int __thread__set_comm(struct thread *thread, const char *comm, u64 timestamp, bool exec); diff --git a/tools/perf/util/thread_map.c b/tools/perf/util/thread_map.c index 5b3511f2b6b1..c9bfe4696943 100644 --- a/tools/perf/util/thread_map.c +++ b/tools/perf/util/thread_map.c @@ -28,34 +28,11 @@ static int filter(const struct dirent *dir) return 1; } -static void thread_map__reset(struct 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; -} +#define thread_map__alloc(__nr) perf_thread_map__realloc(NULL, __nr) -static struct thread_map *thread_map__realloc(struct thread_map *map, int nr) +struct perf_thread_map *thread_map__new_by_pid(pid_t pid) { - 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) - thread_map__reset(map, start, nr); - - return map; -} - -#define thread_map__alloc(__nr) thread_map__realloc(NULL, __nr) - -struct thread_map *thread_map__new_by_pid(pid_t pid) -{ - struct thread_map *threads; + struct perf_thread_map *threads; char name[256]; int items; struct dirent **namelist = NULL; @@ -69,7 +46,7 @@ struct thread_map *thread_map__new_by_pid(pid_t pid) threads = thread_map__alloc(items); if (threads != NULL) { for (i = 0; i < items; i++) - thread_map__set_pid(threads, i, atoi(namelist[i]->d_name)); + perf_thread_map__set_pid(threads, i, atoi(namelist[i]->d_name)); threads->nr = items; refcount_set(&threads->refcnt, 1); } @@ -81,12 +58,12 @@ struct thread_map *thread_map__new_by_pid(pid_t pid) return threads; } -struct thread_map *thread_map__new_by_tid(pid_t tid) +struct perf_thread_map *thread_map__new_by_tid(pid_t tid) { - struct thread_map *threads = thread_map__alloc(1); + struct perf_thread_map *threads = thread_map__alloc(1); if (threads != NULL) { - thread_map__set_pid(threads, 0, tid); + perf_thread_map__set_pid(threads, 0, tid); threads->nr = 1; refcount_set(&threads->refcnt, 1); } @@ -94,13 +71,13 @@ struct thread_map *thread_map__new_by_tid(pid_t tid) return threads; } -static struct thread_map *__thread_map__new_all_cpus(uid_t uid) +static struct perf_thread_map *__thread_map__new_all_cpus(uid_t uid) { DIR *proc; int max_threads = 32, items, i; char path[NAME_MAX + 1 + 6]; struct dirent *dirent, **namelist = NULL; - struct thread_map *threads = thread_map__alloc(max_threads); + struct perf_thread_map *threads = thread_map__alloc(max_threads); if (threads == NULL) goto out; @@ -140,9 +117,9 @@ static struct thread_map *__thread_map__new_all_cpus(uid_t uid) } if (grow) { - struct thread_map *tmp; + struct perf_thread_map *tmp; - tmp = thread_map__realloc(threads, max_threads); + tmp = perf_thread_map__realloc(threads, max_threads); if (tmp == NULL) goto out_free_namelist; @@ -150,8 +127,8 @@ static struct thread_map *__thread_map__new_all_cpus(uid_t uid) } for (i = 0; i < items; i++) { - thread_map__set_pid(threads, threads->nr + i, - atoi(namelist[i]->d_name)); + perf_thread_map__set_pid(threads, threads->nr + i, + atoi(namelist[i]->d_name)); } for (i = 0; i < items; i++) @@ -180,17 +157,17 @@ out_free_closedir: goto out_closedir; } -struct thread_map *thread_map__new_all_cpus(void) +struct perf_thread_map *thread_map__new_all_cpus(void) { return __thread_map__new_all_cpus(UINT_MAX); } -struct thread_map *thread_map__new_by_uid(uid_t uid) +struct perf_thread_map *thread_map__new_by_uid(uid_t uid) { return __thread_map__new_all_cpus(uid); } -struct thread_map *thread_map__new(pid_t pid, pid_t tid, uid_t uid) +struct perf_thread_map *thread_map__new(pid_t pid, pid_t tid, uid_t uid) { if (pid != -1) return thread_map__new_by_pid(pid); @@ -201,9 +178,9 @@ struct thread_map *thread_map__new(pid_t pid, pid_t tid, uid_t uid) return thread_map__new_by_tid(tid); } -static struct thread_map *thread_map__new_by_pid_str(const char *pid_str) +static struct perf_thread_map *thread_map__new_by_pid_str(const char *pid_str) { - struct thread_map *threads = NULL, *nt; + struct perf_thread_map *threads = NULL, *nt; char name[256]; int items, total_tasks = 0; struct dirent **namelist = NULL; @@ -233,14 +210,14 @@ static struct thread_map *thread_map__new_by_pid_str(const char *pid_str) goto out_free_threads; total_tasks += items; - nt = thread_map__realloc(threads, total_tasks); + nt = perf_thread_map__realloc(threads, total_tasks); if (nt == NULL) goto out_free_namelist; threads = nt; for (i = 0; i < items; i++) { - thread_map__set_pid(threads, j++, atoi(namelist[i]->d_name)); + perf_thread_map__set_pid(threads, j++, atoi(namelist[i]->d_name)); zfree(&namelist[i]); } threads->nr = total_tasks; @@ -263,21 +240,9 @@ out_free_threads: goto out; } -struct thread_map *thread_map__new_dummy(void) -{ - struct thread_map *threads = thread_map__alloc(1); - - if (threads != NULL) { - thread_map__set_pid(threads, 0, -1); - threads->nr = 1; - refcount_set(&threads->refcnt, 1); - } - return threads; -} - -struct thread_map *thread_map__new_by_tid_str(const char *tid_str) +struct perf_thread_map *thread_map__new_by_tid_str(const char *tid_str) { - struct thread_map *threads = NULL, *nt; + struct perf_thread_map *threads = NULL, *nt; int ntasks = 0; pid_t tid, prev_tid = INT_MAX; char *end_ptr; @@ -287,7 +252,7 @@ struct thread_map *thread_map__new_by_tid_str(const char *tid_str) /* perf-stat expects threads to be generated even if tid not given */ if (!tid_str) - return thread_map__new_dummy(); + return perf_thread_map__new_dummy(); slist = strlist__new(tid_str, &slist_config); if (!slist) @@ -304,13 +269,13 @@ struct thread_map *thread_map__new_by_tid_str(const char *tid_str) continue; ntasks++; - nt = thread_map__realloc(threads, ntasks); + nt = perf_thread_map__realloc(threads, ntasks); if (nt == NULL) goto out_free_threads; threads = nt; - thread_map__set_pid(threads, ntasks - 1, tid); + perf_thread_map__set_pid(threads, ntasks - 1, tid); threads->nr = ntasks; } out: @@ -324,7 +289,7 @@ out_free_threads: goto out; } -struct thread_map *thread_map__new_str(const char *pid, const char *tid, +struct perf_thread_map *thread_map__new_str(const char *pid, const char *tid, uid_t uid, bool all_threads) { if (pid) @@ -339,39 +304,13 @@ struct thread_map *thread_map__new_str(const char *pid, const char *tid, return thread_map__new_by_tid_str(tid); } -static void thread_map__delete(struct 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(thread_map__comm(threads, i)); - free(threads); - } -} - -struct thread_map *thread_map__get(struct thread_map *map) -{ - if (map) - refcount_inc(&map->refcnt); - return map; -} - -void thread_map__put(struct thread_map *map) -{ - if (map && refcount_dec_and_test(&map->refcnt)) - thread_map__delete(map); -} - -size_t thread_map__fprintf(struct thread_map *threads, FILE *fp) +size_t thread_map__fprintf(struct perf_thread_map *threads, FILE *fp) { int i; size_t printed = fprintf(fp, "%d thread%s: ", threads->nr, threads->nr > 1 ? "s" : ""); for (i = 0; i < threads->nr; ++i) - printed += fprintf(fp, "%s%d", i ? ", " : "", thread_map__pid(threads, i)); + printed += fprintf(fp, "%s%d", i ? ", " : "", perf_thread_map__pid(threads, i)); return printed + fprintf(fp, "\n"); } @@ -400,9 +339,9 @@ static int get_comm(char **comm, pid_t pid) return err; } -static void comm_init(struct thread_map *map, int i) +static void comm_init(struct perf_thread_map *map, int i) { - pid_t pid = thread_map__pid(map, i); + pid_t pid = perf_thread_map__pid(map, i); char *comm = NULL; /* dummy pid comm initialization */ @@ -421,7 +360,7 @@ static void comm_init(struct thread_map *map, int i) map->map[i].comm = comm; } -void thread_map__read_comms(struct thread_map *threads) +void thread_map__read_comms(struct perf_thread_map *threads) { int i; @@ -429,24 +368,24 @@ void thread_map__read_comms(struct thread_map *threads) comm_init(threads, i); } -static void thread_map__copy_event(struct thread_map *threads, - struct thread_map_event *event) +static void thread_map__copy_event(struct perf_thread_map *threads, + struct perf_record_thread_map *event) { unsigned i; threads->nr = (int) event->nr; for (i = 0; i < event->nr; i++) { - thread_map__set_pid(threads, i, (pid_t) event->entries[i].pid); + perf_thread_map__set_pid(threads, i, (pid_t) event->entries[i].pid); threads->map[i].comm = strndup(event->entries[i].comm, 16); } refcount_set(&threads->refcnt, 1); } -struct thread_map *thread_map__new_event(struct thread_map_event *event) +struct perf_thread_map *thread_map__new_event(struct perf_record_thread_map *event) { - struct thread_map *threads; + struct perf_thread_map *threads; threads = thread_map__alloc(event->nr); if (threads) @@ -455,7 +394,7 @@ struct thread_map *thread_map__new_event(struct thread_map_event *event) return threads; } -bool thread_map__has(struct thread_map *threads, pid_t pid) +bool thread_map__has(struct perf_thread_map *threads, pid_t pid) { int i; @@ -467,7 +406,7 @@ bool thread_map__has(struct thread_map *threads, pid_t pid) return false; } -int thread_map__remove(struct thread_map *threads, int idx) +int thread_map__remove(struct perf_thread_map *threads, int idx) { int i; diff --git a/tools/perf/util/thread_map.h b/tools/perf/util/thread_map.h index 2f689c90a8c6..3bb860a32b8e 100644 --- a/tools/perf/util/thread_map.h +++ b/tools/perf/util/thread_map.h @@ -5,61 +5,27 @@ #include <sys/types.h> #include <stdio.h> #include <linux/refcount.h> +#include <internal/threadmap.h> +#include <perf/threadmap.h> -struct thread_map_data { - pid_t pid; - char *comm; -}; +struct perf_record_thread_map; -struct thread_map { - refcount_t refcnt; - int nr; - int err_thread; - struct thread_map_data map[]; -}; +struct perf_thread_map *thread_map__new_dummy(void); +struct perf_thread_map *thread_map__new_by_pid(pid_t pid); +struct perf_thread_map *thread_map__new_by_tid(pid_t tid); +struct perf_thread_map *thread_map__new_by_uid(uid_t uid); +struct perf_thread_map *thread_map__new_all_cpus(void); +struct perf_thread_map *thread_map__new(pid_t pid, pid_t tid, uid_t uid); +struct perf_thread_map *thread_map__new_event(struct perf_record_thread_map *event); -struct thread_map_event; - -struct thread_map *thread_map__new_dummy(void); -struct thread_map *thread_map__new_by_pid(pid_t pid); -struct thread_map *thread_map__new_by_tid(pid_t tid); -struct thread_map *thread_map__new_by_uid(uid_t uid); -struct thread_map *thread_map__new_all_cpus(void); -struct thread_map *thread_map__new(pid_t pid, pid_t tid, uid_t uid); -struct thread_map *thread_map__new_event(struct thread_map_event *event); - -struct thread_map *thread_map__get(struct thread_map *map); -void thread_map__put(struct thread_map *map); - -struct thread_map *thread_map__new_str(const char *pid, +struct perf_thread_map *thread_map__new_str(const char *pid, const char *tid, uid_t uid, bool all_threads); -struct thread_map *thread_map__new_by_tid_str(const char *tid_str); - -size_t thread_map__fprintf(struct thread_map *threads, FILE *fp); - -static inline int thread_map__nr(struct thread_map *threads) -{ - return threads ? threads->nr : 1; -} - -static inline pid_t thread_map__pid(struct thread_map *map, int thread) -{ - return map->map[thread].pid; -} - -static inline void -thread_map__set_pid(struct thread_map *map, int thread, pid_t pid) -{ - map->map[thread].pid = pid; -} +struct perf_thread_map *thread_map__new_by_tid_str(const char *tid_str); -static inline char *thread_map__comm(struct thread_map *map, int thread) -{ - return map->map[thread].comm; -} +size_t thread_map__fprintf(struct perf_thread_map *threads, FILE *fp); -void thread_map__read_comms(struct thread_map *threads); -bool thread_map__has(struct thread_map *threads, pid_t pid); -int thread_map__remove(struct thread_map *threads, int idx); +void thread_map__read_comms(struct perf_thread_map *threads); +bool thread_map__has(struct perf_thread_map *threads, pid_t pid); +int thread_map__remove(struct perf_thread_map *threads, int idx); #endif /* __PERF_THREAD_MAP_H */ diff --git a/tools/perf/util/time-utils.c b/tools/perf/util/time-utils.c index c2abc259b51d..9796a2e43f67 100644 --- a/tools/perf/util/time-utils.c +++ b/tools/perf/util/time-utils.c @@ -10,7 +10,6 @@ #include <math.h> #include <linux/ctype.h> -#include "perf.h" #include "debug.h" #include "time-utils.h" #include "session.h" diff --git a/tools/perf/util/time-utils.h b/tools/perf/util/time-utils.h index 72a42ea1d513..4f42988eb2f7 100644 --- a/tools/perf/util/time-utils.h +++ b/tools/perf/util/time-utils.h @@ -3,6 +3,7 @@ #define _TIME_UTILS_H_ #include <stddef.h> +#include <time.h> #include <linux/types.h> struct perf_time_interval { @@ -34,4 +35,12 @@ int timestamp__scnprintf_nsec(u64 timestamp, char *buf, size_t sz); int fetch_current_timestamp(char *buf, size_t sz); +static inline unsigned long long rdclock(void) +{ + struct timespec ts; + + clock_gettime(CLOCK_MONOTONIC, &ts); + return ts.tv_sec * 1000000000ULL + ts.tv_nsec; +} + #endif diff --git a/tools/perf/util/tool.h b/tools/perf/util/tool.h index 9096a6e3de59..2abbf668b8de 100644 --- a/tools/perf/util/tool.h +++ b/tools/perf/util/tool.h @@ -8,8 +8,8 @@ struct perf_session; union perf_event; -struct perf_evlist; -struct perf_evsel; +struct evlist; +struct evsel; struct perf_sample; struct perf_tool; struct machine; @@ -17,14 +17,14 @@ struct ordered_events; typedef int (*event_sample)(struct perf_tool *tool, union perf_event *event, struct perf_sample *sample, - struct perf_evsel *evsel, struct machine *machine); + struct evsel *evsel, struct machine *machine); typedef int (*event_op)(struct perf_tool *tool, union perf_event *event, struct perf_sample *sample, struct machine *machine); typedef int (*event_attr_op)(struct perf_tool *tool, union perf_event *event, - struct perf_evlist **pevlist); + struct evlist **pevlist); typedef int (*event_op2)(struct perf_session *session, union perf_event *event); typedef s64 (*event_op3)(struct perf_session *session, union perf_event *event); @@ -56,7 +56,7 @@ struct perf_tool { throttle, unthrottle, ksymbol, - bpf_event; + bpf; event_attr_op attr; event_attr_op event_update; diff --git a/tools/perf/util/top.c b/tools/perf/util/top.c index 251bbf124fb0..51fb574998bb 100644 --- a/tools/perf/util/top.c +++ b/tools/perf/util/top.c @@ -12,6 +12,7 @@ #include "parse-events.h" #include "symbol.h" #include "top.h" +#include "../perf.h" #include <inttypes.h> #define SNPRINTF(buf, size, fmt, args...) \ @@ -70,10 +71,10 @@ size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size) esamples_percent); } - if (top->evlist->nr_entries == 1) { - struct perf_evsel *first = perf_evlist__first(top->evlist); + if (top->evlist->core.nr_entries == 1) { + struct evsel *first = perf_evlist__first(top->evlist); ret += SNPRINTF(bf + ret, size - ret, "%" PRIu64 "%s ", - (uint64_t)first->attr.sample_period, + (uint64_t)first->core.attr.sample_period, opts->freq ? "Hz" : ""); } @@ -95,15 +96,15 @@ size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size) if (target->cpu_list) ret += SNPRINTF(bf + ret, size - ret, ", CPU%s: %s)", - top->evlist->cpus->nr > 1 ? "s" : "", + top->evlist->core.cpus->nr > 1 ? "s" : "", target->cpu_list); else { if (target->tid) ret += SNPRINTF(bf + ret, size - ret, ")"); else ret += SNPRINTF(bf + ret, size - ret, ", %d CPU%s)", - top->evlist->cpus->nr, - top->evlist->cpus->nr > 1 ? "s" : ""); + top->evlist->core.cpus->nr, + top->evlist->core.cpus->nr > 1 ? "s" : ""); } perf_top__reset_sample_counters(top); diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h index 19f95eaf75c8..f117d4f4821e 100644 --- a/tools/perf/util/top.h +++ b/tools/perf/util/top.h @@ -3,21 +3,25 @@ #define __PERF_TOP_H 1 #include "tool.h" +#include "evswitch.h" #include "annotate.h" +#include "ordered-events.h" +#include "record.h" #include <linux/types.h> #include <stddef.h> #include <stdbool.h> #include <sys/ioctl.h> -struct perf_evlist; -struct perf_evsel; +struct evlist; +struct evsel; struct perf_session; struct perf_top { struct perf_tool tool; - struct perf_evlist *evlist; + struct evlist *evlist; struct record_opts record_opts; struct annotation_options annotation_opts; + struct evswitch evswitch; /* * Symbols will be added here in perf_event__process_sample and will * get out after decayed. @@ -33,7 +37,7 @@ struct perf_top { bool vmlinux_warned; bool dump_symtab; struct hist_entry *sym_filter_entry; - struct perf_evsel *sym_evsel; + struct evsel *sym_evsel; struct perf_session *session; struct winsize winsize; int realtime_prio; diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c index 4550015b9d5d..d63d542b2cde 100644 --- a/tools/perf/util/trace-event-info.c +++ b/tools/perf/util/trace-event-info.c @@ -20,7 +20,6 @@ #include <linux/kernel.h> #include <linux/zalloc.h> -#include "../perf.h" #include "trace-event.h" #include <api/fs/tracing_path.h> #include "evsel.h" @@ -405,11 +404,11 @@ static struct tracepoint_path * get_tracepoints_path(struct list_head *pattrs) { struct tracepoint_path path, *ppath = &path; - struct perf_evsel *pos; + struct evsel *pos; int nr_tracepoints = 0; - list_for_each_entry(pos, pattrs, node) { - if (pos->attr.type != PERF_TYPE_TRACEPOINT) + list_for_each_entry(pos, pattrs, core.node) { + if (pos->core.attr.type != PERF_TYPE_TRACEPOINT) continue; ++nr_tracepoints; @@ -425,7 +424,7 @@ get_tracepoints_path(struct list_head *pattrs) } try_id: - ppath->next = tracepoint_id_to_path(pos->attr.config); + ppath->next = tracepoint_id_to_path(pos->core.attr.config); if (!ppath->next) { error: pr_debug("No memory to alloc tracepoints list\n"); @@ -441,10 +440,10 @@ next: bool have_tracepoints(struct list_head *pattrs) { - struct perf_evsel *pos; + struct evsel *pos; - list_for_each_entry(pos, pattrs, node) - if (pos->attr.type == PERF_TYPE_TRACEPOINT) + list_for_each_entry(pos, pattrs, core.node) + if (pos->core.attr.type == PERF_TYPE_TRACEPOINT) return true; return false; diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c index b3982e1bb4c5..5d6bfc70b210 100644 --- a/tools/perf/util/trace-event-parse.c +++ b/tools/perf/util/trace-event-parse.c @@ -7,7 +7,6 @@ #include <string.h> #include <errno.h> -#include "../perf.h" #include "debug.h" #include "trace-event.h" @@ -110,7 +109,7 @@ void event_format__fprintf(struct tep_event *event, record.data = data; trace_seq_init(&s); - tep_event_info(&s, event, &record); + tep_print_event(event->tep, &s, &record, "%s", TEP_PRINT_INFO); trace_seq_do_fprintf(&s, fp); trace_seq_destroy(&s); } diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c index 13c1cf60d1bc..b6c0db068be0 100644 --- a/tools/perf/util/trace-event-read.c +++ b/tools/perf/util/trace-event-read.c @@ -15,7 +15,6 @@ #include <unistd.h> #include <errno.h> -#include "../perf.h" #include "util.h" #include "trace-event.h" #include "debug.h" diff --git a/tools/perf/util/trace-event-scripting.c b/tools/perf/util/trace-event-scripting.c index ba58f69777a1..714581b0de65 100644 --- a/tools/perf/util/trace-event-scripting.c +++ b/tools/perf/util/trace-event-scripting.c @@ -10,7 +10,6 @@ #include <string.h> #include <errno.h> -#include "../perf.h" #include "debug.h" #include "trace-event.h" #include <linux/zalloc.h> @@ -29,7 +28,7 @@ static int stop_script_unsupported(void) static void process_event_unsupported(union perf_event *event __maybe_unused, struct perf_sample *sample __maybe_unused, - struct perf_evsel *evsel __maybe_unused, + struct evsel *evsel __maybe_unused, struct addr_location *al __maybe_unused) { } diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h index c7002fe11673..2e158387b3d7 100644 --- a/tools/perf/util/trace-event.h +++ b/tools/perf/util/trace-event.h @@ -3,7 +3,6 @@ #define _PERF_UTIL_TRACE_EVENT_H #include <traceevent/event-parse.h> -#include <traceevent/trace-seq.h> #include "parse-events.h" struct machine; @@ -79,13 +78,13 @@ struct scripting_ops { int (*stop_script) (void); void (*process_event) (union perf_event *event, struct perf_sample *sample, - struct perf_evsel *evsel, + struct evsel *evsel, struct addr_location *al); void (*process_switch)(union perf_event *event, struct perf_sample *sample, struct machine *machine); void (*process_stat)(struct perf_stat_config *config, - struct perf_evsel *evsel, u64 tstamp); + struct evsel *evsel, u64 tstamp); void (*process_stat_interval)(u64 tstamp); int (*generate_script) (struct tep_handle *pevent, const char *outfile); }; diff --git a/tools/perf/util/trigger.h b/tools/perf/util/trigger.h index 88223bc7c82b..33e997f9ccc8 100644 --- a/tools/perf/util/trigger.h +++ b/tools/perf/util/trigger.h @@ -2,7 +2,6 @@ #ifndef __TRIGGER_H_ #define __TRIGGER_H_ 1 -#include "util/debug.h" #include "asm/bug.h" /* diff --git a/tools/perf/util/unwind-libdw.c b/tools/perf/util/unwind-libdw.c index 28f71ca6ce1c..9ece188ae48a 100644 --- a/tools/perf/util/unwind-libdw.c +++ b/tools/perf/util/unwind-libdw.c @@ -5,6 +5,7 @@ #include <inttypes.h> #include <errno.h> #include "debug.h" +#include "dso.h" #include "unwind.h" #include "unwind-libdw.h" #include "machine.h" diff --git a/tools/perf/util/unwind-libunwind-local.c b/tools/perf/util/unwind-libunwind-local.c index 71a788921b62..ebdbb056510c 100644 --- a/tools/perf/util/unwind-libunwind-local.c +++ b/tools/perf/util/unwind-libunwind-local.c @@ -616,26 +616,26 @@ static unw_accessors_t accessors = { .get_proc_name = get_proc_name, }; -static int _unwind__prepare_access(struct thread *thread) +static int _unwind__prepare_access(struct map_groups *mg) { - thread->addr_space = unw_create_addr_space(&accessors, 0); - if (!thread->addr_space) { + mg->addr_space = unw_create_addr_space(&accessors, 0); + if (!mg->addr_space) { pr_err("unwind: Can't create unwind address space.\n"); return -ENOMEM; } - unw_set_caching_policy(thread->addr_space, UNW_CACHE_GLOBAL); + unw_set_caching_policy(mg->addr_space, UNW_CACHE_GLOBAL); return 0; } -static void _unwind__flush_access(struct thread *thread) +static void _unwind__flush_access(struct map_groups *mg) { - unw_flush_cache(thread->addr_space, 0, 0); + unw_flush_cache(mg->addr_space, 0, 0); } -static void _unwind__finish_access(struct thread *thread) +static void _unwind__finish_access(struct map_groups *mg) { - unw_destroy_addr_space(thread->addr_space); + unw_destroy_addr_space(mg->addr_space); } static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb, @@ -660,7 +660,7 @@ static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb, */ if (max_stack - 1 > 0) { WARN_ONCE(!ui->thread, "WARNING: ui->thread is NULL"); - addr_space = ui->thread->addr_space; + addr_space = ui->thread->mg->addr_space; if (addr_space == NULL) return -1; diff --git a/tools/perf/util/unwind-libunwind.c b/tools/perf/util/unwind-libunwind.c index c0811977d7d5..a24fb57c9b2c 100644 --- a/tools/perf/util/unwind-libunwind.c +++ b/tools/perf/util/unwind-libunwind.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 #include "unwind.h" +#include "dso.h" #include "map.h" #include "thread.h" #include "session.h" @@ -11,13 +12,13 @@ struct unwind_libunwind_ops __weak *local_unwind_libunwind_ops; struct unwind_libunwind_ops __weak *x86_32_unwind_libunwind_ops; struct unwind_libunwind_ops __weak *arm64_unwind_libunwind_ops; -static void unwind__register_ops(struct thread *thread, +static void unwind__register_ops(struct map_groups *mg, struct unwind_libunwind_ops *ops) { - thread->unwind_libunwind_ops = ops; + mg->unwind_libunwind_ops = ops; } -int unwind__prepare_access(struct thread *thread, struct map *map, +int unwind__prepare_access(struct map_groups *mg, struct map *map, bool *initialized) { const char *arch; @@ -28,7 +29,7 @@ int unwind__prepare_access(struct thread *thread, struct map *map, if (!dwarf_callchain_users) return 0; - if (thread->addr_space) { + if (mg->addr_space) { pr_debug("unwind: thread map already set, dso=%s\n", map->dso->name); if (initialized) @@ -37,14 +38,14 @@ int unwind__prepare_access(struct thread *thread, struct map *map, } /* env->arch is NULL for live-mode (i.e. perf top) */ - if (!thread->mg->machine->env || !thread->mg->machine->env->arch) + if (!mg->machine->env || !mg->machine->env->arch) goto out_register; - dso_type = dso__type(map->dso, thread->mg->machine); + dso_type = dso__type(map->dso, mg->machine); if (dso_type == DSO__TYPE_UNKNOWN) return 0; - arch = perf_env__arch(thread->mg->machine->env); + arch = perf_env__arch(mg->machine->env); if (!strcmp(arch, "x86")) { if (dso_type != DSO__TYPE_64BIT) @@ -59,37 +60,31 @@ int unwind__prepare_access(struct thread *thread, struct map *map, return 0; } out_register: - unwind__register_ops(thread, ops); + unwind__register_ops(mg, ops); - err = thread->unwind_libunwind_ops->prepare_access(thread); + err = mg->unwind_libunwind_ops->prepare_access(mg); if (initialized) *initialized = err ? false : true; return err; } -void unwind__flush_access(struct thread *thread) +void unwind__flush_access(struct map_groups *mg) { - if (!dwarf_callchain_users) - return; - - if (thread->unwind_libunwind_ops) - thread->unwind_libunwind_ops->flush_access(thread); + if (mg->unwind_libunwind_ops) + mg->unwind_libunwind_ops->flush_access(mg); } -void unwind__finish_access(struct thread *thread) +void unwind__finish_access(struct map_groups *mg) { - if (!dwarf_callchain_users) - return; - - if (thread->unwind_libunwind_ops) - thread->unwind_libunwind_ops->finish_access(thread); + if (mg->unwind_libunwind_ops) + mg->unwind_libunwind_ops->finish_access(mg); } int unwind__get_entries(unwind_entry_cb_t cb, void *arg, struct thread *thread, struct perf_sample *data, int max_stack) { - if (thread->unwind_libunwind_ops) - return thread->unwind_libunwind_ops->get_entries(cb, arg, thread, data, max_stack); + if (thread->mg->unwind_libunwind_ops) + return thread->mg->unwind_libunwind_ops->get_entries(cb, arg, thread, data, max_stack); return 0; } diff --git a/tools/perf/util/unwind.h b/tools/perf/util/unwind.h index 8a44a1569a21..3a7d00c20d86 100644 --- a/tools/perf/util/unwind.h +++ b/tools/perf/util/unwind.h @@ -6,6 +6,7 @@ #include <linux/types.h> struct map; +struct map_groups; struct perf_sample; struct symbol; struct thread; @@ -19,9 +20,9 @@ struct unwind_entry { typedef int (*unwind_entry_cb_t)(struct unwind_entry *entry, void *arg); struct unwind_libunwind_ops { - int (*prepare_access)(struct thread *thread); - void (*flush_access)(struct thread *thread); - void (*finish_access)(struct thread *thread); + int (*prepare_access)(struct map_groups *mg); + void (*flush_access)(struct map_groups *mg); + void (*finish_access)(struct map_groups *mg); int (*get_entries)(unwind_entry_cb_t cb, void *arg, struct thread *thread, struct perf_sample *data, int max_stack); @@ -46,20 +47,20 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg, #endif int LIBUNWIND__ARCH_REG_ID(int regnum); -int unwind__prepare_access(struct thread *thread, struct map *map, +int unwind__prepare_access(struct map_groups *mg, struct map *map, bool *initialized); -void unwind__flush_access(struct thread *thread); -void unwind__finish_access(struct thread *thread); +void unwind__flush_access(struct map_groups *mg); +void unwind__finish_access(struct map_groups *mg); #else -static inline int unwind__prepare_access(struct thread *thread __maybe_unused, +static inline int unwind__prepare_access(struct map_groups *mg __maybe_unused, struct map *map __maybe_unused, bool *initialized __maybe_unused) { return 0; } -static inline void unwind__flush_access(struct thread *thread __maybe_unused) {} -static inline void unwind__finish_access(struct thread *thread __maybe_unused) {} +static inline void unwind__flush_access(struct map_groups *mg __maybe_unused) {} +static inline void unwind__finish_access(struct map_groups *mg __maybe_unused) {} #endif #else static inline int @@ -72,14 +73,14 @@ unwind__get_entries(unwind_entry_cb_t cb __maybe_unused, return 0; } -static inline int unwind__prepare_access(struct thread *thread __maybe_unused, +static inline int unwind__prepare_access(struct map_groups *mg __maybe_unused, struct map *map __maybe_unused, bool *initialized __maybe_unused) { return 0; } -static inline void unwind__flush_access(struct thread *thread __maybe_unused) {} -static inline void unwind__finish_access(struct thread *thread __maybe_unused) {} +static inline void unwind__flush_access(struct map_groups *mg __maybe_unused) {} +static inline void unwind__finish_access(struct map_groups *mg __maybe_unused) {} #endif /* HAVE_DWARF_UNWIND_SUPPORT */ #endif /* __UNWIND_H */ diff --git a/tools/perf/util/util-cxx.h b/tools/perf/util/util-cxx.h deleted file mode 100644 index 80a99e458d4e..000000000000 --- a/tools/perf/util/util-cxx.h +++ /dev/null @@ -1,27 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Support C++ source use utilities defined in util.h - */ - -#ifndef PERF_UTIL_UTIL_CXX_H -#define PERF_UTIL_UTIL_CXX_H - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * Now 'new' is the only C++ keyword found in util.h: - * in tools/include/linux/rbtree.h - * - * Other keywords, like class and delete, should be - * redefined if necessary. - */ -#define new _new -#include "util.h" -#undef new - -#ifdef __cplusplus -} -#endif -#endif diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c index a61535cf1bca..32322a20a68b 100644 --- a/tools/perf/util/util.c +++ b/tools/perf/util/util.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 -#include "../perf.h" #include "util.h" #include "debug.h" +#include "event.h" #include "namespaces.h" #include <api/fs/fs.h> #include <sys/mman.h> @@ -16,10 +16,12 @@ #include <string.h> #include <errno.h> #include <limits.h> +#include <linux/capability.h> #include <linux/kernel.h> #include <linux/log2.h> #include <linux/time64.h> #include <unistd.h> +#include "cap.h" #include "strlist.h" #include "string2.h" @@ -41,26 +43,6 @@ void perf_set_multithreaded(void) unsigned int page_size; -#ifdef _SC_LEVEL1_DCACHE_LINESIZE -#define cache_line_size(cacheline_sizep) *cacheline_sizep = sysconf(_SC_LEVEL1_DCACHE_LINESIZE) -#else -static void cache_line_size(int *cacheline_sizep) -{ - if (sysfs__read_int("devices/system/cpu/cpu0/cache/index0/coherency_line_size", cacheline_sizep)) - pr_debug("cannot determine cache line size"); -} -#endif - -int cacheline_size(void) -{ - static int size; - - if (!size) - cache_line_size(&size); - - return size; -} - int sysctl_perf_event_max_stack = PERF_MAX_STACK_DEPTH; int sysctl_perf_event_max_contexts_per_stack = PERF_MAX_CONTEXTS_PER_STACK; @@ -384,46 +366,6 @@ int copyfile(const char *from, const char *to) return copyfile_mode(from, to, 0755); } -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); -} - size_t hex_width(u64 v) { size_t n = 1; @@ -443,6 +385,13 @@ int perf_event_paranoid(void) return value; } + +bool perf_event_paranoid_check(int max_level) +{ + return perf_cap__capable(CAP_SYS_ADMIN) || + perf_event_paranoid() <= max_level; +} + static int fetch_ubuntu_kernel_version(unsigned int *puint) { diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index dc7a469921e9..45a5c6f20197 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h @@ -11,6 +11,7 @@ #include <stddef.h> #include <linux/compiler.h> #include <sys/types.h> +#include <internal/lib.h> /* General helper functions */ void usage(const char *err) __noreturn; @@ -30,13 +31,9 @@ int copyfile_mode(const char *from, const char *to, mode_t mode); int copyfile_ns(const char *from, const char *to, struct nsinfo *nsi); int copyfile_offset(int ifd, loff_t off_in, int ofd, loff_t off_out, u64 size); -ssize_t readn(int fd, void *buf, size_t n); -ssize_t writen(int fd, const void *buf, size_t n); - size_t hex_width(u64 v); extern unsigned int page_size; -int __pure cacheline_size(void); int sysctl__max_stack(void); diff --git a/tools/perf/util/values.c b/tools/perf/util/values.c index c59154e2d124..b9823f414f10 100644 --- a/tools/perf/util/values.c +++ b/tools/perf/util/values.c @@ -2,6 +2,7 @@ #include <inttypes.h> #include <stdio.h> #include <stdlib.h> +#include <string.h> #include <errno.h> #include <linux/zalloc.h> diff --git a/tools/perf/util/vdso.c b/tools/perf/util/vdso.c index 7f427bab6c12..e5e6599603f4 100644 --- a/tools/perf/util/vdso.c +++ b/tools/perf/util/vdso.c @@ -10,6 +10,7 @@ #include <linux/kernel.h> #include "vdso.h" +#include "dso.h" #include "util.h" #include "map.h" #include "symbol.h" diff --git a/tools/perf/util/xyarray.h b/tools/perf/util/xyarray.h deleted file mode 100644 index 7ffe562e7ae7..000000000000 --- a/tools/perf/util/xyarray.h +++ /dev/null @@ -1,35 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef _PERF_XYARRAY_H_ -#define _PERF_XYARRAY_H_ 1 - -#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[]; -}; - -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 /* _PERF_XYARRAY_H_ */ diff --git a/tools/perf/util/zlib.c b/tools/perf/util/zlib.c index 512ad7c09b13..59d456f716e9 100644 --- a/tools/perf/util/zlib.c +++ b/tools/perf/util/zlib.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 #include <fcntl.h> #include <stdio.h> +#include <string.h> #include <unistd.h> #include <sys/stat.h> #include <sys/mman.h> |