summaryrefslogtreecommitdiff
path: root/tools/perf/builtin-trace.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/builtin-trace.c')
-rw-r--r--tools/perf/builtin-trace.c158
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);