summaryrefslogtreecommitdiff
path: root/tools/perf/util/auxtrace.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util/auxtrace.c')
-rw-r--r--tools/perf/util/auxtrace.c143
1 files changed, 112 insertions, 31 deletions
diff --git a/tools/perf/util/auxtrace.c b/tools/perf/util/auxtrace.c
index e2f317063eec..a224687ffbc1 100644
--- a/tools/perf/util/auxtrace.c
+++ b/tools/perf/util/auxtrace.c
@@ -55,12 +55,29 @@
#include "hisi-ptt.h"
#include "s390-cpumsf.h"
#include "util/mmap.h"
+#include "powerpc-vpadtl.h"
#include <linux/ctype.h>
#include "symbol/kallsyms.h"
#include <internal/lib.h>
#include "util/sample.h"
+#define AUXTRACE_SYNTH_EVENT_ID_OFFSET 1000000000ULL
+
+/*
+ * Event IDs are allocated sequentially, so a big offset from any
+ * existing ID will reach a unused range.
+ */
+u64 auxtrace_synth_id_range_start(struct evsel *evsel)
+{
+ u64 id = evsel->core.id[0] + AUXTRACE_SYNTH_EVENT_ID_OFFSET;
+
+ if (!id)
+ id = 1;
+
+ return id;
+}
+
/*
* Make a group from 'leader' to 'last', requiring that the events were not
* already grouped to a different leader.
@@ -185,10 +202,7 @@ void auxtrace_mmap_params__set_idx(struct auxtrace_mmap_params *mp,
if (per_cpu) {
mp->cpu = perf_cpu_map__cpu(evlist->core.all_cpus, idx);
- if (evlist->core.threads)
- mp->tid = perf_thread_map__pid(evlist->core.threads, 0);
- else
- mp->tid = -1;
+ mp->tid = perf_thread_map__pid(evlist->core.threads, 0);
} else {
mp->cpu.cpu = -1;
mp->tid = perf_thread_map__pid(evlist->core.threads, idx);
@@ -671,11 +685,11 @@ int auxtrace_record__read_finish(struct auxtrace_record *itr, int idx)
{
struct evsel *evsel;
- if (!itr->evlist || !itr->pmu)
+ if (!itr->evlist)
return -EINVAL;
evlist__for_each_entry(itr->evlist, evsel) {
- if (evsel->core.attr.type == itr->pmu->type) {
+ if (evsel__is_aux_event(evsel)) {
if (evsel->disabled)
return 0;
return evlist__enable_event_idx(itr->evlist, evsel, idx);
@@ -810,19 +824,76 @@ no_opt:
return auxtrace_validate_aux_sample_size(evlist, opts);
}
-void auxtrace_regroup_aux_output(struct evlist *evlist)
+static struct aux_action_opt {
+ const char *str;
+ u32 aux_action;
+ bool aux_event_opt;
+} aux_action_opts[] = {
+ {"start-paused", BIT(0), true},
+ {"pause", BIT(1), false},
+ {"resume", BIT(2), false},
+ {.str = NULL},
+};
+
+static const struct aux_action_opt *auxtrace_parse_aux_action_str(const char *str)
+{
+ const struct aux_action_opt *opt;
+
+ if (!str)
+ return NULL;
+
+ for (opt = aux_action_opts; opt->str; opt++)
+ if (!strcmp(str, opt->str))
+ return opt;
+
+ return NULL;
+}
+
+int auxtrace_parse_aux_action(struct evlist *evlist)
{
- struct evsel *evsel, *aux_evsel = NULL;
struct evsel_config_term *term;
+ struct evsel *aux_evsel = NULL;
+ struct evsel *evsel;
evlist__for_each_entry(evlist, evsel) {
- if (evsel__is_aux_event(evsel))
+ bool is_aux_event = evsel__is_aux_event(evsel);
+ const struct aux_action_opt *opt;
+
+ if (is_aux_event)
aux_evsel = evsel;
- term = evsel__get_config_term(evsel, AUX_OUTPUT);
+ term = evsel__get_config_term(evsel, AUX_ACTION);
+ if (!term) {
+ if (evsel__get_config_term(evsel, AUX_OUTPUT))
+ goto regroup;
+ continue;
+ }
+ opt = auxtrace_parse_aux_action_str(term->val.str);
+ if (!opt) {
+ pr_err("Bad aux-action '%s'\n", term->val.str);
+ return -EINVAL;
+ }
+ if (opt->aux_event_opt && !is_aux_event) {
+ pr_err("aux-action '%s' can only be used with AUX area event\n",
+ term->val.str);
+ return -EINVAL;
+ }
+ if (!opt->aux_event_opt && is_aux_event) {
+ pr_err("aux-action '%s' cannot be used for AUX area event itself\n",
+ term->val.str);
+ return -EINVAL;
+ }
+ evsel->core.attr.aux_action = opt->aux_action;
+regroup:
/* If possible, group with the AUX event */
- if (term && aux_evsel)
+ if (aux_evsel)
evlist__regroup(evlist, aux_evsel, evsel);
+ if (!evsel__is_aux_event(evsel__leader(evsel))) {
+ pr_err("Events with aux-action must have AUX area event group leader\n");
+ return -EINVAL;
+ }
}
+
+ return 0;
}
struct auxtrace_record *__weak
@@ -1116,16 +1187,19 @@ static int auxtrace_queue_data_cb(struct perf_session *session,
if (!qd->samples || event->header.type != PERF_RECORD_SAMPLE)
return 0;
+ perf_sample__init(&sample, /*all=*/false);
err = evlist__parse_sample(session->evlist, event, &sample);
if (err)
- return err;
-
- if (!sample.aux_sample.size)
- return 0;
+ goto out;
- offset += sample.aux_sample.data - (void *)event;
+ if (sample.aux_sample.size) {
+ offset += sample.aux_sample.data - (void *)event;
- return session->auxtrace->queue_data(session, &sample, NULL, offset);
+ err = session->auxtrace->queue_data(session, &sample, NULL, offset);
+ }
+out:
+ perf_sample__exit(&sample);
+ return err;
}
int auxtrace_queue_data(struct perf_session *session, bool samples, bool events)
@@ -1240,7 +1314,7 @@ void auxtrace_synth_error(struct perf_record_auxtrace_error *auxtrace_error, int
}
int perf_event__synthesize_auxtrace_info(struct auxtrace_record *itr,
- struct perf_tool *tool,
+ const struct perf_tool *tool,
struct perf_session *session,
perf_event__handler_t process)
{
@@ -1305,7 +1379,8 @@ static void unleader_auxtrace(struct perf_session *session)
}
}
-int perf_event__process_auxtrace_info(struct perf_session *session,
+int perf_event__process_auxtrace_info(const struct perf_tool *tool __maybe_unused,
+ struct perf_session *session,
union perf_event *event)
{
enum auxtrace_type type = event->auxtrace_info.type;
@@ -1333,6 +1408,9 @@ int perf_event__process_auxtrace_info(struct perf_session *session,
case PERF_AUXTRACE_HISI_PTT:
err = hisi_ptt_process_auxtrace_info(event, session);
break;
+ case PERF_AUXTRACE_VPA_DTL:
+ err = powerpc_vpadtl_process_auxtrace_info(event, session);
+ break;
case PERF_AUXTRACE_UNKNOWN:
default:
return -EINVAL;
@@ -1346,7 +1424,8 @@ int perf_event__process_auxtrace_info(struct perf_session *session,
return 0;
}
-s64 perf_event__process_auxtrace(struct perf_session *session,
+s64 perf_event__process_auxtrace(const struct perf_tool *tool __maybe_unused,
+ struct perf_session *session,
union perf_event *event)
{
s64 err;
@@ -1743,7 +1822,8 @@ void events_stats__auxtrace_error_warn(const struct events_stats *stats)
}
}
-int perf_event__process_auxtrace_error(struct perf_session *session,
+int perf_event__process_auxtrace_error(const struct perf_tool *tool __maybe_unused,
+ struct perf_session *session,
union perf_event *event)
{
if (auxtrace__dont_decode(session))
@@ -1830,8 +1910,8 @@ int __weak compat_auxtrace_mmap__write_tail(struct auxtrace_mmap *mm, u64 tail)
}
static int __auxtrace_mmap__read(struct mmap *map,
- struct auxtrace_record *itr,
- struct perf_tool *tool, process_auxtrace_t fn,
+ struct auxtrace_record *itr, struct perf_env *env,
+ const struct perf_tool *tool, process_auxtrace_t fn,
bool snapshot, size_t snapshot_size)
{
struct auxtrace_mmap *mm = &map->auxtrace_mmap;
@@ -1840,7 +1920,7 @@ static int __auxtrace_mmap__read(struct mmap *map,
size_t size, head_off, old_off, len1, len2, padding;
union perf_event ev;
void *data1, *data2;
- int kernel_is_64_bit = perf_env__kernel_is_64_bit(evsel__env(NULL));
+ int kernel_is_64_bit = perf_env__kernel_is_64_bit(env);
head = auxtrace_mmap__read_head(mm, kernel_is_64_bit);
@@ -1942,17 +2022,18 @@ static int __auxtrace_mmap__read(struct mmap *map,
}
int auxtrace_mmap__read(struct mmap *map, struct auxtrace_record *itr,
- struct perf_tool *tool, process_auxtrace_t fn)
+ struct perf_env *env, const struct perf_tool *tool,
+ process_auxtrace_t fn)
{
- return __auxtrace_mmap__read(map, itr, tool, fn, false, 0);
+ return __auxtrace_mmap__read(map, itr, env, tool, fn, false, 0);
}
int auxtrace_mmap__read_snapshot(struct mmap *map,
- struct auxtrace_record *itr,
- struct perf_tool *tool, process_auxtrace_t fn,
+ struct auxtrace_record *itr, struct perf_env *env,
+ const struct perf_tool *tool, process_auxtrace_t fn,
size_t snapshot_size)
{
- return __auxtrace_mmap__read(map, itr, tool, fn, true, snapshot_size);
+ return __auxtrace_mmap__read(map, itr, env, tool, fn, true, snapshot_size);
}
/**
@@ -2829,7 +2910,7 @@ int auxtrace_parse_filters(struct evlist *evlist)
}
int auxtrace__process_event(struct perf_session *session, union perf_event *event,
- struct perf_sample *sample, struct perf_tool *tool)
+ struct perf_sample *sample, const struct perf_tool *tool)
{
if (!session->auxtrace)
return 0;
@@ -2847,7 +2928,7 @@ void auxtrace__dump_auxtrace_sample(struct perf_session *session,
session->auxtrace->dump_auxtrace_sample(session, sample);
}
-int auxtrace__flush_events(struct perf_session *session, struct perf_tool *tool)
+int auxtrace__flush_events(struct perf_session *session, const struct perf_tool *tool)
{
if (!session->auxtrace)
return 0;