Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d20031bb authored by Adrian Hunter's avatar Adrian Hunter Committed by Arnaldo Carvalho de Melo
Browse files

perf tools: Add AUX area tracing Snapshot Mode



Add support for making snapshots of AUX area tracing data.

Signed-off-by: default avatarAdrian Hunter <adrian.hunter@intel.com>
Acked-by: default avatarJiri Olsa <jolsa@kernel.org>
Cc: David Ahern <dsahern@gmail.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Namhyung Kim <namhyung@gmail.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/r/1430404667-10593-9-git-send-email-adrian.hunter@intel.com


Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent 0ad21f68
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -55,6 +55,7 @@ struct record_opts {
	bool	     sample_intr_regs;
	bool	     running_time;
	bool	     full_auxtrace;
	bool	     auxtrace_snapshot_mode;
	unsigned int freq;
	unsigned int mmap_pages;
	unsigned int auxtrace_mmap_pages;
@@ -62,6 +63,8 @@ struct record_opts {
	u64          branch_stack;
	u64	     default_interval;
	u64	     user_interval;
	size_t	     auxtrace_snapshot_size;
	const char   *auxtrace_snapshot_opts;
	bool	     sample_transaction;
	unsigned     initial_delay;
	bool         use_clockid;
+75 −10
Original line number Diff line number Diff line
@@ -504,6 +504,29 @@ void auxtrace_record__free(struct auxtrace_record *itr)
		itr->free(itr);
}

int auxtrace_record__snapshot_start(struct auxtrace_record *itr)
{
	if (itr && itr->snapshot_start)
		return itr->snapshot_start(itr);
	return 0;
}

int auxtrace_record__snapshot_finish(struct auxtrace_record *itr)
{
	if (itr && itr->snapshot_finish)
		return itr->snapshot_finish(itr);
	return 0;
}

int auxtrace_record__find_snapshot(struct auxtrace_record *itr, int idx,
				   struct auxtrace_mmap *mm,
				   unsigned char *data, u64 *head, u64 *old)
{
	if (itr && itr->find_snapshot)
		return itr->find_snapshot(itr, idx, mm, data, head, old);
	return 0;
}

int auxtrace_record__options(struct auxtrace_record *itr,
			     struct perf_evlist *evlist,
			     struct record_opts *opts)
@@ -520,6 +543,19 @@ u64 auxtrace_record__reference(struct auxtrace_record *itr)
	return 0;
}

int auxtrace_parse_snapshot_options(struct auxtrace_record *itr,
				    struct record_opts *opts, const char *str)
{
	if (!str)
		return 0;

	if (itr)
		return itr->parse_snapshot_options(itr, opts, str);

	pr_err("No AUX area tracing to snapshot\n");
	return -EINVAL;
}

struct auxtrace_record *__weak
auxtrace_record__init(struct perf_evlist *evlist __maybe_unused, int *err)
{
@@ -1077,16 +1113,26 @@ int perf_event__process_auxtrace_error(struct perf_tool *tool __maybe_unused,
	return 0;
}

int auxtrace_mmap__read(struct auxtrace_mmap *mm, struct auxtrace_record *itr,
			struct perf_tool *tool, process_auxtrace_t fn)
static int __auxtrace_mmap__read(struct auxtrace_mmap *mm,
				 struct auxtrace_record *itr,
				 struct perf_tool *tool, process_auxtrace_t fn,
				 bool snapshot, size_t snapshot_size)
{
	u64 head = auxtrace_mmap__read_head(mm);
	u64 old = mm->prev, offset, ref;
	u64 head, old = mm->prev, offset, ref;
	unsigned char *data = mm->base;
	size_t size, head_off, old_off, len1, len2, padding;
	union perf_event ev;
	void *data1, *data2;

	if (snapshot) {
		head = auxtrace_mmap__read_snapshot_head(mm);
		if (auxtrace_record__find_snapshot(itr, mm->idx, mm, data,
						   &head, &old))
			return -1;
	} else {
		head = auxtrace_mmap__read_head(mm);
	}

	if (old == head)
		return 0;

@@ -1106,6 +1152,9 @@ int auxtrace_mmap__read(struct auxtrace_mmap *mm, struct auxtrace_record *itr,
	else
		size = mm->len - (old_off - head_off);

	if (snapshot && size > snapshot_size)
		size = snapshot_size;

	ref = auxtrace_record__reference(itr);

	if (head > old || size <= head || mm->mask) {
@@ -1153,6 +1202,7 @@ int auxtrace_mmap__read(struct auxtrace_mmap *mm, struct auxtrace_record *itr,

	mm->prev = head;

	if (!snapshot) {
		auxtrace_mmap__write_tail(mm, head);
		if (itr->read_finish) {
			int err;
@@ -1161,10 +1211,25 @@ int auxtrace_mmap__read(struct auxtrace_mmap *mm, struct auxtrace_record *itr,
			if (err < 0)
				return err;
		}
	}

	return 1;
}

int auxtrace_mmap__read(struct auxtrace_mmap *mm, struct auxtrace_record *itr,
			struct perf_tool *tool, process_auxtrace_t fn)
{
	return __auxtrace_mmap__read(mm, itr, tool, fn, false, 0);
}

int auxtrace_mmap__read_snapshot(struct auxtrace_mmap *mm,
				 struct auxtrace_record *itr,
				 struct perf_tool *tool, process_auxtrace_t fn,
				 size_t snapshot_size)
{
	return __auxtrace_mmap__read(mm, itr, tool, fn, true, snapshot_size);
}

/**
 * struct auxtrace_cache - hash table to implement a cache
 * @hashtable: the hashtable
+41 −0
Original line number Diff line number Diff line
@@ -276,6 +276,10 @@ struct auxtrace_mmap_params {
 * @info_priv_size: return the size of the private data in auxtrace_info_event
 * @info_fill: fill-in the private data in auxtrace_info_event
 * @free: free this auxtrace record structure
 * @snapshot_start: starting a snapshot
 * @snapshot_finish: finishing a snapshot
 * @find_snapshot: find data to snapshot within auxtrace mmap
 * @parse_snapshot_options: parse snapshot options
 * @reference: provide a 64-bit reference number for auxtrace_event
 * @read_finish: called after reading from an auxtrace mmap
 */
@@ -289,12 +293,36 @@ struct auxtrace_record {
			 struct auxtrace_info_event *auxtrace_info,
			 size_t priv_size);
	void (*free)(struct auxtrace_record *itr);
	int (*snapshot_start)(struct auxtrace_record *itr);
	int (*snapshot_finish)(struct auxtrace_record *itr);
	int (*find_snapshot)(struct auxtrace_record *itr, int idx,
			     struct auxtrace_mmap *mm, unsigned char *data,
			     u64 *head, u64 *old);
	int (*parse_snapshot_options)(struct auxtrace_record *itr,
				      struct record_opts *opts,
				      const char *str);
	u64 (*reference)(struct auxtrace_record *itr);
	int (*read_finish)(struct auxtrace_record *itr, int idx);
};

#ifdef HAVE_AUXTRACE_SUPPORT

/*
 * In snapshot mode the mmapped page is read-only which makes using
 * __sync_val_compare_and_swap() problematic.  However, snapshot mode expects
 * the buffer is not updated while the snapshot is made (e.g. Intel PT disables
 * the event) so there is not a race anyway.
 */
static inline u64 auxtrace_mmap__read_snapshot_head(struct auxtrace_mmap *mm)
{
	struct perf_event_mmap_page *pc = mm->userpg;
	u64 head = ACCESS_ONCE(pc->aux_head);

	/* Ensure all reads are done after we read the head */
	rmb();
	return head;
}

static inline u64 auxtrace_mmap__read_head(struct auxtrace_mmap *mm)
{
	struct perf_event_mmap_page *pc = mm->userpg;
@@ -346,6 +374,11 @@ typedef int (*process_auxtrace_t)(struct perf_tool *tool,
int auxtrace_mmap__read(struct auxtrace_mmap *mm, struct auxtrace_record *itr,
			struct perf_tool *tool, process_auxtrace_t fn);

int auxtrace_mmap__read_snapshot(struct auxtrace_mmap *mm,
				 struct auxtrace_record *itr,
				 struct perf_tool *tool, process_auxtrace_t fn,
				 size_t snapshot_size);

int auxtrace_queues__init(struct auxtrace_queues *queues);
int auxtrace_queues__add_event(struct auxtrace_queues *queues,
			       struct perf_session *session,
@@ -383,6 +416,9 @@ void *auxtrace_cache__lookup(struct auxtrace_cache *c, u32 key);
struct auxtrace_record *auxtrace_record__init(struct perf_evlist *evlist,
					      int *err);

int auxtrace_parse_snapshot_options(struct auxtrace_record *itr,
				    struct record_opts *opts,
				    const char *str);
int auxtrace_record__options(struct auxtrace_record *itr,
			     struct perf_evlist *evlist,
			     struct record_opts *opts);
@@ -392,6 +428,11 @@ int auxtrace_record__info_fill(struct auxtrace_record *itr,
			       struct auxtrace_info_event *auxtrace_info,
			       size_t priv_size);
void auxtrace_record__free(struct auxtrace_record *itr);
int auxtrace_record__snapshot_start(struct auxtrace_record *itr);
int auxtrace_record__snapshot_finish(struct auxtrace_record *itr);
int auxtrace_record__find_snapshot(struct auxtrace_record *itr, int idx,
				   struct auxtrace_mmap *mm,
				   unsigned char *data, u64 *head, u64 *old);
u64 auxtrace_record__reference(struct auxtrace_record *itr);

int auxtrace_index__auxtrace_event(struct list_head *head, union perf_event *event,