perf tools: Add AUX area tracing Snapshot Mode
Add support for making snapshots of AUX area tracing data. Signed-off-by: Adrian Hunter <adrian.hunter@intel.com> Acked-by: Jiri 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: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
parent
0ad21f6869
commit
d20031bb63
3 changed files with 119 additions and 10 deletions
|
@ -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 {
|
||||||
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)
|
||||||
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)
|
||||||
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,
|
||||||
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,
|
||||||
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,6 +1202,7 @@ int auxtrace_mmap__read(struct auxtrace_mmap *mm, struct auxtrace_record *itr,
|
||||||
|
|
||||||
mm->prev = head;
|
mm->prev = head;
|
||||||
|
|
||||||
|
if (!snapshot) {
|
||||||
auxtrace_mmap__write_tail(mm, head);
|
auxtrace_mmap__write_tail(mm, head);
|
||||||
if (itr->read_finish) {
|
if (itr->read_finish) {
|
||||||
int err;
|
int err;
|
||||||
|
@ -1161,10 +1211,25 @@ int auxtrace_mmap__read(struct auxtrace_mmap *mm, struct auxtrace_record *itr,
|
||||||
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 {
|
||||||
* @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 {
|
||||||
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,
|
||||||
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);
|
||||||
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,
|
||||||
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,
|
||||||
|
|
Loading…
Add table
Reference in a new issue