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

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.comSigned-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent 0ad21f68
...@@ -55,6 +55,7 @@ struct record_opts { ...@@ -55,6 +55,7 @@ struct record_opts {
bool sample_intr_regs; bool sample_intr_regs;
bool running_time; bool running_time;
bool full_auxtrace; bool full_auxtrace;
bool auxtrace_snapshot_mode;
unsigned int freq; unsigned int freq;
unsigned int mmap_pages; unsigned int mmap_pages;
unsigned int auxtrace_mmap_pages; unsigned int auxtrace_mmap_pages;
...@@ -62,6 +63,8 @@ struct record_opts { ...@@ -62,6 +63,8 @@ struct record_opts {
u64 branch_stack; u64 branch_stack;
u64 default_interval; u64 default_interval;
u64 user_interval; u64 user_interval;
size_t auxtrace_snapshot_size;
const char *auxtrace_snapshot_opts;
bool sample_transaction; bool sample_transaction;
unsigned initial_delay; unsigned initial_delay;
bool use_clockid; bool use_clockid;
......
...@@ -504,6 +504,29 @@ void auxtrace_record__free(struct auxtrace_record *itr) ...@@ -504,6 +504,29 @@ void auxtrace_record__free(struct auxtrace_record *itr)
itr->free(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, int auxtrace_record__options(struct auxtrace_record *itr,
struct perf_evlist *evlist, struct perf_evlist *evlist,
struct record_opts *opts) struct record_opts *opts)
...@@ -520,6 +543,19 @@ u64 auxtrace_record__reference(struct auxtrace_record *itr) ...@@ -520,6 +543,19 @@ u64 auxtrace_record__reference(struct auxtrace_record *itr)
return 0; 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 struct auxtrace_record *__weak
auxtrace_record__init(struct perf_evlist *evlist __maybe_unused, int *err) 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, ...@@ -1077,16 +1113,26 @@ int perf_event__process_auxtrace_error(struct perf_tool *tool __maybe_unused,
return 0; return 0;
} }
int auxtrace_mmap__read(struct auxtrace_mmap *mm, struct auxtrace_record *itr, static int __auxtrace_mmap__read(struct auxtrace_mmap *mm,
struct perf_tool *tool, process_auxtrace_t fn) 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 head, old = mm->prev, offset, ref;
u64 old = mm->prev, offset, ref;
unsigned char *data = mm->base; unsigned char *data = mm->base;
size_t size, head_off, old_off, len1, len2, padding; size_t size, head_off, old_off, len1, len2, padding;
union perf_event ev; union perf_event ev;
void *data1, *data2; 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) if (old == head)
return 0; return 0;
...@@ -1106,6 +1152,9 @@ int auxtrace_mmap__read(struct auxtrace_mmap *mm, struct auxtrace_record *itr, ...@@ -1106,6 +1152,9 @@ int auxtrace_mmap__read(struct auxtrace_mmap *mm, struct auxtrace_record *itr,
else else
size = mm->len - (old_off - head_off); size = mm->len - (old_off - head_off);
if (snapshot && size > snapshot_size)
size = snapshot_size;
ref = auxtrace_record__reference(itr); ref = auxtrace_record__reference(itr);
if (head > old || size <= head || mm->mask) { if (head > old || size <= head || mm->mask) {
...@@ -1153,18 +1202,34 @@ int auxtrace_mmap__read(struct auxtrace_mmap *mm, struct auxtrace_record *itr, ...@@ -1153,18 +1202,34 @@ int auxtrace_mmap__read(struct auxtrace_mmap *mm, struct auxtrace_record *itr,
mm->prev = head; mm->prev = head;
auxtrace_mmap__write_tail(mm, head); if (!snapshot) {
if (itr->read_finish) { auxtrace_mmap__write_tail(mm, head);
int err; if (itr->read_finish) {
int err;
err = itr->read_finish(itr, mm->idx); err = itr->read_finish(itr, mm->idx);
if (err < 0) if (err < 0)
return err; return err;
}
} }
return 1; 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 * struct auxtrace_cache - hash table to implement a cache
* @hashtable: the hashtable * @hashtable: the hashtable
......
...@@ -276,6 +276,10 @@ struct auxtrace_mmap_params { ...@@ -276,6 +276,10 @@ struct auxtrace_mmap_params {
* @info_priv_size: return the size of the private data in auxtrace_info_event * @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 * @info_fill: fill-in the private data in auxtrace_info_event
* @free: free this auxtrace record structure * @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 * @reference: provide a 64-bit reference number for auxtrace_event
* @read_finish: called after reading from an auxtrace mmap * @read_finish: called after reading from an auxtrace mmap
*/ */
...@@ -289,12 +293,36 @@ struct auxtrace_record { ...@@ -289,12 +293,36 @@ struct auxtrace_record {
struct auxtrace_info_event *auxtrace_info, struct auxtrace_info_event *auxtrace_info,
size_t priv_size); size_t priv_size);
void (*free)(struct auxtrace_record *itr); 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); u64 (*reference)(struct auxtrace_record *itr);
int (*read_finish)(struct auxtrace_record *itr, int idx); int (*read_finish)(struct auxtrace_record *itr, int idx);
}; };
#ifdef HAVE_AUXTRACE_SUPPORT #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) static inline u64 auxtrace_mmap__read_head(struct auxtrace_mmap *mm)
{ {
struct perf_event_mmap_page *pc = mm->userpg; struct perf_event_mmap_page *pc = mm->userpg;
...@@ -346,6 +374,11 @@ typedef int (*process_auxtrace_t)(struct perf_tool *tool, ...@@ -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, int auxtrace_mmap__read(struct auxtrace_mmap *mm, struct auxtrace_record *itr,
struct perf_tool *tool, process_auxtrace_t fn); 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__init(struct auxtrace_queues *queues);
int auxtrace_queues__add_event(struct auxtrace_queues *queues, int auxtrace_queues__add_event(struct auxtrace_queues *queues,
struct perf_session *session, struct perf_session *session,
...@@ -383,6 +416,9 @@ void *auxtrace_cache__lookup(struct auxtrace_cache *c, u32 key); ...@@ -383,6 +416,9 @@ void *auxtrace_cache__lookup(struct auxtrace_cache *c, u32 key);
struct auxtrace_record *auxtrace_record__init(struct perf_evlist *evlist, struct auxtrace_record *auxtrace_record__init(struct perf_evlist *evlist,
int *err); 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, int auxtrace_record__options(struct auxtrace_record *itr,
struct perf_evlist *evlist, struct perf_evlist *evlist,
struct record_opts *opts); struct record_opts *opts);
...@@ -392,6 +428,11 @@ int auxtrace_record__info_fill(struct auxtrace_record *itr, ...@@ -392,6 +428,11 @@ int auxtrace_record__info_fill(struct auxtrace_record *itr,
struct auxtrace_info_event *auxtrace_info, struct auxtrace_info_event *auxtrace_info,
size_t priv_size); size_t priv_size);
void auxtrace_record__free(struct auxtrace_record *itr); 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); u64 auxtrace_record__reference(struct auxtrace_record *itr);
int auxtrace_index__auxtrace_event(struct list_head *head, union perf_event *event, int auxtrace_index__auxtrace_event(struct list_head *head, union perf_event *event,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment