diff options
Diffstat (limited to 'tools/perf/builtin-trace.c')
| -rw-r--r-- | tools/perf/builtin-trace.c | 158 |
1 files changed, 116 insertions, 42 deletions
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index ba0f8749fc7d..310ee8df33eb 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -226,6 +226,7 @@ struct trace { bool force; bool vfs_getname; bool force_btf; + bool bitmask_list; bool summary_bpf; int trace_pgfaults; char *perfconfig_events; @@ -460,10 +461,10 @@ static int evsel__init_tp_ptr_field(struct evsel *evsel, struct tp_field *field, ({ struct syscall_tp *sc = __evsel__syscall_tp(evsel);\ evsel__init_tp_ptr_field(evsel, &sc->name, #name); }) -static void evsel__delete_priv(struct evsel *evsel) +static void evsel__put_and_free_priv(struct evsel *evsel) { zfree(&evsel->priv); - evsel__delete(evsel); + evsel__put(evsel); } static int evsel__init_syscall_tp(struct evsel *evsel) @@ -543,7 +544,7 @@ static struct evsel *perf_evsel__raw_syscall_newtp(const char *direction, void * return evsel; out_delete: - evsel__delete_priv(evsel); + evsel__put_and_free_priv(evsel); return NULL; } @@ -2023,7 +2024,7 @@ static int trace__symbols_init(struct trace *trace, int argc, const char **argv, goto out; err = __machine__synthesize_threads(trace->host, &trace->tool, &trace->opts.target, - evlist->core.threads, trace__tool_process, + evlist__core(evlist)->threads, trace__tool_process, /*needs_mmap=*/callchain_param.enabled && !trace->summary_only, /*mmap_data=*/false, @@ -3207,6 +3208,29 @@ static void bpf_output__fprintf(struct trace *trace, ++trace->nr_events_printed; } +static unsigned char bitmap_byte(const unsigned long *mask, int byte_idx) +{ + unsigned char b_val = 0; + int bit_in_byte; + + for (bit_in_byte = 0; bit_in_byte < 8; bit_in_byte++) { + int b_idx = byte_idx * 8 + bit_in_byte; + int host_w_idx = b_idx / BITS_PER_LONG; + int host_bit_in_word = b_idx % BITS_PER_LONG; + + if (mask[host_w_idx] & (1UL << host_bit_in_word)) + b_val |= (1 << bit_in_byte); + } + return b_val; +} + +static bool trace__field_is_ip(const char *name) +{ + return !strcmp(name, "__probe_ip") || + !strcmp(name, "caller_ip") || + !strcmp(name, "call_site"); +} + static size_t trace__fprintf_tp_fields(struct trace *trace, struct perf_sample *sample, struct thread *thread, void *augmented_args, int augmented_args_size) { @@ -3219,6 +3243,7 @@ static size_t trace__fprintf_tp_fields(struct trace *trace, struct perf_sample * size_t printed = 0, btf_printed; unsigned long val; u8 bit = 1; + bool is_probe_ip; struct syscall_arg syscall_arg = { .augmented = { .size = augmented_args_size, @@ -3238,17 +3263,57 @@ static size_t trace__fprintf_tp_fields(struct trace *trace, struct perf_sample * syscall_arg.len = 0; syscall_arg.fmt = arg; if (field->flags & TEP_FIELD_IS_ARRAY) { - int offset = field->offset; - - if (field->flags & TEP_FIELD_IS_DYNAMIC) { - offset = format_field__intval(field, sample, evsel->needs_swap); - syscall_arg.len = offset >> 16; - offset &= 0xffff; - if (tep_field_is_relative(field->flags)) - offset += field->offset + field->size; + void *ptr = format_field__get_raw_data(field, sample, + evsel->needs_swap, + &syscall_arg.len); + + if (!ptr) { + pr_err("Problem processing %s field, skipping...\n", field->name); + continue; + } + val = (uintptr_t)ptr; + } else if ((field->flags & TEP_FIELD_IS_DYNAMIC) && + strstr(field->type, "cpumask")) { + unsigned long *mask = format_field__get_cpumask(field, sample, + evsel->needs_swap, + &syscall_arg.len); + + if (!mask) { + pr_err("Problem processing %s field, skipping...\n", field->name); + continue; } - val = (uintptr_t)(sample->raw_data + offset); + printed += scnprintf(bf + printed, size - printed, "%s", printed ? ", " : ""); + if (trace->show_arg_names) + printed += scnprintf(bf + printed, size - printed, "%s: ", field->name); + + if (syscall_arg.len == 0) { + printed += scnprintf(bf + printed, size - printed, "0"); + } else if (trace->bitmask_list) { + printed += bitmap_scnprintf(mask, syscall_arg.len * 8, + bf + printed, size - printed); + } else { + int i; + bool skip_zero = true; + + printed += scnprintf(bf + printed, size - printed, "0x"); + /* Print bytes from most significant to least significant */ + for (i = syscall_arg.len - 1; i >= 0; i--) { + unsigned char b_val = bitmap_byte(mask, i); + + if (skip_zero && b_val == 0 && i > 0) + continue; + + if (skip_zero) { + printed += scnprintf(bf + printed, size - printed, "%x", b_val); + skip_zero = false; + } else { + printed += scnprintf(bf + printed, size - printed, "%02x", b_val); + } + } + } + free(mask); + continue; } else val = format_field__intval(field, sample, evsel->needs_swap); /* @@ -3266,9 +3331,14 @@ static size_t trace__fprintf_tp_fields(struct trace *trace, struct perf_sample * * Suppress it by default to avoid cluttering the output. * If verbose mode is enabled, ensure it is formatted as a * hexadecimal memory address rather than a signed integer. + * + * caller_ip and call_site are also expected to be instruction + * pointers and should always be represented in hexadecimal. */ - if (evsel__is_probe(evsel) && !strcmp(field->name, "__probe_ip")) { - if (!verbose) + is_probe_ip = evsel__is_probe(evsel) && !strcmp(field->name, "__probe_ip"); + + if (is_probe_ip || trace__field_is_ip(field->name)) { + if (is_probe_ip && !verbose) continue; printed += scnprintf(bf + printed, size - printed, @@ -3633,7 +3703,7 @@ static bool evlist__add_vfs_getname(struct evlist *evlist) list_del_init(&evsel->core.node); evsel->evlist = NULL; - evsel__delete(evsel); + evsel__put(evsel); } return found; @@ -3678,8 +3748,11 @@ static void trace__handle_event(struct trace *trace, union perf_event *event, st return; } - if (sample->evsel == NULL) + if (sample->evsel == NULL) { sample->evsel = evlist__id2evsel(trace->evlist, sample->id); + if (sample->evsel) + evsel__get(sample->evsel); + } if (sample->evsel == NULL) { fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample->id); @@ -3749,9 +3822,9 @@ out: return ret; out_delete_sys_exit: - evsel__delete_priv(sys_exit); + evsel__put_and_free_priv(sys_exit); out_delete_sys_enter: - evsel__delete_priv(sys_enter); + evsel__put_and_free_priv(sys_enter); goto out; } @@ -4216,7 +4289,7 @@ static int trace__set_filter_pids(struct trace *trace) err = augmented_syscalls__set_filter_pids(trace->filter_pids.nr, trace->filter_pids.entries); } - } else if (perf_thread_map__pid(trace->evlist->core.threads, 0) == -1) { + } else if (perf_thread_map__pid(evlist__core(trace->evlist)->threads, 0) == -1) { err = trace__set_filter_loop_pids(trace); } @@ -4439,7 +4512,7 @@ static int trace__run(struct trace *trace, int argc, const char **argv) if (trace->summary_bpf) { if (trace_prepare_bpf_summary(trace->summary_mode) < 0) - goto out_delete_evlist; + goto out_put_evlist; if (trace->summary_only) goto create_maps; @@ -4507,19 +4580,19 @@ create_maps: err = evlist__create_maps(evlist, &trace->opts.target); if (err < 0) { fprintf(trace->output, "Problems parsing the target to trace, check your options!\n"); - goto out_delete_evlist; + goto out_put_evlist; } err = trace__symbols_init(trace, argc, argv, evlist); if (err < 0) { fprintf(trace->output, "Problems initializing symbol libraries!\n"); - goto out_delete_evlist; + goto out_put_evlist; } if (trace->summary_mode == SUMMARY__BY_TOTAL && !trace->summary_bpf) { trace->syscall_stats = alloc_syscall_stats(); if (!trace->syscall_stats) - goto out_delete_evlist; + goto out_put_evlist; } evlist__config(evlist, &trace->opts, &callchain_param); @@ -4528,9 +4601,9 @@ create_maps: err = evlist__prepare_workload(evlist, &trace->opts.target, argv, false, NULL); if (err < 0) { fprintf(trace->output, "Couldn't run the workload!\n"); - goto out_delete_evlist; + goto out_put_evlist; } - workload_pid = evlist->workload.pid; + workload_pid = evlist__workload_pid(evlist); } err = evlist__open(evlist); @@ -4576,13 +4649,13 @@ create_maps: err = trace__expand_filters(trace, &evsel); if (err) - goto out_delete_evlist; + goto out_put_evlist; err = evlist__apply_filters(evlist, &evsel, &trace->opts.target); if (err < 0) goto out_error_apply_filters; if (!trace->summary_only || !trace->summary_bpf) { - err = evlist__mmap(evlist, trace->opts.mmap_pages); + err = evlist__do_mmap(evlist, trace->opts.mmap_pages); if (err < 0) goto out_error_mmap; } @@ -4601,8 +4674,8 @@ create_maps: if (trace->summary_bpf) trace_start_bpf_summary(); - trace->multiple_threads = perf_thread_map__pid(evlist->core.threads, 0) == -1 || - perf_thread_map__nr(evlist->core.threads) > 1 || + trace->multiple_threads = perf_thread_map__pid(evlist__core(evlist)->threads, 0) == -1 || + perf_thread_map__nr(evlist__core(evlist)->threads) > 1 || evlist__first(evlist)->core.attr.inherit; /* @@ -4619,11 +4692,11 @@ create_maps: again: before = trace->nr_events; - for (i = 0; i < evlist->core.nr_mmaps; i++) { + for (i = 0; i < evlist__core(evlist)->nr_mmaps; i++) { union perf_event *event; struct mmap *md; - md = &evlist->mmap[i]; + md = &evlist__mmap(evlist)[i]; if (perf_mmap__read_init(&md->core) < 0) continue; @@ -4693,12 +4766,12 @@ out_disable: } } -out_delete_evlist: +out_put_evlist: trace_cleanup_bpf_summary(); delete_syscall_stats(trace->syscall_stats); trace__symbols__exit(trace); evlist__free_syscall_tp_fields(evlist); - evlist__delete(evlist); + evlist__put(evlist); cgroup__put(trace->cgroup); trace->evlist = NULL; trace->live = false; @@ -4723,21 +4796,21 @@ out_error_open: out_error: fprintf(trace->output, "%s\n", errbuf); - goto out_delete_evlist; + goto out_put_evlist; out_error_apply_filters: fprintf(trace->output, "Failed to set filter \"%s\" on event %s: %m\n", evsel->filter, evsel__name(evsel)); - goto out_delete_evlist; + goto out_put_evlist; } out_error_mem: fprintf(trace->output, "Not enough memory to run!\n"); - goto out_delete_evlist; + goto out_put_evlist; out_errno: fprintf(trace->output, "%m\n"); - goto out_delete_evlist; + goto out_put_evlist; } static int trace__replay(struct trace *trace) @@ -5325,7 +5398,7 @@ static int trace__parse_cgroups(const struct option *opt, const char *str, int u { struct trace *trace = opt->value; - if (!list_empty(&trace->evlist->core.entries)) { + if (!list_empty(&evlist__core(trace->evlist)->entries)) { struct option o = { .value = &trace->evlist, }; @@ -5417,7 +5490,7 @@ static void trace__exit(struct trace *trace) zfree(&trace->syscalls.table); } zfree(&trace->perfconfig_events); - evlist__delete(trace->evlist); + evlist__put(trace->evlist); trace->evlist = NULL; ordered_events__free(&trace->oe.data); #ifdef HAVE_LIBBPF_SUPPORT @@ -5537,6 +5610,7 @@ int cmd_trace(int argc, const char **argv) "start"), OPT_BOOLEAN(0, "force-btf", &trace.force_btf, "Prefer btf_dump general pretty printer" "to customized ones"), + OPT_BOOLEAN(0, "bitmask-list", &trace.bitmask_list, "Show bitmask as a human-readable list"), OPT_BOOLEAN(0, "bpf-summary", &trace.summary_bpf, "Summary syscall stats in BPF"), OPT_INTEGER(0, "max-summary", &trace.max_summary, "Max number of entries in the summary."), @@ -5599,7 +5673,7 @@ int cmd_trace(int argc, const char **argv) * .perfconfig trace.add_events, and filter those out. */ if (!trace.trace_syscalls && !trace.trace_pgfaults && - trace.evlist->core.nr_entries == 0 /* Was --events used? */) { + evlist__nr_entries(trace.evlist) == 0 /* Was --events used? */) { trace.trace_syscalls = true; } /* @@ -5685,7 +5759,7 @@ skip_augmentation: symbol_conf.use_callchain = true; } - if (trace.evlist->core.nr_entries > 0) { + if (evlist__nr_entries(trace.evlist) > 0) { bool use_btf = false; evlist__set_default_evsel_handler(trace.evlist, trace__event_handler); |
