From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1945921AbbDXTcv (ORCPT ); Fri, 24 Apr 2015 15:32:51 -0400 Received: from mga11.intel.com ([192.55.52.93]:40019 "EHLO mga11.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1030884AbbDXTcs (ORCPT ); Fri, 24 Apr 2015 15:32:48 -0400 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.11,642,1422950400"; d="scan'208";a="685230569" From: Adrian Hunter To: Arnaldo Carvalho de Melo Cc: Peter Zijlstra , linux-kernel@vger.kernel.org, David Ahern , Frederic Weisbecker , Jiri Olsa , Namhyung Kim , Stephane Eranian Subject: [PATCH V3 10/25] perf tools: Add AUX area tracing Snapshot Mode Date: Fri, 24 Apr 2015 22:29:52 +0300 Message-Id: <1429903807-20559-11-git-send-email-adrian.hunter@intel.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1429903807-20559-1-git-send-email-adrian.hunter@intel.com> References: <1429903807-20559-1-git-send-email-adrian.hunter@intel.com> Organization: Intel Finland Oy, Registered Address: PL 281, 00181 Helsinki, Business Identity Code: 0357606 - 4, Domiciled in Helsinki Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Add support for making snapshots of AUX area tracing data. Signed-off-by: Adrian Hunter --- tools/perf/perf.h | 3 ++ tools/perf/util/auxtrace.c | 85 ++++++++++++++++++++++++++++++++++++++++------ tools/perf/util/auxtrace.h | 41 ++++++++++++++++++++++ 3 files changed, 119 insertions(+), 10 deletions(-) diff --git a/tools/perf/perf.h b/tools/perf/perf.h index 5042093..aa79fb8 100644 --- a/tools/perf/perf.h +++ b/tools/perf/perf.h @@ -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; diff --git a/tools/perf/util/auxtrace.c b/tools/perf/util/auxtrace.c index 2883376..4f024eb 100644 --- a/tools/perf/util/auxtrace.c +++ b/tools/perf/util/auxtrace.c @@ -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) { @@ -1078,16 +1114,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; @@ -1107,6 +1153,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) { @@ -1154,18 +1203,34 @@ int auxtrace_mmap__read(struct auxtrace_mmap *mm, struct auxtrace_record *itr, mm->prev = head; - auxtrace_mmap__write_tail(mm, head); - if (itr->read_finish) { - int err; + if (!snapshot) { + auxtrace_mmap__write_tail(mm, head); + if (itr->read_finish) { + int err; - err = itr->read_finish(itr, mm->idx); - if (err < 0) - return err; + err = itr->read_finish(itr, mm->idx); + 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 diff --git a/tools/perf/util/auxtrace.h b/tools/perf/util/auxtrace.h index 8c6cbb1..f0bacb6 100644 --- a/tools/perf/util/auxtrace.h +++ b/tools/perf/util/auxtrace.h @@ -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, -- 1.9.1