diff options
| author | Ingo Molnar <mingo@kernel.org> | 2018-08-18 07:11:51 -0400 |
|---|---|---|
| committer | Ingo Molnar <mingo@kernel.org> | 2018-08-18 07:11:51 -0400 |
| commit | 5804b11034a21e4287daaf017c5ad60ad7af8d67 (patch) | |
| tree | 79dd4998b58e3124bc2e5749914e4046afe5d0fd /tools/perf | |
| parent | 13e091b6dd0e78a518a7d8756607d3acb8215768 (diff) | |
| parent | 6855dc41b24619c3d1de3dbd27dd0546b0e45272 (diff) | |
Merge tag 'perf-core-for-mingo-4.19-20180815' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/urgent
Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo:
kernel:
- kallsyms, x86: Export addresses of PTI entry trampolines (Alexander Shishkin)
- kallsyms: Simplify update_iter_mod() (Adrian Hunter)
- x86: Add entry trampolines to kcore (Adrian Hunter)
Hardware tracing:
- Fix auxtrace queue resize (Adrian Hunter)
Arch specific:
- Fix uninitialized ARM SPE record error variable (Kim Phillips)
- Fix trace event post-processing in powerpc (Sandipan Das)
Build:
- Fix check-headers.sh AND list path of execution (Alexander Kapshuk)
- Remove -mcet and -fcf-protection when building the python binding
with older clang versions (Arnaldo Carvalho de Melo)
- Make check-headers.sh check based on kernel dir (Jiri Olsa)
- Move syscall_64.tbl check into check-headers.sh (Jiri Olsa)
Infrastructure:
- Check for null when copying nsinfo. (Benno Evers)
Libraries:
- Rename libtraceevent prefixes, prep work for making it a shared
library generaly available (Tzvetomir Stoyanov (VMware))
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools/perf')
52 files changed, 1906 insertions, 337 deletions
diff --git a/tools/perf/Documentation/perf-annotate.txt b/tools/perf/Documentation/perf-annotate.txt index 749cc6055dac..e8c972f89357 100644 --- a/tools/perf/Documentation/perf-annotate.txt +++ b/tools/perf/Documentation/perf-annotate.txt | |||
| @@ -118,6 +118,15 @@ OPTIONS | |||
| 118 | --group:: | 118 | --group:: |
| 119 | Show event group information together | 119 | Show event group information together |
| 120 | 120 | ||
| 121 | --percent-type:: | ||
| 122 | Set annotation percent type from following choices: | ||
| 123 | global-period, local-period, global-hits, local-hits | ||
| 124 | |||
| 125 | The local/global keywords set if the percentage is computed | ||
| 126 | in the scope of the function (local) or the whole data (global). | ||
| 127 | The period/hits keywords set the base the percentage is computed | ||
| 128 | on - the samples period or the number of samples (hits). | ||
| 129 | |||
| 121 | SEE ALSO | 130 | SEE ALSO |
| 122 | -------- | 131 | -------- |
| 123 | linkperf:perf-record[1], linkperf:perf-report[1] | 132 | linkperf:perf-record[1], linkperf:perf-report[1] |
diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt index 917e36fde6d8..474a4941f65d 100644 --- a/tools/perf/Documentation/perf-report.txt +++ b/tools/perf/Documentation/perf-report.txt | |||
| @@ -477,6 +477,15 @@ include::itrace.txt[] | |||
| 477 | Display monitored tasks stored in perf data. Displaying pid/tid/ppid | 477 | Display monitored tasks stored in perf data. Displaying pid/tid/ppid |
| 478 | plus the command string aligned to distinguish parent and child tasks. | 478 | plus the command string aligned to distinguish parent and child tasks. |
| 479 | 479 | ||
| 480 | --percent-type:: | ||
| 481 | Set annotation percent type from following choices: | ||
| 482 | global-period, local-period, global-hits, local-hits | ||
| 483 | |||
| 484 | The local/global keywords set if the percentage is computed | ||
| 485 | in the scope of the function (local) or the whole data (global). | ||
| 486 | The period/hits keywords set the base the percentage is computed | ||
| 487 | on - the samples period or the number of samples (hits). | ||
| 488 | |||
| 480 | include::callchain-overhead-calculation.txt[] | 489 | include::callchain-overhead-calculation.txt[] |
| 481 | 490 | ||
| 482 | SEE ALSO | 491 | SEE ALSO |
diff --git a/tools/perf/arch/arm64/util/arm-spe.c b/tools/perf/arch/arm64/util/arm-spe.c index 1120e39c1b00..5ccfce87e693 100644 --- a/tools/perf/arch/arm64/util/arm-spe.c +++ b/tools/perf/arch/arm64/util/arm-spe.c | |||
| @@ -194,6 +194,7 @@ struct auxtrace_record *arm_spe_recording_init(int *err, | |||
| 194 | sper->itr.read_finish = arm_spe_read_finish; | 194 | sper->itr.read_finish = arm_spe_read_finish; |
| 195 | sper->itr.alignment = 0; | 195 | sper->itr.alignment = 0; |
| 196 | 196 | ||
| 197 | *err = 0; | ||
| 197 | return &sper->itr; | 198 | return &sper->itr; |
| 198 | } | 199 | } |
| 199 | 200 | ||
diff --git a/tools/perf/arch/powerpc/util/sym-handling.c b/tools/perf/arch/powerpc/util/sym-handling.c index 53d83d7e6a09..20e7d74d86cd 100644 --- a/tools/perf/arch/powerpc/util/sym-handling.c +++ b/tools/perf/arch/powerpc/util/sym-handling.c | |||
| @@ -141,8 +141,10 @@ void arch__post_process_probe_trace_events(struct perf_probe_event *pev, | |||
| 141 | for (i = 0; i < ntevs; i++) { | 141 | for (i = 0; i < ntevs; i++) { |
| 142 | tev = &pev->tevs[i]; | 142 | tev = &pev->tevs[i]; |
| 143 | map__for_each_symbol(map, sym, tmp) { | 143 | map__for_each_symbol(map, sym, tmp) { |
| 144 | if (map->unmap_ip(map, sym->start) == tev->point.address) | 144 | if (map->unmap_ip(map, sym->start) == tev->point.address) { |
| 145 | arch__fix_tev_from_maps(pev, tev, map, sym); | 145 | arch__fix_tev_from_maps(pev, tev, map, sym); |
| 146 | break; | ||
| 147 | } | ||
| 146 | } | 148 | } |
| 147 | } | 149 | } |
| 148 | } | 150 | } |
diff --git a/tools/perf/arch/s390/util/auxtrace.c b/tools/perf/arch/s390/util/auxtrace.c index 3afe8256eff2..44c857388897 100644 --- a/tools/perf/arch/s390/util/auxtrace.c +++ b/tools/perf/arch/s390/util/auxtrace.c | |||
| @@ -30,6 +30,7 @@ cpumsf_info_fill(struct auxtrace_record *itr __maybe_unused, | |||
| 30 | struct auxtrace_info_event *auxtrace_info __maybe_unused, | 30 | struct auxtrace_info_event *auxtrace_info __maybe_unused, |
| 31 | size_t priv_size __maybe_unused) | 31 | size_t priv_size __maybe_unused) |
| 32 | { | 32 | { |
| 33 | auxtrace_info->type = PERF_AUXTRACE_S390_CPUMSF; | ||
| 33 | return 0; | 34 | return 0; |
| 34 | } | 35 | } |
| 35 | 36 | ||
diff --git a/tools/perf/arch/x86/Makefile b/tools/perf/arch/x86/Makefile index 1a38e78117ce..8cc6642fce7a 100644 --- a/tools/perf/arch/x86/Makefile +++ b/tools/perf/arch/x86/Makefile | |||
| @@ -19,9 +19,6 @@ systbl := $(sys)/syscalltbl.sh | |||
| 19 | _dummy := $(shell [ -d '$(out)' ] || mkdir -p '$(out)') | 19 | _dummy := $(shell [ -d '$(out)' ] || mkdir -p '$(out)') |
| 20 | 20 | ||
| 21 | $(header): $(sys)/syscall_64.tbl $(systbl) | 21 | $(header): $(sys)/syscall_64.tbl $(systbl) |
| 22 | @(test -d ../../kernel -a -d ../../tools -a -d ../perf && ( \ | ||
| 23 | (diff -B arch/x86/entry/syscalls/syscall_64.tbl ../../arch/x86/entry/syscalls/syscall_64.tbl >/dev/null) \ | ||
| 24 | || echo "Warning: Kernel ABI header at 'tools/perf/arch/x86/entry/syscalls/syscall_64.tbl' differs from latest version at 'arch/x86/entry/syscalls/syscall_64.tbl'" >&2 )) || true | ||
| 25 | $(Q)$(SHELL) '$(systbl)' $(sys)/syscall_64.tbl 'x86_64' > $@ | 22 | $(Q)$(SHELL) '$(systbl)' $(sys)/syscall_64.tbl 'x86_64' > $@ |
| 26 | 23 | ||
| 27 | clean:: | 24 | clean:: |
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 8180319285af..830481b8db26 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c | |||
| @@ -542,6 +542,10 @@ int cmd_annotate(int argc, const char **argv) | |||
| 542 | OPT_CALLBACK_DEFAULT(0, "stdio-color", NULL, "mode", | 542 | OPT_CALLBACK_DEFAULT(0, "stdio-color", NULL, "mode", |
| 543 | "'always' (default), 'never' or 'auto' only applicable to --stdio mode", | 543 | "'always' (default), 'never' or 'auto' only applicable to --stdio mode", |
| 544 | stdio__config_color, "always"), | 544 | stdio__config_color, "always"), |
| 545 | OPT_CALLBACK(0, "percent-type", &annotate.opts, "local-period", | ||
| 546 | "Set percent type local/global-period/hits", | ||
| 547 | annotate_parse_percent_type), | ||
| 548 | |||
| 545 | OPT_END() | 549 | OPT_END() |
| 546 | }; | 550 | }; |
| 547 | int ret; | 551 | int ret; |
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c index 54d3f21b0e62..b63bca4b0c2a 100644 --- a/tools/perf/builtin-kmem.c +++ b/tools/perf/builtin-kmem.c | |||
| @@ -729,7 +729,7 @@ static char *compact_gfp_string(unsigned long gfp_flags) | |||
| 729 | static int parse_gfp_flags(struct perf_evsel *evsel, struct perf_sample *sample, | 729 | static int parse_gfp_flags(struct perf_evsel *evsel, struct perf_sample *sample, |
| 730 | unsigned int gfp_flags) | 730 | unsigned int gfp_flags) |
| 731 | { | 731 | { |
| 732 | struct pevent_record record = { | 732 | struct tep_record record = { |
| 733 | .cpu = sample->cpu, | 733 | .cpu = sample->cpu, |
| 734 | .data = sample->raw_data, | 734 | .data = sample->raw_data, |
| 735 | .size = sample->raw_size, | 735 | .size = sample->raw_size, |
| @@ -747,7 +747,7 @@ static int parse_gfp_flags(struct perf_evsel *evsel, struct perf_sample *sample, | |||
| 747 | } | 747 | } |
| 748 | 748 | ||
| 749 | trace_seq_init(&seq); | 749 | trace_seq_init(&seq); |
| 750 | pevent_event_info(&seq, evsel->tp_format, &record); | 750 | tep_event_info(&seq, evsel->tp_format, &record); |
| 751 | 751 | ||
| 752 | str = strtok_r(seq.buffer, " ", &pos); | 752 | str = strtok_r(seq.buffer, " ", &pos); |
| 753 | while (str) { | 753 | while (str) { |
| @@ -1974,7 +1974,7 @@ int cmd_kmem(int argc, const char **argv) | |||
| 1974 | goto out_delete; | 1974 | goto out_delete; |
| 1975 | } | 1975 | } |
| 1976 | 1976 | ||
| 1977 | kmem_page_size = pevent_get_page_size(evsel->tp_format->pevent); | 1977 | kmem_page_size = tep_get_page_size(evsel->tp_format->pevent); |
| 1978 | symbol_conf.use_callchain = true; | 1978 | symbol_conf.use_callchain = true; |
| 1979 | } | 1979 | } |
| 1980 | 1980 | ||
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 02f7a3c27761..76e12bcd1765 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c | |||
| @@ -1124,6 +1124,9 @@ int cmd_report(int argc, const char **argv) | |||
| 1124 | "Time span of interest (start,stop)"), | 1124 | "Time span of interest (start,stop)"), |
| 1125 | OPT_BOOLEAN(0, "inline", &symbol_conf.inline_name, | 1125 | OPT_BOOLEAN(0, "inline", &symbol_conf.inline_name, |
| 1126 | "Show inline function"), | 1126 | "Show inline function"), |
| 1127 | OPT_CALLBACK(0, "percent-type", &report.annotation_opts, "local-period", | ||
| 1128 | "Set percent type local/global-period/hits", | ||
| 1129 | annotate_parse_percent_type), | ||
| 1127 | OPT_END() | 1130 | OPT_END() |
| 1128 | }; | 1131 | }; |
| 1129 | struct perf_data data = { | 1132 | struct perf_data data = { |
| @@ -1366,9 +1369,9 @@ repeat: | |||
| 1366 | } | 1369 | } |
| 1367 | 1370 | ||
| 1368 | if (session->tevent.pevent && | 1371 | if (session->tevent.pevent && |
| 1369 | pevent_set_function_resolver(session->tevent.pevent, | 1372 | tep_set_function_resolver(session->tevent.pevent, |
| 1370 | machine__resolve_kernel_addr, | 1373 | machine__resolve_kernel_addr, |
| 1371 | &session->machines.host) < 0) { | 1374 | &session->machines.host) < 0) { |
| 1372 | pr_err("%s: failed to set libtraceevent function resolver\n", | 1375 | pr_err("%s: failed to set libtraceevent function resolver\n", |
| 1373 | __func__); | 1376 | __func__); |
| 1374 | return -1; | 1377 | return -1; |
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 568ddfac3213..ba481d73f910 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c | |||
| @@ -3429,9 +3429,9 @@ int cmd_script(int argc, const char **argv) | |||
| 3429 | symbol_conf.use_callchain = false; | 3429 | symbol_conf.use_callchain = false; |
| 3430 | 3430 | ||
| 3431 | if (session->tevent.pevent && | 3431 | if (session->tevent.pevent && |
| 3432 | pevent_set_function_resolver(session->tevent.pevent, | 3432 | tep_set_function_resolver(session->tevent.pevent, |
| 3433 | machine__resolve_kernel_addr, | 3433 | machine__resolve_kernel_addr, |
| 3434 | &session->machines.host) < 0) { | 3434 | &session->machines.host) < 0) { |
| 3435 | pr_err("%s: failed to set libtraceevent function resolver\n", __func__); | 3435 | pr_err("%s: failed to set libtraceevent function resolver\n", __func__); |
| 3436 | err = -1; | 3436 | err = -1; |
| 3437 | goto out_delete; | 3437 | goto out_delete; |
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 88561eed7950..22ab8e67c760 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c | |||
| @@ -77,7 +77,8 @@ struct trace { | |||
| 77 | struct syscall *table; | 77 | struct syscall *table; |
| 78 | struct { | 78 | struct { |
| 79 | struct perf_evsel *sys_enter, | 79 | struct perf_evsel *sys_enter, |
| 80 | *sys_exit; | 80 | *sys_exit, |
| 81 | *augmented; | ||
| 81 | } events; | 82 | } events; |
| 82 | } syscalls; | 83 | } syscalls; |
| 83 | struct record_opts opts; | 84 | struct record_opts opts; |
| @@ -121,7 +122,6 @@ struct trace { | |||
| 121 | bool force; | 122 | bool force; |
| 122 | bool vfs_getname; | 123 | bool vfs_getname; |
| 123 | int trace_pgfaults; | 124 | int trace_pgfaults; |
| 124 | int open_id; | ||
| 125 | }; | 125 | }; |
| 126 | 126 | ||
| 127 | struct tp_field { | 127 | struct tp_field { |
| @@ -157,13 +157,11 @@ TP_UINT_FIELD__SWAPPED(16); | |||
| 157 | TP_UINT_FIELD__SWAPPED(32); | 157 | TP_UINT_FIELD__SWAPPED(32); |
| 158 | TP_UINT_FIELD__SWAPPED(64); | 158 | TP_UINT_FIELD__SWAPPED(64); |
| 159 | 159 | ||
| 160 | static int tp_field__init_uint(struct tp_field *field, | 160 | static int __tp_field__init_uint(struct tp_field *field, int size, int offset, bool needs_swap) |
| 161 | struct format_field *format_field, | ||
| 162 | bool needs_swap) | ||
| 163 | { | 161 | { |
| 164 | field->offset = format_field->offset; | 162 | field->offset = offset; |
| 165 | 163 | ||
| 166 | switch (format_field->size) { | 164 | switch (size) { |
| 167 | case 1: | 165 | case 1: |
| 168 | field->integer = tp_field__u8; | 166 | field->integer = tp_field__u8; |
| 169 | break; | 167 | break; |
| @@ -183,18 +181,28 @@ static int tp_field__init_uint(struct tp_field *field, | |||
| 183 | return 0; | 181 | return 0; |
| 184 | } | 182 | } |
| 185 | 183 | ||
| 184 | static int tp_field__init_uint(struct tp_field *field, struct format_field *format_field, bool needs_swap) | ||
| 185 | { | ||
| 186 | return __tp_field__init_uint(field, format_field->size, format_field->offset, needs_swap); | ||
| 187 | } | ||
| 188 | |||
| 186 | static void *tp_field__ptr(struct tp_field *field, struct perf_sample *sample) | 189 | static void *tp_field__ptr(struct tp_field *field, struct perf_sample *sample) |
| 187 | { | 190 | { |
| 188 | return sample->raw_data + field->offset; | 191 | return sample->raw_data + field->offset; |
| 189 | } | 192 | } |
| 190 | 193 | ||
| 191 | static int tp_field__init_ptr(struct tp_field *field, struct format_field *format_field) | 194 | static int __tp_field__init_ptr(struct tp_field *field, int offset) |
| 192 | { | 195 | { |
| 193 | field->offset = format_field->offset; | 196 | field->offset = offset; |
| 194 | field->pointer = tp_field__ptr; | 197 | field->pointer = tp_field__ptr; |
| 195 | return 0; | 198 | return 0; |
| 196 | } | 199 | } |
| 197 | 200 | ||
| 201 | static int tp_field__init_ptr(struct tp_field *field, struct format_field *format_field) | ||
| 202 | { | ||
| 203 | return __tp_field__init_ptr(field, format_field->offset); | ||
| 204 | } | ||
| 205 | |||
| 198 | struct syscall_tp { | 206 | struct syscall_tp { |
| 199 | struct tp_field id; | 207 | struct tp_field id; |
| 200 | union { | 208 | union { |
| @@ -240,7 +248,47 @@ static void perf_evsel__delete_priv(struct perf_evsel *evsel) | |||
| 240 | perf_evsel__delete(evsel); | 248 | perf_evsel__delete(evsel); |
| 241 | } | 249 | } |
| 242 | 250 | ||
| 243 | static int perf_evsel__init_syscall_tp(struct perf_evsel *evsel, void *handler) | 251 | static int perf_evsel__init_syscall_tp(struct perf_evsel *evsel) |
| 252 | { | ||
| 253 | struct syscall_tp *sc = evsel->priv = malloc(sizeof(struct syscall_tp)); | ||
| 254 | |||
| 255 | if (evsel->priv != NULL) { | ||
| 256 | if (perf_evsel__init_tp_uint_field(evsel, &sc->id, "__syscall_nr")) | ||
| 257 | goto out_delete; | ||
| 258 | return 0; | ||
| 259 | } | ||
| 260 | |||
| 261 | return -ENOMEM; | ||
| 262 | out_delete: | ||
| 263 | zfree(&evsel->priv); | ||
| 264 | return -ENOENT; | ||
| 265 | } | ||
| 266 | |||
| 267 | static int perf_evsel__init_augmented_syscall_tp(struct perf_evsel *evsel) | ||
| 268 | { | ||
| 269 | struct syscall_tp *sc = evsel->priv = malloc(sizeof(struct syscall_tp)); | ||
| 270 | |||
| 271 | if (evsel->priv != NULL) { /* field, sizeof_field, offsetof_field */ | ||
| 272 | if (__tp_field__init_uint(&sc->id, sizeof(long), sizeof(long long), evsel->needs_swap)) | ||
| 273 | goto out_delete; | ||
| 274 | |||
| 275 | return 0; | ||
| 276 | } | ||
| 277 | |||
| 278 | return -ENOMEM; | ||
| 279 | out_delete: | ||
| 280 | zfree(&evsel->priv); | ||
| 281 | return -EINVAL; | ||
| 282 | } | ||
| 283 | |||
| 284 | static int perf_evsel__init_augmented_syscall_tp_args(struct perf_evsel *evsel) | ||
| 285 | { | ||
| 286 | struct syscall_tp *sc = evsel->priv; | ||
| 287 | |||
| 288 | return __tp_field__init_ptr(&sc->args, sc->id.offset + sizeof(u64)); | ||
| 289 | } | ||
| 290 | |||
| 291 | static int perf_evsel__init_raw_syscall_tp(struct perf_evsel *evsel, void *handler) | ||
| 244 | { | 292 | { |
| 245 | evsel->priv = malloc(sizeof(struct syscall_tp)); | 293 | evsel->priv = malloc(sizeof(struct syscall_tp)); |
| 246 | if (evsel->priv != NULL) { | 294 | if (evsel->priv != NULL) { |
| @@ -258,7 +306,7 @@ out_delete: | |||
| 258 | return -ENOENT; | 306 | return -ENOENT; |
| 259 | } | 307 | } |
| 260 | 308 | ||
| 261 | static struct perf_evsel *perf_evsel__syscall_newtp(const char *direction, void *handler) | 309 | static struct perf_evsel *perf_evsel__raw_syscall_newtp(const char *direction, void *handler) |
| 262 | { | 310 | { |
| 263 | struct perf_evsel *evsel = perf_evsel__newtp("raw_syscalls", direction); | 311 | struct perf_evsel *evsel = perf_evsel__newtp("raw_syscalls", direction); |
| 264 | 312 | ||
| @@ -269,7 +317,7 @@ static struct perf_evsel *perf_evsel__syscall_newtp(const char *direction, void | |||
| 269 | if (IS_ERR(evsel)) | 317 | if (IS_ERR(evsel)) |
| 270 | return NULL; | 318 | return NULL; |
| 271 | 319 | ||
| 272 | if (perf_evsel__init_syscall_tp(evsel, handler)) | 320 | if (perf_evsel__init_raw_syscall_tp(evsel, handler)) |
| 273 | goto out_delete; | 321 | goto out_delete; |
| 274 | 322 | ||
| 275 | return evsel; | 323 | return evsel; |
| @@ -805,12 +853,17 @@ static struct syscall_fmt *syscall_fmt__find(const char *name) | |||
| 805 | return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp); | 853 | return bsearch(name, syscall_fmts, nmemb, sizeof(struct syscall_fmt), syscall_fmt__cmp); |
| 806 | } | 854 | } |
| 807 | 855 | ||
| 856 | /* | ||
| 857 | * is_exit: is this "exit" or "exit_group"? | ||
| 858 | * is_open: is this "open" or "openat"? To associate the fd returned in sys_exit with the pathname in sys_enter. | ||
| 859 | */ | ||
| 808 | struct syscall { | 860 | struct syscall { |
| 809 | struct event_format *tp_format; | 861 | struct event_format *tp_format; |
| 810 | int nr_args; | 862 | int nr_args; |
| 863 | bool is_exit; | ||
| 864 | bool is_open; | ||
| 811 | struct format_field *args; | 865 | struct format_field *args; |
| 812 | const char *name; | 866 | const char *name; |
| 813 | bool is_exit; | ||
| 814 | struct syscall_fmt *fmt; | 867 | struct syscall_fmt *fmt; |
| 815 | struct syscall_arg_fmt *arg_fmt; | 868 | struct syscall_arg_fmt *arg_fmt; |
| 816 | }; | 869 | }; |
| @@ -1299,6 +1352,7 @@ static int trace__read_syscall_info(struct trace *trace, int id) | |||
| 1299 | } | 1352 | } |
| 1300 | 1353 | ||
| 1301 | sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit"); | 1354 | sc->is_exit = !strcmp(name, "exit_group") || !strcmp(name, "exit"); |
| 1355 | sc->is_open = !strcmp(name, "open") || !strcmp(name, "openat"); | ||
| 1302 | 1356 | ||
| 1303 | return syscall__set_arg_fmts(sc); | 1357 | return syscall__set_arg_fmts(sc); |
| 1304 | } | 1358 | } |
| @@ -1661,6 +1715,37 @@ out_put: | |||
| 1661 | return err; | 1715 | return err; |
| 1662 | } | 1716 | } |
| 1663 | 1717 | ||
| 1718 | static int trace__fprintf_sys_enter(struct trace *trace, struct perf_evsel *evsel, | ||
| 1719 | struct perf_sample *sample) | ||
| 1720 | { | ||
| 1721 | struct thread_trace *ttrace; | ||
| 1722 | struct thread *thread; | ||
| 1723 | int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1; | ||
| 1724 | struct syscall *sc = trace__syscall_info(trace, evsel, id); | ||
| 1725 | char msg[1024]; | ||
| 1726 | void *args; | ||
| 1727 | |||
| 1728 | if (sc == NULL) | ||
| 1729 | return -1; | ||
| 1730 | |||
| 1731 | thread = machine__findnew_thread(trace->host, sample->pid, sample->tid); | ||
| 1732 | ttrace = thread__trace(thread, trace->output); | ||
| 1733 | /* | ||
| 1734 | * We need to get ttrace just to make sure it is there when syscall__scnprintf_args() | ||
| 1735 | * and the rest of the beautifiers accessing it via struct syscall_arg touches it. | ||
| 1736 | */ | ||
| 1737 | if (ttrace == NULL) | ||
| 1738 | goto out_put; | ||
| 1739 | |||
| 1740 | args = perf_evsel__sc_tp_ptr(evsel, args, sample); | ||
| 1741 | syscall__scnprintf_args(sc, msg, sizeof(msg), args, trace, thread); | ||
| 1742 | fprintf(trace->output, "%s", msg); | ||
| 1743 | err = 0; | ||
| 1744 | out_put: | ||
| 1745 | thread__put(thread); | ||
| 1746 | return err; | ||
| 1747 | } | ||
| 1748 | |||
| 1664 | static int trace__resolve_callchain(struct trace *trace, struct perf_evsel *evsel, | 1749 | static int trace__resolve_callchain(struct trace *trace, struct perf_evsel *evsel, |
| 1665 | struct perf_sample *sample, | 1750 | struct perf_sample *sample, |
| 1666 | struct callchain_cursor *cursor) | 1751 | struct callchain_cursor *cursor) |
| @@ -1722,7 +1807,7 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel, | |||
| 1722 | 1807 | ||
| 1723 | ret = perf_evsel__sc_tp_uint(evsel, ret, sample); | 1808 | ret = perf_evsel__sc_tp_uint(evsel, ret, sample); |
| 1724 | 1809 | ||
| 1725 | if (id == trace->open_id && ret >= 0 && ttrace->filename.pending_open) { | 1810 | if (sc->is_open && ret >= 0 && ttrace->filename.pending_open) { |
| 1726 | trace__set_fd_pathname(thread, ret, ttrace->filename.name); | 1811 | trace__set_fd_pathname(thread, ret, ttrace->filename.name); |
| 1727 | ttrace->filename.pending_open = false; | 1812 | ttrace->filename.pending_open = false; |
| 1728 | ++trace->stats.vfs_getname; | 1813 | ++trace->stats.vfs_getname; |
| @@ -1957,11 +2042,17 @@ static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel, | |||
| 1957 | fprintf(trace->output, "%s:", evsel->name); | 2042 | fprintf(trace->output, "%s:", evsel->name); |
| 1958 | 2043 | ||
| 1959 | if (perf_evsel__is_bpf_output(evsel)) { | 2044 | if (perf_evsel__is_bpf_output(evsel)) { |
| 1960 | bpf_output__fprintf(trace, sample); | 2045 | if (evsel == trace->syscalls.events.augmented) |
| 2046 | trace__fprintf_sys_enter(trace, evsel, sample); | ||
| 2047 | else | ||
| 2048 | bpf_output__fprintf(trace, sample); | ||
| 1961 | } else if (evsel->tp_format) { | 2049 | } else if (evsel->tp_format) { |
| 1962 | event_format__fprintf(evsel->tp_format, sample->cpu, | 2050 | if (strncmp(evsel->tp_format->name, "sys_enter_", 10) || |
| 1963 | sample->raw_data, sample->raw_size, | 2051 | trace__fprintf_sys_enter(trace, evsel, sample)) { |
| 1964 | trace->output); | 2052 | event_format__fprintf(evsel->tp_format, sample->cpu, |
| 2053 | sample->raw_data, sample->raw_size, | ||
| 2054 | trace->output); | ||
| 2055 | } | ||
| 1965 | } | 2056 | } |
| 1966 | 2057 | ||
| 1967 | fprintf(trace->output, "\n"); | 2058 | fprintf(trace->output, "\n"); |
| @@ -2242,14 +2333,14 @@ static int trace__add_syscall_newtp(struct trace *trace) | |||
| 2242 | struct perf_evlist *evlist = trace->evlist; | 2333 | struct perf_evlist *evlist = trace->evlist; |
| 2243 | struct perf_evsel *sys_enter, *sys_exit; | 2334 | struct perf_evsel *sys_enter, *sys_exit; |
| 2244 | 2335 | ||
| 2245 | sys_enter = perf_evsel__syscall_newtp("sys_enter", trace__sys_enter); | 2336 | sys_enter = perf_evsel__raw_syscall_newtp("sys_enter", trace__sys_enter); |
| 2246 | if (sys_enter == NULL) | 2337 | if (sys_enter == NULL) |
| 2247 | goto out; | 2338 | goto out; |
| 2248 | 2339 | ||
| 2249 | if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args)) | 2340 | if (perf_evsel__init_sc_tp_ptr_field(sys_enter, args)) |
| 2250 | goto out_delete_sys_enter; | 2341 | goto out_delete_sys_enter; |
| 2251 | 2342 | ||
| 2252 | sys_exit = perf_evsel__syscall_newtp("sys_exit", trace__sys_exit); | 2343 | sys_exit = perf_evsel__raw_syscall_newtp("sys_exit", trace__sys_exit); |
| 2253 | if (sys_exit == NULL) | 2344 | if (sys_exit == NULL) |
| 2254 | goto out_delete_sys_enter; | 2345 | goto out_delete_sys_enter; |
| 2255 | 2346 | ||
| @@ -2671,7 +2762,7 @@ static int trace__replay(struct trace *trace) | |||
| 2671 | "syscalls:sys_enter"); | 2762 | "syscalls:sys_enter"); |
| 2672 | 2763 | ||
| 2673 | if (evsel && | 2764 | if (evsel && |
| 2674 | (perf_evsel__init_syscall_tp(evsel, trace__sys_enter) < 0 || | 2765 | (perf_evsel__init_raw_syscall_tp(evsel, trace__sys_enter) < 0 || |
| 2675 | perf_evsel__init_sc_tp_ptr_field(evsel, args))) { | 2766 | perf_evsel__init_sc_tp_ptr_field(evsel, args))) { |
| 2676 | pr_err("Error during initialize raw_syscalls:sys_enter event\n"); | 2767 | pr_err("Error during initialize raw_syscalls:sys_enter event\n"); |
| 2677 | goto out; | 2768 | goto out; |
| @@ -2683,7 +2774,7 @@ static int trace__replay(struct trace *trace) | |||
| 2683 | evsel = perf_evlist__find_tracepoint_by_name(session->evlist, | 2774 | evsel = perf_evlist__find_tracepoint_by_name(session->evlist, |
| 2684 | "syscalls:sys_exit"); | 2775 | "syscalls:sys_exit"); |
| 2685 | if (evsel && | 2776 | if (evsel && |
| 2686 | (perf_evsel__init_syscall_tp(evsel, trace__sys_exit) < 0 || | 2777 | (perf_evsel__init_raw_syscall_tp(evsel, trace__sys_exit) < 0 || |
| 2687 | perf_evsel__init_sc_tp_uint_field(evsel, ret))) { | 2778 | perf_evsel__init_sc_tp_uint_field(evsel, ret))) { |
| 2688 | pr_err("Error during initialize raw_syscalls:sys_exit event\n"); | 2779 | pr_err("Error during initialize raw_syscalls:sys_exit event\n"); |
| 2689 | goto out; | 2780 | goto out; |
| @@ -2923,6 +3014,36 @@ static void evlist__set_evsel_handler(struct perf_evlist *evlist, void *handler) | |||
| 2923 | evsel->handler = handler; | 3014 | evsel->handler = handler; |
| 2924 | } | 3015 | } |
| 2925 | 3016 | ||
| 3017 | static int evlist__set_syscall_tp_fields(struct perf_evlist *evlist) | ||
| 3018 | { | ||
| 3019 | struct perf_evsel *evsel; | ||
| 3020 | |||
| 3021 | evlist__for_each_entry(evlist, evsel) { | ||
| 3022 | if (evsel->priv || !evsel->tp_format) | ||
| 3023 | continue; | ||
| 3024 | |||
| 3025 | if (strcmp(evsel->tp_format->system, "syscalls")) | ||
| 3026 | continue; | ||
| 3027 | |||
| 3028 | if (perf_evsel__init_syscall_tp(evsel)) | ||
| 3029 | return -1; | ||
| 3030 | |||
| 3031 | if (!strncmp(evsel->tp_format->name, "sys_enter_", 10)) { | ||
| 3032 | struct syscall_tp *sc = evsel->priv; | ||
| 3033 | |||
| 3034 | if (__tp_field__init_ptr(&sc->args, sc->id.offset + sizeof(u64))) | ||
| 3035 | return -1; | ||
| 3036 | } else if (!strncmp(evsel->tp_format->name, "sys_exit_", 9)) { | ||
| 3037 | struct syscall_tp *sc = evsel->priv; | ||
| 3038 | |||
| 3039 | if (__tp_field__init_uint(&sc->ret, sizeof(u64), sc->id.offset + sizeof(u64), evsel->needs_swap)) | ||
| 3040 | return -1; | ||
| 3041 | } | ||
| 3042 | } | ||
| 3043 | |||
| 3044 | return 0; | ||
| 3045 | } | ||
| 3046 | |||
| 2926 | /* | 3047 | /* |
| 2927 | * XXX: Hackish, just splitting the combined -e+--event (syscalls | 3048 | * XXX: Hackish, just splitting the combined -e+--event (syscalls |
| 2928 | * (raw_syscalls:{sys_{enter,exit}} + events (tracepoints, HW, SW, etc) to use | 3049 | * (raw_syscalls:{sys_{enter,exit}} + events (tracepoints, HW, SW, etc) to use |
| @@ -3123,8 +3244,9 @@ int cmd_trace(int argc, const char **argv) | |||
| 3123 | }; | 3244 | }; |
| 3124 | bool __maybe_unused max_stack_user_set = true; | 3245 | bool __maybe_unused max_stack_user_set = true; |
| 3125 | bool mmap_pages_user_set = true; | 3246 | bool mmap_pages_user_set = true; |
| 3247 | struct perf_evsel *evsel; | ||
| 3126 | const char * const trace_subcommands[] = { "record", NULL }; | 3248 | const char * const trace_subcommands[] = { "record", NULL }; |
| 3127 | int err; | 3249 | int err = -1; |
| 3128 | char bf[BUFSIZ]; | 3250 | char bf[BUFSIZ]; |
| 3129 | 3251 | ||
| 3130 | signal(SIGSEGV, sighandler_dump_stack); | 3252 | signal(SIGSEGV, sighandler_dump_stack); |
| @@ -3147,6 +3269,20 @@ int cmd_trace(int argc, const char **argv) | |||
| 3147 | "cgroup monitoring only available in system-wide mode"); | 3269 | "cgroup monitoring only available in system-wide mode"); |
| 3148 | } | 3270 | } |
| 3149 | 3271 | ||
| 3272 | evsel = bpf__setup_output_event(trace.evlist, "__augmented_syscalls__"); | ||
| 3273 | if (IS_ERR(evsel)) { | ||
| 3274 | bpf__strerror_setup_output_event(trace.evlist, PTR_ERR(evsel), bf, sizeof(bf)); | ||
| 3275 | pr_err("ERROR: Setup trace syscalls enter failed: %s\n", bf); | ||
| 3276 | goto out; | ||
| 3277 | } | ||
| 3278 | |||
| 3279 | if (evsel) { | ||
| 3280 | if (perf_evsel__init_augmented_syscall_tp(evsel) || | ||
| 3281 | perf_evsel__init_augmented_syscall_tp_args(evsel)) | ||
| 3282 | goto out; | ||
| 3283 | trace.syscalls.events.augmented = evsel; | ||
| 3284 | } | ||
| 3285 | |||
| 3150 | err = bpf__setup_stdout(trace.evlist); | 3286 | err = bpf__setup_stdout(trace.evlist); |
| 3151 | if (err) { | 3287 | if (err) { |
| 3152 | bpf__strerror_setup_stdout(trace.evlist, err, bf, sizeof(bf)); | 3288 | bpf__strerror_setup_stdout(trace.evlist, err, bf, sizeof(bf)); |
| @@ -3182,8 +3318,13 @@ int cmd_trace(int argc, const char **argv) | |||
| 3182 | symbol_conf.use_callchain = true; | 3318 | symbol_conf.use_callchain = true; |
| 3183 | } | 3319 | } |
| 3184 | 3320 | ||
| 3185 | if (trace.evlist->nr_entries > 0) | 3321 | if (trace.evlist->nr_entries > 0) { |
| 3186 | evlist__set_evsel_handler(trace.evlist, trace__event_handler); | 3322 | evlist__set_evsel_handler(trace.evlist, trace__event_handler); |
| 3323 | if (evlist__set_syscall_tp_fields(trace.evlist)) { | ||
| 3324 | perror("failed to set syscalls:* tracepoint fields"); | ||
| 3325 | goto out; | ||
| 3326 | } | ||
| 3327 | } | ||
| 3187 | 3328 | ||
| 3188 | if ((argc >= 1) && (strcmp(argv[0], "record") == 0)) | 3329 | if ((argc >= 1) && (strcmp(argv[0], "record") == 0)) |
| 3189 | return trace__record(&trace, argc-1, &argv[1]); | 3330 | return trace__record(&trace, argc-1, &argv[1]); |
| @@ -3205,8 +3346,6 @@ int cmd_trace(int argc, const char **argv) | |||
| 3205 | } | 3346 | } |
| 3206 | } | 3347 | } |
| 3207 | 3348 | ||
| 3208 | trace.open_id = syscalltbl__id(trace.sctbl, "open"); | ||
| 3209 | |||
| 3210 | err = target__validate(&trace.opts.target); | 3349 | err = target__validate(&trace.opts.target); |
| 3211 | if (err) { | 3350 | if (err) { |
| 3212 | target__strerror(&trace.opts.target, err, bf, sizeof(bf)); | 3351 | target__strerror(&trace.opts.target, err, bf, sizeof(bf)); |
diff --git a/tools/perf/check-headers.sh b/tools/perf/check-headers.sh index de28466c0186..466540ee8ea7 100755 --- a/tools/perf/check-headers.sh +++ b/tools/perf/check-headers.sh | |||
| @@ -67,8 +67,12 @@ check_2 () { | |||
| 67 | 67 | ||
| 68 | cmd="diff $* $file1 $file2 > /dev/null" | 68 | cmd="diff $* $file1 $file2 > /dev/null" |
| 69 | 69 | ||
| 70 | test -f $file2 && | 70 | test -f $file2 && { |
| 71 | eval $cmd || echo "Warning: Kernel ABI header at 'tools/$file' differs from latest version at '$file'" >&2 | 71 | eval $cmd || { |
| 72 | echo "Warning: Kernel ABI header at '$file1' differs from latest version at '$file2'" >&2 | ||
| 73 | echo diff -u $file1 $file2 | ||
| 74 | } | ||
| 75 | } | ||
| 72 | } | 76 | } |
| 73 | 77 | ||
| 74 | check () { | 78 | check () { |
| @@ -76,7 +80,7 @@ check () { | |||
| 76 | 80 | ||
| 77 | shift | 81 | shift |
| 78 | 82 | ||
| 79 | check_2 ../$file ../../$file $* | 83 | check_2 tools/$file $file $* |
| 80 | } | 84 | } |
| 81 | 85 | ||
| 82 | # Check if we have the kernel headers (tools/perf/../../include), else | 86 | # Check if we have the kernel headers (tools/perf/../../include), else |
| @@ -84,6 +88,8 @@ check () { | |||
| 84 | # differences. | 88 | # differences. |
| 85 | test -d ../../include || exit 0 | 89 | test -d ../../include || exit 0 |
| 86 | 90 | ||
| 91 | cd ../.. | ||
| 92 | |||
| 87 | # simple diff check | 93 | # simple diff check |
| 88 | for i in $HEADERS; do | 94 | for i in $HEADERS; do |
| 89 | check $i -B | 95 | check $i -B |
| @@ -94,3 +100,8 @@ check arch/x86/lib/memcpy_64.S '-I "^EXPORT_SYMBOL" -I "^#include <asm/ex | |||
| 94 | check arch/x86/lib/memset_64.S '-I "^EXPORT_SYMBOL" -I "^#include <asm/export.h>"' | 100 | check arch/x86/lib/memset_64.S '-I "^EXPORT_SYMBOL" -I "^#include <asm/export.h>"' |
| 95 | check include/uapi/asm-generic/mman.h '-I "^#include <\(uapi/\)*asm-generic/mman-common.h>"' | 101 | check include/uapi/asm-generic/mman.h '-I "^#include <\(uapi/\)*asm-generic/mman-common.h>"' |
| 96 | check include/uapi/linux/mman.h '-I "^#include <\(uapi/\)*asm/mman.h>"' | 102 | check include/uapi/linux/mman.h '-I "^#include <\(uapi/\)*asm/mman.h>"' |
| 103 | |||
| 104 | # diff non-symmetric files | ||
| 105 | check_2 tools/perf/arch/x86/entry/syscalls/syscall_64.tbl arch/x86/entry/syscalls/syscall_64.tbl | ||
| 106 | |||
| 107 | cd tools/perf | ||
diff --git a/tools/perf/examples/bpf/augmented_syscalls.c b/tools/perf/examples/bpf/augmented_syscalls.c new file mode 100644 index 000000000000..69a31386d8cd --- /dev/null +++ b/tools/perf/examples/bpf/augmented_syscalls.c | |||
| @@ -0,0 +1,55 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | /* | ||
| 3 | * Augment the openat syscall with the contents of the filename pointer argument. | ||
| 4 | * | ||
| 5 | * Test it with: | ||
| 6 | * | ||
| 7 | * perf trace -e tools/perf/examples/bpf/augmented_syscalls.c cat /etc/passwd > /dev/null | ||
| 8 | * | ||
| 9 | * It'll catch some openat syscalls related to the dynamic linked and | ||
| 10 | * the last one should be the one for '/etc/passwd'. | ||
| 11 | * | ||
| 12 | * This matches what is marshalled into the raw_syscall:sys_enter payload | ||
| 13 | * expected by the 'perf trace' beautifiers, and can be used by them unmodified, | ||
| 14 | * which will be done as that feature is implemented in the next csets, for now | ||
| 15 | * it will appear in a dump done by the default tracepoint handler in 'perf trace', | ||
| 16 | * that uses bpf_output__fprintf() to just dump those contents, as done with | ||
| 17 | * the bpf-output event associated with the __bpf_output__ map declared in | ||
| 18 | * tools/perf/include/bpf/stdio.h. | ||
| 19 | */ | ||
| 20 | |||
| 21 | #include <stdio.h> | ||
| 22 | |||
| 23 | struct bpf_map SEC("maps") __augmented_syscalls__ = { | ||
| 24 | .type = BPF_MAP_TYPE_PERF_EVENT_ARRAY, | ||
| 25 | .key_size = sizeof(int), | ||
| 26 | .value_size = sizeof(u32), | ||
| 27 | .max_entries = __NR_CPUS__, | ||
| 28 | }; | ||
| 29 | |||
| 30 | struct syscall_enter_openat_args { | ||
| 31 | unsigned long long common_tp_fields; | ||
| 32 | long syscall_nr; | ||
| 33 | long dfd; | ||
| 34 | char *filename_ptr; | ||
| 35 | long flags; | ||
| 36 | long mode; | ||
| 37 | }; | ||
| 38 | |||
| 39 | struct augmented_enter_openat_args { | ||
| 40 | struct syscall_enter_openat_args args; | ||
| 41 | char filename[64]; | ||
| 42 | }; | ||
| 43 | |||
| 44 | int syscall_enter(openat)(struct syscall_enter_openat_args *args) | ||
| 45 | { | ||
| 46 | struct augmented_enter_openat_args augmented_args; | ||
| 47 | |||
| 48 | probe_read(&augmented_args.args, sizeof(augmented_args.args), args); | ||
| 49 | probe_read_str(&augmented_args.filename, sizeof(augmented_args.filename), args->filename_ptr); | ||
| 50 | perf_event_output(args, &__augmented_syscalls__, BPF_F_CURRENT_CPU, | ||
| 51 | &augmented_args, sizeof(augmented_args)); | ||
| 52 | return 1; | ||
| 53 | } | ||
| 54 | |||
| 55 | license(GPL); | ||
diff --git a/tools/perf/examples/bpf/hello.c b/tools/perf/examples/bpf/hello.c new file mode 100644 index 000000000000..cf3c2fdc7f79 --- /dev/null +++ b/tools/perf/examples/bpf/hello.c | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | #include <stdio.h> | ||
| 2 | |||
| 3 | int syscall_enter(openat)(void *args) | ||
| 4 | { | ||
| 5 | puts("Hello, world\n"); | ||
| 6 | return 0; | ||
| 7 | } | ||
| 8 | |||
| 9 | license(GPL); | ||
diff --git a/tools/perf/examples/bpf/sys_enter_openat.c b/tools/perf/examples/bpf/sys_enter_openat.c new file mode 100644 index 000000000000..9cd124b09392 --- /dev/null +++ b/tools/perf/examples/bpf/sys_enter_openat.c | |||
| @@ -0,0 +1,33 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | /* | ||
| 3 | * Hook into 'openat' syscall entry tracepoint | ||
| 4 | * | ||
| 5 | * Test it with: | ||
| 6 | * | ||
| 7 | * perf trace -e tools/perf/examples/bpf/sys_enter_openat.c cat /etc/passwd > /dev/null | ||
| 8 | * | ||
| 9 | * It'll catch some openat syscalls related to the dynamic linked and | ||
| 10 | * the last one should be the one for '/etc/passwd'. | ||
| 11 | * | ||
| 12 | * The syscall_enter_openat_args can be used to get the syscall fields | ||
| 13 | * and use them for filtering calls, i.e. use in expressions for | ||
| 14 | * the return value. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include <bpf.h> | ||
| 18 | |||
| 19 | struct syscall_enter_openat_args { | ||
| 20 | unsigned long long unused; | ||
| 21 | long syscall_nr; | ||
| 22 | long dfd; | ||
| 23 | char *filename_ptr; | ||
| 24 | long flags; | ||
| 25 | long mode; | ||
| 26 | }; | ||
| 27 | |||
| 28 | int syscall_enter(openat)(struct syscall_enter_openat_args *args) | ||
| 29 | { | ||
| 30 | return 1; | ||
| 31 | } | ||
| 32 | |||
| 33 | license(GPL); | ||
diff --git a/tools/perf/include/bpf/bpf.h b/tools/perf/include/bpf/bpf.h index a63aa6241b7f..47897d65e799 100644 --- a/tools/perf/include/bpf/bpf.h +++ b/tools/perf/include/bpf/bpf.h | |||
| @@ -4,13 +4,33 @@ | |||
| 4 | 4 | ||
| 5 | #include <uapi/linux/bpf.h> | 5 | #include <uapi/linux/bpf.h> |
| 6 | 6 | ||
| 7 | /* | ||
| 8 | * A helper structure used by eBPF C program to describe map attributes to | ||
| 9 | * elf_bpf loader, taken from tools/testing/selftests/bpf/bpf_helpers.h: | ||
| 10 | */ | ||
| 11 | struct bpf_map { | ||
| 12 | unsigned int type; | ||
| 13 | unsigned int key_size; | ||
| 14 | unsigned int value_size; | ||
| 15 | unsigned int max_entries; | ||
| 16 | unsigned int map_flags; | ||
| 17 | unsigned int inner_map_idx; | ||
| 18 | unsigned int numa_node; | ||
| 19 | }; | ||
| 20 | |||
| 7 | #define SEC(NAME) __attribute__((section(NAME), used)) | 21 | #define SEC(NAME) __attribute__((section(NAME), used)) |
| 8 | 22 | ||
| 9 | #define probe(function, vars) \ | 23 | #define probe(function, vars) \ |
| 10 | SEC(#function "=" #function " " #vars) function | 24 | SEC(#function "=" #function " " #vars) function |
| 11 | 25 | ||
| 26 | #define syscall_enter(name) \ | ||
| 27 | SEC("syscalls:sys_enter_" #name) syscall_enter_ ## name | ||
| 28 | |||
| 12 | #define license(name) \ | 29 | #define license(name) \ |
| 13 | char _license[] SEC("license") = #name; \ | 30 | char _license[] SEC("license") = #name; \ |
| 14 | int _version SEC("version") = LINUX_VERSION_CODE; | 31 | int _version SEC("version") = LINUX_VERSION_CODE; |
| 15 | 32 | ||
| 33 | static int (*probe_read)(void *dst, int size, const void *unsafe_addr) = (void *)BPF_FUNC_probe_read; | ||
| 34 | static int (*probe_read_str)(void *dst, int size, const void *unsafe_addr) = (void *)BPF_FUNC_probe_read_str; | ||
| 35 | |||
| 16 | #endif /* _PERF_BPF_H */ | 36 | #endif /* _PERF_BPF_H */ |
diff --git a/tools/perf/include/bpf/stdio.h b/tools/perf/include/bpf/stdio.h new file mode 100644 index 000000000000..2899cb7bfed8 --- /dev/null +++ b/tools/perf/include/bpf/stdio.h | |||
| @@ -0,0 +1,19 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | |||
| 3 | #include <bpf.h> | ||
| 4 | |||
| 5 | struct bpf_map SEC("maps") __bpf_stdout__ = { | ||
| 6 | .type = BPF_MAP_TYPE_PERF_EVENT_ARRAY, | ||
| 7 | .key_size = sizeof(int), | ||
| 8 | .value_size = sizeof(u32), | ||
| 9 | .max_entries = __NR_CPUS__, | ||
| 10 | }; | ||
| 11 | |||
| 12 | static int (*perf_event_output)(void *, struct bpf_map *, int, void *, unsigned long) = | ||
| 13 | (void *)BPF_FUNC_perf_event_output; | ||
| 14 | |||
| 15 | #define puts(from) \ | ||
| 16 | ({ const int __len = sizeof(from); \ | ||
| 17 | char __from[__len] = from; \ | ||
| 18 | perf_event_output(args, &__bpf_stdout__, BPF_F_CURRENT_CPU, \ | ||
| 19 | &__from, __len & (sizeof(from) - 1)); }) | ||
diff --git a/tools/perf/pmu-events/arch/arm64/ampere/emag/core-imp-def.json b/tools/perf/pmu-events/arch/arm64/ampere/emag/core-imp-def.json new file mode 100644 index 000000000000..bc03c06c3918 --- /dev/null +++ b/tools/perf/pmu-events/arch/arm64/ampere/emag/core-imp-def.json | |||
| @@ -0,0 +1,32 @@ | |||
| 1 | [ | ||
| 2 | { | ||
| 3 | "ArchStdEvent": "L1D_CACHE_RD", | ||
| 4 | }, | ||
| 5 | { | ||
| 6 | "ArchStdEvent": "L1D_CACHE_WR", | ||
| 7 | }, | ||
| 8 | { | ||
| 9 | "ArchStdEvent": "L1D_CACHE_REFILL_RD", | ||
| 10 | }, | ||
| 11 | { | ||
| 12 | "ArchStdEvent": "L1D_CACHE_REFILL_WR", | ||
| 13 | }, | ||
| 14 | { | ||
| 15 | "ArchStdEvent": "L1D_TLB_REFILL_RD", | ||
| 16 | }, | ||
| 17 | { | ||
| 18 | "ArchStdEvent": "L1D_TLB_REFILL_WR", | ||
| 19 | }, | ||
| 20 | { | ||
| 21 | "ArchStdEvent": "L1D_TLB_RD", | ||
| 22 | }, | ||
| 23 | { | ||
| 24 | "ArchStdEvent": "L1D_TLB_WR", | ||
| 25 | }, | ||
| 26 | { | ||
| 27 | "ArchStdEvent": "BUS_ACCESS_RD", | ||
| 28 | }, | ||
| 29 | { | ||
| 30 | "ArchStdEvent": "BUS_ACCESS_WR", | ||
| 31 | } | ||
| 32 | ] | ||
diff --git a/tools/perf/pmu-events/arch/arm64/mapfile.csv b/tools/perf/pmu-events/arch/arm64/mapfile.csv index f03e26ecb658..59cd8604b0bd 100644 --- a/tools/perf/pmu-events/arch/arm64/mapfile.csv +++ b/tools/perf/pmu-events/arch/arm64/mapfile.csv | |||
| @@ -16,3 +16,4 @@ | |||
| 16 | 0x00000000420f5160,v1,cavium/thunderx2,core | 16 | 0x00000000420f5160,v1,cavium/thunderx2,core |
| 17 | 0x00000000430f0af0,v1,cavium/thunderx2,core | 17 | 0x00000000430f0af0,v1,cavium/thunderx2,core |
| 18 | 0x00000000480fd010,v1,hisilicon/hip08,core | 18 | 0x00000000480fd010,v1,hisilicon/hip08,core |
| 19 | 0x00000000500f0000,v1,ampere/emag,core | ||
diff --git a/tools/perf/tests/bitmap.c b/tools/perf/tests/bitmap.c index 47bedf25ba69..96e7fc1ad3f9 100644 --- a/tools/perf/tests/bitmap.c +++ b/tools/perf/tests/bitmap.c | |||
| @@ -16,8 +16,6 @@ static unsigned long *get_bitmap(const char *str, int nbits) | |||
| 16 | bm = bitmap_alloc(nbits); | 16 | bm = bitmap_alloc(nbits); |
| 17 | 17 | ||
| 18 | if (map && bm) { | 18 | if (map && bm) { |
| 19 | bitmap_zero(bm, nbits); | ||
| 20 | |||
| 21 | for (i = 0; i < map->nr; i++) | 19 | for (i = 0; i < map->nr; i++) |
| 22 | set_bit(map->map[i], bm); | 20 | set_bit(map->map[i], bm); |
| 23 | } | 21 | } |
diff --git a/tools/perf/tests/mem2node.c b/tools/perf/tests/mem2node.c index 0c3c87f86e03..9e9e4d37cc77 100644 --- a/tools/perf/tests/mem2node.c +++ b/tools/perf/tests/mem2node.c | |||
| @@ -24,8 +24,6 @@ static unsigned long *get_bitmap(const char *str, int nbits) | |||
| 24 | bm = bitmap_alloc(nbits); | 24 | bm = bitmap_alloc(nbits); |
| 25 | 25 | ||
| 26 | if (map && bm) { | 26 | if (map && bm) { |
| 27 | bitmap_zero(bm, nbits); | ||
| 28 | |||
| 29 | for (i = 0; i < map->nr; i++) { | 27 | for (i = 0; i < map->nr; i++) { |
| 30 | set_bit(map->map[i], bm); | 28 | set_bit(map->map[i], bm); |
| 31 | } | 29 | } |
diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 3b4f1c10ff57..1d00e5ec7906 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c | |||
| @@ -15,6 +15,7 @@ | |||
| 15 | #include <linux/kernel.h> | 15 | #include <linux/kernel.h> |
| 16 | #include <linux/string.h> | 16 | #include <linux/string.h> |
| 17 | #include <sys/ttydefaults.h> | 17 | #include <sys/ttydefaults.h> |
| 18 | #include <asm/bug.h> | ||
| 18 | 19 | ||
| 19 | struct disasm_line_samples { | 20 | struct disasm_line_samples { |
| 20 | double percent; | 21 | double percent; |
| @@ -115,7 +116,7 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int | |||
| 115 | if (!browser->navkeypressed) | 116 | if (!browser->navkeypressed) |
| 116 | ops.width += 1; | 117 | ops.width += 1; |
| 117 | 118 | ||
| 118 | annotation_line__write(al, notes, &ops); | 119 | annotation_line__write(al, notes, &ops, ab->opts); |
| 119 | 120 | ||
| 120 | if (ops.current_entry) | 121 | if (ops.current_entry) |
| 121 | ab->selection = al; | 122 | ab->selection = al; |
| @@ -227,10 +228,10 @@ static int disasm__cmp(struct annotation_line *a, struct annotation_line *b) | |||
| 227 | { | 228 | { |
| 228 | int i; | 229 | int i; |
| 229 | 230 | ||
| 230 | for (i = 0; i < a->samples_nr; i++) { | 231 | for (i = 0; i < a->data_nr; i++) { |
| 231 | if (a->samples[i].percent == b->samples[i].percent) | 232 | if (a->data[i].percent == b->data[i].percent) |
| 232 | continue; | 233 | continue; |
| 233 | return a->samples[i].percent < b->samples[i].percent; | 234 | return a->data[i].percent < b->data[i].percent; |
| 234 | } | 235 | } |
| 235 | return 0; | 236 | return 0; |
| 236 | } | 237 | } |
| @@ -314,11 +315,14 @@ static void annotate_browser__calc_percent(struct annotate_browser *browser, | |||
| 314 | continue; | 315 | continue; |
| 315 | } | 316 | } |
| 316 | 317 | ||
| 317 | for (i = 0; i < pos->al.samples_nr; i++) { | 318 | for (i = 0; i < pos->al.data_nr; i++) { |
| 318 | struct annotation_data *sample = &pos->al.samples[i]; | 319 | double percent; |
| 319 | 320 | ||
| 320 | if (max_percent < sample->percent) | 321 | percent = annotation_data__percent(&pos->al.data[i], |
| 321 | max_percent = sample->percent; | 322 | browser->opts->percent_type); |
| 323 | |||
| 324 | if (max_percent < percent) | ||
| 325 | max_percent = percent; | ||
| 322 | } | 326 | } |
| 323 | 327 | ||
| 324 | if (max_percent < 0.01 && pos->al.ipc == 0) { | 328 | if (max_percent < 0.01 && pos->al.ipc == 0) { |
| @@ -380,9 +384,10 @@ static void ui_browser__init_asm_mode(struct ui_browser *browser) | |||
| 380 | #define SYM_TITLE_MAX_SIZE (PATH_MAX + 64) | 384 | #define SYM_TITLE_MAX_SIZE (PATH_MAX + 64) |
| 381 | 385 | ||
| 382 | static int sym_title(struct symbol *sym, struct map *map, char *title, | 386 | static int sym_title(struct symbol *sym, struct map *map, char *title, |
| 383 | size_t sz) | 387 | size_t sz, int percent_type) |
| 384 | { | 388 | { |
| 385 | return snprintf(title, sz, "%s %s", sym->name, map->dso->long_name); | 389 | return snprintf(title, sz, "%s %s [Percent: %s]", sym->name, map->dso->long_name, |
| 390 | percent_type_str(percent_type)); | ||
| 386 | } | 391 | } |
| 387 | 392 | ||
| 388 | /* | 393 | /* |
| @@ -420,7 +425,7 @@ static bool annotate_browser__callq(struct annotate_browser *browser, | |||
| 420 | 425 | ||
| 421 | pthread_mutex_unlock(¬es->lock); | 426 | pthread_mutex_unlock(¬es->lock); |
| 422 | symbol__tui_annotate(dl->ops.target.sym, ms->map, evsel, hbt, browser->opts); | 427 | symbol__tui_annotate(dl->ops.target.sym, ms->map, evsel, hbt, browser->opts); |
| 423 | sym_title(ms->sym, ms->map, title, sizeof(title)); | 428 | sym_title(ms->sym, ms->map, title, sizeof(title), browser->opts->percent_type); |
| 424 | ui_browser__show_title(&browser->b, title); | 429 | ui_browser__show_title(&browser->b, title); |
| 425 | return true; | 430 | return true; |
| 426 | } | 431 | } |
| @@ -595,6 +600,7 @@ bool annotate_browser__continue_search_reverse(struct annotate_browser *browser, | |||
| 595 | 600 | ||
| 596 | static int annotate_browser__show(struct ui_browser *browser, char *title, const char *help) | 601 | static int annotate_browser__show(struct ui_browser *browser, char *title, const char *help) |
| 597 | { | 602 | { |
| 603 | struct annotate_browser *ab = container_of(browser, struct annotate_browser, b); | ||
| 598 | struct map_symbol *ms = browser->priv; | 604 | struct map_symbol *ms = browser->priv; |
| 599 | struct symbol *sym = ms->sym; | 605 | struct symbol *sym = ms->sym; |
| 600 | char symbol_dso[SYM_TITLE_MAX_SIZE]; | 606 | char symbol_dso[SYM_TITLE_MAX_SIZE]; |
| @@ -602,7 +608,7 @@ static int annotate_browser__show(struct ui_browser *browser, char *title, const | |||
| 602 | if (ui_browser__show(browser, title, help) < 0) | 608 | if (ui_browser__show(browser, title, help) < 0) |
| 603 | return -1; | 609 | return -1; |
| 604 | 610 | ||
| 605 | sym_title(sym, ms->map, symbol_dso, sizeof(symbol_dso)); | 611 | sym_title(sym, ms->map, symbol_dso, sizeof(symbol_dso), ab->opts->percent_type); |
| 606 | 612 | ||
| 607 | ui_browser__gotorc_title(browser, 0, 0); | 613 | ui_browser__gotorc_title(browser, 0, 0); |
| 608 | ui_browser__set_color(browser, HE_COLORSET_ROOT); | 614 | ui_browser__set_color(browser, HE_COLORSET_ROOT); |
| @@ -610,6 +616,39 @@ static int annotate_browser__show(struct ui_browser *browser, char *title, const | |||
| 610 | return 0; | 616 | return 0; |
| 611 | } | 617 | } |
| 612 | 618 | ||
| 619 | static void | ||
| 620 | switch_percent_type(struct annotation_options *opts, bool base) | ||
| 621 | { | ||
| 622 | switch (opts->percent_type) { | ||
| 623 | case PERCENT_HITS_LOCAL: | ||
| 624 | if (base) | ||
| 625 | opts->percent_type = PERCENT_PERIOD_LOCAL; | ||
| 626 | else | ||
| 627 | opts->percent_type = PERCENT_HITS_GLOBAL; | ||
| 628 | break; | ||
| 629 | case PERCENT_HITS_GLOBAL: | ||
| 630 | if (base) | ||
| 631 | opts->percent_type = PERCENT_PERIOD_GLOBAL; | ||
| 632 | else | ||
| 633 | opts->percent_type = PERCENT_HITS_LOCAL; | ||
| 634 | break; | ||
| 635 | case PERCENT_PERIOD_LOCAL: | ||
| 636 | if (base) | ||
| 637 | opts->percent_type = PERCENT_HITS_LOCAL; | ||
| 638 | else | ||
| 639 | opts->percent_type = PERCENT_PERIOD_GLOBAL; | ||
| 640 | break; | ||
| 641 | case PERCENT_PERIOD_GLOBAL: | ||
| 642 | if (base) | ||
| 643 | opts->percent_type = PERCENT_HITS_GLOBAL; | ||
| 644 | else | ||
| 645 | opts->percent_type = PERCENT_PERIOD_LOCAL; | ||
| 646 | break; | ||
| 647 | default: | ||
| 648 | WARN_ON(1); | ||
| 649 | } | ||
| 650 | } | ||
| 651 | |||
| 613 | static int annotate_browser__run(struct annotate_browser *browser, | 652 | static int annotate_browser__run(struct annotate_browser *browser, |
| 614 | struct perf_evsel *evsel, | 653 | struct perf_evsel *evsel, |
| 615 | struct hist_browser_timer *hbt) | 654 | struct hist_browser_timer *hbt) |
| @@ -624,8 +663,7 @@ static int annotate_browser__run(struct annotate_browser *browser, | |||
| 624 | char title[256]; | 663 | char title[256]; |
| 625 | int key; | 664 | int key; |
| 626 | 665 | ||
| 627 | annotation__scnprintf_samples_period(notes, title, sizeof(title), evsel); | 666 | hists__scnprintf_title(hists, title, sizeof(title)); |
| 628 | |||
| 629 | if (annotate_browser__show(&browser->b, title, help) < 0) | 667 | if (annotate_browser__show(&browser->b, title, help) < 0) |
| 630 | return -1; | 668 | return -1; |
| 631 | 669 | ||
| @@ -701,6 +739,8 @@ static int annotate_browser__run(struct annotate_browser *browser, | |||
| 701 | "k Toggle line numbers\n" | 739 | "k Toggle line numbers\n" |
| 702 | "P Print to [symbol_name].annotation file.\n" | 740 | "P Print to [symbol_name].annotation file.\n" |
| 703 | "r Run available scripts\n" | 741 | "r Run available scripts\n" |
| 742 | "p Toggle percent type [local/global]\n" | ||
| 743 | "b Toggle percent base [period/hits]\n" | ||
| 704 | "? Search string backwards\n"); | 744 | "? Search string backwards\n"); |
| 705 | continue; | 745 | continue; |
| 706 | case 'r': | 746 | case 'r': |
| @@ -781,7 +821,7 @@ show_sup_ins: | |||
| 781 | continue; | 821 | continue; |
| 782 | } | 822 | } |
| 783 | case 'P': | 823 | case 'P': |
| 784 | map_symbol__annotation_dump(ms, evsel); | 824 | map_symbol__annotation_dump(ms, evsel, browser->opts); |
| 785 | continue; | 825 | continue; |
| 786 | case 't': | 826 | case 't': |
| 787 | if (notes->options->show_total_period) { | 827 | if (notes->options->show_total_period) { |
| @@ -800,6 +840,12 @@ show_sup_ins: | |||
| 800 | notes->options->show_minmax_cycle = true; | 840 | notes->options->show_minmax_cycle = true; |
| 801 | annotation__update_column_widths(notes); | 841 | annotation__update_column_widths(notes); |
| 802 | continue; | 842 | continue; |
| 843 | case 'p': | ||
| 844 | case 'b': | ||
| 845 | switch_percent_type(browser->opts, key == 'b'); | ||
| 846 | hists__scnprintf_title(hists, title, sizeof(title)); | ||
| 847 | annotate_browser__show(&browser->b, title, help); | ||
| 848 | continue; | ||
| 803 | case K_LEFT: | 849 | case K_LEFT: |
| 804 | case K_ESC: | 850 | case K_ESC: |
| 805 | case 'q': | 851 | case 'q': |
diff --git a/tools/perf/util/Build b/tools/perf/util/Build index b604ef334dc9..7efe15b9618d 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build | |||
| @@ -87,6 +87,7 @@ libperf-$(CONFIG_AUXTRACE) += intel-pt.o | |||
| 87 | libperf-$(CONFIG_AUXTRACE) += intel-bts.o | 87 | libperf-$(CONFIG_AUXTRACE) += intel-bts.o |
| 88 | libperf-$(CONFIG_AUXTRACE) += arm-spe.o | 88 | libperf-$(CONFIG_AUXTRACE) += arm-spe.o |
| 89 | libperf-$(CONFIG_AUXTRACE) += arm-spe-pkt-decoder.o | 89 | libperf-$(CONFIG_AUXTRACE) += arm-spe-pkt-decoder.o |
| 90 | libperf-$(CONFIG_AUXTRACE) += s390-cpumsf.o | ||
| 90 | 91 | ||
| 91 | ifdef CONFIG_LIBOPENCSD | 92 | ifdef CONFIG_LIBOPENCSD |
| 92 | libperf-$(CONFIG_AUXTRACE) += cs-etm.o | 93 | libperf-$(CONFIG_AUXTRACE) += cs-etm.o |
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index f91775b4bc3c..e4268b948e0e 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c | |||
| @@ -49,6 +49,7 @@ struct annotation_options annotation__default_options = { | |||
| 49 | .jump_arrows = true, | 49 | .jump_arrows = true, |
| 50 | .annotate_src = true, | 50 | .annotate_src = true, |
| 51 | .offset_level = ANNOTATION__OFFSET_JUMP_TARGETS, | 51 | .offset_level = ANNOTATION__OFFSET_JUMP_TARGETS, |
| 52 | .percent_type = PERCENT_PERIOD_LOCAL, | ||
| 52 | }; | 53 | }; |
| 53 | 54 | ||
| 54 | static regex_t file_lineno; | 55 | static regex_t file_lineno; |
| @@ -1108,7 +1109,7 @@ annotation_line__new(struct annotate_args *args, size_t privsize) | |||
| 1108 | if (perf_evsel__is_group_event(evsel)) | 1109 | if (perf_evsel__is_group_event(evsel)) |
| 1109 | nr = evsel->nr_members; | 1110 | nr = evsel->nr_members; |
| 1110 | 1111 | ||
| 1111 | size += sizeof(al->samples[0]) * nr; | 1112 | size += sizeof(al->data[0]) * nr; |
| 1112 | 1113 | ||
| 1113 | al = zalloc(size); | 1114 | al = zalloc(size); |
| 1114 | if (al) { | 1115 | if (al) { |
| @@ -1117,7 +1118,7 @@ annotation_line__new(struct annotate_args *args, size_t privsize) | |||
| 1117 | al->offset = args->offset; | 1118 | al->offset = args->offset; |
| 1118 | al->line = strdup(args->line); | 1119 | al->line = strdup(args->line); |
| 1119 | al->line_nr = args->line_nr; | 1120 | al->line_nr = args->line_nr; |
| 1120 | al->samples_nr = nr; | 1121 | al->data_nr = nr; |
| 1121 | } | 1122 | } |
| 1122 | 1123 | ||
| 1123 | return al; | 1124 | return al; |
| @@ -1297,7 +1298,8 @@ static int disasm_line__print(struct disasm_line *dl, u64 start, int addr_fmt_wi | |||
| 1297 | static int | 1298 | static int |
| 1298 | annotation_line__print(struct annotation_line *al, struct symbol *sym, u64 start, | 1299 | annotation_line__print(struct annotation_line *al, struct symbol *sym, u64 start, |
| 1299 | struct perf_evsel *evsel, u64 len, int min_pcnt, int printed, | 1300 | struct perf_evsel *evsel, u64 len, int min_pcnt, int printed, |
| 1300 | int max_lines, struct annotation_line *queue, int addr_fmt_width) | 1301 | int max_lines, struct annotation_line *queue, int addr_fmt_width, |
| 1302 | int percent_type) | ||
| 1301 | { | 1303 | { |
| 1302 | struct disasm_line *dl = container_of(al, struct disasm_line, al); | 1304 | struct disasm_line *dl = container_of(al, struct disasm_line, al); |
| 1303 | static const char *prev_line; | 1305 | static const char *prev_line; |
| @@ -1309,15 +1311,18 @@ annotation_line__print(struct annotation_line *al, struct symbol *sym, u64 start | |||
| 1309 | const char *color; | 1311 | const char *color; |
| 1310 | struct annotation *notes = symbol__annotation(sym); | 1312 | struct annotation *notes = symbol__annotation(sym); |
| 1311 | 1313 | ||
| 1312 | for (i = 0; i < al->samples_nr; i++) { | 1314 | for (i = 0; i < al->data_nr; i++) { |
| 1313 | struct annotation_data *sample = &al->samples[i]; | 1315 | double percent; |
| 1314 | 1316 | ||
| 1315 | if (sample->percent > max_percent) | 1317 | percent = annotation_data__percent(&al->data[i], |
| 1316 | max_percent = sample->percent; | 1318 | percent_type); |
| 1319 | |||
| 1320 | if (percent > max_percent) | ||
| 1321 | max_percent = percent; | ||
| 1317 | } | 1322 | } |
| 1318 | 1323 | ||
| 1319 | if (al->samples_nr > nr_percent) | 1324 | if (al->data_nr > nr_percent) |
| 1320 | nr_percent = al->samples_nr; | 1325 | nr_percent = al->data_nr; |
| 1321 | 1326 | ||
| 1322 | if (max_percent < min_pcnt) | 1327 | if (max_percent < min_pcnt) |
| 1323 | return -1; | 1328 | return -1; |
| @@ -1330,7 +1335,8 @@ annotation_line__print(struct annotation_line *al, struct symbol *sym, u64 start | |||
| 1330 | if (queue == al) | 1335 | if (queue == al) |
| 1331 | break; | 1336 | break; |
| 1332 | annotation_line__print(queue, sym, start, evsel, len, | 1337 | annotation_line__print(queue, sym, start, evsel, len, |
| 1333 | 0, 0, 1, NULL, addr_fmt_width); | 1338 | 0, 0, 1, NULL, addr_fmt_width, |
| 1339 | percent_type); | ||
| 1334 | } | 1340 | } |
| 1335 | } | 1341 | } |
| 1336 | 1342 | ||
| @@ -1351,18 +1357,20 @@ annotation_line__print(struct annotation_line *al, struct symbol *sym, u64 start | |||
| 1351 | } | 1357 | } |
| 1352 | 1358 | ||
| 1353 | for (i = 0; i < nr_percent; i++) { | 1359 | for (i = 0; i < nr_percent; i++) { |
| 1354 | struct annotation_data *sample = &al->samples[i]; | 1360 | struct annotation_data *data = &al->data[i]; |
| 1361 | double percent; | ||
| 1355 | 1362 | ||
| 1356 | color = get_percent_color(sample->percent); | 1363 | percent = annotation_data__percent(data, percent_type); |
| 1364 | color = get_percent_color(percent); | ||
| 1357 | 1365 | ||
| 1358 | if (symbol_conf.show_total_period) | 1366 | if (symbol_conf.show_total_period) |
| 1359 | color_fprintf(stdout, color, " %11" PRIu64, | 1367 | color_fprintf(stdout, color, " %11" PRIu64, |
| 1360 | sample->he.period); | 1368 | data->he.period); |
| 1361 | else if (symbol_conf.show_nr_samples) | 1369 | else if (symbol_conf.show_nr_samples) |
| 1362 | color_fprintf(stdout, color, " %7" PRIu64, | 1370 | color_fprintf(stdout, color, " %7" PRIu64, |
| 1363 | sample->he.nr_samples); | 1371 | data->he.nr_samples); |
| 1364 | else | 1372 | else |
| 1365 | color_fprintf(stdout, color, " %7.2f", sample->percent); | 1373 | color_fprintf(stdout, color, " %7.2f", percent); |
| 1366 | } | 1374 | } |
| 1367 | 1375 | ||
| 1368 | printf(" : "); | 1376 | printf(" : "); |
| @@ -1753,34 +1761,45 @@ out_close_stdout: | |||
| 1753 | goto out_free_command; | 1761 | goto out_free_command; |
| 1754 | } | 1762 | } |
| 1755 | 1763 | ||
| 1756 | static void calc_percent(struct sym_hist *hist, | 1764 | static void calc_percent(struct sym_hist *sym_hist, |
| 1757 | struct annotation_data *sample, | 1765 | struct hists *hists, |
| 1766 | struct annotation_data *data, | ||
| 1758 | s64 offset, s64 end) | 1767 | s64 offset, s64 end) |
| 1759 | { | 1768 | { |
| 1760 | unsigned int hits = 0; | 1769 | unsigned int hits = 0; |
| 1761 | u64 period = 0; | 1770 | u64 period = 0; |
| 1762 | 1771 | ||
| 1763 | while (offset < end) { | 1772 | while (offset < end) { |
| 1764 | hits += hist->addr[offset].nr_samples; | 1773 | hits += sym_hist->addr[offset].nr_samples; |
| 1765 | period += hist->addr[offset].period; | 1774 | period += sym_hist->addr[offset].period; |
| 1766 | ++offset; | 1775 | ++offset; |
| 1767 | } | 1776 | } |
| 1768 | 1777 | ||
| 1769 | if (hist->nr_samples) { | 1778 | if (sym_hist->nr_samples) { |
| 1770 | sample->he.period = period; | 1779 | data->he.period = period; |
| 1771 | sample->he.nr_samples = hits; | 1780 | data->he.nr_samples = hits; |
| 1772 | sample->percent = 100.0 * hits / hist->nr_samples; | 1781 | data->percent[PERCENT_HITS_LOCAL] = 100.0 * hits / sym_hist->nr_samples; |
| 1773 | } | 1782 | } |
| 1783 | |||
| 1784 | if (hists->stats.nr_non_filtered_samples) | ||
| 1785 | data->percent[PERCENT_HITS_GLOBAL] = 100.0 * hits / hists->stats.nr_non_filtered_samples; | ||
| 1786 | |||
| 1787 | if (sym_hist->period) | ||
| 1788 | data->percent[PERCENT_PERIOD_LOCAL] = 100.0 * period / sym_hist->period; | ||
| 1789 | |||
| 1790 | if (hists->stats.total_period) | ||
| 1791 | data->percent[PERCENT_PERIOD_GLOBAL] = 100.0 * period / hists->stats.total_period; | ||
| 1774 | } | 1792 | } |
| 1775 | 1793 | ||
| 1776 | static void annotation__calc_percent(struct annotation *notes, | 1794 | static void annotation__calc_percent(struct annotation *notes, |
| 1777 | struct perf_evsel *evsel, s64 len) | 1795 | struct perf_evsel *leader, s64 len) |
| 1778 | { | 1796 | { |
| 1779 | struct annotation_line *al, *next; | 1797 | struct annotation_line *al, *next; |
| 1798 | struct perf_evsel *evsel; | ||
| 1780 | 1799 | ||
| 1781 | list_for_each_entry(al, ¬es->src->source, node) { | 1800 | list_for_each_entry(al, ¬es->src->source, node) { |
| 1782 | s64 end; | 1801 | s64 end; |
| 1783 | int i; | 1802 | int i = 0; |
| 1784 | 1803 | ||
| 1785 | if (al->offset == -1) | 1804 | if (al->offset == -1) |
| 1786 | continue; | 1805 | continue; |
| @@ -1788,14 +1807,17 @@ static void annotation__calc_percent(struct annotation *notes, | |||
| 1788 | next = annotation_line__next(al, ¬es->src->source); | 1807 | next = annotation_line__next(al, ¬es->src->source); |
| 1789 | end = next ? next->offset : len; | 1808 | end = next ? next->offset : len; |
| 1790 | 1809 | ||
| 1791 | for (i = 0; i < al->samples_nr; i++) { | 1810 | for_each_group_evsel(evsel, leader) { |
| 1792 | struct annotation_data *sample; | 1811 | struct hists *hists = evsel__hists(evsel); |
| 1793 | struct sym_hist *hist; | 1812 | struct annotation_data *data; |
| 1813 | struct sym_hist *sym_hist; | ||
| 1814 | |||
| 1815 | BUG_ON(i >= al->data_nr); | ||
| 1794 | 1816 | ||
| 1795 | hist = annotation__histogram(notes, evsel->idx + i); | 1817 | sym_hist = annotation__histogram(notes, evsel->idx); |
| 1796 | sample = &al->samples[i]; | 1818 | data = &al->data[i++]; |
| 1797 | 1819 | ||
| 1798 | calc_percent(hist, sample, al->offset, end); | 1820 | calc_percent(sym_hist, hists, data, al->offset, end); |
| 1799 | } | 1821 | } |
| 1800 | } | 1822 | } |
| 1801 | } | 1823 | } |
| @@ -1846,7 +1868,8 @@ int symbol__annotate(struct symbol *sym, struct map *map, | |||
| 1846 | return symbol__disassemble(sym, &args); | 1868 | return symbol__disassemble(sym, &args); |
| 1847 | } | 1869 | } |
| 1848 | 1870 | ||
| 1849 | static void insert_source_line(struct rb_root *root, struct annotation_line *al) | 1871 | static void insert_source_line(struct rb_root *root, struct annotation_line *al, |
| 1872 | struct annotation_options *opts) | ||
| 1850 | { | 1873 | { |
| 1851 | struct annotation_line *iter; | 1874 | struct annotation_line *iter; |
| 1852 | struct rb_node **p = &root->rb_node; | 1875 | struct rb_node **p = &root->rb_node; |
| @@ -1859,8 +1882,10 @@ static void insert_source_line(struct rb_root *root, struct annotation_line *al) | |||
| 1859 | 1882 | ||
| 1860 | ret = strcmp(iter->path, al->path); | 1883 | ret = strcmp(iter->path, al->path); |
| 1861 | if (ret == 0) { | 1884 | if (ret == 0) { |
| 1862 | for (i = 0; i < al->samples_nr; i++) | 1885 | for (i = 0; i < al->data_nr; i++) { |
| 1863 | iter->samples[i].percent_sum += al->samples[i].percent; | 1886 | iter->data[i].percent_sum += annotation_data__percent(&al->data[i], |
| 1887 | opts->percent_type); | ||
| 1888 | } | ||
| 1864 | return; | 1889 | return; |
| 1865 | } | 1890 | } |
| 1866 | 1891 | ||
| @@ -1870,8 +1895,10 @@ static void insert_source_line(struct rb_root *root, struct annotation_line *al) | |||
| 1870 | p = &(*p)->rb_right; | 1895 | p = &(*p)->rb_right; |
| 1871 | } | 1896 | } |
| 1872 | 1897 | ||
| 1873 | for (i = 0; i < al->samples_nr; i++) | 1898 | for (i = 0; i < al->data_nr; i++) { |
| 1874 | al->samples[i].percent_sum = al->samples[i].percent; | 1899 | al->data[i].percent_sum = annotation_data__percent(&al->data[i], |
| 1900 | opts->percent_type); | ||
| 1901 | } | ||
| 1875 | 1902 | ||
| 1876 | rb_link_node(&al->rb_node, parent, p); | 1903 | rb_link_node(&al->rb_node, parent, p); |
| 1877 | rb_insert_color(&al->rb_node, root); | 1904 | rb_insert_color(&al->rb_node, root); |
| @@ -1881,10 +1908,10 @@ static int cmp_source_line(struct annotation_line *a, struct annotation_line *b) | |||
| 1881 | { | 1908 | { |
| 1882 | int i; | 1909 | int i; |
| 1883 | 1910 | ||
| 1884 | for (i = 0; i < a->samples_nr; i++) { | 1911 | for (i = 0; i < a->data_nr; i++) { |
| 1885 | if (a->samples[i].percent_sum == b->samples[i].percent_sum) | 1912 | if (a->data[i].percent_sum == b->data[i].percent_sum) |
| 1886 | continue; | 1913 | continue; |
| 1887 | return a->samples[i].percent_sum > b->samples[i].percent_sum; | 1914 | return a->data[i].percent_sum > b->data[i].percent_sum; |
| 1888 | } | 1915 | } |
| 1889 | 1916 | ||
| 1890 | return 0; | 1917 | return 0; |
| @@ -1949,8 +1976,8 @@ static void print_summary(struct rb_root *root, const char *filename) | |||
| 1949 | int i; | 1976 | int i; |
| 1950 | 1977 | ||
| 1951 | al = rb_entry(node, struct annotation_line, rb_node); | 1978 | al = rb_entry(node, struct annotation_line, rb_node); |
| 1952 | for (i = 0; i < al->samples_nr; i++) { | 1979 | for (i = 0; i < al->data_nr; i++) { |
| 1953 | percent = al->samples[i].percent_sum; | 1980 | percent = al->data[i].percent_sum; |
| 1954 | color = get_percent_color(percent); | 1981 | color = get_percent_color(percent); |
| 1955 | color_fprintf(stdout, color, " %7.2f", percent); | 1982 | color_fprintf(stdout, color, " %7.2f", percent); |
| 1956 | 1983 | ||
| @@ -2029,10 +2056,12 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, | |||
| 2029 | evsel_name = buf; | 2056 | evsel_name = buf; |
| 2030 | } | 2057 | } |
| 2031 | 2058 | ||
| 2032 | graph_dotted_len = printf(" %-*.*s| Source code & Disassembly of %s for %s (%" PRIu64 " samples)\n", | 2059 | graph_dotted_len = printf(" %-*.*s| Source code & Disassembly of %s for %s (%" PRIu64 " samples, " |
| 2060 | "percent: %s)\n", | ||
| 2033 | width, width, symbol_conf.show_total_period ? "Period" : | 2061 | width, width, symbol_conf.show_total_period ? "Period" : |
| 2034 | symbol_conf.show_nr_samples ? "Samples" : "Percent", | 2062 | symbol_conf.show_nr_samples ? "Samples" : "Percent", |
| 2035 | d_filename, evsel_name, h->nr_samples); | 2063 | d_filename, evsel_name, h->nr_samples, |
| 2064 | percent_type_str(opts->percent_type)); | ||
| 2036 | 2065 | ||
| 2037 | printf("%-*.*s----\n", | 2066 | printf("%-*.*s----\n", |
| 2038 | graph_dotted_len, graph_dotted_len, graph_dotted_line); | 2067 | graph_dotted_len, graph_dotted_len, graph_dotted_line); |
| @@ -2052,7 +2081,7 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, | |||
| 2052 | 2081 | ||
| 2053 | err = annotation_line__print(pos, sym, start, evsel, len, | 2082 | err = annotation_line__print(pos, sym, start, evsel, len, |
| 2054 | opts->min_pcnt, printed, opts->max_lines, | 2083 | opts->min_pcnt, printed, opts->max_lines, |
| 2055 | queue, addr_fmt_width); | 2084 | queue, addr_fmt_width, opts->percent_type); |
| 2056 | 2085 | ||
| 2057 | switch (err) { | 2086 | switch (err) { |
| 2058 | case 0: | 2087 | case 0: |
| @@ -2129,10 +2158,11 @@ static void FILE__write_graph(void *fp, int graph) | |||
| 2129 | fputs(s, fp); | 2158 | fputs(s, fp); |
| 2130 | } | 2159 | } |
| 2131 | 2160 | ||
| 2132 | int symbol__annotate_fprintf2(struct symbol *sym, FILE *fp) | 2161 | static int symbol__annotate_fprintf2(struct symbol *sym, FILE *fp, |
| 2162 | struct annotation_options *opts) | ||
| 2133 | { | 2163 | { |
| 2134 | struct annotation *notes = symbol__annotation(sym); | 2164 | struct annotation *notes = symbol__annotation(sym); |
| 2135 | struct annotation_write_ops ops = { | 2165 | struct annotation_write_ops wops = { |
| 2136 | .first_line = true, | 2166 | .first_line = true, |
| 2137 | .obj = fp, | 2167 | .obj = fp, |
| 2138 | .set_color = FILE__set_color, | 2168 | .set_color = FILE__set_color, |
| @@ -2146,15 +2176,16 @@ int symbol__annotate_fprintf2(struct symbol *sym, FILE *fp) | |||
| 2146 | list_for_each_entry(al, ¬es->src->source, node) { | 2176 | list_for_each_entry(al, ¬es->src->source, node) { |
| 2147 | if (annotation_line__filter(al, notes)) | 2177 | if (annotation_line__filter(al, notes)) |
| 2148 | continue; | 2178 | continue; |
| 2149 | annotation_line__write(al, notes, &ops); | 2179 | annotation_line__write(al, notes, &wops, opts); |
| 2150 | fputc('\n', fp); | 2180 | fputc('\n', fp); |
| 2151 | ops.first_line = false; | 2181 | wops.first_line = false; |
| 2152 | } | 2182 | } |
| 2153 | 2183 | ||
| 2154 | return 0; | 2184 | return 0; |
| 2155 | } | 2185 | } |
| 2156 | 2186 | ||
| 2157 | int map_symbol__annotation_dump(struct map_symbol *ms, struct perf_evsel *evsel) | 2187 | int map_symbol__annotation_dump(struct map_symbol *ms, struct perf_evsel *evsel, |
| 2188 | struct annotation_options *opts) | ||
| 2158 | { | 2189 | { |
| 2159 | const char *ev_name = perf_evsel__name(evsel); | 2190 | const char *ev_name = perf_evsel__name(evsel); |
| 2160 | char buf[1024]; | 2191 | char buf[1024]; |
| @@ -2176,7 +2207,7 @@ int map_symbol__annotation_dump(struct map_symbol *ms, struct perf_evsel *evsel) | |||
| 2176 | 2207 | ||
| 2177 | fprintf(fp, "%s() %s\nEvent: %s\n\n", | 2208 | fprintf(fp, "%s() %s\nEvent: %s\n\n", |
| 2178 | ms->sym->name, ms->map->dso->long_name, ev_name); | 2209 | ms->sym->name, ms->map->dso->long_name, ev_name); |
| 2179 | symbol__annotate_fprintf2(ms->sym, fp); | 2210 | symbol__annotate_fprintf2(ms->sym, fp, opts); |
| 2180 | 2211 | ||
| 2181 | fclose(fp); | 2212 | fclose(fp); |
| 2182 | err = 0; | 2213 | err = 0; |
| @@ -2346,7 +2377,8 @@ void annotation__update_column_widths(struct annotation *notes) | |||
| 2346 | } | 2377 | } |
| 2347 | 2378 | ||
| 2348 | static void annotation__calc_lines(struct annotation *notes, struct map *map, | 2379 | static void annotation__calc_lines(struct annotation *notes, struct map *map, |
| 2349 | struct rb_root *root) | 2380 | struct rb_root *root, |
| 2381 | struct annotation_options *opts) | ||
| 2350 | { | 2382 | { |
| 2351 | struct annotation_line *al; | 2383 | struct annotation_line *al; |
| 2352 | struct rb_root tmp_root = RB_ROOT; | 2384 | struct rb_root tmp_root = RB_ROOT; |
| @@ -2355,13 +2387,14 @@ static void annotation__calc_lines(struct annotation *notes, struct map *map, | |||
| 2355 | double percent_max = 0.0; | 2387 | double percent_max = 0.0; |
| 2356 | int i; | 2388 | int i; |
| 2357 | 2389 | ||
| 2358 | for (i = 0; i < al->samples_nr; i++) { | 2390 | for (i = 0; i < al->data_nr; i++) { |
| 2359 | struct annotation_data *sample; | 2391 | double percent; |
| 2360 | 2392 | ||
| 2361 | sample = &al->samples[i]; | 2393 | percent = annotation_data__percent(&al->data[i], |
| 2394 | opts->percent_type); | ||
| 2362 | 2395 | ||
| 2363 | if (sample->percent > percent_max) | 2396 | if (percent > percent_max) |
| 2364 | percent_max = sample->percent; | 2397 | percent_max = percent; |
| 2365 | } | 2398 | } |
| 2366 | 2399 | ||
| 2367 | if (percent_max <= 0.5) | 2400 | if (percent_max <= 0.5) |
| @@ -2369,18 +2402,19 @@ static void annotation__calc_lines(struct annotation *notes, struct map *map, | |||
| 2369 | 2402 | ||
| 2370 | al->path = get_srcline(map->dso, notes->start + al->offset, NULL, | 2403 | al->path = get_srcline(map->dso, notes->start + al->offset, NULL, |
| 2371 | false, true, notes->start + al->offset); | 2404 | false, true, notes->start + al->offset); |
| 2372 | insert_source_line(&tmp_root, al); | 2405 | insert_source_line(&tmp_root, al, opts); |
| 2373 | } | 2406 | } |
| 2374 | 2407 | ||
| 2375 | resort_source_line(root, &tmp_root); | 2408 | resort_source_line(root, &tmp_root); |
| 2376 | } | 2409 | } |
| 2377 | 2410 | ||
| 2378 | static void symbol__calc_lines(struct symbol *sym, struct map *map, | 2411 | static void symbol__calc_lines(struct symbol *sym, struct map *map, |
| 2379 | struct rb_root *root) | 2412 | struct rb_root *root, |
| 2413 | struct annotation_options *opts) | ||
| 2380 | { | 2414 | { |
| 2381 | struct annotation *notes = symbol__annotation(sym); | 2415 | struct annotation *notes = symbol__annotation(sym); |
| 2382 | 2416 | ||
| 2383 | annotation__calc_lines(notes, map, root); | 2417 | annotation__calc_lines(notes, map, root, opts); |
| 2384 | } | 2418 | } |
| 2385 | 2419 | ||
| 2386 | int symbol__tty_annotate2(struct symbol *sym, struct map *map, | 2420 | int symbol__tty_annotate2(struct symbol *sym, struct map *map, |
| @@ -2389,7 +2423,7 @@ int symbol__tty_annotate2(struct symbol *sym, struct map *map, | |||
| 2389 | { | 2423 | { |
| 2390 | struct dso *dso = map->dso; | 2424 | struct dso *dso = map->dso; |
| 2391 | struct rb_root source_line = RB_ROOT; | 2425 | struct rb_root source_line = RB_ROOT; |
| 2392 | struct annotation *notes = symbol__annotation(sym); | 2426 | struct hists *hists = evsel__hists(evsel); |
| 2393 | char buf[1024]; | 2427 | char buf[1024]; |
| 2394 | 2428 | ||
| 2395 | if (symbol__annotate2(sym, map, evsel, opts, NULL) < 0) | 2429 | if (symbol__annotate2(sym, map, evsel, opts, NULL) < 0) |
| @@ -2397,13 +2431,14 @@ int symbol__tty_annotate2(struct symbol *sym, struct map *map, | |||
| 2397 | 2431 | ||
| 2398 | if (opts->print_lines) { | 2432 | if (opts->print_lines) { |
| 2399 | srcline_full_filename = opts->full_path; | 2433 | srcline_full_filename = opts->full_path; |
| 2400 | symbol__calc_lines(sym, map, &source_line); | 2434 | symbol__calc_lines(sym, map, &source_line, opts); |
| 2401 | print_summary(&source_line, dso->long_name); | 2435 | print_summary(&source_line, dso->long_name); |
| 2402 | } | 2436 | } |
| 2403 | 2437 | ||
| 2404 | annotation__scnprintf_samples_period(notes, buf, sizeof(buf), evsel); | 2438 | hists__scnprintf_title(hists, buf, sizeof(buf)); |
| 2405 | fprintf(stdout, "%s\n%s() %s\n", buf, sym->name, dso->long_name); | 2439 | fprintf(stdout, "%s, [percent: %s]\n%s() %s\n", |
| 2406 | symbol__annotate_fprintf2(sym, stdout); | 2440 | buf, percent_type_str(opts->percent_type), sym->name, dso->long_name); |
| 2441 | symbol__annotate_fprintf2(sym, stdout, opts); | ||
| 2407 | 2442 | ||
| 2408 | annotated_source__purge(symbol__annotation(sym)->src); | 2443 | annotated_source__purge(symbol__annotation(sym)->src); |
| 2409 | 2444 | ||
| @@ -2424,7 +2459,7 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map, | |||
| 2424 | 2459 | ||
| 2425 | if (opts->print_lines) { | 2460 | if (opts->print_lines) { |
| 2426 | srcline_full_filename = opts->full_path; | 2461 | srcline_full_filename = opts->full_path; |
| 2427 | symbol__calc_lines(sym, map, &source_line); | 2462 | symbol__calc_lines(sym, map, &source_line, opts); |
| 2428 | print_summary(&source_line, dso->long_name); | 2463 | print_summary(&source_line, dso->long_name); |
| 2429 | } | 2464 | } |
| 2430 | 2465 | ||
| @@ -2441,14 +2476,21 @@ bool ui__has_annotation(void) | |||
| 2441 | } | 2476 | } |
| 2442 | 2477 | ||
| 2443 | 2478 | ||
| 2444 | double annotation_line__max_percent(struct annotation_line *al, struct annotation *notes) | 2479 | static double annotation_line__max_percent(struct annotation_line *al, |
| 2480 | struct annotation *notes, | ||
| 2481 | unsigned int percent_type) | ||
| 2445 | { | 2482 | { |
| 2446 | double percent_max = 0.0; | 2483 | double percent_max = 0.0; |
| 2447 | int i; | 2484 | int i; |
| 2448 | 2485 | ||
| 2449 | for (i = 0; i < notes->nr_events; i++) { | 2486 | for (i = 0; i < notes->nr_events; i++) { |
| 2450 | if (al->samples[i].percent > percent_max) | 2487 | double percent; |
| 2451 | percent_max = al->samples[i].percent; | 2488 | |
| 2489 | percent = annotation_data__percent(&al->data[i], | ||
| 2490 | percent_type); | ||
| 2491 | |||
| 2492 | if (percent > percent_max) | ||
| 2493 | percent_max = percent; | ||
| 2452 | } | 2494 | } |
| 2453 | 2495 | ||
| 2454 | return percent_max; | 2496 | return percent_max; |
| @@ -2487,7 +2529,7 @@ call_like: | |||
| 2487 | 2529 | ||
| 2488 | static void __annotation_line__write(struct annotation_line *al, struct annotation *notes, | 2530 | static void __annotation_line__write(struct annotation_line *al, struct annotation *notes, |
| 2489 | bool first_line, bool current_entry, bool change_color, int width, | 2531 | bool first_line, bool current_entry, bool change_color, int width, |
| 2490 | void *obj, | 2532 | void *obj, unsigned int percent_type, |
| 2491 | int (*obj__set_color)(void *obj, int color), | 2533 | int (*obj__set_color)(void *obj, int color), |
| 2492 | void (*obj__set_percent_color)(void *obj, double percent, bool current), | 2534 | void (*obj__set_percent_color)(void *obj, double percent, bool current), |
| 2493 | int (*obj__set_jumps_percent_color)(void *obj, int nr, bool current), | 2535 | int (*obj__set_jumps_percent_color)(void *obj, int nr, bool current), |
| @@ -2495,7 +2537,7 @@ static void __annotation_line__write(struct annotation_line *al, struct annotati | |||
| 2495 | void (*obj__write_graph)(void *obj, int graph)) | 2537 | void (*obj__write_graph)(void *obj, int graph)) |
| 2496 | 2538 | ||
| 2497 | { | 2539 | { |
| 2498 | double percent_max = annotation_line__max_percent(al, notes); | 2540 | double percent_max = annotation_line__max_percent(al, notes, percent_type); |
| 2499 | int pcnt_width = annotation__pcnt_width(notes), | 2541 | int pcnt_width = annotation__pcnt_width(notes), |
| 2500 | cycles_width = annotation__cycles_width(notes); | 2542 | cycles_width = annotation__cycles_width(notes); |
| 2501 | bool show_title = false; | 2543 | bool show_title = false; |
| @@ -2514,15 +2556,18 @@ static void __annotation_line__write(struct annotation_line *al, struct annotati | |||
| 2514 | int i; | 2556 | int i; |
| 2515 | 2557 | ||
| 2516 | for (i = 0; i < notes->nr_events; i++) { | 2558 | for (i = 0; i < notes->nr_events; i++) { |
| 2517 | obj__set_percent_color(obj, al->samples[i].percent, current_entry); | 2559 | double percent; |
| 2560 | |||
| 2561 | percent = annotation_data__percent(&al->data[i], percent_type); | ||
| 2562 | |||
| 2563 | obj__set_percent_color(obj, percent, current_entry); | ||
| 2518 | if (notes->options->show_total_period) { | 2564 | if (notes->options->show_total_period) { |
| 2519 | obj__printf(obj, "%11" PRIu64 " ", al->samples[i].he.period); | 2565 | obj__printf(obj, "%11" PRIu64 " ", al->data[i].he.period); |
| 2520 | } else if (notes->options->show_nr_samples) { | 2566 | } else if (notes->options->show_nr_samples) { |
| 2521 | obj__printf(obj, "%6" PRIu64 " ", | 2567 | obj__printf(obj, "%6" PRIu64 " ", |
| 2522 | al->samples[i].he.nr_samples); | 2568 | al->data[i].he.nr_samples); |
| 2523 | } else { | 2569 | } else { |
| 2524 | obj__printf(obj, "%6.2f ", | 2570 | obj__printf(obj, "%6.2f ", percent); |
| 2525 | al->samples[i].percent); | ||
| 2526 | } | 2571 | } |
| 2527 | } | 2572 | } |
| 2528 | } else { | 2573 | } else { |
| @@ -2640,13 +2685,15 @@ print_addr: | |||
| 2640 | } | 2685 | } |
| 2641 | 2686 | ||
| 2642 | void annotation_line__write(struct annotation_line *al, struct annotation *notes, | 2687 | void annotation_line__write(struct annotation_line *al, struct annotation *notes, |
| 2643 | struct annotation_write_ops *ops) | 2688 | struct annotation_write_ops *wops, |
| 2689 | struct annotation_options *opts) | ||
| 2644 | { | 2690 | { |
| 2645 | __annotation_line__write(al, notes, ops->first_line, ops->current_entry, | 2691 | __annotation_line__write(al, notes, wops->first_line, wops->current_entry, |
| 2646 | ops->change_color, ops->width, ops->obj, | 2692 | wops->change_color, wops->width, wops->obj, |
| 2647 | ops->set_color, ops->set_percent_color, | 2693 | opts->percent_type, |
| 2648 | ops->set_jumps_percent_color, ops->printf, | 2694 | wops->set_color, wops->set_percent_color, |
| 2649 | ops->write_graph); | 2695 | wops->set_jumps_percent_color, wops->printf, |
| 2696 | wops->write_graph); | ||
| 2650 | } | 2697 | } |
| 2651 | 2698 | ||
| 2652 | int symbol__annotate2(struct symbol *sym, struct map *map, struct perf_evsel *evsel, | 2699 | int symbol__annotate2(struct symbol *sym, struct map *map, struct perf_evsel *evsel, |
| @@ -2688,46 +2735,6 @@ out_free_offsets: | |||
| 2688 | return -1; | 2735 | return -1; |
| 2689 | } | 2736 | } |
| 2690 | 2737 | ||
| 2691 | int __annotation__scnprintf_samples_period(struct annotation *notes, | ||
| 2692 | char *bf, size_t size, | ||
| 2693 | struct perf_evsel *evsel, | ||
| 2694 | bool show_freq) | ||
| 2695 | { | ||
| 2696 | const char *ev_name = perf_evsel__name(evsel); | ||
| 2697 | char buf[1024], ref[30] = " show reference callgraph, "; | ||
| 2698 | char sample_freq_str[64] = ""; | ||
| 2699 | unsigned long nr_samples = 0; | ||
| 2700 | int nr_members = 1; | ||
| 2701 | bool enable_ref = false; | ||
| 2702 | u64 nr_events = 0; | ||
| 2703 | char unit; | ||
| 2704 | int i; | ||
| 2705 | |||
| 2706 | if (perf_evsel__is_group_event(evsel)) { | ||
| 2707 | perf_evsel__group_desc(evsel, buf, sizeof(buf)); | ||
| 2708 | ev_name = buf; | ||
| 2709 | nr_members = evsel->nr_members; | ||
| 2710 | } | ||
| 2711 | |||
| 2712 | for (i = 0; i < nr_members; i++) { | ||
| 2713 | struct sym_hist *ah = annotation__histogram(notes, evsel->idx + i); | ||
| 2714 | |||
| 2715 | nr_samples += ah->nr_samples; | ||
| 2716 | nr_events += ah->period; | ||
| 2717 | } | ||
| 2718 | |||
| 2719 | if (symbol_conf.show_ref_callgraph && strstr(ev_name, "call-graph=no")) | ||
| 2720 | enable_ref = true; | ||
| 2721 | |||
| 2722 | if (show_freq) | ||
| 2723 | scnprintf(sample_freq_str, sizeof(sample_freq_str), " %d Hz,", evsel->attr.sample_freq); | ||
| 2724 | |||
| 2725 | nr_samples = convert_unit(nr_samples, &unit); | ||
| 2726 | return scnprintf(bf, size, "Samples: %lu%c of event%s '%s',%s%sEvent count (approx.): %" PRIu64, | ||
| 2727 | nr_samples, unit, evsel->nr_members > 1 ? "s" : "", | ||
| 2728 | ev_name, sample_freq_str, enable_ref ? ref : " ", nr_events); | ||
| 2729 | } | ||
| 2730 | |||
| 2731 | #define ANNOTATION__CFG(n) \ | 2738 | #define ANNOTATION__CFG(n) \ |
| 2732 | { .name = #n, .value = &annotation__default_options.n, } | 2739 | { .name = #n, .value = &annotation__default_options.n, } |
| 2733 | 2740 | ||
| @@ -2792,3 +2799,55 @@ void annotation_config__init(void) | |||
| 2792 | annotation__default_options.show_total_period = symbol_conf.show_total_period; | 2799 | annotation__default_options.show_total_period = symbol_conf.show_total_period; |
| 2793 | annotation__default_options.show_nr_samples = symbol_conf.show_nr_samples; | 2800 | annotation__default_options.show_nr_samples = symbol_conf.show_nr_samples; |
| 2794 | } | 2801 | } |
| 2802 | |||
| 2803 | static unsigned int parse_percent_type(char *str1, char *str2) | ||
| 2804 | { | ||
| 2805 | unsigned int type = (unsigned int) -1; | ||
| 2806 | |||
| 2807 | if (!strcmp("period", str1)) { | ||
| 2808 | if (!strcmp("local", str2)) | ||
| 2809 | type = PERCENT_PERIOD_LOCAL; | ||
| 2810 | else if (!strcmp("global", str2)) | ||
| 2811 | type = PERCENT_PERIOD_GLOBAL; | ||
| 2812 | } | ||
| 2813 | |||
| 2814 | if (!strcmp("hits", str1)) { | ||
| 2815 | if (!strcmp("local", str2)) | ||
| 2816 | type = PERCENT_HITS_LOCAL; | ||
| 2817 | else if (!strcmp("global", str2)) | ||
| 2818 | type = PERCENT_HITS_GLOBAL; | ||
| 2819 | } | ||
| 2820 | |||
| 2821 | return type; | ||
| 2822 | } | ||
| 2823 | |||
| 2824 | int annotate_parse_percent_type(const struct option *opt, const char *_str, | ||
| 2825 | int unset __maybe_unused) | ||
| 2826 | { | ||
| 2827 | struct annotation_options *opts = opt->value; | ||
| 2828 | unsigned int type; | ||
| 2829 | char *str1, *str2; | ||
| 2830 | int err = -1; | ||
| 2831 | |||
| 2832 | str1 = strdup(_str); | ||
| 2833 | if (!str1) | ||
| 2834 | return -ENOMEM; | ||
| 2835 | |||
| 2836 | str2 = strchr(str1, '-'); | ||
| 2837 | if (!str2) | ||
| 2838 | goto out; | ||
| 2839 | |||
| 2840 | *str2++ = 0; | ||
| 2841 | |||
| 2842 | type = parse_percent_type(str1, str2); | ||
| 2843 | if (type == (unsigned int) -1) | ||
| 2844 | type = parse_percent_type(str2, str1); | ||
| 2845 | if (type != (unsigned int) -1) { | ||
| 2846 | opts->percent_type = type; | ||
| 2847 | err = 0; | ||
| 2848 | } | ||
| 2849 | |||
| 2850 | out: | ||
| 2851 | free(str1); | ||
| 2852 | return err; | ||
| 2853 | } | ||
diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index a4c0d91907e6..005a5fe8a8c6 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h | |||
| @@ -11,6 +11,7 @@ | |||
| 11 | #include <linux/list.h> | 11 | #include <linux/list.h> |
| 12 | #include <linux/rbtree.h> | 12 | #include <linux/rbtree.h> |
| 13 | #include <pthread.h> | 13 | #include <pthread.h> |
| 14 | #include <asm/bug.h> | ||
| 14 | 15 | ||
| 15 | struct ins_ops; | 16 | struct ins_ops; |
| 16 | 17 | ||
| @@ -82,6 +83,7 @@ struct annotation_options { | |||
| 82 | int context; | 83 | int context; |
| 83 | const char *objdump_path; | 84 | const char *objdump_path; |
| 84 | const char *disassembler_style; | 85 | const char *disassembler_style; |
| 86 | unsigned int percent_type; | ||
| 85 | }; | 87 | }; |
| 86 | 88 | ||
| 87 | enum { | 89 | enum { |
| @@ -101,8 +103,16 @@ struct sym_hist_entry { | |||
| 101 | u64 period; | 103 | u64 period; |
| 102 | }; | 104 | }; |
| 103 | 105 | ||
| 106 | enum { | ||
| 107 | PERCENT_HITS_LOCAL, | ||
| 108 | PERCENT_HITS_GLOBAL, | ||
| 109 | PERCENT_PERIOD_LOCAL, | ||
| 110 | PERCENT_PERIOD_GLOBAL, | ||
| 111 | PERCENT_MAX, | ||
| 112 | }; | ||
| 113 | |||
| 104 | struct annotation_data { | 114 | struct annotation_data { |
| 105 | double percent; | 115 | double percent[PERCENT_MAX]; |
| 106 | double percent_sum; | 116 | double percent_sum; |
| 107 | struct sym_hist_entry he; | 117 | struct sym_hist_entry he; |
| 108 | }; | 118 | }; |
| @@ -122,8 +132,8 @@ struct annotation_line { | |||
| 122 | char *path; | 132 | char *path; |
| 123 | u32 idx; | 133 | u32 idx; |
| 124 | int idx_asm; | 134 | int idx_asm; |
| 125 | int samples_nr; | 135 | int data_nr; |
| 126 | struct annotation_data samples[0]; | 136 | struct annotation_data data[0]; |
| 127 | }; | 137 | }; |
| 128 | 138 | ||
| 129 | struct disasm_line { | 139 | struct disasm_line { |
| @@ -134,6 +144,27 @@ struct disasm_line { | |||
| 134 | struct annotation_line al; | 144 | struct annotation_line al; |
| 135 | }; | 145 | }; |
| 136 | 146 | ||
| 147 | static inline double annotation_data__percent(struct annotation_data *data, | ||
| 148 | unsigned int which) | ||
| 149 | { | ||
| 150 | return which < PERCENT_MAX ? data->percent[which] : -1; | ||
| 151 | } | ||
| 152 | |||
| 153 | static inline const char *percent_type_str(unsigned int type) | ||
| 154 | { | ||
| 155 | static const char *str[PERCENT_MAX] = { | ||
| 156 | "local hits", | ||
| 157 | "global hits", | ||
| 158 | "local period", | ||
| 159 | "global period", | ||
| 160 | }; | ||
| 161 | |||
| 162 | if (WARN_ON(type >= PERCENT_MAX)) | ||
| 163 | return "N/A"; | ||
| 164 | |||
| 165 | return str[type]; | ||
| 166 | } | ||
| 167 | |||
| 137 | static inline struct disasm_line *disasm_line(struct annotation_line *al) | 168 | static inline struct disasm_line *disasm_line(struct annotation_line *al) |
| 138 | { | 169 | { |
| 139 | return al ? container_of(al, struct disasm_line, al) : NULL; | 170 | return al ? container_of(al, struct disasm_line, al) : NULL; |
| @@ -169,22 +200,15 @@ struct annotation_write_ops { | |||
| 169 | void (*write_graph)(void *obj, int graph); | 200 | void (*write_graph)(void *obj, int graph); |
| 170 | }; | 201 | }; |
| 171 | 202 | ||
| 172 | double annotation_line__max_percent(struct annotation_line *al, struct annotation *notes); | ||
| 173 | void annotation_line__write(struct annotation_line *al, struct annotation *notes, | 203 | void annotation_line__write(struct annotation_line *al, struct annotation *notes, |
| 174 | struct annotation_write_ops *ops); | 204 | struct annotation_write_ops *ops, |
| 205 | struct annotation_options *opts); | ||
| 175 | 206 | ||
| 176 | int __annotation__scnprintf_samples_period(struct annotation *notes, | 207 | int __annotation__scnprintf_samples_period(struct annotation *notes, |
| 177 | char *bf, size_t size, | 208 | char *bf, size_t size, |
| 178 | struct perf_evsel *evsel, | 209 | struct perf_evsel *evsel, |
| 179 | bool show_freq); | 210 | bool show_freq); |
| 180 | 211 | ||
| 181 | static inline int annotation__scnprintf_samples_period(struct annotation *notes, | ||
| 182 | char *bf, size_t size, | ||
| 183 | struct perf_evsel *evsel) | ||
| 184 | { | ||
| 185 | return __annotation__scnprintf_samples_period(notes, bf, size, evsel, true); | ||
| 186 | } | ||
| 187 | |||
| 188 | int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw); | 212 | int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw); |
| 189 | size_t disasm__fprintf(struct list_head *head, FILE *fp); | 213 | size_t disasm__fprintf(struct list_head *head, FILE *fp); |
| 190 | void symbol__calc_percent(struct symbol *sym, struct perf_evsel *evsel); | 214 | void symbol__calc_percent(struct symbol *sym, struct perf_evsel *evsel); |
| @@ -340,12 +364,12 @@ int symbol__strerror_disassemble(struct symbol *sym, struct map *map, | |||
| 340 | int symbol__annotate_printf(struct symbol *sym, struct map *map, | 364 | int symbol__annotate_printf(struct symbol *sym, struct map *map, |
| 341 | struct perf_evsel *evsel, | 365 | struct perf_evsel *evsel, |
| 342 | struct annotation_options *options); | 366 | struct annotation_options *options); |
| 343 | int symbol__annotate_fprintf2(struct symbol *sym, FILE *fp); | ||
| 344 | void symbol__annotate_zero_histogram(struct symbol *sym, int evidx); | 367 | void symbol__annotate_zero_histogram(struct symbol *sym, int evidx); |
| 345 | void symbol__annotate_decay_histogram(struct symbol *sym, int evidx); | 368 | void symbol__annotate_decay_histogram(struct symbol *sym, int evidx); |
| 346 | void annotated_source__purge(struct annotated_source *as); | 369 | void annotated_source__purge(struct annotated_source *as); |
| 347 | 370 | ||
| 348 | int map_symbol__annotation_dump(struct map_symbol *ms, struct perf_evsel *evsel); | 371 | int map_symbol__annotation_dump(struct map_symbol *ms, struct perf_evsel *evsel, |
| 372 | struct annotation_options *opts); | ||
| 349 | 373 | ||
| 350 | bool ui__has_annotation(void); | 374 | bool ui__has_annotation(void); |
| 351 | 375 | ||
| @@ -373,4 +397,6 @@ static inline int symbol__tui_annotate(struct symbol *sym __maybe_unused, | |||
| 373 | 397 | ||
| 374 | void annotation_config__init(void); | 398 | void annotation_config__init(void); |
| 375 | 399 | ||
| 400 | int annotate_parse_percent_type(const struct option *opt, const char *_str, | ||
| 401 | int unset); | ||
| 376 | #endif /* __PERF_ANNOTATE_H */ | 402 | #endif /* __PERF_ANNOTATE_H */ |
diff --git a/tools/perf/util/auxtrace.c b/tools/perf/util/auxtrace.c index d056447520a2..db1511359c5e 100644 --- a/tools/perf/util/auxtrace.c +++ b/tools/perf/util/auxtrace.c | |||
| @@ -56,6 +56,7 @@ | |||
| 56 | #include "intel-pt.h" | 56 | #include "intel-pt.h" |
| 57 | #include "intel-bts.h" | 57 | #include "intel-bts.h" |
| 58 | #include "arm-spe.h" | 58 | #include "arm-spe.h" |
| 59 | #include "s390-cpumsf.h" | ||
| 59 | 60 | ||
| 60 | #include "sane_ctype.h" | 61 | #include "sane_ctype.h" |
| 61 | #include "symbol/kallsyms.h" | 62 | #include "symbol/kallsyms.h" |
| @@ -202,6 +203,9 @@ static int auxtrace_queues__grow(struct auxtrace_queues *queues, | |||
| 202 | for (i = 0; i < queues->nr_queues; i++) { | 203 | for (i = 0; i < queues->nr_queues; i++) { |
| 203 | list_splice_tail(&queues->queue_array[i].head, | 204 | list_splice_tail(&queues->queue_array[i].head, |
| 204 | &queue_array[i].head); | 205 | &queue_array[i].head); |
| 206 | queue_array[i].tid = queues->queue_array[i].tid; | ||
| 207 | queue_array[i].cpu = queues->queue_array[i].cpu; | ||
| 208 | queue_array[i].set = queues->queue_array[i].set; | ||
| 205 | queue_array[i].priv = queues->queue_array[i].priv; | 209 | queue_array[i].priv = queues->queue_array[i].priv; |
| 206 | } | 210 | } |
| 207 | 211 | ||
| @@ -920,6 +924,8 @@ int perf_event__process_auxtrace_info(struct perf_tool *tool __maybe_unused, | |||
| 920 | return arm_spe_process_auxtrace_info(event, session); | 924 | return arm_spe_process_auxtrace_info(event, session); |
| 921 | case PERF_AUXTRACE_CS_ETM: | 925 | case PERF_AUXTRACE_CS_ETM: |
| 922 | return cs_etm__process_auxtrace_info(event, session); | 926 | return cs_etm__process_auxtrace_info(event, session); |
| 927 | case PERF_AUXTRACE_S390_CPUMSF: | ||
| 928 | return s390_cpumsf_process_auxtrace_info(event, session); | ||
| 923 | case PERF_AUXTRACE_UNKNOWN: | 929 | case PERF_AUXTRACE_UNKNOWN: |
| 924 | default: | 930 | default: |
| 925 | return -EINVAL; | 931 | return -EINVAL; |
diff --git a/tools/perf/util/auxtrace.h b/tools/perf/util/auxtrace.h index e731f55da072..71fc3bd74299 100644 --- a/tools/perf/util/auxtrace.h +++ b/tools/perf/util/auxtrace.h | |||
| @@ -44,6 +44,7 @@ enum auxtrace_type { | |||
| 44 | PERF_AUXTRACE_INTEL_BTS, | 44 | PERF_AUXTRACE_INTEL_BTS, |
| 45 | PERF_AUXTRACE_CS_ETM, | 45 | PERF_AUXTRACE_CS_ETM, |
| 46 | PERF_AUXTRACE_ARM_SPE, | 46 | PERF_AUXTRACE_ARM_SPE, |
| 47 | PERF_AUXTRACE_S390_CPUMSF, | ||
| 47 | }; | 48 | }; |
| 48 | 49 | ||
| 49 | enum itrace_period_type { | 50 | enum itrace_period_type { |
diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c index 3d02ae38ec56..47aac41349a2 100644 --- a/tools/perf/util/bpf-loader.c +++ b/tools/perf/util/bpf-loader.c | |||
| @@ -1529,13 +1529,13 @@ int bpf__apply_obj_config(void) | |||
| 1529 | bpf_object__for_each_safe(obj, objtmp) \ | 1529 | bpf_object__for_each_safe(obj, objtmp) \ |
| 1530 | bpf_map__for_each(pos, obj) | 1530 | bpf_map__for_each(pos, obj) |
| 1531 | 1531 | ||
| 1532 | #define bpf__for_each_stdout_map(pos, obj, objtmp) \ | 1532 | #define bpf__for_each_map_named(pos, obj, objtmp, name) \ |
| 1533 | bpf__for_each_map(pos, obj, objtmp) \ | 1533 | bpf__for_each_map(pos, obj, objtmp) \ |
| 1534 | if (bpf_map__name(pos) && \ | 1534 | if (bpf_map__name(pos) && \ |
| 1535 | (strcmp("__bpf_stdout__", \ | 1535 | (strcmp(name, \ |
| 1536 | bpf_map__name(pos)) == 0)) | 1536 | bpf_map__name(pos)) == 0)) |
| 1537 | 1537 | ||
| 1538 | int bpf__setup_stdout(struct perf_evlist *evlist) | 1538 | struct perf_evsel *bpf__setup_output_event(struct perf_evlist *evlist, const char *name) |
| 1539 | { | 1539 | { |
| 1540 | struct bpf_map_priv *tmpl_priv = NULL; | 1540 | struct bpf_map_priv *tmpl_priv = NULL; |
| 1541 | struct bpf_object *obj, *tmp; | 1541 | struct bpf_object *obj, *tmp; |
| @@ -1544,11 +1544,11 @@ int bpf__setup_stdout(struct perf_evlist *evlist) | |||
| 1544 | int err; | 1544 | int err; |
| 1545 | bool need_init = false; | 1545 | bool need_init = false; |
| 1546 | 1546 | ||
| 1547 | bpf__for_each_stdout_map(map, obj, tmp) { | 1547 | bpf__for_each_map_named(map, obj, tmp, name) { |
| 1548 | struct bpf_map_priv *priv = bpf_map__priv(map); | 1548 | struct bpf_map_priv *priv = bpf_map__priv(map); |
| 1549 | 1549 | ||
| 1550 | if (IS_ERR(priv)) | 1550 | if (IS_ERR(priv)) |
| 1551 | return -BPF_LOADER_ERRNO__INTERNAL; | 1551 | return ERR_PTR(-BPF_LOADER_ERRNO__INTERNAL); |
| 1552 | 1552 | ||
| 1553 | /* | 1553 | /* |
| 1554 | * No need to check map type: type should have been | 1554 | * No need to check map type: type should have been |
| @@ -1561,49 +1561,61 @@ int bpf__setup_stdout(struct perf_evlist *evlist) | |||
| 1561 | } | 1561 | } |
| 1562 | 1562 | ||
| 1563 | if (!need_init) | 1563 | if (!need_init) |
| 1564 | return 0; | 1564 | return NULL; |
| 1565 | 1565 | ||
| 1566 | if (!tmpl_priv) { | 1566 | if (!tmpl_priv) { |
| 1567 | err = parse_events(evlist, "bpf-output/no-inherit=1,name=__bpf_stdout__/", | 1567 | char *event_definition = NULL; |
| 1568 | NULL); | 1568 | |
| 1569 | if (asprintf(&event_definition, "bpf-output/no-inherit=1,name=%s/", name) < 0) | ||
| 1570 | return ERR_PTR(-ENOMEM); | ||
| 1571 | |||
| 1572 | err = parse_events(evlist, event_definition, NULL); | ||
| 1573 | free(event_definition); | ||
| 1574 | |||
| 1569 | if (err) { | 1575 | if (err) { |
| 1570 | pr_debug("ERROR: failed to create bpf-output event\n"); | 1576 | pr_debug("ERROR: failed to create the \"%s\" bpf-output event\n", name); |
| 1571 | return -err; | 1577 | return ERR_PTR(-err); |
| 1572 | } | 1578 | } |
| 1573 | 1579 | ||
| 1574 | evsel = perf_evlist__last(evlist); | 1580 | evsel = perf_evlist__last(evlist); |
| 1575 | } | 1581 | } |
| 1576 | 1582 | ||
| 1577 | bpf__for_each_stdout_map(map, obj, tmp) { | 1583 | bpf__for_each_map_named(map, obj, tmp, name) { |
| 1578 | struct bpf_map_priv *priv = bpf_map__priv(map); | 1584 | struct bpf_map_priv *priv = bpf_map__priv(map); |
| 1579 | 1585 | ||
| 1580 | if (IS_ERR(priv)) | 1586 | if (IS_ERR(priv)) |
| 1581 | return -BPF_LOADER_ERRNO__INTERNAL; | 1587 | return ERR_PTR(-BPF_LOADER_ERRNO__INTERNAL); |
| 1582 | if (priv) | 1588 | if (priv) |
| 1583 | continue; | 1589 | continue; |
| 1584 | 1590 | ||
| 1585 | if (tmpl_priv) { | 1591 | if (tmpl_priv) { |
| 1586 | priv = bpf_map_priv__clone(tmpl_priv); | 1592 | priv = bpf_map_priv__clone(tmpl_priv); |
| 1587 | if (!priv) | 1593 | if (!priv) |
| 1588 | return -ENOMEM; | 1594 | return ERR_PTR(-ENOMEM); |
| 1589 | 1595 | ||
| 1590 | err = bpf_map__set_priv(map, priv, bpf_map_priv__clear); | 1596 | err = bpf_map__set_priv(map, priv, bpf_map_priv__clear); |
| 1591 | if (err) { | 1597 | if (err) { |
| 1592 | bpf_map_priv__clear(map, priv); | 1598 | bpf_map_priv__clear(map, priv); |
| 1593 | return err; | 1599 | return ERR_PTR(err); |
| 1594 | } | 1600 | } |
| 1595 | } else if (evsel) { | 1601 | } else if (evsel) { |
| 1596 | struct bpf_map_op *op; | 1602 | struct bpf_map_op *op; |
| 1597 | 1603 | ||
| 1598 | op = bpf_map__add_newop(map, NULL); | 1604 | op = bpf_map__add_newop(map, NULL); |
| 1599 | if (IS_ERR(op)) | 1605 | if (IS_ERR(op)) |
| 1600 | return PTR_ERR(op); | 1606 | return ERR_PTR(PTR_ERR(op)); |
| 1601 | op->op_type = BPF_MAP_OP_SET_EVSEL; | 1607 | op->op_type = BPF_MAP_OP_SET_EVSEL; |
| 1602 | op->v.evsel = evsel; | 1608 | op->v.evsel = evsel; |
| 1603 | } | 1609 | } |
| 1604 | } | 1610 | } |
| 1605 | 1611 | ||
| 1606 | return 0; | 1612 | return evsel; |
| 1613 | } | ||
| 1614 | |||
| 1615 | int bpf__setup_stdout(struct perf_evlist *evlist) | ||
| 1616 | { | ||
| 1617 | struct perf_evsel *evsel = bpf__setup_output_event(evlist, "__bpf_stdout__"); | ||
| 1618 | return IS_ERR(evsel) ? PTR_ERR(evsel) : 0; | ||
| 1607 | } | 1619 | } |
| 1608 | 1620 | ||
| 1609 | #define ERRNO_OFFSET(e) ((e) - __BPF_LOADER_ERRNO__START) | 1621 | #define ERRNO_OFFSET(e) ((e) - __BPF_LOADER_ERRNO__START) |
| @@ -1780,8 +1792,8 @@ int bpf__strerror_apply_obj_config(int err, char *buf, size_t size) | |||
| 1780 | return 0; | 1792 | return 0; |
| 1781 | } | 1793 | } |
| 1782 | 1794 | ||
| 1783 | int bpf__strerror_setup_stdout(struct perf_evlist *evlist __maybe_unused, | 1795 | int bpf__strerror_setup_output_event(struct perf_evlist *evlist __maybe_unused, |
| 1784 | int err, char *buf, size_t size) | 1796 | int err, char *buf, size_t size) |
| 1785 | { | 1797 | { |
| 1786 | bpf__strerror_head(err, buf, size); | 1798 | bpf__strerror_head(err, buf, size); |
| 1787 | bpf__strerror_end(buf, size); | 1799 | bpf__strerror_end(buf, size); |
diff --git a/tools/perf/util/bpf-loader.h b/tools/perf/util/bpf-loader.h index 5d3aefd6fae7..62d245a90e1d 100644 --- a/tools/perf/util/bpf-loader.h +++ b/tools/perf/util/bpf-loader.h | |||
| @@ -43,6 +43,7 @@ enum bpf_loader_errno { | |||
| 43 | __BPF_LOADER_ERRNO__END, | 43 | __BPF_LOADER_ERRNO__END, |
| 44 | }; | 44 | }; |
| 45 | 45 | ||
| 46 | struct perf_evsel; | ||
| 46 | struct bpf_object; | 47 | struct bpf_object; |
| 47 | struct parse_events_term; | 48 | struct parse_events_term; |
| 48 | #define PERF_BPF_PROBE_GROUP "perf_bpf_probe" | 49 | #define PERF_BPF_PROBE_GROUP "perf_bpf_probe" |
| @@ -82,9 +83,8 @@ int bpf__apply_obj_config(void); | |||
| 82 | int bpf__strerror_apply_obj_config(int err, char *buf, size_t size); | 83 | int bpf__strerror_apply_obj_config(int err, char *buf, size_t size); |
| 83 | 84 | ||
| 84 | int bpf__setup_stdout(struct perf_evlist *evlist); | 85 | int bpf__setup_stdout(struct perf_evlist *evlist); |
| 85 | int bpf__strerror_setup_stdout(struct perf_evlist *evlist, int err, | 86 | struct perf_evsel *bpf__setup_output_event(struct perf_evlist *evlist, const char *name); |
| 86 | char *buf, size_t size); | 87 | int bpf__strerror_setup_output_event(struct perf_evlist *evlist, int err, char *buf, size_t size); |
| 87 | |||
| 88 | #else | 88 | #else |
| 89 | #include <errno.h> | 89 | #include <errno.h> |
| 90 | 90 | ||
| @@ -138,6 +138,12 @@ bpf__setup_stdout(struct perf_evlist *evlist __maybe_unused) | |||
| 138 | return 0; | 138 | return 0; |
| 139 | } | 139 | } |
| 140 | 140 | ||
| 141 | static inline struct perf_evsel * | ||
| 142 | bpf__setup_output_event(struct perf_evlist *evlist __maybe_unused, const char *name __maybe_unused) | ||
| 143 | { | ||
| 144 | return NULL; | ||
| 145 | } | ||
| 146 | |||
| 141 | static inline int | 147 | static inline int |
| 142 | __bpf_strerror(char *buf, size_t size) | 148 | __bpf_strerror(char *buf, size_t size) |
| 143 | { | 149 | { |
| @@ -193,11 +199,16 @@ bpf__strerror_apply_obj_config(int err __maybe_unused, | |||
| 193 | } | 199 | } |
| 194 | 200 | ||
| 195 | static inline int | 201 | static inline int |
| 196 | bpf__strerror_setup_stdout(struct perf_evlist *evlist __maybe_unused, | 202 | bpf__strerror_setup_output_event(struct perf_evlist *evlist __maybe_unused, |
| 197 | int err __maybe_unused, char *buf, | 203 | int err __maybe_unused, char *buf, size_t size) |
| 198 | size_t size) | ||
| 199 | { | 204 | { |
| 200 | return __bpf_strerror(buf, size); | 205 | return __bpf_strerror(buf, size); |
| 201 | } | 206 | } |
| 207 | |||
| 202 | #endif | 208 | #endif |
| 209 | |||
| 210 | static inline int bpf__strerror_setup_stdout(struct perf_evlist *evlist, int err, char *buf, size_t size) | ||
| 211 | { | ||
| 212 | return bpf__strerror_setup_output_event(evlist, err, buf, size); | ||
| 213 | } | ||
| 203 | #endif | 214 | #endif |
diff --git a/tools/perf/util/data-convert-bt.c b/tools/perf/util/data-convert-bt.c index 5744c12641a5..abd38abf1d91 100644 --- a/tools/perf/util/data-convert-bt.c +++ b/tools/perf/util/data-convert-bt.c | |||
| @@ -310,8 +310,8 @@ static int add_tracepoint_field_value(struct ctf_writer *cw, | |||
| 310 | if (flags & FIELD_IS_DYNAMIC) { | 310 | if (flags & FIELD_IS_DYNAMIC) { |
| 311 | unsigned long long tmp_val; | 311 | unsigned long long tmp_val; |
| 312 | 312 | ||
| 313 | tmp_val = pevent_read_number(fmtf->event->pevent, | 313 | tmp_val = tep_read_number(fmtf->event->pevent, |
| 314 | data + offset, len); | 314 | data + offset, len); |
| 315 | offset = tmp_val; | 315 | offset = tmp_val; |
| 316 | len = offset >> 16; | 316 | len = offset >> 16; |
| 317 | offset &= 0xffff; | 317 | offset &= 0xffff; |
| @@ -353,7 +353,7 @@ static int add_tracepoint_field_value(struct ctf_writer *cw, | |||
| 353 | else { | 353 | else { |
| 354 | unsigned long long value_int; | 354 | unsigned long long value_int; |
| 355 | 355 | ||
| 356 | value_int = pevent_read_number( | 356 | value_int = tep_read_number( |
| 357 | fmtf->event->pevent, | 357 | fmtf->event->pevent, |
| 358 | data + offset + i * len, len); | 358 | data + offset + i * len, len); |
| 359 | 359 | ||
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 0c8ecf0c78a4..0cd42150f712 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c | |||
| @@ -541,10 +541,17 @@ static int __event__synthesize_thread(union perf_event *comm_event, | |||
| 541 | tgid, process, machine) < 0) | 541 | tgid, process, machine) < 0) |
| 542 | return -1; | 542 | return -1; |
| 543 | 543 | ||
| 544 | /* | ||
| 545 | * send mmap only for thread group leader | ||
| 546 | * see thread__init_map_groups | ||
| 547 | */ | ||
| 548 | if (pid == tgid && | ||
| 549 | perf_event__synthesize_mmap_events(tool, mmap_event, pid, tgid, | ||
| 550 | process, machine, mmap_data, | ||
| 551 | proc_map_timeout)) | ||
| 552 | return -1; | ||
| 544 | 553 | ||
| 545 | return perf_event__synthesize_mmap_events(tool, mmap_event, pid, tgid, | 554 | return 0; |
| 546 | process, machine, mmap_data, | ||
| 547 | proc_map_timeout); | ||
| 548 | } | 555 | } |
| 549 | 556 | ||
| 550 | if (machine__is_default_guest(machine)) | 557 | if (machine__is_default_guest(machine)) |
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index ddf84b941abf..c980bbff6353 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c | |||
| @@ -2683,7 +2683,7 @@ int perf_event__synthesize_sample(union perf_event *event, u64 type, | |||
| 2683 | 2683 | ||
| 2684 | struct format_field *perf_evsel__field(struct perf_evsel *evsel, const char *name) | 2684 | struct format_field *perf_evsel__field(struct perf_evsel *evsel, const char *name) |
| 2685 | { | 2685 | { |
| 2686 | return pevent_find_field(evsel->tp_format, name); | 2686 | return tep_find_field(evsel->tp_format, name); |
| 2687 | } | 2687 | } |
| 2688 | 2688 | ||
| 2689 | void *perf_evsel__rawptr(struct perf_evsel *evsel, struct perf_sample *sample, | 2689 | void *perf_evsel__rawptr(struct perf_evsel *evsel, struct perf_sample *sample, |
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 973c03167947..163c960614d3 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h | |||
| @@ -452,11 +452,18 @@ static inline int perf_evsel__group_idx(struct perf_evsel *evsel) | |||
| 452 | return evsel->idx - evsel->leader->idx; | 452 | return evsel->idx - evsel->leader->idx; |
| 453 | } | 453 | } |
| 454 | 454 | ||
| 455 | /* Iterates group WITHOUT the leader. */ | ||
| 455 | #define for_each_group_member(_evsel, _leader) \ | 456 | #define for_each_group_member(_evsel, _leader) \ |
| 456 | for ((_evsel) = list_entry((_leader)->node.next, struct perf_evsel, node); \ | 457 | for ((_evsel) = list_entry((_leader)->node.next, struct perf_evsel, node); \ |
| 457 | (_evsel) && (_evsel)->leader == (_leader); \ | 458 | (_evsel) && (_evsel)->leader == (_leader); \ |
| 458 | (_evsel) = list_entry((_evsel)->node.next, struct perf_evsel, node)) | 459 | (_evsel) = list_entry((_evsel)->node.next, struct perf_evsel, node)) |
| 459 | 460 | ||
| 461 | /* Iterates group WITH the leader. */ | ||
| 462 | #define for_each_group_evsel(_evsel, _leader) \ | ||
| 463 | for ((_evsel) = _leader; \ | ||
| 464 | (_evsel) && (_evsel)->leader == (_leader); \ | ||
| 465 | (_evsel) = list_entry((_evsel)->node.next, struct perf_evsel, node)) | ||
| 466 | |||
| 460 | static inline bool perf_evsel__has_branch_callstack(const struct perf_evsel *evsel) | 467 | static inline bool perf_evsel__has_branch_callstack(const struct perf_evsel *evsel) |
| 461 | { | 468 | { |
| 462 | return evsel->attr.branch_sample_type & PERF_SAMPLE_BRANCH_CALL_STACK; | 469 | return evsel->attr.branch_sample_type & PERF_SAMPLE_BRANCH_CALL_STACK; |
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 5af58aac91ad..3cadc252dd89 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c | |||
| @@ -279,8 +279,6 @@ static int do_read_bitmap(struct feat_fd *ff, unsigned long **pset, u64 *psize) | |||
| 279 | if (!set) | 279 | if (!set) |
| 280 | return -ENOMEM; | 280 | return -ENOMEM; |
| 281 | 281 | ||
| 282 | bitmap_zero(set, size); | ||
| 283 | |||
| 284 | p = (u64 *) set; | 282 | p = (u64 *) set; |
| 285 | 283 | ||
| 286 | for (i = 0; (u64) i < BITS_TO_U64(size); i++) { | 284 | for (i = 0; (u64) i < BITS_TO_U64(size); i++) { |
| @@ -1285,7 +1283,6 @@ static int memory_node__read(struct memory_node *n, unsigned long idx) | |||
| 1285 | return -ENOMEM; | 1283 | return -ENOMEM; |
| 1286 | } | 1284 | } |
| 1287 | 1285 | ||
| 1288 | bitmap_zero(n->set, size); | ||
| 1289 | n->node = idx; | 1286 | n->node = idx; |
| 1290 | n->size = size; | 1287 | n->size = size; |
| 1291 | 1288 | ||
| @@ -3207,7 +3204,7 @@ static int read_attr(int fd, struct perf_header *ph, | |||
| 3207 | } | 3204 | } |
| 3208 | 3205 | ||
| 3209 | static int perf_evsel__prepare_tracepoint_event(struct perf_evsel *evsel, | 3206 | static int perf_evsel__prepare_tracepoint_event(struct perf_evsel *evsel, |
| 3210 | struct pevent *pevent) | 3207 | struct tep_handle *pevent) |
| 3211 | { | 3208 | { |
| 3212 | struct event_format *event; | 3209 | struct event_format *event; |
| 3213 | char bf[128]; | 3210 | char bf[128]; |
| @@ -3221,7 +3218,7 @@ static int perf_evsel__prepare_tracepoint_event(struct perf_evsel *evsel, | |||
| 3221 | return -1; | 3218 | return -1; |
| 3222 | } | 3219 | } |
| 3223 | 3220 | ||
| 3224 | event = pevent_find_event(pevent, evsel->attr.config); | 3221 | event = tep_find_event(pevent, evsel->attr.config); |
| 3225 | if (event == NULL) { | 3222 | if (event == NULL) { |
| 3226 | pr_debug("cannot find event format for %d\n", (int)evsel->attr.config); | 3223 | pr_debug("cannot find event format for %d\n", (int)evsel->attr.config); |
| 3227 | return -1; | 3224 | return -1; |
| @@ -3239,7 +3236,7 @@ static int perf_evsel__prepare_tracepoint_event(struct perf_evsel *evsel, | |||
| 3239 | } | 3236 | } |
| 3240 | 3237 | ||
| 3241 | static int perf_evlist__prepare_tracepoint_events(struct perf_evlist *evlist, | 3238 | static int perf_evlist__prepare_tracepoint_events(struct perf_evlist *evlist, |
| 3242 | struct pevent *pevent) | 3239 | struct tep_handle *pevent) |
| 3243 | { | 3240 | { |
| 3244 | struct perf_evsel *pos; | 3241 | struct perf_evsel *pos; |
| 3245 | 3242 | ||
diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h index 1de7660d93e9..d856b85862e2 100644 --- a/tools/perf/util/machine.h +++ b/tools/perf/util/machine.h | |||
| @@ -265,7 +265,7 @@ pid_t machine__get_current_tid(struct machine *machine, int cpu); | |||
| 265 | int machine__set_current_tid(struct machine *machine, int cpu, pid_t pid, | 265 | int machine__set_current_tid(struct machine *machine, int cpu, pid_t pid, |
| 266 | pid_t tid); | 266 | pid_t tid); |
| 267 | /* | 267 | /* |
| 268 | * For use with libtraceevent's pevent_set_function_resolver() | 268 | * For use with libtraceevent's tep_set_function_resolver() |
| 269 | */ | 269 | */ |
| 270 | char *machine__resolve_kernel_addr(void *vmachine, unsigned long long *addrp, char **modp); | 270 | char *machine__resolve_kernel_addr(void *vmachine, unsigned long long *addrp, char **modp); |
| 271 | 271 | ||
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c index 89ac5b5dc218..36d0763311ef 100644 --- a/tools/perf/util/map.c +++ b/tools/perf/util/map.c | |||
| @@ -381,20 +381,6 @@ struct map *map__clone(struct map *from) | |||
| 381 | return map; | 381 | return map; |
| 382 | } | 382 | } |
| 383 | 383 | ||
| 384 | int map__overlap(struct map *l, struct map *r) | ||
| 385 | { | ||
| 386 | if (l->start > r->start) { | ||
| 387 | struct map *t = l; | ||
| 388 | l = r; | ||
| 389 | r = t; | ||
| 390 | } | ||
| 391 | |||
| 392 | if (l->end > r->start) | ||
| 393 | return 1; | ||
| 394 | |||
| 395 | return 0; | ||
| 396 | } | ||
| 397 | |||
| 398 | size_t map__fprintf(struct map *map, FILE *fp) | 384 | size_t map__fprintf(struct map *map, FILE *fp) |
| 399 | { | 385 | { |
| 400 | return fprintf(fp, " %" PRIx64 "-%" PRIx64 " %" PRIx64 " %s\n", | 386 | return fprintf(fp, " %" PRIx64 "-%" PRIx64 " %" PRIx64 " %s\n", |
| @@ -675,20 +661,42 @@ static void __map_groups__insert(struct map_groups *mg, struct map *map) | |||
| 675 | static int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp) | 661 | static int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp) |
| 676 | { | 662 | { |
| 677 | struct rb_root *root; | 663 | struct rb_root *root; |
| 678 | struct rb_node *next; | 664 | struct rb_node *next, *first; |
| 679 | int err = 0; | 665 | int err = 0; |
| 680 | 666 | ||
| 681 | down_write(&maps->lock); | 667 | down_write(&maps->lock); |
| 682 | 668 | ||
| 683 | root = &maps->entries; | 669 | root = &maps->entries; |
| 684 | next = rb_first(root); | ||
| 685 | 670 | ||
| 671 | /* | ||
| 672 | * Find first map where end > map->start. | ||
| 673 | * Same as find_vma() in kernel. | ||
| 674 | */ | ||
| 675 | next = root->rb_node; | ||
| 676 | first = NULL; | ||
| 677 | while (next) { | ||
| 678 | struct map *pos = rb_entry(next, struct map, rb_node); | ||
| 679 | |||
| 680 | if (pos->end > map->start) { | ||
| 681 | first = next; | ||
| 682 | if (pos->start <= map->start) | ||
| 683 | break; | ||
| 684 | next = next->rb_left; | ||
| 685 | } else | ||
| 686 | next = next->rb_right; | ||
| 687 | } | ||
| 688 | |||
| 689 | next = first; | ||
| 686 | while (next) { | 690 | while (next) { |
| 687 | struct map *pos = rb_entry(next, struct map, rb_node); | 691 | struct map *pos = rb_entry(next, struct map, rb_node); |
| 688 | next = rb_next(&pos->rb_node); | 692 | next = rb_next(&pos->rb_node); |
| 689 | 693 | ||
| 690 | if (!map__overlap(pos, map)) | 694 | /* |
| 691 | continue; | 695 | * Stop if current map starts after map->end. |
| 696 | * Maps are ordered by start: next will not overlap for sure. | ||
| 697 | */ | ||
| 698 | if (pos->start >= map->end) | ||
| 699 | break; | ||
| 692 | 700 | ||
| 693 | if (verbose >= 2) { | 701 | if (verbose >= 2) { |
| 694 | 702 | ||
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h index 4cb90f242bed..e0f327b51e66 100644 --- a/tools/perf/util/map.h +++ b/tools/perf/util/map.h | |||
| @@ -166,7 +166,6 @@ static inline void __map__zput(struct map **map) | |||
| 166 | 166 | ||
| 167 | #define map__zput(map) __map__zput(&map) | 167 | #define map__zput(map) __map__zput(&map) |
| 168 | 168 | ||
| 169 | int map__overlap(struct map *l, struct map *r); | ||
| 170 | size_t map__fprintf(struct map *map, FILE *fp); | 169 | size_t map__fprintf(struct map *map, FILE *fp); |
| 171 | size_t map__fprintf_dsoname(struct map *map, FILE *fp); | 170 | size_t map__fprintf_dsoname(struct map *map, FILE *fp); |
| 172 | char *map__srcline(struct map *map, u64 addr, struct symbol *sym); | 171 | char *map__srcline(struct map *map, u64 addr, struct symbol *sym); |
diff --git a/tools/perf/util/namespaces.c b/tools/perf/util/namespaces.c index 5be021701f34..cf8bd123cf73 100644 --- a/tools/perf/util/namespaces.c +++ b/tools/perf/util/namespaces.c | |||
| @@ -139,6 +139,9 @@ struct nsinfo *nsinfo__copy(struct nsinfo *nsi) | |||
| 139 | { | 139 | { |
| 140 | struct nsinfo *nnsi; | 140 | struct nsinfo *nnsi; |
| 141 | 141 | ||
| 142 | if (nsi == NULL) | ||
| 143 | return NULL; | ||
| 144 | |||
| 142 | nnsi = calloc(1, sizeof(*nnsi)); | 145 | nnsi = calloc(1, sizeof(*nnsi)); |
| 143 | if (nnsi != NULL) { | 146 | if (nnsi != NULL) { |
| 144 | nnsi->pid = nsi->pid; | 147 | nnsi->pid = nsi->pid; |
diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c index 863b61478edd..f74fbb652a4f 100644 --- a/tools/perf/util/python.c +++ b/tools/perf/util/python.c | |||
| @@ -341,7 +341,7 @@ static bool is_tracepoint(struct pyrf_event *pevent) | |||
| 341 | static PyObject* | 341 | static PyObject* |
| 342 | tracepoint_field(struct pyrf_event *pe, struct format_field *field) | 342 | tracepoint_field(struct pyrf_event *pe, struct format_field *field) |
| 343 | { | 343 | { |
| 344 | struct pevent *pevent = field->event->pevent; | 344 | struct tep_handle *pevent = field->event->pevent; |
| 345 | void *data = pe->sample.raw_data; | 345 | void *data = pe->sample.raw_data; |
| 346 | PyObject *ret = NULL; | 346 | PyObject *ret = NULL; |
| 347 | unsigned long long val; | 347 | unsigned long long val; |
| @@ -351,7 +351,7 @@ tracepoint_field(struct pyrf_event *pe, struct format_field *field) | |||
| 351 | offset = field->offset; | 351 | offset = field->offset; |
| 352 | len = field->size; | 352 | len = field->size; |
| 353 | if (field->flags & FIELD_IS_DYNAMIC) { | 353 | if (field->flags & FIELD_IS_DYNAMIC) { |
| 354 | val = pevent_read_number(pevent, data + offset, len); | 354 | val = tep_read_number(pevent, data + offset, len); |
| 355 | offset = val; | 355 | offset = val; |
| 356 | len = offset >> 16; | 356 | len = offset >> 16; |
| 357 | offset &= 0xffff; | 357 | offset &= 0xffff; |
| @@ -364,8 +364,8 @@ tracepoint_field(struct pyrf_event *pe, struct format_field *field) | |||
| 364 | field->flags &= ~FIELD_IS_STRING; | 364 | field->flags &= ~FIELD_IS_STRING; |
| 365 | } | 365 | } |
| 366 | } else { | 366 | } else { |
| 367 | val = pevent_read_number(pevent, data + field->offset, | 367 | val = tep_read_number(pevent, data + field->offset, |
| 368 | field->size); | 368 | field->size); |
| 369 | if (field->flags & FIELD_IS_POINTER) | 369 | if (field->flags & FIELD_IS_POINTER) |
| 370 | ret = PyLong_FromUnsignedLong((unsigned long) val); | 370 | ret = PyLong_FromUnsignedLong((unsigned long) val); |
| 371 | else if (field->flags & FIELD_IS_SIGNED) | 371 | else if (field->flags & FIELD_IS_SIGNED) |
| @@ -394,7 +394,7 @@ get_tracepoint_field(struct pyrf_event *pevent, PyObject *attr_name) | |||
| 394 | evsel->tp_format = tp_format; | 394 | evsel->tp_format = tp_format; |
| 395 | } | 395 | } |
| 396 | 396 | ||
| 397 | field = pevent_find_any_field(evsel->tp_format, str); | 397 | field = tep_find_any_field(evsel->tp_format, str); |
| 398 | if (!field) | 398 | if (!field) |
| 399 | return NULL; | 399 | return NULL; |
| 400 | 400 | ||
diff --git a/tools/perf/util/s390-cpumsf-kernel.h b/tools/perf/util/s390-cpumsf-kernel.h new file mode 100644 index 000000000000..de8c7ad0eca8 --- /dev/null +++ b/tools/perf/util/s390-cpumsf-kernel.h | |||
| @@ -0,0 +1,71 @@ | |||
| 1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
| 2 | /* | ||
| 3 | * Auxtrace support for s390 CPU measurement sampling facility | ||
| 4 | * | ||
| 5 | * Copyright IBM Corp. 2018 | ||
| 6 | * Author(s): Hendrik Brueckner <brueckner@linux.ibm.com> | ||
| 7 | * Thomas Richter <tmricht@linux.ibm.com> | ||
| 8 | */ | ||
| 9 | #ifndef S390_CPUMSF_KERNEL_H | ||
| 10 | #define S390_CPUMSF_KERNEL_H | ||
| 11 | |||
| 12 | #define S390_CPUMSF_PAGESZ 4096 /* Size of sample block units */ | ||
| 13 | #define S390_CPUMSF_DIAG_DEF_FIRST 0x8001 /* Diagnostic entry lowest id */ | ||
| 14 | |||
| 15 | struct hws_basic_entry { | ||
| 16 | unsigned int def:16; /* 0-15 Data Entry Format */ | ||
| 17 | unsigned int R:4; /* 16-19 reserved */ | ||
| 18 | unsigned int U:4; /* 20-23 Number of unique instruct. */ | ||
| 19 | unsigned int z:2; /* zeros */ | ||
| 20 | unsigned int T:1; /* 26 PSW DAT mode */ | ||
| 21 | unsigned int W:1; /* 27 PSW wait state */ | ||
| 22 | unsigned int P:1; /* 28 PSW Problem state */ | ||
| 23 | unsigned int AS:2; /* 29-30 PSW address-space control */ | ||
| 24 | unsigned int I:1; /* 31 entry valid or invalid */ | ||
| 25 | unsigned int CL:2; /* 32-33 Configuration Level */ | ||
| 26 | unsigned int:14; | ||
| 27 | unsigned int prim_asn:16; /* primary ASN */ | ||
| 28 | unsigned long long ia; /* Instruction Address */ | ||
| 29 | unsigned long long gpp; /* Guest Program Parameter */ | ||
| 30 | unsigned long long hpp; /* Host Program Parameter */ | ||
| 31 | }; | ||
| 32 | |||
| 33 | struct hws_diag_entry { | ||
| 34 | unsigned int def:16; /* 0-15 Data Entry Format */ | ||
| 35 | unsigned int R:15; /* 16-19 and 20-30 reserved */ | ||
| 36 | unsigned int I:1; /* 31 entry valid or invalid */ | ||
| 37 | u8 data[]; /* Machine-dependent sample data */ | ||
| 38 | }; | ||
| 39 | |||
| 40 | struct hws_combined_entry { | ||
| 41 | struct hws_basic_entry basic; /* Basic-sampling data entry */ | ||
| 42 | struct hws_diag_entry diag; /* Diagnostic-sampling data entry */ | ||
| 43 | }; | ||
| 44 | |||
| 45 | struct hws_trailer_entry { | ||
| 46 | union { | ||
| 47 | struct { | ||
| 48 | unsigned int f:1; /* 0 - Block Full Indicator */ | ||
| 49 | unsigned int a:1; /* 1 - Alert request control */ | ||
| 50 | unsigned int t:1; /* 2 - Timestamp format */ | ||
| 51 | unsigned int:29; /* 3 - 31: Reserved */ | ||
| 52 | unsigned int bsdes:16; /* 32-47: size of basic SDE */ | ||
| 53 | unsigned int dsdes:16; /* 48-63: size of diagnostic SDE */ | ||
| 54 | }; | ||
| 55 | unsigned long long flags; /* 0 - 64: All indicators */ | ||
| 56 | }; | ||
| 57 | unsigned long long overflow; /* 64 - sample Overflow count */ | ||
| 58 | unsigned char timestamp[16]; /* 16 - 31 timestamp */ | ||
| 59 | unsigned long long reserved1; /* 32 -Reserved */ | ||
| 60 | unsigned long long reserved2; /* */ | ||
| 61 | union { /* 48 - reserved for programming use */ | ||
| 62 | struct { | ||
| 63 | unsigned long long clock_base:1; /* in progusage2 */ | ||
| 64 | unsigned long long progusage1:63; | ||
| 65 | unsigned long long progusage2; | ||
| 66 | }; | ||
| 67 | unsigned long long progusage[2]; | ||
| 68 | }; | ||
| 69 | }; | ||
| 70 | |||
| 71 | #endif | ||
diff --git a/tools/perf/util/s390-cpumsf.c b/tools/perf/util/s390-cpumsf.c new file mode 100644 index 000000000000..d2c78ffd9fee --- /dev/null +++ b/tools/perf/util/s390-cpumsf.c | |||
| @@ -0,0 +1,945 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | /* | ||
| 3 | * Copyright IBM Corp. 2018 | ||
| 4 | * Auxtrace support for s390 CPU-Measurement Sampling Facility | ||
| 5 | * | ||
| 6 | * Author(s): Thomas Richter <tmricht@linux.ibm.com> | ||
| 7 | * | ||
| 8 | * Auxiliary traces are collected during 'perf record' using rbd000 event. | ||
| 9 | * Several PERF_RECORD_XXX are generated during recording: | ||
| 10 | * | ||
| 11 | * PERF_RECORD_AUX: | ||
| 12 | * Records that new data landed in the AUX buffer part. | ||
| 13 | * PERF_RECORD_AUXTRACE: | ||
| 14 | * Defines auxtrace data. Followed by the actual data. The contents of | ||
| 15 | * the auxtrace data is dependent on the event and the CPU. | ||
| 16 | * This record is generated by perf record command. For details | ||
| 17 | * see Documentation/perf.data-file-format.txt. | ||
| 18 | * PERF_RECORD_AUXTRACE_INFO: | ||
| 19 | * Defines a table of contains for PERF_RECORD_AUXTRACE records. This | ||
| 20 | * record is generated during 'perf record' command. Each record contains up | ||
| 21 | * to 256 entries describing offset and size of the AUXTRACE data in the | ||
| 22 | * perf.data file. | ||
| 23 | * PERF_RECORD_AUXTRACE_ERROR: | ||
| 24 | * Indicates an error during AUXTRACE collection such as buffer overflow. | ||
| 25 | * PERF_RECORD_FINISHED_ROUND: | ||
| 26 | * Perf events are not necessarily in time stamp order, as they can be | ||
| 27 | * collected in parallel on different CPUs. If the events should be | ||
| 28 | * processed in time order they need to be sorted first. | ||
| 29 | * Perf report guarantees that there is no reordering over a | ||
| 30 | * PERF_RECORD_FINISHED_ROUND boundary event. All perf records with a | ||
| 31 | * time stamp lower than this record are processed (and displayed) before | ||
| 32 | * the succeeding perf record are processed. | ||
| 33 | * | ||
| 34 | * These records are evaluated during perf report command. | ||
| 35 | * | ||
| 36 | * 1. PERF_RECORD_AUXTRACE_INFO is used to set up the infrastructure for | ||
| 37 | * auxiliary trace data processing. See s390_cpumsf_process_auxtrace_info() | ||
| 38 | * below. | ||
| 39 | * Auxiliary trace data is collected per CPU. To merge the data into the report | ||
| 40 | * an auxtrace_queue is created for each CPU. It is assumed that the auxtrace | ||
| 41 | * data is in ascending order. | ||
| 42 | * | ||
| 43 | * Each queue has a double linked list of auxtrace_buffers. This list contains | ||
| 44 | * the offset and size of a CPU's auxtrace data. During auxtrace processing | ||
| 45 | * the data portion is mmap()'ed. | ||
| 46 | * | ||
| 47 | * To sort the queues in chronological order, all queue access is controlled | ||
| 48 | * by the auxtrace_heap. This is basicly a stack, each stack element has two | ||
| 49 | * entries, the queue number and a time stamp. However the stack is sorted by | ||
| 50 | * the time stamps. The highest time stamp is at the bottom the lowest | ||
| 51 | * (nearest) time stamp is at the top. That sort order is maintained at all | ||
| 52 | * times! | ||
| 53 | * | ||
| 54 | * After the auxtrace infrastructure has been setup, the auxtrace queues are | ||
| 55 | * filled with data (offset/size pairs) and the auxtrace_heap is populated. | ||
| 56 | * | ||
| 57 | * 2. PERF_RECORD_XXX processing triggers access to the auxtrace_queues. | ||
| 58 | * Each record is handled by s390_cpumsf_process_event(). The time stamp of | ||
| 59 | * the perf record is compared with the time stamp located on the auxtrace_heap | ||
| 60 | * top element. If that time stamp is lower than the time stamp from the | ||
| 61 | * record sample, the auxtrace queues will be processed. As auxtrace queues | ||
| 62 | * control many auxtrace_buffers and each buffer can be quite large, the | ||
| 63 | * auxtrace buffer might be processed only partially. In this case the | ||
| 64 | * position in the auxtrace_buffer of that queue is remembered and the time | ||
| 65 | * stamp of the last processed entry of the auxtrace_buffer replaces the | ||
| 66 | * current auxtrace_heap top. | ||
| 67 | * | ||
| 68 | * 3. Auxtrace_queues might run of out data and are feeded by the | ||
| 69 | * PERF_RECORD_AUXTRACE handling, see s390_cpumsf_process_auxtrace_event(). | ||
| 70 | * | ||
| 71 | * Event Generation | ||
| 72 | * Each sampling-data entry in the auxilary trace data generates a perf sample. | ||
| 73 | * This sample is filled | ||
| 74 | * with data from the auxtrace such as PID/TID, instruction address, CPU state, | ||
| 75 | * etc. This sample is processed with perf_session__deliver_synth_event() to | ||
| 76 | * be included into the GUI. | ||
| 77 | * | ||
| 78 | * 4. PERF_RECORD_FINISHED_ROUND event is used to process all the remaining | ||
| 79 | * auxiliary traces entries until the time stamp of this record is reached | ||
| 80 | * auxtrace_heap top. This is triggered by ordered_event->deliver(). | ||
| 81 | * | ||
| 82 | * | ||
| 83 | * Perf event processing. | ||
| 84 | * Event processing of PERF_RECORD_XXX entries relies on time stamp entries. | ||
| 85 | * This is the function call sequence: | ||
| 86 | * | ||
| 87 | * __cmd_report() | ||
| 88 | * | | ||
| 89 | * perf_session__process_events() | ||
| 90 | * | | ||
| 91 | * __perf_session__process_events() | ||
| 92 | * | | ||
| 93 | * perf_session__process_event() | ||
| 94 | * | This functions splits the PERF_RECORD_XXX records. | ||
| 95 | * | - Those generated by perf record command (type number equal or higher | ||
| 96 | * | than PERF_RECORD_USER_TYPE_START) are handled by | ||
| 97 | * | perf_session__process_user_event(see below) | ||
| 98 | * | - Those generated by the kernel are handled by | ||
| 99 | * | perf_evlist__parse_sample_timestamp() | ||
| 100 | * | | ||
| 101 | * perf_evlist__parse_sample_timestamp() | ||
| 102 | * | Extract time stamp from sample data. | ||
| 103 | * | | ||
| 104 | * perf_session__queue_event() | ||
| 105 | * | If timestamp is positive the sample is entered into an ordered_event | ||
| 106 | * | list, sort order is the timestamp. The event processing is deferred until | ||
| 107 | * | later (see perf_session__process_user_event()). | ||
| 108 | * | Other timestamps (0 or -1) are handled immediately by | ||
| 109 | * | perf_session__deliver_event(). These are events generated at start up | ||
| 110 | * | of command perf record. They create PERF_RECORD_COMM and PERF_RECORD_MMAP* | ||
| 111 | * | records. They are needed to create a list of running processes and its | ||
| 112 | * | memory mappings and layout. They are needed at the beginning to enable | ||
| 113 | * | command perf report to create process trees and memory mappings. | ||
| 114 | * | | ||
| 115 | * perf_session__deliver_event() | ||
| 116 | * | Delivers a PERF_RECORD_XXX entry for handling. | ||
| 117 | * | | ||
| 118 | * auxtrace__process_event() | ||
| 119 | * | The timestamp of the PERF_RECORD_XXX entry is taken to correlate with | ||
| 120 | * | time stamps from the auxiliary trace buffers. This enables | ||
| 121 | * | synchronization between auxiliary trace data and the events on the | ||
| 122 | * | perf.data file. | ||
| 123 | * | | ||
| 124 | * machine__deliver_event() | ||
| 125 | * | Handles the PERF_RECORD_XXX event. This depends on the record type. | ||
| 126 | * It might update the process tree, update a process memory map or enter | ||
| 127 | * a sample with IP and call back chain data into GUI data pool. | ||
| 128 | * | ||
| 129 | * | ||
| 130 | * Deferred processing determined by perf_session__process_user_event() is | ||
| 131 | * finally processed when a PERF_RECORD_FINISHED_ROUND is encountered. These | ||
| 132 | * are generated during command perf record. | ||
| 133 | * The timestamp of PERF_RECORD_FINISHED_ROUND event is taken to process all | ||
| 134 | * PERF_RECORD_XXX entries stored in the ordered_event list. This list was | ||
| 135 | * built up while reading the perf.data file. | ||
| 136 | * Each event is now processed by calling perf_session__deliver_event(). | ||
| 137 | * This enables time synchronization between the data in the perf.data file and | ||
| 138 | * the data in the auxiliary trace buffers. | ||
| 139 | */ | ||
| 140 | |||
| 141 | #include <endian.h> | ||
| 142 | #include <errno.h> | ||
| 143 | #include <byteswap.h> | ||
| 144 | #include <inttypes.h> | ||
| 145 | #include <linux/kernel.h> | ||
| 146 | #include <linux/types.h> | ||
| 147 | #include <linux/bitops.h> | ||
| 148 | #include <linux/log2.h> | ||
| 149 | |||
| 150 | #include "cpumap.h" | ||
| 151 | #include "color.h" | ||
| 152 | #include "evsel.h" | ||
| 153 | #include "evlist.h" | ||
| 154 | #include "machine.h" | ||
| 155 | #include "session.h" | ||
| 156 | #include "util.h" | ||
| 157 | #include "thread.h" | ||
| 158 | #include "debug.h" | ||
| 159 | #include "auxtrace.h" | ||
| 160 | #include "s390-cpumsf.h" | ||
| 161 | #include "s390-cpumsf-kernel.h" | ||
| 162 | |||
| 163 | struct s390_cpumsf { | ||
| 164 | struct auxtrace auxtrace; | ||
| 165 | struct auxtrace_queues queues; | ||
| 166 | struct auxtrace_heap heap; | ||
| 167 | struct perf_session *session; | ||
| 168 | struct machine *machine; | ||
| 169 | u32 auxtrace_type; | ||
| 170 | u32 pmu_type; | ||
| 171 | u16 machine_type; | ||
| 172 | bool data_queued; | ||
| 173 | }; | ||
| 174 | |||
| 175 | struct s390_cpumsf_queue { | ||
| 176 | struct s390_cpumsf *sf; | ||
| 177 | unsigned int queue_nr; | ||
| 178 | struct auxtrace_buffer *buffer; | ||
| 179 | int cpu; | ||
| 180 | }; | ||
| 181 | |||
| 182 | /* Display s390 CPU measurement facility basic-sampling data entry */ | ||
| 183 | static bool s390_cpumsf_basic_show(const char *color, size_t pos, | ||
| 184 | struct hws_basic_entry *basic) | ||
| 185 | { | ||
| 186 | if (basic->def != 1) { | ||
| 187 | pr_err("Invalid AUX trace basic entry [%#08zx]\n", pos); | ||
| 188 | return false; | ||
| 189 | } | ||
| 190 | color_fprintf(stdout, color, " [%#08zx] Basic Def:%04x Inst:%#04x" | ||
| 191 | " %c%c%c%c AS:%d ASN:%#04x IA:%#018llx\n" | ||
| 192 | "\t\tCL:%d HPP:%#018llx GPP:%#018llx\n", | ||
| 193 | pos, basic->def, basic->U, | ||
| 194 | basic->T ? 'T' : ' ', | ||
| 195 | basic->W ? 'W' : ' ', | ||
| 196 | basic->P ? 'P' : ' ', | ||
| 197 | basic->I ? 'I' : ' ', | ||
| 198 | basic->AS, basic->prim_asn, basic->ia, basic->CL, | ||
| 199 | basic->hpp, basic->gpp); | ||
| 200 | return true; | ||
| 201 | } | ||
| 202 | |||
| 203 | /* Display s390 CPU measurement facility diagnostic-sampling data entry */ | ||
| 204 | static bool s390_cpumsf_diag_show(const char *color, size_t pos, | ||
| 205 | struct hws_diag_entry *diag) | ||
| 206 | { | ||
| 207 | if (diag->def < S390_CPUMSF_DIAG_DEF_FIRST) { | ||
| 208 | pr_err("Invalid AUX trace diagnostic entry [%#08zx]\n", pos); | ||
| 209 | return false; | ||
| 210 | } | ||
| 211 | color_fprintf(stdout, color, " [%#08zx] Diag Def:%04x %c\n", | ||
| 212 | pos, diag->def, diag->I ? 'I' : ' '); | ||
| 213 | return true; | ||
| 214 | } | ||
| 215 | |||
| 216 | /* Return TOD timestamp contained in an trailer entry */ | ||
| 217 | static unsigned long long trailer_timestamp(struct hws_trailer_entry *te) | ||
| 218 | { | ||
| 219 | /* te->t set: TOD in STCKE format, bytes 8-15 | ||
| 220 | * to->t not set: TOD in STCK format, bytes 0-7 | ||
| 221 | */ | ||
| 222 | unsigned long long ts; | ||
| 223 | |||
| 224 | memcpy(&ts, &te->timestamp[te->t], sizeof(ts)); | ||
| 225 | return ts; | ||
| 226 | } | ||
| 227 | |||
| 228 | /* Display s390 CPU measurement facility trailer entry */ | ||
| 229 | static bool s390_cpumsf_trailer_show(const char *color, size_t pos, | ||
| 230 | struct hws_trailer_entry *te) | ||
| 231 | { | ||
| 232 | if (te->bsdes != sizeof(struct hws_basic_entry)) { | ||
| 233 | pr_err("Invalid AUX trace trailer entry [%#08zx]\n", pos); | ||
| 234 | return false; | ||
| 235 | } | ||
| 236 | color_fprintf(stdout, color, " [%#08zx] Trailer %c%c%c bsdes:%d" | ||
| 237 | " dsdes:%d Overflow:%lld Time:%#llx\n" | ||
| 238 | "\t\tC:%d TOD:%#lx 1:%#llx 2:%#llx\n", | ||
| 239 | pos, | ||
| 240 | te->f ? 'F' : ' ', | ||
| 241 | te->a ? 'A' : ' ', | ||
| 242 | te->t ? 'T' : ' ', | ||
| 243 | te->bsdes, te->dsdes, te->overflow, | ||
| 244 | trailer_timestamp(te), te->clock_base, te->progusage2, | ||
| 245 | te->progusage[0], te->progusage[1]); | ||
| 246 | return true; | ||
| 247 | } | ||
| 248 | |||
| 249 | /* Test a sample data block. It must be 4KB or a multiple thereof in size and | ||
| 250 | * 4KB page aligned. Each sample data page has a trailer entry at the | ||
| 251 | * end which contains the sample entry data sizes. | ||
| 252 | * | ||
| 253 | * Return true if the sample data block passes the checks and set the | ||
| 254 | * basic set entry size and diagnostic set entry size. | ||
| 255 | * | ||
| 256 | * Return false on failure. | ||
| 257 | * | ||
| 258 | * Note: Old hardware does not set the basic or diagnostic entry sizes | ||
| 259 | * in the trailer entry. Use the type number instead. | ||
| 260 | */ | ||
| 261 | static bool s390_cpumsf_validate(int machine_type, | ||
| 262 | unsigned char *buf, size_t len, | ||
| 263 | unsigned short *bsdes, | ||
| 264 | unsigned short *dsdes) | ||
| 265 | { | ||
| 266 | struct hws_basic_entry *basic = (struct hws_basic_entry *)buf; | ||
| 267 | struct hws_trailer_entry *te; | ||
| 268 | |||
| 269 | *dsdes = *bsdes = 0; | ||
| 270 | if (len & (S390_CPUMSF_PAGESZ - 1)) /* Illegal size */ | ||
| 271 | return false; | ||
| 272 | if (basic->def != 1) /* No basic set entry, must be first */ | ||
| 273 | return false; | ||
| 274 | /* Check for trailer entry at end of SDB */ | ||
| 275 | te = (struct hws_trailer_entry *)(buf + S390_CPUMSF_PAGESZ | ||
| 276 | - sizeof(*te)); | ||
| 277 | *bsdes = te->bsdes; | ||
| 278 | *dsdes = te->dsdes; | ||
| 279 | if (!te->bsdes && !te->dsdes) { | ||
| 280 | /* Very old hardware, use CPUID */ | ||
| 281 | switch (machine_type) { | ||
| 282 | case 2097: | ||
| 283 | case 2098: | ||
| 284 | *dsdes = 64; | ||
| 285 | *bsdes = 32; | ||
| 286 | break; | ||
| 287 | case 2817: | ||
| 288 | case 2818: | ||
| 289 | *dsdes = 74; | ||
| 290 | *bsdes = 32; | ||
| 291 | break; | ||
| 292 | case 2827: | ||
| 293 | case 2828: | ||
| 294 | *dsdes = 85; | ||
| 295 | *bsdes = 32; | ||
| 296 | break; | ||
| 297 | default: | ||
| 298 | /* Illegal trailer entry */ | ||
| 299 | return false; | ||
| 300 | } | ||
| 301 | } | ||
| 302 | return true; | ||
| 303 | } | ||
| 304 | |||
| 305 | /* Return true if there is room for another entry */ | ||
| 306 | static bool s390_cpumsf_reached_trailer(size_t entry_sz, size_t pos) | ||
| 307 | { | ||
| 308 | size_t payload = S390_CPUMSF_PAGESZ - sizeof(struct hws_trailer_entry); | ||
| 309 | |||
| 310 | if (payload - (pos & (S390_CPUMSF_PAGESZ - 1)) < entry_sz) | ||
| 311 | return false; | ||
| 312 | return true; | ||
| 313 | } | ||
| 314 | |||
| 315 | /* Dump an auxiliary buffer. These buffers are multiple of | ||
| 316 | * 4KB SDB pages. | ||
| 317 | */ | ||
| 318 | static void s390_cpumsf_dump(struct s390_cpumsf *sf, | ||
| 319 | unsigned char *buf, size_t len) | ||
| 320 | { | ||
| 321 | const char *color = PERF_COLOR_BLUE; | ||
| 322 | struct hws_basic_entry *basic; | ||
| 323 | struct hws_diag_entry *diag; | ||
| 324 | unsigned short bsdes, dsdes; | ||
| 325 | size_t pos = 0; | ||
| 326 | |||
| 327 | color_fprintf(stdout, color, | ||
| 328 | ". ... s390 AUX data: size %zu bytes\n", | ||
| 329 | len); | ||
| 330 | |||
| 331 | if (!s390_cpumsf_validate(sf->machine_type, buf, len, &bsdes, | ||
| 332 | &dsdes)) { | ||
| 333 | pr_err("Invalid AUX trace data block size:%zu" | ||
| 334 | " (type:%d bsdes:%hd dsdes:%hd)\n", | ||
| 335 | len, sf->machine_type, bsdes, dsdes); | ||
| 336 | return; | ||
| 337 | } | ||
| 338 | |||
| 339 | /* s390 kernel always returns 4KB blocks fully occupied, | ||
| 340 | * no partially filled SDBs. | ||
| 341 | */ | ||
| 342 | while (pos < len) { | ||
| 343 | /* Handle Basic entry */ | ||
| 344 | basic = (struct hws_basic_entry *)(buf + pos); | ||
| 345 | if (s390_cpumsf_basic_show(color, pos, basic)) | ||
| 346 | pos += bsdes; | ||
| 347 | else | ||
| 348 | return; | ||
| 349 | |||
| 350 | /* Handle Diagnostic entry */ | ||
| 351 | diag = (struct hws_diag_entry *)(buf + pos); | ||
| 352 | if (s390_cpumsf_diag_show(color, pos, diag)) | ||
| 353 | pos += dsdes; | ||
| 354 | else | ||
| 355 | return; | ||
| 356 | |||
| 357 | /* Check for trailer entry */ | ||
| 358 | if (!s390_cpumsf_reached_trailer(bsdes + dsdes, pos)) { | ||
| 359 | /* Show trailer entry */ | ||
| 360 | struct hws_trailer_entry te; | ||
| 361 | |||
| 362 | pos = (pos + S390_CPUMSF_PAGESZ) | ||
| 363 | & ~(S390_CPUMSF_PAGESZ - 1); | ||
| 364 | pos -= sizeof(te); | ||
| 365 | memcpy(&te, buf + pos, sizeof(te)); | ||
| 366 | /* Set descriptor sizes in case of old hardware | ||
| 367 | * where these values are not set. | ||
| 368 | */ | ||
| 369 | te.bsdes = bsdes; | ||
| 370 | te.dsdes = dsdes; | ||
| 371 | if (s390_cpumsf_trailer_show(color, pos, &te)) | ||
| 372 | pos += sizeof(te); | ||
| 373 | else | ||
| 374 | return; | ||
| 375 | } | ||
| 376 | } | ||
| 377 | } | ||
| 378 | |||
| 379 | static void s390_cpumsf_dump_event(struct s390_cpumsf *sf, unsigned char *buf, | ||
| 380 | size_t len) | ||
| 381 | { | ||
| 382 | printf(".\n"); | ||
| 383 | s390_cpumsf_dump(sf, buf, len); | ||
| 384 | } | ||
| 385 | |||
| 386 | #define S390_LPP_PID_MASK 0xffffffff | ||
| 387 | |||
| 388 | static bool s390_cpumsf_make_event(size_t pos, | ||
| 389 | struct hws_basic_entry *basic, | ||
| 390 | struct s390_cpumsf_queue *sfq) | ||
| 391 | { | ||
| 392 | struct perf_sample sample = { | ||
| 393 | .ip = basic->ia, | ||
| 394 | .pid = basic->hpp & S390_LPP_PID_MASK, | ||
| 395 | .tid = basic->hpp & S390_LPP_PID_MASK, | ||
| 396 | .cpumode = PERF_RECORD_MISC_CPUMODE_UNKNOWN, | ||
| 397 | .cpu = sfq->cpu, | ||
| 398 | .period = 1 | ||
| 399 | }; | ||
| 400 | union perf_event event; | ||
| 401 | |||
| 402 | memset(&event, 0, sizeof(event)); | ||
| 403 | if (basic->CL == 1) /* Native LPAR mode */ | ||
| 404 | sample.cpumode = basic->P ? PERF_RECORD_MISC_USER | ||
| 405 | : PERF_RECORD_MISC_KERNEL; | ||
| 406 | else if (basic->CL == 2) /* Guest kernel/user space */ | ||
| 407 | sample.cpumode = basic->P ? PERF_RECORD_MISC_GUEST_USER | ||
| 408 | : PERF_RECORD_MISC_GUEST_KERNEL; | ||
| 409 | else if (basic->gpp || basic->prim_asn != 0xffff) | ||
| 410 | /* Use heuristics on old hardware */ | ||
| 411 | sample.cpumode = basic->P ? PERF_RECORD_MISC_GUEST_USER | ||
| 412 | : PERF_RECORD_MISC_GUEST_KERNEL; | ||
| 413 | else | ||
| 414 | sample.cpumode = basic->P ? PERF_RECORD_MISC_USER | ||
| 415 | : PERF_RECORD_MISC_KERNEL; | ||
| 416 | |||
| 417 | event.sample.header.type = PERF_RECORD_SAMPLE; | ||
| 418 | event.sample.header.misc = sample.cpumode; | ||
| 419 | event.sample.header.size = sizeof(struct perf_event_header); | ||
| 420 | |||
| 421 | pr_debug4("%s pos:%#zx ip:%#" PRIx64 " P:%d CL:%d pid:%d.%d cpumode:%d cpu:%d\n", | ||
| 422 | __func__, pos, sample.ip, basic->P, basic->CL, sample.pid, | ||
| 423 | sample.tid, sample.cpumode, sample.cpu); | ||
| 424 | if (perf_session__deliver_synth_event(sfq->sf->session, &event, | ||
| 425 | &sample)) { | ||
| 426 | pr_err("s390 Auxiliary Trace: failed to deliver event\n"); | ||
| 427 | return false; | ||
| 428 | } | ||
| 429 | return true; | ||
| 430 | } | ||
| 431 | |||
| 432 | static unsigned long long get_trailer_time(const unsigned char *buf) | ||
| 433 | { | ||
| 434 | struct hws_trailer_entry *te; | ||
| 435 | unsigned long long aux_time; | ||
| 436 | |||
| 437 | te = (struct hws_trailer_entry *)(buf + S390_CPUMSF_PAGESZ | ||
| 438 | - sizeof(*te)); | ||
| 439 | |||
| 440 | if (!te->clock_base) /* TOD_CLOCK_BASE value missing */ | ||
| 441 | return 0; | ||
| 442 | |||
| 443 | /* Correct calculation to convert time stamp in trailer entry to | ||
| 444 | * nano seconds (taken from arch/s390 function tod_to_ns()). | ||
| 445 | * TOD_CLOCK_BASE is stored in trailer entry member progusage2. | ||
| 446 | */ | ||
| 447 | aux_time = trailer_timestamp(te) - te->progusage2; | ||
| 448 | aux_time = (aux_time >> 9) * 125 + (((aux_time & 0x1ff) * 125) >> 9); | ||
| 449 | return aux_time; | ||
| 450 | } | ||
| 451 | |||
| 452 | /* Process the data samples of a single queue. The first parameter is a | ||
| 453 | * pointer to the queue, the second parameter is the time stamp. This | ||
| 454 | * is the time stamp: | ||
| 455 | * - of the event that triggered this processing. | ||
| 456 | * - or the time stamp when the last proccesing of this queue stopped. | ||
| 457 | * In this case it stopped at a 4KB page boundary and record the | ||
| 458 | * position on where to continue processing on the next invocation | ||
| 459 | * (see buffer->use_data and buffer->use_size). | ||
| 460 | * | ||
| 461 | * When this function returns the second parameter is updated to | ||
| 462 | * reflect the time stamp of the last processed auxiliary data entry | ||
| 463 | * (taken from the trailer entry of that page). The caller uses this | ||
| 464 | * returned time stamp to record the last processed entry in this | ||
| 465 | * queue. | ||
| 466 | * | ||
| 467 | * The function returns: | ||
| 468 | * 0: Processing successful. The second parameter returns the | ||
| 469 | * time stamp from the trailer entry until which position | ||
| 470 | * processing took place. Subsequent calls resume from this | ||
| 471 | * position. | ||
| 472 | * <0: An error occurred during processing. The second parameter | ||
| 473 | * returns the maximum time stamp. | ||
| 474 | * >0: Done on this queue. The second parameter returns the | ||
| 475 | * maximum time stamp. | ||
| 476 | */ | ||
| 477 | static int s390_cpumsf_samples(struct s390_cpumsf_queue *sfq, u64 *ts) | ||
| 478 | { | ||
| 479 | struct s390_cpumsf *sf = sfq->sf; | ||
| 480 | unsigned char *buf = sfq->buffer->use_data; | ||
| 481 | size_t len = sfq->buffer->use_size; | ||
| 482 | struct hws_basic_entry *basic; | ||
| 483 | unsigned short bsdes, dsdes; | ||
| 484 | size_t pos = 0; | ||
| 485 | int err = 1; | ||
| 486 | u64 aux_ts; | ||
| 487 | |||
| 488 | if (!s390_cpumsf_validate(sf->machine_type, buf, len, &bsdes, | ||
| 489 | &dsdes)) { | ||
| 490 | *ts = ~0ULL; | ||
| 491 | return -1; | ||
| 492 | } | ||
| 493 | |||
| 494 | /* Get trailer entry time stamp and check if entries in | ||
| 495 | * this auxiliary page are ready for processing. If the | ||
| 496 | * time stamp of the first entry is too high, whole buffer | ||
| 497 | * can be skipped. In this case return time stamp. | ||
| 498 | */ | ||
| 499 | aux_ts = get_trailer_time(buf); | ||
| 500 | if (!aux_ts) { | ||
| 501 | pr_err("[%#08" PRIx64 "] Invalid AUX trailer entry TOD clock base\n", | ||
| 502 | sfq->buffer->data_offset); | ||
| 503 | aux_ts = ~0ULL; | ||
| 504 | goto out; | ||
| 505 | } | ||
| 506 | if (aux_ts > *ts) { | ||
| 507 | *ts = aux_ts; | ||
| 508 | return 0; | ||
| 509 | } | ||
| 510 | |||
| 511 | while (pos < len) { | ||
| 512 | /* Handle Basic entry */ | ||
| 513 | basic = (struct hws_basic_entry *)(buf + pos); | ||
| 514 | if (s390_cpumsf_make_event(pos, basic, sfq)) | ||
| 515 | pos += bsdes; | ||
| 516 | else { | ||
| 517 | err = -EBADF; | ||
| 518 | goto out; | ||
| 519 | } | ||
| 520 | |||
| 521 | pos += dsdes; /* Skip diagnositic entry */ | ||
| 522 | |||
| 523 | /* Check for trailer entry */ | ||
| 524 | if (!s390_cpumsf_reached_trailer(bsdes + dsdes, pos)) { | ||
| 525 | pos = (pos + S390_CPUMSF_PAGESZ) | ||
| 526 | & ~(S390_CPUMSF_PAGESZ - 1); | ||
| 527 | /* Check existence of next page */ | ||
| 528 | if (pos >= len) | ||
| 529 | break; | ||
| 530 | aux_ts = get_trailer_time(buf + pos); | ||
| 531 | if (!aux_ts) { | ||
| 532 | aux_ts = ~0ULL; | ||
| 533 | goto out; | ||
| 534 | } | ||
| 535 | if (aux_ts > *ts) { | ||
| 536 | *ts = aux_ts; | ||
| 537 | sfq->buffer->use_data += pos; | ||
| 538 | sfq->buffer->use_size -= pos; | ||
| 539 | return 0; | ||
| 540 | } | ||
| 541 | } | ||
| 542 | } | ||
| 543 | out: | ||
| 544 | *ts = aux_ts; | ||
| 545 | sfq->buffer->use_size = 0; | ||
| 546 | sfq->buffer->use_data = NULL; | ||
| 547 | return err; /* Buffer completely scanned or error */ | ||
| 548 | } | ||
| 549 | |||
| 550 | /* Run the s390 auxiliary trace decoder. | ||
| 551 | * Select the queue buffer to operate on, the caller already selected | ||
| 552 | * the proper queue, depending on second parameter 'ts'. | ||
| 553 | * This is the time stamp until which the auxiliary entries should | ||
| 554 | * be processed. This value is updated by called functions and | ||
| 555 | * returned to the caller. | ||
| 556 | * | ||
| 557 | * Resume processing in the current buffer. If there is no buffer | ||
| 558 | * get a new buffer from the queue and setup start position for | ||
| 559 | * processing. | ||
| 560 | * When a buffer is completely processed remove it from the queue | ||
| 561 | * before returning. | ||
| 562 | * | ||
| 563 | * This function returns | ||
| 564 | * 1: When the queue is empty. Second parameter will be set to | ||
| 565 | * maximum time stamp. | ||
| 566 | * 0: Normal processing done. | ||
| 567 | * <0: Error during queue buffer setup. This causes the caller | ||
| 568 | * to stop processing completely. | ||
| 569 | */ | ||
| 570 | static int s390_cpumsf_run_decoder(struct s390_cpumsf_queue *sfq, | ||
| 571 | u64 *ts) | ||
| 572 | { | ||
| 573 | |||
| 574 | struct auxtrace_buffer *buffer; | ||
| 575 | struct auxtrace_queue *queue; | ||
| 576 | int err; | ||
| 577 | |||
| 578 | queue = &sfq->sf->queues.queue_array[sfq->queue_nr]; | ||
| 579 | |||
| 580 | /* Get buffer and last position in buffer to resume | ||
| 581 | * decoding the auxiliary entries. One buffer might be large | ||
| 582 | * and decoding might stop in between. This depends on the time | ||
| 583 | * stamp of the trailer entry in each page of the auxiliary | ||
| 584 | * data and the time stamp of the event triggering the decoding. | ||
| 585 | */ | ||
| 586 | if (sfq->buffer == NULL) { | ||
| 587 | sfq->buffer = buffer = auxtrace_buffer__next(queue, | ||
| 588 | sfq->buffer); | ||
| 589 | if (!buffer) { | ||
| 590 | *ts = ~0ULL; | ||
| 591 | return 1; /* Processing done on this queue */ | ||
| 592 | } | ||
| 593 | /* Start with a new buffer on this queue */ | ||
| 594 | if (buffer->data) { | ||
| 595 | buffer->use_size = buffer->size; | ||
| 596 | buffer->use_data = buffer->data; | ||
| 597 | } | ||
| 598 | } else | ||
| 599 | buffer = sfq->buffer; | ||
| 600 | |||
| 601 | if (!buffer->data) { | ||
| 602 | int fd = perf_data__fd(sfq->sf->session->data); | ||
| 603 | |||
| 604 | buffer->data = auxtrace_buffer__get_data(buffer, fd); | ||
| 605 | if (!buffer->data) | ||
| 606 | return -ENOMEM; | ||
| 607 | buffer->use_size = buffer->size; | ||
| 608 | buffer->use_data = buffer->data; | ||
| 609 | } | ||
| 610 | pr_debug4("%s queue_nr:%d buffer:%" PRId64 " offset:%#" PRIx64 " size:%#zx rest:%#zx\n", | ||
| 611 | __func__, sfq->queue_nr, buffer->buffer_nr, buffer->offset, | ||
| 612 | buffer->size, buffer->use_size); | ||
| 613 | err = s390_cpumsf_samples(sfq, ts); | ||
| 614 | |||
| 615 | /* If non-zero, there is either an error (err < 0) or the buffer is | ||
| 616 | * completely done (err > 0). The error is unrecoverable, usually | ||
| 617 | * some descriptors could not be read successfully, so continue with | ||
| 618 | * the next buffer. | ||
| 619 | * In both cases the parameter 'ts' has been updated. | ||
| 620 | */ | ||
| 621 | if (err) { | ||
| 622 | sfq->buffer = NULL; | ||
| 623 | list_del(&buffer->list); | ||
| 624 | auxtrace_buffer__free(buffer); | ||
| 625 | if (err > 0) /* Buffer done, no error */ | ||
| 626 | err = 0; | ||
| 627 | } | ||
| 628 | return err; | ||
| 629 | } | ||
| 630 | |||
| 631 | static struct s390_cpumsf_queue * | ||
| 632 | s390_cpumsf_alloc_queue(struct s390_cpumsf *sf, unsigned int queue_nr) | ||
| 633 | { | ||
| 634 | struct s390_cpumsf_queue *sfq; | ||
| 635 | |||
| 636 | sfq = zalloc(sizeof(struct s390_cpumsf_queue)); | ||
| 637 | if (sfq == NULL) | ||
| 638 | return NULL; | ||
| 639 | |||
| 640 | sfq->sf = sf; | ||
| 641 | sfq->queue_nr = queue_nr; | ||
| 642 | sfq->cpu = -1; | ||
| 643 | return sfq; | ||
| 644 | } | ||
| 645 | |||
| 646 | static int s390_cpumsf_setup_queue(struct s390_cpumsf *sf, | ||
| 647 | struct auxtrace_queue *queue, | ||
| 648 | unsigned int queue_nr, u64 ts) | ||
| 649 | { | ||
| 650 | struct s390_cpumsf_queue *sfq = queue->priv; | ||
| 651 | |||
| 652 | if (list_empty(&queue->head)) | ||
| 653 | return 0; | ||
| 654 | |||
| 655 | if (sfq == NULL) { | ||
| 656 | sfq = s390_cpumsf_alloc_queue(sf, queue_nr); | ||
| 657 | if (!sfq) | ||
| 658 | return -ENOMEM; | ||
| 659 | queue->priv = sfq; | ||
| 660 | |||
| 661 | if (queue->cpu != -1) | ||
| 662 | sfq->cpu = queue->cpu; | ||
| 663 | } | ||
| 664 | return auxtrace_heap__add(&sf->heap, queue_nr, ts); | ||
| 665 | } | ||
| 666 | |||
| 667 | static int s390_cpumsf_setup_queues(struct s390_cpumsf *sf, u64 ts) | ||
| 668 | { | ||
| 669 | unsigned int i; | ||
| 670 | int ret = 0; | ||
| 671 | |||
| 672 | for (i = 0; i < sf->queues.nr_queues; i++) { | ||
| 673 | ret = s390_cpumsf_setup_queue(sf, &sf->queues.queue_array[i], | ||
| 674 | i, ts); | ||
| 675 | if (ret) | ||
| 676 | break; | ||
| 677 | } | ||
| 678 | return ret; | ||
| 679 | } | ||
| 680 | |||
| 681 | static int s390_cpumsf_update_queues(struct s390_cpumsf *sf, u64 ts) | ||
| 682 | { | ||
| 683 | if (!sf->queues.new_data) | ||
| 684 | return 0; | ||
| 685 | |||
| 686 | sf->queues.new_data = false; | ||
| 687 | return s390_cpumsf_setup_queues(sf, ts); | ||
| 688 | } | ||
| 689 | |||
| 690 | static int s390_cpumsf_process_queues(struct s390_cpumsf *sf, u64 timestamp) | ||
| 691 | { | ||
| 692 | unsigned int queue_nr; | ||
| 693 | u64 ts; | ||
| 694 | int ret; | ||
| 695 | |||
| 696 | while (1) { | ||
| 697 | struct auxtrace_queue *queue; | ||
| 698 | struct s390_cpumsf_queue *sfq; | ||
| 699 | |||
| 700 | if (!sf->heap.heap_cnt) | ||
| 701 | return 0; | ||
| 702 | |||
| 703 | if (sf->heap.heap_array[0].ordinal >= timestamp) | ||
| 704 | return 0; | ||
| 705 | |||
| 706 | queue_nr = sf->heap.heap_array[0].queue_nr; | ||
| 707 | queue = &sf->queues.queue_array[queue_nr]; | ||
| 708 | sfq = queue->priv; | ||
| 709 | |||
| 710 | auxtrace_heap__pop(&sf->heap); | ||
| 711 | if (sf->heap.heap_cnt) { | ||
| 712 | ts = sf->heap.heap_array[0].ordinal + 1; | ||
| 713 | if (ts > timestamp) | ||
| 714 | ts = timestamp; | ||
| 715 | } else { | ||
| 716 | ts = timestamp; | ||
| 717 | } | ||
| 718 | |||
| 719 | ret = s390_cpumsf_run_decoder(sfq, &ts); | ||
| 720 | if (ret < 0) { | ||
| 721 | auxtrace_heap__add(&sf->heap, queue_nr, ts); | ||
| 722 | return ret; | ||
| 723 | } | ||
| 724 | if (!ret) { | ||
| 725 | ret = auxtrace_heap__add(&sf->heap, queue_nr, ts); | ||
| 726 | if (ret < 0) | ||
| 727 | return ret; | ||
| 728 | } | ||
| 729 | } | ||
| 730 | return 0; | ||
| 731 | } | ||
| 732 | |||
| 733 | static int s390_cpumsf_synth_error(struct s390_cpumsf *sf, int code, int cpu, | ||
| 734 | pid_t pid, pid_t tid, u64 ip) | ||
| 735 | { | ||
| 736 | char msg[MAX_AUXTRACE_ERROR_MSG]; | ||
| 737 | union perf_event event; | ||
| 738 | int err; | ||
| 739 | |||
| 740 | strncpy(msg, "Lost Auxiliary Trace Buffer", sizeof(msg) - 1); | ||
| 741 | auxtrace_synth_error(&event.auxtrace_error, PERF_AUXTRACE_ERROR_ITRACE, | ||
| 742 | code, cpu, pid, tid, ip, msg); | ||
| 743 | |||
| 744 | err = perf_session__deliver_synth_event(sf->session, &event, NULL); | ||
| 745 | if (err) | ||
| 746 | pr_err("s390 Auxiliary Trace: failed to deliver error event," | ||
| 747 | "error %d\n", err); | ||
| 748 | return err; | ||
| 749 | } | ||
| 750 | |||
| 751 | static int s390_cpumsf_lost(struct s390_cpumsf *sf, struct perf_sample *sample) | ||
| 752 | { | ||
| 753 | return s390_cpumsf_synth_error(sf, 1, sample->cpu, | ||
| 754 | sample->pid, sample->tid, 0); | ||
| 755 | } | ||
| 756 | |||
| 757 | static int | ||
| 758 | s390_cpumsf_process_event(struct perf_session *session __maybe_unused, | ||
| 759 | union perf_event *event, | ||
| 760 | struct perf_sample *sample, | ||
| 761 | struct perf_tool *tool) | ||
| 762 | { | ||
| 763 | struct s390_cpumsf *sf = container_of(session->auxtrace, | ||
| 764 | struct s390_cpumsf, | ||
| 765 | auxtrace); | ||
| 766 | u64 timestamp = sample->time; | ||
| 767 | int err = 0; | ||
| 768 | |||
| 769 | if (dump_trace) | ||
| 770 | return 0; | ||
| 771 | |||
| 772 | if (!tool->ordered_events) { | ||
| 773 | pr_err("s390 Auxiliary Trace requires ordered events\n"); | ||
| 774 | return -EINVAL; | ||
| 775 | } | ||
| 776 | |||
| 777 | if (event->header.type == PERF_RECORD_AUX && | ||
| 778 | event->aux.flags & PERF_AUX_FLAG_TRUNCATED) | ||
| 779 | return s390_cpumsf_lost(sf, sample); | ||
| 780 | |||
| 781 | if (timestamp) { | ||
| 782 | err = s390_cpumsf_update_queues(sf, timestamp); | ||
| 783 | if (!err) | ||
| 784 | err = s390_cpumsf_process_queues(sf, timestamp); | ||
| 785 | } | ||
| 786 | return err; | ||
| 787 | } | ||
| 788 | |||
| 789 | struct s390_cpumsf_synth { | ||
| 790 | struct perf_tool cpumsf_tool; | ||
| 791 | struct perf_session *session; | ||
| 792 | }; | ||
| 793 | |||
| 794 | static int | ||
| 795 | s390_cpumsf_process_auxtrace_event(struct perf_session *session, | ||
| 796 | union perf_event *event __maybe_unused, | ||
| 797 | struct perf_tool *tool __maybe_unused) | ||
| 798 | { | ||
| 799 | struct s390_cpumsf *sf = container_of(session->auxtrace, | ||
| 800 | struct s390_cpumsf, | ||
| 801 | auxtrace); | ||
| 802 | |||
| 803 | int fd = perf_data__fd(session->data); | ||
| 804 | struct auxtrace_buffer *buffer; | ||
| 805 | off_t data_offset; | ||
| 806 | int err; | ||
| 807 | |||
| 808 | if (sf->data_queued) | ||
| 809 | return 0; | ||
| 810 | |||
| 811 | if (perf_data__is_pipe(session->data)) { | ||
| 812 | data_offset = 0; | ||
| 813 | } else { | ||
| 814 | data_offset = lseek(fd, 0, SEEK_CUR); | ||
| 815 | if (data_offset == -1) | ||
| 816 | return -errno; | ||
| 817 | } | ||
| 818 | |||
| 819 | err = auxtrace_queues__add_event(&sf->queues, session, event, | ||
| 820 | data_offset, &buffer); | ||
| 821 | if (err) | ||
| 822 | return err; | ||
| 823 | |||
| 824 | /* Dump here after copying piped trace out of the pipe */ | ||
| 825 | if (dump_trace) { | ||
| 826 | if (auxtrace_buffer__get_data(buffer, fd)) { | ||
| 827 | s390_cpumsf_dump_event(sf, buffer->data, | ||
| 828 | buffer->size); | ||
| 829 | auxtrace_buffer__put_data(buffer); | ||
| 830 | } | ||
| 831 | } | ||
| 832 | return 0; | ||
| 833 | } | ||
| 834 | |||
| 835 | static void s390_cpumsf_free_events(struct perf_session *session __maybe_unused) | ||
| 836 | { | ||
| 837 | } | ||
| 838 | |||
| 839 | static int s390_cpumsf_flush(struct perf_session *session __maybe_unused, | ||
| 840 | struct perf_tool *tool __maybe_unused) | ||
| 841 | { | ||
| 842 | return 0; | ||
| 843 | } | ||
| 844 | |||
| 845 | static void s390_cpumsf_free_queues(struct perf_session *session) | ||
| 846 | { | ||
| 847 | struct s390_cpumsf *sf = container_of(session->auxtrace, | ||
| 848 | struct s390_cpumsf, | ||
| 849 | auxtrace); | ||
| 850 | struct auxtrace_queues *queues = &sf->queues; | ||
| 851 | unsigned int i; | ||
| 852 | |||
| 853 | for (i = 0; i < queues->nr_queues; i++) | ||
| 854 | zfree(&queues->queue_array[i].priv); | ||
| 855 | auxtrace_queues__free(queues); | ||
| 856 | } | ||
| 857 | |||
| 858 | static void s390_cpumsf_free(struct perf_session *session) | ||
| 859 | { | ||
| 860 | struct s390_cpumsf *sf = container_of(session->auxtrace, | ||
| 861 | struct s390_cpumsf, | ||
| 862 | auxtrace); | ||
| 863 | |||
| 864 | auxtrace_heap__free(&sf->heap); | ||
| 865 | s390_cpumsf_free_queues(session); | ||
| 866 | session->auxtrace = NULL; | ||
| 867 | free(sf); | ||
| 868 | } | ||
| 869 | |||
| 870 | static int s390_cpumsf_get_type(const char *cpuid) | ||
| 871 | { | ||
| 872 | int ret, family = 0; | ||
| 873 | |||
| 874 | ret = sscanf(cpuid, "%*[^,],%u", &family); | ||
| 875 | return (ret == 1) ? family : 0; | ||
| 876 | } | ||
| 877 | |||
| 878 | /* Check itrace options set on perf report command. | ||
| 879 | * Return true, if none are set or all options specified can be | ||
| 880 | * handled on s390. | ||
| 881 | * Return false otherwise. | ||
| 882 | */ | ||
| 883 | static bool check_auxtrace_itrace(struct itrace_synth_opts *itops) | ||
| 884 | { | ||
| 885 | if (!itops || !itops->set) | ||
| 886 | return true; | ||
| 887 | pr_err("No --itrace options supported\n"); | ||
| 888 | return false; | ||
| 889 | } | ||
| 890 | |||
| 891 | int s390_cpumsf_process_auxtrace_info(union perf_event *event, | ||
| 892 | struct perf_session *session) | ||
| 893 | { | ||
| 894 | struct auxtrace_info_event *auxtrace_info = &event->auxtrace_info; | ||
| 895 | struct s390_cpumsf *sf; | ||
| 896 | int err; | ||
| 897 | |||
| 898 | if (auxtrace_info->header.size < sizeof(struct auxtrace_info_event)) | ||
| 899 | return -EINVAL; | ||
| 900 | |||
| 901 | sf = zalloc(sizeof(struct s390_cpumsf)); | ||
| 902 | if (sf == NULL) | ||
| 903 | return -ENOMEM; | ||
| 904 | |||
| 905 | if (!check_auxtrace_itrace(session->itrace_synth_opts)) { | ||
| 906 | err = -EINVAL; | ||
| 907 | goto err_free; | ||
| 908 | } | ||
| 909 | |||
| 910 | err = auxtrace_queues__init(&sf->queues); | ||
| 911 | if (err) | ||
| 912 | goto err_free; | ||
| 913 | |||
| 914 | sf->session = session; | ||
| 915 | sf->machine = &session->machines.host; /* No kvm support */ | ||
| 916 | sf->auxtrace_type = auxtrace_info->type; | ||
| 917 | sf->pmu_type = PERF_TYPE_RAW; | ||
| 918 | sf->machine_type = s390_cpumsf_get_type(session->evlist->env->cpuid); | ||
| 919 | |||
| 920 | sf->auxtrace.process_event = s390_cpumsf_process_event; | ||
| 921 | sf->auxtrace.process_auxtrace_event = s390_cpumsf_process_auxtrace_event; | ||
| 922 | sf->auxtrace.flush_events = s390_cpumsf_flush; | ||
| 923 | sf->auxtrace.free_events = s390_cpumsf_free_events; | ||
| 924 | sf->auxtrace.free = s390_cpumsf_free; | ||
| 925 | session->auxtrace = &sf->auxtrace; | ||
| 926 | |||
| 927 | if (dump_trace) | ||
| 928 | return 0; | ||
| 929 | |||
| 930 | err = auxtrace_queues__process_index(&sf->queues, session); | ||
| 931 | if (err) | ||
| 932 | goto err_free_queues; | ||
| 933 | |||
| 934 | if (sf->queues.populated) | ||
| 935 | sf->data_queued = true; | ||
| 936 | |||
| 937 | return 0; | ||
| 938 | |||
| 939 | err_free_queues: | ||
| 940 | auxtrace_queues__free(&sf->queues); | ||
| 941 | session->auxtrace = NULL; | ||
| 942 | err_free: | ||
| 943 | free(sf); | ||
| 944 | return err; | ||
| 945 | } | ||
diff --git a/tools/perf/util/s390-cpumsf.h b/tools/perf/util/s390-cpumsf.h new file mode 100644 index 000000000000..fb64d100555c --- /dev/null +++ b/tools/perf/util/s390-cpumsf.h | |||
| @@ -0,0 +1,21 @@ | |||
| 1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
| 2 | /* | ||
| 3 | * Copyright IBM Corp. 2018 | ||
| 4 | * Auxtrace support for s390 CPU-Measurement Sampling Facility | ||
| 5 | * | ||
| 6 | * Author(s): Thomas Richter <tmricht@linux.ibm.com> | ||
| 7 | */ | ||
| 8 | |||
| 9 | #ifndef INCLUDE__PERF_S390_CPUMSF_H | ||
| 10 | #define INCLUDE__PERF_S390_CPUMSF_H | ||
| 11 | |||
| 12 | union perf_event; | ||
| 13 | struct perf_session; | ||
| 14 | struct perf_pmu; | ||
| 15 | |||
| 16 | struct auxtrace_record * | ||
| 17 | s390_cpumsf_recording_init(int *err, struct perf_pmu *s390_cpumsf_pmu); | ||
| 18 | |||
| 19 | int s390_cpumsf_process_auxtrace_info(union perf_event *event, | ||
| 20 | struct perf_session *session); | ||
| 21 | #endif | ||
diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c index 7b79c413486b..45484f0f7292 100644 --- a/tools/perf/util/scripting-engines/trace-event-perl.c +++ b/tools/perf/util/scripting-engines/trace-event-perl.c | |||
| @@ -535,7 +535,7 @@ static int perl_stop_script(void) | |||
| 535 | return 0; | 535 | return 0; |
| 536 | } | 536 | } |
| 537 | 537 | ||
| 538 | static int perl_generate_script(struct pevent *pevent, const char *outfile) | 538 | static int perl_generate_script(struct tep_handle *pevent, const char *outfile) |
| 539 | { | 539 | { |
| 540 | struct event_format *event = NULL; | 540 | struct event_format *event = NULL; |
| 541 | struct format_field *f; | 541 | struct format_field *f; |
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index bc32e57d17be..dfc6093f118c 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c | |||
| @@ -871,8 +871,8 @@ static void python_process_tracepoint(struct perf_sample *sample, | |||
| 871 | offset = field->offset; | 871 | offset = field->offset; |
| 872 | len = field->size; | 872 | len = field->size; |
| 873 | if (field->flags & FIELD_IS_DYNAMIC) { | 873 | if (field->flags & FIELD_IS_DYNAMIC) { |
| 874 | val = pevent_read_number(scripting_context->pevent, | 874 | val = tep_read_number(scripting_context->pevent, |
| 875 | data + offset, len); | 875 | data + offset, len); |
| 876 | offset = val; | 876 | offset = val; |
| 877 | len = offset >> 16; | 877 | len = offset >> 16; |
| 878 | offset &= 0xffff; | 878 | offset &= 0xffff; |
| @@ -1588,7 +1588,7 @@ static int python_stop_script(void) | |||
| 1588 | return 0; | 1588 | return 0; |
| 1589 | } | 1589 | } |
| 1590 | 1590 | ||
| 1591 | static int python_generate_script(struct pevent *pevent, const char *outfile) | 1591 | static int python_generate_script(struct tep_handle *pevent, const char *outfile) |
| 1592 | { | 1592 | { |
| 1593 | struct event_format *event = NULL; | 1593 | struct event_format *event = NULL; |
| 1594 | struct format_field *f; | 1594 | struct format_field *f; |
diff --git a/tools/perf/util/setup.py b/tools/perf/util/setup.py index 001be4f9d3b9..97efbcad076e 100644 --- a/tools/perf/util/setup.py +++ b/tools/perf/util/setup.py | |||
| @@ -1,12 +1,20 @@ | |||
| 1 | #!/usr/bin/python | 1 | #!/usr/bin/python |
| 2 | 2 | ||
| 3 | from os import getenv | 3 | from os import getenv |
| 4 | from subprocess import Popen, PIPE | ||
| 5 | from re import sub | ||
| 6 | |||
| 7 | def clang_has_option(option): | ||
| 8 | return [o for o in Popen(['clang', option], stderr=PIPE).stderr.readlines() if "unknown argument" in o] == [ ] | ||
| 4 | 9 | ||
| 5 | cc = getenv("CC") | 10 | cc = getenv("CC") |
| 6 | if cc == "clang": | 11 | if cc == "clang": |
| 7 | from _sysconfigdata import build_time_vars | 12 | from _sysconfigdata import build_time_vars |
| 8 | from re import sub | ||
| 9 | build_time_vars["CFLAGS"] = sub("-specs=[^ ]+", "", build_time_vars["CFLAGS"]) | 13 | build_time_vars["CFLAGS"] = sub("-specs=[^ ]+", "", build_time_vars["CFLAGS"]) |
| 14 | if not clang_has_option("-mcet"): | ||
| 15 | build_time_vars["CFLAGS"] = sub("-mcet", "", build_time_vars["CFLAGS"]) | ||
| 16 | if not clang_has_option("-fcf-protection"): | ||
| 17 | build_time_vars["CFLAGS"] = sub("-fcf-protection", "", build_time_vars["CFLAGS"]) | ||
| 10 | 18 | ||
| 11 | from distutils.core import setup, Extension | 19 | from distutils.core import setup, Extension |
| 12 | 20 | ||
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index fed2952ab45a..b284276ec963 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c | |||
| @@ -601,7 +601,7 @@ static char *get_trace_output(struct hist_entry *he) | |||
| 601 | { | 601 | { |
| 602 | struct trace_seq seq; | 602 | struct trace_seq seq; |
| 603 | struct perf_evsel *evsel; | 603 | struct perf_evsel *evsel; |
| 604 | struct pevent_record rec = { | 604 | struct tep_record rec = { |
| 605 | .data = he->raw_data, | 605 | .data = he->raw_data, |
| 606 | .size = he->raw_size, | 606 | .size = he->raw_size, |
| 607 | }; | 607 | }; |
| @@ -610,10 +610,10 @@ static char *get_trace_output(struct hist_entry *he) | |||
| 610 | 610 | ||
| 611 | trace_seq_init(&seq); | 611 | trace_seq_init(&seq); |
| 612 | if (symbol_conf.raw_trace) { | 612 | if (symbol_conf.raw_trace) { |
| 613 | pevent_print_fields(&seq, he->raw_data, he->raw_size, | 613 | tep_print_fields(&seq, he->raw_data, he->raw_size, |
| 614 | evsel->tp_format); | 614 | evsel->tp_format); |
| 615 | } else { | 615 | } else { |
| 616 | pevent_event_info(&seq, evsel->tp_format, &rec); | 616 | tep_event_info(&seq, evsel->tp_format, &rec); |
| 617 | } | 617 | } |
| 618 | /* | 618 | /* |
| 619 | * Trim the buffer, it starts at 4KB and we're not going to | 619 | * Trim the buffer, it starts at 4KB and we're not going to |
| @@ -2047,7 +2047,7 @@ static int __sort__hde_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, | |||
| 2047 | struct trace_seq seq; | 2047 | struct trace_seq seq; |
| 2048 | raw_field: | 2048 | raw_field: |
| 2049 | trace_seq_init(&seq); | 2049 | trace_seq_init(&seq); |
| 2050 | pevent_print_field(&seq, he->raw_data, hde->field); | 2050 | tep_print_field(&seq, he->raw_data, hde->field); |
| 2051 | str = seq.buffer; | 2051 | str = seq.buffer; |
| 2052 | } | 2052 | } |
| 2053 | 2053 | ||
| @@ -2074,7 +2074,7 @@ static int64_t __sort__hde_cmp(struct perf_hpp_fmt *fmt, | |||
| 2074 | if (field->flags & FIELD_IS_DYNAMIC) { | 2074 | if (field->flags & FIELD_IS_DYNAMIC) { |
| 2075 | unsigned long long dyn; | 2075 | unsigned long long dyn; |
| 2076 | 2076 | ||
| 2077 | pevent_read_number_field(field, a->raw_data, &dyn); | 2077 | tep_read_number_field(field, a->raw_data, &dyn); |
| 2078 | offset = dyn & 0xffff; | 2078 | offset = dyn & 0xffff; |
| 2079 | size = (dyn >> 16) & 0xffff; | 2079 | size = (dyn >> 16) & 0xffff; |
| 2080 | 2080 | ||
| @@ -2311,7 +2311,7 @@ static int add_all_matching_fields(struct perf_evlist *evlist, | |||
| 2311 | if (evsel->attr.type != PERF_TYPE_TRACEPOINT) | 2311 | if (evsel->attr.type != PERF_TYPE_TRACEPOINT) |
| 2312 | continue; | 2312 | continue; |
| 2313 | 2313 | ||
| 2314 | field = pevent_find_any_field(evsel->tp_format, field_name); | 2314 | field = tep_find_any_field(evsel->tp_format, field_name); |
| 2315 | if (field == NULL) | 2315 | if (field == NULL) |
| 2316 | continue; | 2316 | continue; |
| 2317 | 2317 | ||
| @@ -2378,7 +2378,7 @@ static int add_dynamic_entry(struct perf_evlist *evlist, const char *tok, | |||
| 2378 | if (!strcmp(field_name, "*")) { | 2378 | if (!strcmp(field_name, "*")) { |
| 2379 | ret = add_evsel_fields(evsel, raw_trace, level); | 2379 | ret = add_evsel_fields(evsel, raw_trace, level); |
| 2380 | } else { | 2380 | } else { |
| 2381 | field = pevent_find_any_field(evsel->tp_format, field_name); | 2381 | field = tep_find_any_field(evsel->tp_format, field_name); |
| 2382 | if (field == NULL) { | 2382 | if (field == NULL) { |
| 2383 | pr_debug("Cannot find event field for %s.%s\n", | 2383 | pr_debug("Cannot find event field for %s.%s\n", |
| 2384 | event_name, field_name); | 2384 | event_name, field_name); |
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h index 8bf302cafcec..a97cf8e6be86 100644 --- a/tools/perf/util/sort.h +++ b/tools/perf/util/sort.h | |||
| @@ -276,7 +276,7 @@ extern struct sort_entry sort_thread; | |||
| 276 | extern struct list_head hist_entry__sort_list; | 276 | extern struct list_head hist_entry__sort_list; |
| 277 | 277 | ||
| 278 | struct perf_evlist; | 278 | struct perf_evlist; |
| 279 | struct pevent; | 279 | struct tep_handle; |
| 280 | int setup_sorting(struct perf_evlist *evlist); | 280 | int setup_sorting(struct perf_evlist *evlist); |
| 281 | int setup_output_field(void); | 281 | int setup_output_field(void); |
| 282 | void reset_output_field(void); | 282 | void reset_output_field(void); |
diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c index e0a6e9a6a053..920b1d58a068 100644 --- a/tools/perf/util/trace-event-parse.c +++ b/tools/perf/util/trace-event-parse.c | |||
| @@ -32,7 +32,7 @@ | |||
| 32 | static int get_common_field(struct scripting_context *context, | 32 | static int get_common_field(struct scripting_context *context, |
| 33 | int *offset, int *size, const char *type) | 33 | int *offset, int *size, const char *type) |
| 34 | { | 34 | { |
| 35 | struct pevent *pevent = context->pevent; | 35 | struct tep_handle *pevent = context->pevent; |
| 36 | struct event_format *event; | 36 | struct event_format *event; |
| 37 | struct format_field *field; | 37 | struct format_field *field; |
| 38 | 38 | ||
| @@ -41,14 +41,14 @@ static int get_common_field(struct scripting_context *context, | |||
| 41 | return 0; | 41 | return 0; |
| 42 | 42 | ||
| 43 | event = pevent->events[0]; | 43 | event = pevent->events[0]; |
| 44 | field = pevent_find_common_field(event, type); | 44 | field = tep_find_common_field(event, type); |
| 45 | if (!field) | 45 | if (!field) |
| 46 | return 0; | 46 | return 0; |
| 47 | *offset = field->offset; | 47 | *offset = field->offset; |
| 48 | *size = field->size; | 48 | *size = field->size; |
| 49 | } | 49 | } |
| 50 | 50 | ||
| 51 | return pevent_read_number(pevent, context->event_data + *offset, *size); | 51 | return tep_read_number(pevent, context->event_data + *offset, *size); |
| 52 | } | 52 | } |
| 53 | 53 | ||
| 54 | int common_lock_depth(struct scripting_context *context) | 54 | int common_lock_depth(struct scripting_context *context) |
| @@ -99,24 +99,24 @@ raw_field_value(struct event_format *event, const char *name, void *data) | |||
| 99 | struct format_field *field; | 99 | struct format_field *field; |
| 100 | unsigned long long val; | 100 | unsigned long long val; |
| 101 | 101 | ||
| 102 | field = pevent_find_any_field(event, name); | 102 | field = tep_find_any_field(event, name); |
| 103 | if (!field) | 103 | if (!field) |
| 104 | return 0ULL; | 104 | return 0ULL; |
| 105 | 105 | ||
| 106 | pevent_read_number_field(field, data, &val); | 106 | tep_read_number_field(field, data, &val); |
| 107 | 107 | ||
| 108 | return val; | 108 | return val; |
| 109 | } | 109 | } |
| 110 | 110 | ||
| 111 | unsigned long long read_size(struct event_format *event, void *ptr, int size) | 111 | unsigned long long read_size(struct event_format *event, void *ptr, int size) |
| 112 | { | 112 | { |
| 113 | return pevent_read_number(event->pevent, ptr, size); | 113 | return tep_read_number(event->pevent, ptr, size); |
| 114 | } | 114 | } |
| 115 | 115 | ||
| 116 | void event_format__fprintf(struct event_format *event, | 116 | void event_format__fprintf(struct event_format *event, |
| 117 | int cpu, void *data, int size, FILE *fp) | 117 | int cpu, void *data, int size, FILE *fp) |
| 118 | { | 118 | { |
| 119 | struct pevent_record record; | 119 | struct tep_record record; |
| 120 | struct trace_seq s; | 120 | struct trace_seq s; |
| 121 | 121 | ||
| 122 | memset(&record, 0, sizeof(record)); | 122 | memset(&record, 0, sizeof(record)); |
| @@ -125,7 +125,7 @@ void event_format__fprintf(struct event_format *event, | |||
| 125 | record.data = data; | 125 | record.data = data; |
| 126 | 126 | ||
| 127 | trace_seq_init(&s); | 127 | trace_seq_init(&s); |
| 128 | pevent_event_info(&s, event, &record); | 128 | tep_event_info(&s, event, &record); |
| 129 | trace_seq_do_fprintf(&s, fp); | 129 | trace_seq_do_fprintf(&s, fp); |
| 130 | trace_seq_destroy(&s); | 130 | trace_seq_destroy(&s); |
| 131 | } | 131 | } |
| @@ -136,7 +136,7 @@ void event_format__print(struct event_format *event, | |||
| 136 | return event_format__fprintf(event, cpu, data, size, stdout); | 136 | return event_format__fprintf(event, cpu, data, size, stdout); |
| 137 | } | 137 | } |
| 138 | 138 | ||
| 139 | void parse_ftrace_printk(struct pevent *pevent, | 139 | void parse_ftrace_printk(struct tep_handle *pevent, |
| 140 | char *file, unsigned int size __maybe_unused) | 140 | char *file, unsigned int size __maybe_unused) |
| 141 | { | 141 | { |
| 142 | unsigned long long addr; | 142 | unsigned long long addr; |
| @@ -157,11 +157,11 @@ void parse_ftrace_printk(struct pevent *pevent, | |||
| 157 | /* fmt still has a space, skip it */ | 157 | /* fmt still has a space, skip it */ |
| 158 | printk = strdup(fmt+1); | 158 | printk = strdup(fmt+1); |
| 159 | line = strtok_r(NULL, "\n", &next); | 159 | line = strtok_r(NULL, "\n", &next); |
| 160 | pevent_register_print_string(pevent, printk, addr); | 160 | tep_register_print_string(pevent, printk, addr); |
| 161 | } | 161 | } |
| 162 | } | 162 | } |
| 163 | 163 | ||
| 164 | void parse_saved_cmdline(struct pevent *pevent, | 164 | void parse_saved_cmdline(struct tep_handle *pevent, |
| 165 | char *file, unsigned int size __maybe_unused) | 165 | char *file, unsigned int size __maybe_unused) |
| 166 | { | 166 | { |
| 167 | char *comm; | 167 | char *comm; |
| @@ -172,24 +172,24 @@ void parse_saved_cmdline(struct pevent *pevent, | |||
| 172 | line = strtok_r(file, "\n", &next); | 172 | line = strtok_r(file, "\n", &next); |
| 173 | while (line) { | 173 | while (line) { |
| 174 | sscanf(line, "%d %ms", &pid, &comm); | 174 | sscanf(line, "%d %ms", &pid, &comm); |
| 175 | pevent_register_comm(pevent, comm, pid); | 175 | tep_register_comm(pevent, comm, pid); |
| 176 | free(comm); | 176 | free(comm); |
| 177 | line = strtok_r(NULL, "\n", &next); | 177 | line = strtok_r(NULL, "\n", &next); |
| 178 | } | 178 | } |
| 179 | } | 179 | } |
| 180 | 180 | ||
| 181 | int parse_ftrace_file(struct pevent *pevent, char *buf, unsigned long size) | 181 | int parse_ftrace_file(struct tep_handle *pevent, char *buf, unsigned long size) |
| 182 | { | 182 | { |
| 183 | return pevent_parse_event(pevent, buf, size, "ftrace"); | 183 | return tep_parse_event(pevent, buf, size, "ftrace"); |
| 184 | } | 184 | } |
| 185 | 185 | ||
| 186 | int parse_event_file(struct pevent *pevent, | 186 | int parse_event_file(struct tep_handle *pevent, |
| 187 | char *buf, unsigned long size, char *sys) | 187 | char *buf, unsigned long size, char *sys) |
| 188 | { | 188 | { |
| 189 | return pevent_parse_event(pevent, buf, size, sys); | 189 | return tep_parse_event(pevent, buf, size, sys); |
| 190 | } | 190 | } |
| 191 | 191 | ||
| 192 | struct event_format *trace_find_next_event(struct pevent *pevent, | 192 | struct event_format *trace_find_next_event(struct tep_handle *pevent, |
| 193 | struct event_format *event) | 193 | struct event_format *event) |
| 194 | { | 194 | { |
| 195 | static int idx; | 195 | static int idx; |
diff --git a/tools/perf/util/trace-event-read.c b/tools/perf/util/trace-event-read.c index 40b425949aa3..3dfc1db6b25b 100644 --- a/tools/perf/util/trace-event-read.c +++ b/tools/perf/util/trace-event-read.c | |||
| @@ -96,7 +96,7 @@ static void skip(int size) | |||
| 96 | }; | 96 | }; |
| 97 | } | 97 | } |
| 98 | 98 | ||
| 99 | static unsigned int read4(struct pevent *pevent) | 99 | static unsigned int read4(struct tep_handle *pevent) |
| 100 | { | 100 | { |
| 101 | unsigned int data; | 101 | unsigned int data; |
| 102 | 102 | ||
| @@ -105,7 +105,7 @@ static unsigned int read4(struct pevent *pevent) | |||
| 105 | return __data2host4(pevent, data); | 105 | return __data2host4(pevent, data); |
| 106 | } | 106 | } |
| 107 | 107 | ||
| 108 | static unsigned long long read8(struct pevent *pevent) | 108 | static unsigned long long read8(struct tep_handle *pevent) |
| 109 | { | 109 | { |
| 110 | unsigned long long data; | 110 | unsigned long long data; |
| 111 | 111 | ||
| @@ -158,7 +158,7 @@ out: | |||
| 158 | return str; | 158 | return str; |
| 159 | } | 159 | } |
| 160 | 160 | ||
| 161 | static int read_proc_kallsyms(struct pevent *pevent) | 161 | static int read_proc_kallsyms(struct tep_handle *pevent) |
| 162 | { | 162 | { |
| 163 | unsigned int size; | 163 | unsigned int size; |
| 164 | 164 | ||
| @@ -181,7 +181,7 @@ static int read_proc_kallsyms(struct pevent *pevent) | |||
| 181 | return 0; | 181 | return 0; |
| 182 | } | 182 | } |
| 183 | 183 | ||
| 184 | static int read_ftrace_printk(struct pevent *pevent) | 184 | static int read_ftrace_printk(struct tep_handle *pevent) |
| 185 | { | 185 | { |
| 186 | unsigned int size; | 186 | unsigned int size; |
| 187 | char *buf; | 187 | char *buf; |
| @@ -208,7 +208,7 @@ static int read_ftrace_printk(struct pevent *pevent) | |||
| 208 | return 0; | 208 | return 0; |
| 209 | } | 209 | } |
| 210 | 210 | ||
| 211 | static int read_header_files(struct pevent *pevent) | 211 | static int read_header_files(struct tep_handle *pevent) |
| 212 | { | 212 | { |
| 213 | unsigned long long size; | 213 | unsigned long long size; |
| 214 | char *header_page; | 214 | char *header_page; |
| @@ -235,13 +235,13 @@ static int read_header_files(struct pevent *pevent) | |||
| 235 | return -1; | 235 | return -1; |
| 236 | } | 236 | } |
| 237 | 237 | ||
| 238 | if (!pevent_parse_header_page(pevent, header_page, size, | 238 | if (!tep_parse_header_page(pevent, header_page, size, |
| 239 | pevent_get_long_size(pevent))) { | 239 | tep_get_long_size(pevent))) { |
| 240 | /* | 240 | /* |
| 241 | * The commit field in the page is of type long, | 241 | * The commit field in the page is of type long, |
| 242 | * use that instead, since it represents the kernel. | 242 | * use that instead, since it represents the kernel. |
| 243 | */ | 243 | */ |
| 244 | pevent_set_long_size(pevent, pevent->header_page_size_size); | 244 | tep_set_long_size(pevent, pevent->header_page_size_size); |
| 245 | } | 245 | } |
| 246 | free(header_page); | 246 | free(header_page); |
| 247 | 247 | ||
| @@ -259,7 +259,7 @@ static int read_header_files(struct pevent *pevent) | |||
| 259 | return ret; | 259 | return ret; |
| 260 | } | 260 | } |
| 261 | 261 | ||
| 262 | static int read_ftrace_file(struct pevent *pevent, unsigned long long size) | 262 | static int read_ftrace_file(struct tep_handle *pevent, unsigned long long size) |
| 263 | { | 263 | { |
| 264 | int ret; | 264 | int ret; |
| 265 | char *buf; | 265 | char *buf; |
| @@ -284,8 +284,8 @@ out: | |||
| 284 | return ret; | 284 | return ret; |
| 285 | } | 285 | } |
| 286 | 286 | ||
| 287 | static int read_event_file(struct pevent *pevent, char *sys, | 287 | static int read_event_file(struct tep_handle *pevent, char *sys, |
| 288 | unsigned long long size) | 288 | unsigned long long size) |
| 289 | { | 289 | { |
| 290 | int ret; | 290 | int ret; |
| 291 | char *buf; | 291 | char *buf; |
| @@ -310,7 +310,7 @@ out: | |||
| 310 | return ret; | 310 | return ret; |
| 311 | } | 311 | } |
| 312 | 312 | ||
| 313 | static int read_ftrace_files(struct pevent *pevent) | 313 | static int read_ftrace_files(struct tep_handle *pevent) |
| 314 | { | 314 | { |
| 315 | unsigned long long size; | 315 | unsigned long long size; |
| 316 | int count; | 316 | int count; |
| @@ -328,7 +328,7 @@ static int read_ftrace_files(struct pevent *pevent) | |||
| 328 | return 0; | 328 | return 0; |
| 329 | } | 329 | } |
| 330 | 330 | ||
| 331 | static int read_event_files(struct pevent *pevent) | 331 | static int read_event_files(struct tep_handle *pevent) |
| 332 | { | 332 | { |
| 333 | unsigned long long size; | 333 | unsigned long long size; |
| 334 | char *sys; | 334 | char *sys; |
| @@ -356,7 +356,7 @@ static int read_event_files(struct pevent *pevent) | |||
| 356 | return 0; | 356 | return 0; |
| 357 | } | 357 | } |
| 358 | 358 | ||
| 359 | static int read_saved_cmdline(struct pevent *pevent) | 359 | static int read_saved_cmdline(struct tep_handle *pevent) |
| 360 | { | 360 | { |
| 361 | unsigned long long size; | 361 | unsigned long long size; |
| 362 | char *buf; | 362 | char *buf; |
| @@ -399,7 +399,7 @@ ssize_t trace_report(int fd, struct trace_event *tevent, bool __repipe) | |||
| 399 | int host_bigendian; | 399 | int host_bigendian; |
| 400 | int file_long_size; | 400 | int file_long_size; |
| 401 | int file_page_size; | 401 | int file_page_size; |
| 402 | struct pevent *pevent = NULL; | 402 | struct tep_handle *pevent = NULL; |
| 403 | int err; | 403 | int err; |
| 404 | 404 | ||
| 405 | repipe = __repipe; | 405 | repipe = __repipe; |
| @@ -439,9 +439,9 @@ ssize_t trace_report(int fd, struct trace_event *tevent, bool __repipe) | |||
| 439 | 439 | ||
| 440 | pevent = tevent->pevent; | 440 | pevent = tevent->pevent; |
| 441 | 441 | ||
| 442 | pevent_set_flag(pevent, PEVENT_NSEC_OUTPUT); | 442 | tep_set_flag(pevent, TEP_NSEC_OUTPUT); |
| 443 | pevent_set_file_bigendian(pevent, file_bigendian); | 443 | tep_set_file_bigendian(pevent, file_bigendian); |
| 444 | pevent_set_host_bigendian(pevent, host_bigendian); | 444 | tep_set_host_bigendian(pevent, host_bigendian); |
| 445 | 445 | ||
| 446 | if (do_read(buf, 1) < 0) | 446 | if (do_read(buf, 1) < 0) |
| 447 | goto out; | 447 | goto out; |
| @@ -451,8 +451,8 @@ ssize_t trace_report(int fd, struct trace_event *tevent, bool __repipe) | |||
| 451 | if (!file_page_size) | 451 | if (!file_page_size) |
| 452 | goto out; | 452 | goto out; |
| 453 | 453 | ||
| 454 | pevent_set_long_size(pevent, file_long_size); | 454 | tep_set_long_size(pevent, file_long_size); |
| 455 | pevent_set_page_size(pevent, file_page_size); | 455 | tep_set_page_size(pevent, file_page_size); |
| 456 | 456 | ||
| 457 | err = read_header_files(pevent); | 457 | err = read_header_files(pevent); |
| 458 | if (err) | 458 | if (err) |
| @@ -479,9 +479,9 @@ ssize_t trace_report(int fd, struct trace_event *tevent, bool __repipe) | |||
| 479 | repipe = false; | 479 | repipe = false; |
| 480 | 480 | ||
| 481 | if (show_funcs) { | 481 | if (show_funcs) { |
| 482 | pevent_print_funcs(pevent); | 482 | tep_print_funcs(pevent); |
| 483 | } else if (show_printk) { | 483 | } else if (show_printk) { |
| 484 | pevent_print_printk(pevent); | 484 | tep_print_printk(pevent); |
| 485 | } | 485 | } |
| 486 | 486 | ||
| 487 | pevent = NULL; | 487 | pevent = NULL; |
diff --git a/tools/perf/util/trace-event-scripting.c b/tools/perf/util/trace-event-scripting.c index b1e5c3a2b8e3..b749f812ac70 100644 --- a/tools/perf/util/trace-event-scripting.c +++ b/tools/perf/util/trace-event-scripting.c | |||
| @@ -66,7 +66,7 @@ static int python_start_script_unsupported(const char *script __maybe_unused, | |||
| 66 | return -1; | 66 | return -1; |
| 67 | } | 67 | } |
| 68 | 68 | ||
| 69 | static int python_generate_script_unsupported(struct pevent *pevent | 69 | static int python_generate_script_unsupported(struct tep_handle *pevent |
| 70 | __maybe_unused, | 70 | __maybe_unused, |
| 71 | const char *outfile | 71 | const char *outfile |
| 72 | __maybe_unused) | 72 | __maybe_unused) |
| @@ -130,7 +130,7 @@ static int perl_start_script_unsupported(const char *script __maybe_unused, | |||
| 130 | return -1; | 130 | return -1; |
| 131 | } | 131 | } |
| 132 | 132 | ||
| 133 | static int perl_generate_script_unsupported(struct pevent *pevent | 133 | static int perl_generate_script_unsupported(struct tep_handle *pevent |
| 134 | __maybe_unused, | 134 | __maybe_unused, |
| 135 | const char *outfile __maybe_unused) | 135 | const char *outfile __maybe_unused) |
| 136 | { | 136 | { |
diff --git a/tools/perf/util/trace-event.c b/tools/perf/util/trace-event.c index 1aa368603268..58bb72f266f3 100644 --- a/tools/perf/util/trace-event.c +++ b/tools/perf/util/trace-event.c | |||
| @@ -28,10 +28,10 @@ static bool tevent_initialized; | |||
| 28 | 28 | ||
| 29 | int trace_event__init(struct trace_event *t) | 29 | int trace_event__init(struct trace_event *t) |
| 30 | { | 30 | { |
| 31 | struct pevent *pevent = pevent_alloc(); | 31 | struct tep_handle *pevent = tep_alloc(); |
| 32 | 32 | ||
| 33 | if (pevent) { | 33 | if (pevent) { |
| 34 | t->plugin_list = traceevent_load_plugins(pevent); | 34 | t->plugin_list = tep_load_plugins(pevent); |
| 35 | t->pevent = pevent; | 35 | t->pevent = pevent; |
| 36 | } | 36 | } |
| 37 | 37 | ||
| @@ -40,33 +40,33 @@ int trace_event__init(struct trace_event *t) | |||
| 40 | 40 | ||
| 41 | static int trace_event__init2(void) | 41 | static int trace_event__init2(void) |
| 42 | { | 42 | { |
| 43 | int be = traceevent_host_bigendian(); | 43 | int be = tep_host_bigendian(); |
| 44 | struct pevent *pevent; | 44 | struct tep_handle *pevent; |
| 45 | 45 | ||
| 46 | if (trace_event__init(&tevent)) | 46 | if (trace_event__init(&tevent)) |
| 47 | return -1; | 47 | return -1; |
| 48 | 48 | ||
| 49 | pevent = tevent.pevent; | 49 | pevent = tevent.pevent; |
| 50 | pevent_set_flag(pevent, PEVENT_NSEC_OUTPUT); | 50 | tep_set_flag(pevent, TEP_NSEC_OUTPUT); |
| 51 | pevent_set_file_bigendian(pevent, be); | 51 | tep_set_file_bigendian(pevent, be); |
| 52 | pevent_set_host_bigendian(pevent, be); | 52 | tep_set_host_bigendian(pevent, be); |
| 53 | tevent_initialized = true; | 53 | tevent_initialized = true; |
| 54 | return 0; | 54 | return 0; |
| 55 | } | 55 | } |
| 56 | 56 | ||
| 57 | int trace_event__register_resolver(struct machine *machine, | 57 | int trace_event__register_resolver(struct machine *machine, |
| 58 | pevent_func_resolver_t *func) | 58 | tep_func_resolver_t *func) |
| 59 | { | 59 | { |
| 60 | if (!tevent_initialized && trace_event__init2()) | 60 | if (!tevent_initialized && trace_event__init2()) |
| 61 | return -1; | 61 | return -1; |
| 62 | 62 | ||
| 63 | return pevent_set_function_resolver(tevent.pevent, func, machine); | 63 | return tep_set_function_resolver(tevent.pevent, func, machine); |
| 64 | } | 64 | } |
| 65 | 65 | ||
| 66 | void trace_event__cleanup(struct trace_event *t) | 66 | void trace_event__cleanup(struct trace_event *t) |
| 67 | { | 67 | { |
| 68 | traceevent_unload_plugins(t->plugin_list, t->pevent); | 68 | tep_unload_plugins(t->plugin_list, t->pevent); |
| 69 | pevent_free(t->pevent); | 69 | tep_free(t->pevent); |
| 70 | } | 70 | } |
| 71 | 71 | ||
| 72 | /* | 72 | /* |
| @@ -76,7 +76,7 @@ static struct event_format* | |||
| 76 | tp_format(const char *sys, const char *name) | 76 | tp_format(const char *sys, const char *name) |
| 77 | { | 77 | { |
| 78 | char *tp_dir = get_events_file(sys); | 78 | char *tp_dir = get_events_file(sys); |
| 79 | struct pevent *pevent = tevent.pevent; | 79 | struct tep_handle *pevent = tevent.pevent; |
| 80 | struct event_format *event = NULL; | 80 | struct event_format *event = NULL; |
| 81 | char path[PATH_MAX]; | 81 | char path[PATH_MAX]; |
| 82 | size_t size; | 82 | size_t size; |
| @@ -93,7 +93,7 @@ tp_format(const char *sys, const char *name) | |||
| 93 | if (err) | 93 | if (err) |
| 94 | return ERR_PTR(err); | 94 | return ERR_PTR(err); |
| 95 | 95 | ||
| 96 | pevent_parse_format(pevent, &event, data, size, sys); | 96 | tep_parse_format(pevent, &event, data, size, sys); |
| 97 | 97 | ||
| 98 | free(data); | 98 | free(data); |
| 99 | return event; | 99 | return event; |
| @@ -116,5 +116,5 @@ struct event_format *trace_event__tp_format_id(int id) | |||
| 116 | if (!tevent_initialized && trace_event__init2()) | 116 | if (!tevent_initialized && trace_event__init2()) |
| 117 | return ERR_PTR(-ENOMEM); | 117 | return ERR_PTR(-ENOMEM); |
| 118 | 118 | ||
| 119 | return pevent_find_event(tevent.pevent, id); | 119 | return tep_find_event(tevent.pevent, id); |
| 120 | } | 120 | } |
diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h index dcbdb53dc702..40204ec3a7a2 100644 --- a/tools/perf/util/trace-event.h +++ b/tools/perf/util/trace-event.h | |||
| @@ -13,14 +13,14 @@ struct thread; | |||
| 13 | struct plugin_list; | 13 | struct plugin_list; |
| 14 | 14 | ||
| 15 | struct trace_event { | 15 | struct trace_event { |
| 16 | struct pevent *pevent; | 16 | struct tep_handle *pevent; |
| 17 | struct plugin_list *plugin_list; | 17 | struct plugin_list *plugin_list; |
| 18 | }; | 18 | }; |
| 19 | 19 | ||
| 20 | int trace_event__init(struct trace_event *t); | 20 | int trace_event__init(struct trace_event *t); |
| 21 | void trace_event__cleanup(struct trace_event *t); | 21 | void trace_event__cleanup(struct trace_event *t); |
| 22 | int trace_event__register_resolver(struct machine *machine, | 22 | int trace_event__register_resolver(struct machine *machine, |
| 23 | pevent_func_resolver_t *func); | 23 | tep_func_resolver_t *func); |
| 24 | struct event_format* | 24 | struct event_format* |
| 25 | trace_event__tp_format(const char *sys, const char *name); | 25 | trace_event__tp_format(const char *sys, const char *name); |
| 26 | 26 | ||
| @@ -34,20 +34,20 @@ void event_format__fprintf(struct event_format *event, | |||
| 34 | void event_format__print(struct event_format *event, | 34 | void event_format__print(struct event_format *event, |
| 35 | int cpu, void *data, int size); | 35 | int cpu, void *data, int size); |
| 36 | 36 | ||
| 37 | int parse_ftrace_file(struct pevent *pevent, char *buf, unsigned long size); | 37 | int parse_ftrace_file(struct tep_handle *pevent, char *buf, unsigned long size); |
| 38 | int parse_event_file(struct pevent *pevent, | 38 | int parse_event_file(struct tep_handle *pevent, |
| 39 | char *buf, unsigned long size, char *sys); | 39 | char *buf, unsigned long size, char *sys); |
| 40 | 40 | ||
| 41 | unsigned long long | 41 | unsigned long long |
| 42 | raw_field_value(struct event_format *event, const char *name, void *data); | 42 | raw_field_value(struct event_format *event, const char *name, void *data); |
| 43 | 43 | ||
| 44 | void parse_proc_kallsyms(struct pevent *pevent, char *file, unsigned int size); | 44 | void parse_proc_kallsyms(struct tep_handle *pevent, char *file, unsigned int size); |
| 45 | void parse_ftrace_printk(struct pevent *pevent, char *file, unsigned int size); | 45 | void parse_ftrace_printk(struct tep_handle *pevent, char *file, unsigned int size); |
| 46 | void parse_saved_cmdline(struct pevent *pevent, char *file, unsigned int size); | 46 | void parse_saved_cmdline(struct tep_handle *pevent, char *file, unsigned int size); |
| 47 | 47 | ||
| 48 | ssize_t trace_report(int fd, struct trace_event *tevent, bool repipe); | 48 | ssize_t trace_report(int fd, struct trace_event *tevent, bool repipe); |
| 49 | 49 | ||
| 50 | struct event_format *trace_find_next_event(struct pevent *pevent, | 50 | struct event_format *trace_find_next_event(struct tep_handle *pevent, |
| 51 | struct event_format *event); | 51 | struct event_format *event); |
| 52 | unsigned long long read_size(struct event_format *event, void *ptr, int size); | 52 | unsigned long long read_size(struct event_format *event, void *ptr, int size); |
| 53 | unsigned long long eval_flag(const char *flag); | 53 | unsigned long long eval_flag(const char *flag); |
| @@ -83,7 +83,7 @@ struct scripting_ops { | |||
| 83 | void (*process_stat)(struct perf_stat_config *config, | 83 | void (*process_stat)(struct perf_stat_config *config, |
| 84 | struct perf_evsel *evsel, u64 tstamp); | 84 | struct perf_evsel *evsel, u64 tstamp); |
| 85 | void (*process_stat_interval)(u64 tstamp); | 85 | void (*process_stat_interval)(u64 tstamp); |
| 86 | int (*generate_script) (struct pevent *pevent, const char *outfile); | 86 | int (*generate_script) (struct tep_handle *pevent, const char *outfile); |
| 87 | }; | 87 | }; |
| 88 | 88 | ||
| 89 | extern unsigned int scripting_max_stack; | 89 | extern unsigned int scripting_max_stack; |
| @@ -94,7 +94,7 @@ void setup_perl_scripting(void); | |||
| 94 | void setup_python_scripting(void); | 94 | void setup_python_scripting(void); |
| 95 | 95 | ||
| 96 | struct scripting_context { | 96 | struct scripting_context { |
| 97 | struct pevent *pevent; | 97 | struct tep_handle *pevent; |
| 98 | void *event_data; | 98 | void *event_data; |
| 99 | }; | 99 | }; |
| 100 | 100 | ||
