From a16ac0233ea1da8af3c2046a67c2527b4a452166 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Thu, 9 Apr 2015 18:53:43 +0300 Subject: perf tools: Add user events for AUX area tracing Add two user events for AUX area tracing. PERF_RECORD_AUXTRACE_INFO contains metadata, consisting primarily the type of the AUX area tracing data plus some amount of architecture-specific information. There should be only one PERF_RECORD_AUXTRACE_INFO event. PERF_RECORD_AUXTRACE identifies AUX area tracing data copied from the mmapped AUX area tracing region. The actual data is not part of the event but immediately follows it. Signed-off-by: Adrian Hunter Acked-by: Jiri Olsa Cc: David Ahern Cc: Frederic Weisbecker Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1428594864-29309-4-git-send-email-adrian.hunter@intel.com [ s/MIN/min/g and use cast to fix up wrt -Werror=sign-compare till we adopt min_t() ] Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/session.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) (limited to 'tools/perf/util/session.c') diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 0c74012575ac..d46ac4038fc7 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -262,6 +262,40 @@ static int process_id_index_stub(struct perf_tool *tool __maybe_unused, return 0; } +static int process_event_auxtrace_info_stub(struct perf_tool *tool __maybe_unused, + union perf_event *event __maybe_unused, + struct perf_session *session __maybe_unused) +{ + dump_printf(": unhandled!\n"); + return 0; +} + +static int skipn(int fd, off_t n) +{ + char buf[4096]; + ssize_t ret; + + while (n > 0) { + ret = read(fd, buf, min(n, (off_t)sizeof(buf))); + if (ret <= 0) + return ret; + n -= ret; + } + + return 0; +} + +static s64 process_event_auxtrace_stub(struct perf_tool *tool __maybe_unused, + union perf_event *event, + struct perf_session *session + __maybe_unused) +{ + dump_printf(": unhandled!\n"); + if (perf_data_file__is_pipe(session->file)) + skipn(perf_data_file__fd(session->file), event->auxtrace.size); + return event->auxtrace.size; +} + void perf_tool__fill_defaults(struct perf_tool *tool) { if (tool->sample == NULL) @@ -298,6 +332,10 @@ void perf_tool__fill_defaults(struct perf_tool *tool) } if (tool->id_index == NULL) tool->id_index = process_id_index_stub; + if (tool->auxtrace_info == NULL) + tool->auxtrace_info = process_event_auxtrace_info_stub; + if (tool->auxtrace == NULL) + tool->auxtrace = process_event_auxtrace_stub; } static void swap_sample_id_all(union perf_event *event, void *data) @@ -478,6 +516,29 @@ static void perf_event__tracing_data_swap(union perf_event *event, event->tracing_data.size = bswap_32(event->tracing_data.size); } +static void perf_event__auxtrace_info_swap(union perf_event *event, + bool sample_id_all __maybe_unused) +{ + size_t size; + + event->auxtrace_info.type = bswap_32(event->auxtrace_info.type); + + size = event->header.size; + size -= (void *)&event->auxtrace_info.priv - (void *)event; + mem_bswap_64(event->auxtrace_info.priv, size); +} + +static void perf_event__auxtrace_swap(union perf_event *event, + bool sample_id_all __maybe_unused) +{ + event->auxtrace.size = bswap_64(event->auxtrace.size); + event->auxtrace.offset = bswap_64(event->auxtrace.offset); + event->auxtrace.reference = bswap_64(event->auxtrace.reference); + event->auxtrace.idx = bswap_32(event->auxtrace.idx); + event->auxtrace.tid = bswap_32(event->auxtrace.tid); + event->auxtrace.cpu = bswap_32(event->auxtrace.cpu); +} + typedef void (*perf_event__swap_op)(union perf_event *event, bool sample_id_all); @@ -497,6 +558,8 @@ static perf_event__swap_op perf_event__swap_ops[] = { [PERF_RECORD_HEADER_TRACING_DATA] = perf_event__tracing_data_swap, [PERF_RECORD_HEADER_BUILD_ID] = NULL, [PERF_RECORD_ID_INDEX] = perf_event__all64_swap, + [PERF_RECORD_AUXTRACE_INFO] = perf_event__auxtrace_info_swap, + [PERF_RECORD_AUXTRACE] = perf_event__auxtrace_swap, [PERF_RECORD_HEADER_MAX] = NULL, }; @@ -980,6 +1043,12 @@ static s64 perf_session__process_user_event(struct perf_session *session, return tool->finished_round(tool, event, oe); case PERF_RECORD_ID_INDEX: return tool->id_index(tool, event, session); + case PERF_RECORD_AUXTRACE_INFO: + return tool->auxtrace_info(tool, event, session); + case PERF_RECORD_AUXTRACE: + /* setup for reading amidst mmap */ + lseek(fd, file_offset + event->header.size, SEEK_SET); + return tool->auxtrace(tool, event, session); default: return -EINVAL; } -- cgit v1.2.3 From e9bf54d25f4f64c410c2aca644749a3325b96f5a Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Thu, 9 Apr 2015 18:53:47 +0300 Subject: perf tools: Add a user event for AUX area tracing errors Errors encountered when decoding an AUX area trace need to be reported to the user. However the "user" might be a script or another tool, so provide a new user event to capture those errors. Signed-off-by: Adrian Hunter Acked-by: Jiri Olsa Cc: David Ahern Cc: Frederic Weisbecker Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1428594864-29309-8-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/event.c | 1 + tools/perf/util/event.h | 16 ++++++++++++++++ tools/perf/util/session.c | 25 +++++++++++++++++++++++++ tools/perf/util/tool.h | 3 ++- 4 files changed, 44 insertions(+), 1 deletion(-) (limited to 'tools/perf/util/session.c') diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index adada16a3f3b..32323e5d7b25 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -31,6 +31,7 @@ static const char *perf_event__names[] = { [PERF_RECORD_ID_INDEX] = "ID_INDEX", [PERF_RECORD_AUXTRACE_INFO] = "AUXTRACE_INFO", [PERF_RECORD_AUXTRACE] = "AUXTRACE", + [PERF_RECORD_AUXTRACE_ERROR] = "AUXTRACE_ERROR", }; const char *perf_event__name(unsigned int id) diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index 6d81beca1f27..657dcfaf0389 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h @@ -217,6 +217,7 @@ enum perf_user_event_type { /* above any possible kernel type */ PERF_RECORD_ID_INDEX = 69, PERF_RECORD_AUXTRACE_INFO = 70, PERF_RECORD_AUXTRACE = 71, + PERF_RECORD_AUXTRACE_ERROR = 72, PERF_RECORD_HEADER_MAX }; @@ -300,6 +301,20 @@ struct auxtrace_event { u32 reserved__; /* For alignment */ }; +#define MAX_AUXTRACE_ERROR_MSG 64 + +struct auxtrace_error_event { + struct perf_event_header header; + u32 type; + u32 code; + u32 cpu; + u32 pid; + u32 tid; + u32 reserved__; /* For alignment */ + u64 ip; + char msg[MAX_AUXTRACE_ERROR_MSG]; +}; + union perf_event { struct perf_event_header header; struct mmap_event mmap; @@ -317,6 +332,7 @@ union perf_event { struct id_index_event id_index; struct auxtrace_info_event auxtrace_info; struct auxtrace_event auxtrace; + struct auxtrace_error_event auxtrace_error; }; void perf_event__print_totals(void); diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index d46ac4038fc7..4008dab73424 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -296,6 +296,15 @@ static s64 process_event_auxtrace_stub(struct perf_tool *tool __maybe_unused, return event->auxtrace.size; } +static +int process_event_auxtrace_error_stub(struct perf_tool *tool __maybe_unused, + union perf_event *event __maybe_unused, + struct perf_session *session __maybe_unused) +{ + dump_printf(": unhandled!\n"); + return 0; +} + void perf_tool__fill_defaults(struct perf_tool *tool) { if (tool->sample == NULL) @@ -336,6 +345,8 @@ void perf_tool__fill_defaults(struct perf_tool *tool) tool->auxtrace_info = process_event_auxtrace_info_stub; if (tool->auxtrace == NULL) tool->auxtrace = process_event_auxtrace_stub; + if (tool->auxtrace_error == NULL) + tool->auxtrace_error = process_event_auxtrace_error_stub; } static void swap_sample_id_all(union perf_event *event, void *data) @@ -539,6 +550,17 @@ static void perf_event__auxtrace_swap(union perf_event *event, event->auxtrace.cpu = bswap_32(event->auxtrace.cpu); } +static void perf_event__auxtrace_error_swap(union perf_event *event, + bool sample_id_all __maybe_unused) +{ + event->auxtrace_error.type = bswap_32(event->auxtrace_error.type); + event->auxtrace_error.code = bswap_32(event->auxtrace_error.code); + event->auxtrace_error.cpu = bswap_32(event->auxtrace_error.cpu); + event->auxtrace_error.pid = bswap_32(event->auxtrace_error.pid); + event->auxtrace_error.tid = bswap_32(event->auxtrace_error.tid); + event->auxtrace_error.ip = bswap_64(event->auxtrace_error.ip); +} + typedef void (*perf_event__swap_op)(union perf_event *event, bool sample_id_all); @@ -560,6 +582,7 @@ static perf_event__swap_op perf_event__swap_ops[] = { [PERF_RECORD_ID_INDEX] = perf_event__all64_swap, [PERF_RECORD_AUXTRACE_INFO] = perf_event__auxtrace_info_swap, [PERF_RECORD_AUXTRACE] = perf_event__auxtrace_swap, + [PERF_RECORD_AUXTRACE_ERROR] = perf_event__auxtrace_error_swap, [PERF_RECORD_HEADER_MAX] = NULL, }; @@ -1049,6 +1072,8 @@ static s64 perf_session__process_user_event(struct perf_session *session, /* setup for reading amidst mmap */ lseek(fd, file_offset + event->header.size, SEEK_SET); return tool->auxtrace(tool, event, session); + case PERF_RECORD_AUXTRACE_ERROR: + return tool->auxtrace_error(tool, event, session); default: return -EINVAL; } diff --git a/tools/perf/util/tool.h b/tools/perf/util/tool.h index 0146f8ef5cc3..20afe19a8eb0 100644 --- a/tools/perf/util/tool.h +++ b/tools/perf/util/tool.h @@ -50,7 +50,8 @@ struct perf_tool { event_oe finished_round; event_op2 build_id, id_index, - auxtrace_info; + auxtrace_info, + auxtrace_error; event_op3 auxtrace; bool ordered_events; bool ordering_requires_timestamps; -- cgit v1.2.3 From c446870d80f37281a927b5f6984bd47397a7cb03 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Thu, 9 Apr 2015 18:53:48 +0300 Subject: perf session: Add hooks to allow transparent decoding of AUX area tracing data Hook into session processing so that AUX area decoding can synthesize events transparently to the tools. The advantages of transparent decoding are that tools can be used directly with perf.data files containing AUX area tracing data, which is easier for the user and more efficient than having a separate decoding tool. This will work as follows: 1. Tools will feed auxtrace events to the decoder using perf_tool->auxtrace() (support for that still to come). 2. The decoder can process side-band events as needed due to the auxtrace->process_event() hook. 3. The decoder can deliver synthesized events into the event stream using perf_session__deliver_synth_event(). Note the expectation is that decoding will work on data that is time-ordered with respect to the per-cpu or per-thread contexts that were recorded. Signed-off-by: Adrian Hunter Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1428594864-29309-9-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/auxtrace.h | 55 ++++++++++++++++++++++++++++++++++++++++++++++ tools/perf/util/session.c | 54 ++++++++++++++++++++++++++++++++++++--------- tools/perf/util/session.h | 3 +++ 3 files changed, 102 insertions(+), 10 deletions(-) (limited to 'tools/perf/util/session.c') diff --git a/tools/perf/util/auxtrace.h b/tools/perf/util/auxtrace.h index 7ab4850703f0..199fc27b3954 100644 --- a/tools/perf/util/auxtrace.h +++ b/tools/perf/util/auxtrace.h @@ -23,6 +23,7 @@ #include #include "../perf.h" +#include "session.h" union perf_event; struct perf_session; @@ -31,6 +32,24 @@ struct perf_tool; struct record_opts; struct auxtrace_info_event; +/** + * struct auxtrace - session callbacks to allow AUX area data decoding. + * @process_event: lets the decoder see all session events + * @flush_events: process any remaining data + * @free_events: free resources associated with event processing + * @free: free resources associated with the session + */ +struct auxtrace { + int (*process_event)(struct perf_session *session, + union perf_event *event, + struct perf_sample *sample, + struct perf_tool *tool); + int (*flush_events)(struct perf_session *session, + struct perf_tool *tool); + void (*free_events)(struct perf_session *session); + void (*free)(struct perf_session *session); +}; + /** * struct auxtrace_mmap - records an mmap of the auxtrace buffer. * @base: address of mapped area @@ -168,4 +187,40 @@ int perf_event__synthesize_auxtrace_info(struct auxtrace_record *itr, struct perf_session *session, perf_event__handler_t process); +static inline int auxtrace__process_event(struct perf_session *session, + union perf_event *event, + struct perf_sample *sample, + struct perf_tool *tool) +{ + if (!session->auxtrace) + return 0; + + return session->auxtrace->process_event(session, event, sample, tool); +} + +static inline int auxtrace__flush_events(struct perf_session *session, + struct perf_tool *tool) +{ + if (!session->auxtrace) + return 0; + + return session->auxtrace->flush_events(session, tool); +} + +static inline void auxtrace__free_events(struct perf_session *session) +{ + if (!session->auxtrace) + return; + + return session->auxtrace->free_events(session); +} + +static inline void auxtrace__free(struct perf_session *session) +{ + if (!session->auxtrace) + return; + + return session->auxtrace->free(session); +} + #endif diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 4008dab73424..7271c6bcb2dc 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -15,12 +15,13 @@ #include "cpumap.h" #include "perf_regs.h" #include "asm/bug.h" +#include "auxtrace.h" -static int machines__deliver_event(struct machines *machines, - struct perf_evlist *evlist, - union perf_event *event, - struct perf_sample *sample, - struct perf_tool *tool, u64 file_offset); +static int perf_session__deliver_event(struct perf_session *session, + union perf_event *event, + struct perf_sample *sample, + struct perf_tool *tool, + u64 file_offset); static int perf_session__open(struct perf_session *session) { @@ -105,8 +106,8 @@ static int ordered_events__deliver_event(struct ordered_events *oe, return ret; } - return machines__deliver_event(&session->machines, session->evlist, event->event, - &sample, session->tool, event->file_offset); + return perf_session__deliver_event(session, event->event, &sample, + session->tool, event->file_offset); } struct perf_session *perf_session__new(struct perf_data_file *file, @@ -185,6 +186,7 @@ static void perf_session_env__delete(struct perf_session_env *env) void perf_session__delete(struct perf_session *session) { + auxtrace__free(session); perf_session__destroy_kernel_maps(session); perf_session__delete_threads(session); perf_session_env__delete(&session->header.env); @@ -1030,6 +1032,24 @@ static int machines__deliver_event(struct machines *machines, } } +static int perf_session__deliver_event(struct perf_session *session, + union perf_event *event, + struct perf_sample *sample, + struct perf_tool *tool, + u64 file_offset) +{ + int ret; + + ret = auxtrace__process_event(session, event, sample, tool); + if (ret < 0) + return ret; + if (ret > 0) + return 0; + + return machines__deliver_event(&session->machines, session->evlist, + event, sample, tool, file_offset); +} + static s64 perf_session__process_user_event(struct perf_session *session, union perf_event *event, u64 file_offset) @@ -1190,8 +1210,8 @@ static s64 perf_session__process_event(struct perf_session *session, return ret; } - return machines__deliver_event(&session->machines, evlist, event, - &sample, tool, file_offset); + return perf_session__deliver_event(session, event, &sample, tool, + file_offset); } void perf_event_header__bswap(struct perf_event_header *hdr) @@ -1350,10 +1370,14 @@ more: done: /* do the final flush for ordered samples */ err = ordered_events__flush(oe, OE_FLUSH__FINAL); + if (err) + goto out_err; + err = auxtrace__flush_events(session, tool); out_err: free(buf); perf_session__warn_about_errors(session); ordered_events__free(&session->ordered_events); + auxtrace__free_events(session); return err; } @@ -1496,10 +1520,14 @@ more: out: /* do the final flush for ordered samples */ err = ordered_events__flush(oe, OE_FLUSH__FINAL); + if (err) + goto out_err; + err = auxtrace__flush_events(session, tool); out_err: ui_progress__finish(); perf_session__warn_about_errors(session); ordered_events__free(&session->ordered_events); + auxtrace__free_events(session); session->one_mmap = false; return err; } @@ -1582,7 +1610,13 @@ size_t perf_session__fprintf_dsos_buildid(struct perf_session *session, FILE *fp size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp) { - size_t ret = fprintf(fp, "Aggregated stats:\n"); + size_t ret; + const char *msg = ""; + + if (perf_header__has_feat(&session->header, HEADER_AUXTRACE)) + msg = " (excludes AUX area (e.g. instruction trace) decoded / synthesized events)"; + + ret = fprintf(fp, "Aggregated stats:%s\n", msg); ret += events_stats__fprintf(&session->evlist->stats, fp); return ret; diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index d5fa7b7916ef..8a69d3bfafdf 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h @@ -15,10 +15,13 @@ struct ip_callchain; struct thread; +struct auxtrace; + struct perf_session { struct perf_header header; struct machines machines; struct perf_evlist *evlist; + struct auxtrace *auxtrace; struct trace_event tevent; bool repipe; bool one_mmap; -- cgit v1.2.3 From 85ed47299e979b861e314c2e177a6de5d9163a85 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Thu, 9 Apr 2015 18:53:50 +0300 Subject: perf auxtrace: Add helpers for AUX area tracing errors Add functions to synthesize, count and print AUX area tracing error events. Signed-off-by: Adrian Hunter Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1428594864-29309-11-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/auxtrace.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++ tools/perf/util/auxtrace.h | 14 ++++++++ tools/perf/util/event.h | 6 ++++ tools/perf/util/session.c | 3 ++ 4 files changed, 104 insertions(+) (limited to 'tools/perf/util/session.c') diff --git a/tools/perf/util/auxtrace.c b/tools/perf/util/auxtrace.c index db40d6c6c010..905188bd1dfa 100644 --- a/tools/perf/util/auxtrace.c +++ b/tools/perf/util/auxtrace.c @@ -24,6 +24,7 @@ #include #include +#include #include #include @@ -36,6 +37,7 @@ #include "auxtrace.h" #include "event.h" +#include "session.h" #include "debug.h" #include "parse-options.h" @@ -172,6 +174,28 @@ auxtrace_record__init(struct perf_evlist *evlist __maybe_unused, int *err) return NULL; } +void auxtrace_synth_error(struct auxtrace_error_event *auxtrace_error, int type, + int code, int cpu, pid_t pid, pid_t tid, u64 ip, + const char *msg) +{ + size_t size; + + memset(auxtrace_error, 0, sizeof(struct auxtrace_error_event)); + + auxtrace_error->header.type = PERF_RECORD_AUXTRACE_ERROR; + auxtrace_error->type = type; + auxtrace_error->code = code; + auxtrace_error->cpu = cpu; + auxtrace_error->pid = pid; + auxtrace_error->tid = tid; + auxtrace_error->ip = ip; + strlcpy(auxtrace_error->msg, msg, MAX_AUXTRACE_ERROR_MSG); + + size = (void *)auxtrace_error->msg - (void *)auxtrace_error + + strlen(auxtrace_error->msg) + 1; + auxtrace_error->header.size = PERF_ALIGN(size, sizeof(u64)); +} + int perf_event__synthesize_auxtrace_info(struct auxtrace_record *itr, struct perf_tool *tool, struct perf_session *session, @@ -336,6 +360,63 @@ out_err: return -EINVAL; } +static const char * const auxtrace_error_type_name[] = { + [PERF_AUXTRACE_ERROR_ITRACE] = "instruction trace", +}; + +static const char *auxtrace_error_name(int type) +{ + const char *error_type_name = NULL; + + if (type < PERF_AUXTRACE_ERROR_MAX) + error_type_name = auxtrace_error_type_name[type]; + if (!error_type_name) + error_type_name = "unknown AUX"; + return error_type_name; +} + +size_t perf_event__fprintf_auxtrace_error(union perf_event *event, FILE *fp) +{ + struct auxtrace_error_event *e = &event->auxtrace_error; + int ret; + + ret = fprintf(fp, " %s error type %u", + auxtrace_error_name(e->type), e->type); + ret += fprintf(fp, " cpu %d pid %d tid %d ip %#"PRIx64" code %u: %s\n", + e->cpu, e->pid, e->tid, e->ip, e->code, e->msg); + return ret; +} + +void perf_session__auxtrace_error_inc(struct perf_session *session, + union perf_event *event) +{ + struct auxtrace_error_event *e = &event->auxtrace_error; + + if (e->type < PERF_AUXTRACE_ERROR_MAX) + session->evlist->stats.nr_auxtrace_errors[e->type] += 1; +} + +void events_stats__auxtrace_error_warn(const struct events_stats *stats) +{ + int i; + + for (i = 0; i < PERF_AUXTRACE_ERROR_MAX; i++) { + if (!stats->nr_auxtrace_errors[i]) + continue; + ui__warning("%u %s errors\n", + stats->nr_auxtrace_errors[i], + auxtrace_error_name(i)); + } +} + +int perf_event__process_auxtrace_error(struct perf_tool *tool __maybe_unused, + union perf_event *event, + struct perf_session *session __maybe_unused) +{ + perf_event__fprintf_auxtrace_error(event, stdout); + return 0; +} + int auxtrace_mmap__read(struct auxtrace_mmap *mm, struct auxtrace_record *itr, struct perf_tool *tool, process_auxtrace_t fn) { diff --git a/tools/perf/util/auxtrace.h b/tools/perf/util/auxtrace.h index 6355315a91fb..bcfb9288bfea 100644 --- a/tools/perf/util/auxtrace.h +++ b/tools/perf/util/auxtrace.h @@ -23,6 +23,7 @@ #include #include "../perf.h" +#include "event.h" #include "session.h" union perf_event; @@ -32,6 +33,7 @@ struct perf_tool; struct option; struct record_opts; struct auxtrace_info_event; +struct events_stats; enum itrace_period_type { PERF_ITRACE_PERIOD_INSTRUCTIONS, @@ -222,14 +224,26 @@ int auxtrace_record__info_fill(struct auxtrace_record *itr, void auxtrace_record__free(struct auxtrace_record *itr); u64 auxtrace_record__reference(struct auxtrace_record *itr); +void auxtrace_synth_error(struct auxtrace_error_event *auxtrace_error, int type, + int code, int cpu, pid_t pid, pid_t tid, u64 ip, + const char *msg); + int perf_event__synthesize_auxtrace_info(struct auxtrace_record *itr, struct perf_tool *tool, struct perf_session *session, perf_event__handler_t process); +int perf_event__process_auxtrace_error(struct perf_tool *tool, + union perf_event *event, + struct perf_session *session); int itrace_parse_synth_opts(const struct option *opt, const char *str, int unset); void itrace_synth_opts__set_default(struct itrace_synth_opts *synth_opts); +size_t perf_event__fprintf_auxtrace_error(union perf_event *event, FILE *fp); +void perf_session__auxtrace_error_inc(struct perf_session *session, + union perf_event *event); +void events_stats__auxtrace_error_warn(const struct events_stats *stats); + static inline int auxtrace__process_event(struct perf_session *session, union perf_event *event, struct perf_sample *sample, diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index 657dcfaf0389..8ef37251a7a9 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h @@ -221,6 +221,11 @@ enum perf_user_event_type { /* above any possible kernel type */ PERF_RECORD_HEADER_MAX }; +enum auxtrace_error_type { + PERF_AUXTRACE_ERROR_ITRACE = 1, + PERF_AUXTRACE_ERROR_MAX +}; + /* * The kernel collects the number of events it couldn't send in a stretch and * when possible sends this number in a PERF_RECORD_LOST event. The number of @@ -245,6 +250,7 @@ struct events_stats { u32 nr_invalid_chains; u32 nr_unknown_id; u32 nr_unprocessable_samples; + u32 nr_auxtrace_errors[PERF_AUXTRACE_ERROR_MAX]; }; struct attr_event { diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 7271c6bcb2dc..1db3ce118a54 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -1093,6 +1093,7 @@ static s64 perf_session__process_user_event(struct perf_session *session, lseek(fd, file_offset + event->header.size, SEEK_SET); return tool->auxtrace(tool, event, session); case PERF_RECORD_AUXTRACE_ERROR: + perf_session__auxtrace_error_inc(session, event); return tool->auxtrace_error(tool, event, session); default: return -EINVAL; @@ -1282,6 +1283,8 @@ static void perf_session__warn_about_errors(const struct perf_session *session) if (oe->nr_unordered_events != 0) ui__warning("%u out of order events recorded.\n", oe->nr_unordered_events); + + events_stats__auxtrace_error_warn(stats); } volatile int session_done; -- cgit v1.2.3 From 70d73de4cd571df09670e2a7bf36a912e9ff5138 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Thu, 9 Apr 2015 18:54:06 +0300 Subject: perf tools: Add aux_watermark member of struct perf_event_attr Add new AUX area member (aux_watermark) of struct perf_event_attr to debug prints and byte swapping. Signed-off-by: Adrian Hunter Cc: David Ahern Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1428594864-29309-27-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/evsel.c | 1 + tools/perf/util/session.c | 1 + 2 files changed, 2 insertions(+) (limited to 'tools/perf/util/session.c') diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 33e3fd8c2e68..c886b9f7a48d 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -1121,6 +1121,7 @@ int perf_event_attr__fprintf(FILE *fp, struct perf_event_attr *attr, PRINT_ATTRf(sample_stack_user, p_unsigned); PRINT_ATTRf(clockid, p_signed); PRINT_ATTRf(sample_regs_intr, p_hex); + PRINT_ATTRf(aux_watermark, p_unsigned); return ret; } diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 1db3ce118a54..90fa5674ccb4 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -500,6 +500,7 @@ void perf_event__attr_swap(struct perf_event_attr *attr) attr->branch_sample_type = bswap_64(attr->branch_sample_type); attr->sample_regs_user = bswap_64(attr->sample_regs_user); attr->sample_stack_user = bswap_32(attr->sample_stack_user); + attr->aux_watermark = bswap_32(attr->aux_watermark); swap_bitfield((u8 *) (&attr->read_format + 1), sizeof(u64)); } -- cgit v1.2.3 From 99fa298453495ee23801ab500a5fe0138c260edb Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Thu, 30 Apr 2015 17:37:25 +0300 Subject: perf tools: Add AUX area tracing index Add an index of AUX area tracing events within a perf.data file. perf record uses a special user event PERF_RECORD_FINISHED_ROUND to enable sorting of events in chunks instead of having to sort all events altogether. AUX area tracing events contain data that can span back to the very beginning of the recording period. i.e. they do not obey the rules of PERF_RECORD_FINISHED_ROUND. By adding an index, AUX area tracing events can be found in advance and the PERF_RECORD_FINISHED_ROUND approach works as usual. The index is recorded with the auxtrace feature in the perf.data file. A session reads the index but does not process it. An AUX area decoder can queue all the AUX area data in advance using auxtrace_queues__process_index() or otherwise process the index in some custom manner. Signed-off-by: Adrian Hunter Acked-by: Jiri Olsa Cc: David Ahern Cc: Frederic Weisbecker Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1430404667-10593-3-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-inject.c | 15 ++++ tools/perf/builtin-record.c | 15 ++++ tools/perf/util/auxtrace.c | 215 ++++++++++++++++++++++++++++++++++++++++++++ tools/perf/util/auxtrace.h | 35 ++++++++ tools/perf/util/header.c | 31 ++++++- tools/perf/util/session.c | 2 + tools/perf/util/session.h | 1 + 7 files changed, 310 insertions(+), 4 deletions(-) (limited to 'tools/perf/util/session.c') diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c index c5f6515f0723..6d4bbde066fd 100644 --- a/tools/perf/builtin-inject.c +++ b/tools/perf/builtin-inject.c @@ -122,6 +122,18 @@ static s64 perf_event__repipe_auxtrace(struct perf_tool *tool, tool); int ret; + if (!inject->output.is_pipe) { + off_t offset; + + offset = lseek(inject->output.fd, 0, SEEK_CUR); + if (offset == -1) + return -errno; + ret = auxtrace_index__auxtrace_event(&session->auxtrace_index, + event, offset); + if (ret < 0) + return ret; + } + if (perf_data_file__is_pipe(session->file) || !session->one_mmap) { ret = output_bytes(inject, event, event->header.size); if (ret < 0) @@ -487,6 +499,9 @@ static int __cmd_inject(struct perf_inject *inject) output_data_offset = 4096; } + if (!inject->itrace_synth_opts.set) + auxtrace_index__free(&session->auxtrace_index); + if (!file_out->is_pipe) lseek(fd, output_data_offset, SEEK_SET); diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 4c9aaa1f688a..c8c784c430b6 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -117,9 +117,24 @@ static int record__process_auxtrace(struct perf_tool *tool, size_t len1, void *data2, size_t len2) { struct record *rec = container_of(tool, struct record, tool); + struct perf_data_file *file = &rec->file; size_t padding; u8 pad[8] = {0}; + if (!perf_data_file__is_pipe(file)) { + off_t file_offset; + int fd = perf_data_file__fd(file); + int err; + + file_offset = lseek(fd, 0, SEEK_CUR); + if (file_offset == -1) + return -1; + err = auxtrace_index__auxtrace_event(&rec->session->auxtrace_index, + event, file_offset); + if (err) + return err; + } + /* event.auxtrace.size includes padding, see __auxtrace_mmap__read() */ padding = (len1 + len2) & 7; if (padding) diff --git a/tools/perf/util/auxtrace.c b/tools/perf/util/auxtrace.c index 3cd89eca1e88..28ce134a61ad 100644 --- a/tools/perf/util/auxtrace.c +++ b/tools/perf/util/auxtrace.c @@ -344,6 +344,33 @@ out_err: return err; } +static int auxtrace_queues__add_indexed_event(struct auxtrace_queues *queues, + struct perf_session *session, + off_t file_offset, size_t sz) +{ + union perf_event *event; + int err; + char buf[PERF_SAMPLE_MAX_SIZE]; + + err = perf_session__peek_event(session, file_offset, buf, + PERF_SAMPLE_MAX_SIZE, &event, NULL); + if (err) + return err; + + if (event->header.type == PERF_RECORD_AUXTRACE) { + if (event->header.size < sizeof(struct auxtrace_event) || + event->header.size != sz) { + err = -EINVAL; + goto out; + } + file_offset += event->header.size; + err = auxtrace_queues__add_event(queues, session, event, + file_offset, NULL); + } +out: + return err; +} + void auxtrace_queues__free(struct auxtrace_queues *queues) { unsigned int i; @@ -500,6 +527,194 @@ auxtrace_record__init(struct perf_evlist *evlist __maybe_unused, int *err) return NULL; } +static int auxtrace_index__alloc(struct list_head *head) +{ + struct auxtrace_index *auxtrace_index; + + auxtrace_index = malloc(sizeof(struct auxtrace_index)); + if (!auxtrace_index) + return -ENOMEM; + + auxtrace_index->nr = 0; + INIT_LIST_HEAD(&auxtrace_index->list); + + list_add_tail(&auxtrace_index->list, head); + + return 0; +} + +void auxtrace_index__free(struct list_head *head) +{ + struct auxtrace_index *auxtrace_index, *n; + + list_for_each_entry_safe(auxtrace_index, n, head, list) { + list_del(&auxtrace_index->list); + free(auxtrace_index); + } +} + +static struct auxtrace_index *auxtrace_index__last(struct list_head *head) +{ + struct auxtrace_index *auxtrace_index; + int err; + + if (list_empty(head)) { + err = auxtrace_index__alloc(head); + if (err) + return NULL; + } + + auxtrace_index = list_entry(head->prev, struct auxtrace_index, list); + + if (auxtrace_index->nr >= PERF_AUXTRACE_INDEX_ENTRY_COUNT) { + err = auxtrace_index__alloc(head); + if (err) + return NULL; + auxtrace_index = list_entry(head->prev, struct auxtrace_index, + list); + } + + return auxtrace_index; +} + +int auxtrace_index__auxtrace_event(struct list_head *head, + union perf_event *event, off_t file_offset) +{ + struct auxtrace_index *auxtrace_index; + size_t nr; + + auxtrace_index = auxtrace_index__last(head); + if (!auxtrace_index) + return -ENOMEM; + + nr = auxtrace_index->nr; + auxtrace_index->entries[nr].file_offset = file_offset; + auxtrace_index->entries[nr].sz = event->header.size; + auxtrace_index->nr += 1; + + return 0; +} + +static int auxtrace_index__do_write(int fd, + struct auxtrace_index *auxtrace_index) +{ + struct auxtrace_index_entry ent; + size_t i; + + for (i = 0; i < auxtrace_index->nr; i++) { + ent.file_offset = auxtrace_index->entries[i].file_offset; + ent.sz = auxtrace_index->entries[i].sz; + if (writen(fd, &ent, sizeof(ent)) != sizeof(ent)) + return -errno; + } + return 0; +} + +int auxtrace_index__write(int fd, struct list_head *head) +{ + struct auxtrace_index *auxtrace_index; + u64 total = 0; + int err; + + list_for_each_entry(auxtrace_index, head, list) + total += auxtrace_index->nr; + + if (writen(fd, &total, sizeof(total)) != sizeof(total)) + return -errno; + + list_for_each_entry(auxtrace_index, head, list) { + err = auxtrace_index__do_write(fd, auxtrace_index); + if (err) + return err; + } + + return 0; +} + +static int auxtrace_index__process_entry(int fd, struct list_head *head, + bool needs_swap) +{ + struct auxtrace_index *auxtrace_index; + struct auxtrace_index_entry ent; + size_t nr; + + if (readn(fd, &ent, sizeof(ent)) != sizeof(ent)) + return -1; + + auxtrace_index = auxtrace_index__last(head); + if (!auxtrace_index) + return -1; + + nr = auxtrace_index->nr; + if (needs_swap) { + auxtrace_index->entries[nr].file_offset = + bswap_64(ent.file_offset); + auxtrace_index->entries[nr].sz = bswap_64(ent.sz); + } else { + auxtrace_index->entries[nr].file_offset = ent.file_offset; + auxtrace_index->entries[nr].sz = ent.sz; + } + + auxtrace_index->nr = nr + 1; + + return 0; +} + +int auxtrace_index__process(int fd, u64 size, struct perf_session *session, + bool needs_swap) +{ + struct list_head *head = &session->auxtrace_index; + u64 nr; + + if (readn(fd, &nr, sizeof(u64)) != sizeof(u64)) + return -1; + + if (needs_swap) + nr = bswap_64(nr); + + if (sizeof(u64) + nr * sizeof(struct auxtrace_index_entry) > size) + return -1; + + while (nr--) { + int err; + + err = auxtrace_index__process_entry(fd, head, needs_swap); + if (err) + return -1; + } + + return 0; +} + +static int auxtrace_queues__process_index_entry(struct auxtrace_queues *queues, + struct perf_session *session, + struct auxtrace_index_entry *ent) +{ + return auxtrace_queues__add_indexed_event(queues, session, + ent->file_offset, ent->sz); +} + +int auxtrace_queues__process_index(struct auxtrace_queues *queues, + struct perf_session *session) +{ + struct auxtrace_index *auxtrace_index; + struct auxtrace_index_entry *ent; + size_t i; + int err; + + list_for_each_entry(auxtrace_index, &session->auxtrace_index, list) { + for (i = 0; i < auxtrace_index->nr; i++) { + ent = &auxtrace_index->entries[i]; + err = auxtrace_queues__process_index_entry(queues, + session, + ent); + if (err) + return err; + } + } + return 0; +} + struct auxtrace_buffer *auxtrace_buffer__next(struct auxtrace_queue *queue, struct auxtrace_buffer *buffer) { diff --git a/tools/perf/util/auxtrace.h b/tools/perf/util/auxtrace.h index 53b60a64a693..b9e4b9d66f5e 100644 --- a/tools/perf/util/auxtrace.h +++ b/tools/perf/util/auxtrace.h @@ -79,6 +79,32 @@ struct itrace_synth_opts { enum itrace_period_type period_type; }; +/** + * struct auxtrace_index_entry - indexes a AUX area tracing event within a + * perf.data file. + * @file_offset: offset within the perf.data file + * @sz: size of the event + */ +struct auxtrace_index_entry { + u64 file_offset; + u64 sz; +}; + +#define PERF_AUXTRACE_INDEX_ENTRY_COUNT 256 + +/** + * struct auxtrace_index - index of AUX area tracing events within a perf.data + * file. + * @list: linking a number of arrays of entries + * @nr: number of entries + * @entries: array of entries + */ +struct auxtrace_index { + struct list_head list; + size_t nr; + struct auxtrace_index_entry entries[PERF_AUXTRACE_INDEX_ENTRY_COUNT]; +}; + /** * struct auxtrace - session callbacks to allow AUX area data decoding. * @process_event: lets the decoder see all session events @@ -321,6 +347,8 @@ int auxtrace_queues__add_event(struct auxtrace_queues *queues, union perf_event *event, off_t data_offset, struct auxtrace_buffer **buffer_ptr); void auxtrace_queues__free(struct auxtrace_queues *queues); +int auxtrace_queues__process_index(struct auxtrace_queues *queues, + struct perf_session *session); struct auxtrace_buffer *auxtrace_buffer__next(struct auxtrace_queue *queue, struct auxtrace_buffer *buffer); void *auxtrace_buffer__get_data(struct auxtrace_buffer *buffer, int fd); @@ -361,6 +389,13 @@ int auxtrace_record__info_fill(struct auxtrace_record *itr, void auxtrace_record__free(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, + off_t file_offset); +int auxtrace_index__write(int fd, struct list_head *head); +int auxtrace_index__process(int fd, u64 size, struct perf_session *session, + bool needs_swap); +void auxtrace_index__free(struct list_head *head); + void auxtrace_synth_error(struct auxtrace_error_event *auxtrace_error, int type, int code, int cpu, pid_t pid, pid_t tid, u64 ip, const char *msg); diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 589c28028379..3f0d809d853a 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -869,11 +869,18 @@ static int write_branch_stack(int fd __maybe_unused, return 0; } -static int write_auxtrace(int fd __maybe_unused, - struct perf_header *h __maybe_unused, +static int write_auxtrace(int fd, struct perf_header *h, struct perf_evlist *evlist __maybe_unused) { - return 0; + struct perf_session *session; + int err; + + session = container_of(h, struct perf_session, header); + + err = auxtrace_index__write(fd, &session->auxtrace_index); + if (err < 0) + pr_err("Failed to write auxtrace index\n"); + return err; } static void print_hostname(struct perf_header *ph, int fd __maybe_unused, @@ -1834,6 +1841,22 @@ out_free: return ret; } +static int process_auxtrace(struct perf_file_section *section, + struct perf_header *ph, int fd, + void *data __maybe_unused) +{ + struct perf_session *session; + int err; + + session = container_of(ph, struct perf_session, header); + + err = auxtrace_index__process(fd, section->size, session, + ph->needs_swap); + if (err < 0) + pr_err("Failed to process auxtrace index\n"); + return err; +} + struct feature_ops { int (*write)(int fd, struct perf_header *h, struct perf_evlist *evlist); void (*print)(struct perf_header *h, int fd, FILE *fp); @@ -1874,7 +1897,7 @@ static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = { FEAT_OPA(HEADER_BRANCH_STACK, branch_stack), FEAT_OPP(HEADER_PMU_MAPPINGS, pmu_mappings), FEAT_OPP(HEADER_GROUP_DESC, group_desc), - FEAT_OPA(HEADER_AUXTRACE, auxtrace), + FEAT_OPP(HEADER_AUXTRACE, auxtrace), }; struct header_print_data { diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 90fa5674ccb4..b6972b118bc2 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -120,6 +120,7 @@ struct perf_session *perf_session__new(struct perf_data_file *file, session->repipe = repipe; session->tool = tool; + INIT_LIST_HEAD(&session->auxtrace_index); machines__init(&session->machines); ordered_events__init(&session->ordered_events, ordered_events__deliver_event); @@ -187,6 +188,7 @@ static void perf_session_env__delete(struct perf_session_env *env) void perf_session__delete(struct perf_session *session) { auxtrace__free(session); + auxtrace_index__free(&session->auxtrace_index); perf_session__destroy_kernel_maps(session); perf_session__delete_threads(session); perf_session_env__delete(&session->header.env); diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index 9ed51353a3d7..b44afc75d1cc 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h @@ -24,6 +24,7 @@ struct perf_session { struct perf_evlist *evlist; struct auxtrace *auxtrace; struct itrace_synth_opts *itrace_synth_opts; + struct list_head auxtrace_index; struct trace_event tevent; bool repipe; bool one_mmap; -- cgit v1.2.3 From 4a96f7a02eb52b1b618ab610e689bd82770f00b0 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Thu, 30 Apr 2015 17:37:29 +0300 Subject: perf tools: Add support for PERF_RECORD_AUX Add support for the PERF_RECORD_AUX event type. PERF_RECORD_AUX is a new kernel event that records when new data lands in the AUX buffer. Currently it is assumed that AUX data follows the same ring buffer conventions used by the perf events buffer, and consequently the AUX event is not processed during recording. It is processed during session processing so that the information in the 'flags' member is made available. The format of PERF_RECORD_AUX is outlined in the linux/perf_events.h header file. The 'flags' are also enumerated. Intel PT and Intel BTS use the flag named PERF_AUX_FLAG_TRUNCATED to determine if data has been lost because the buffer became full as perf was not able to empty it fast enough. Signed-off-by: Adrian Hunter Acked-by: Jiri Olsa Cc: David Ahern Cc: Frederic Weisbecker Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1430404667-10593-7-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-inject.c | 1 + tools/perf/util/event.c | 21 +++++++++++++++++++++ tools/perf/util/event.h | 13 +++++++++++++ tools/perf/util/machine.c | 10 ++++++++++ tools/perf/util/machine.h | 2 ++ tools/perf/util/session.c | 15 +++++++++++++++ tools/perf/util/tool.h | 1 + 7 files changed, 63 insertions(+) (limited to 'tools/perf/util/session.c') diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c index 7c7a7eea900d..3e8f730c7dee 100644 --- a/tools/perf/builtin-inject.c +++ b/tools/perf/builtin-inject.c @@ -558,6 +558,7 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused) .fork = perf_event__repipe, .exit = perf_event__repipe, .lost = perf_event__repipe, + .aux = perf_event__repipe, .read = perf_event__repipe_sample, .throttle = perf_event__repipe, .unthrottle = perf_event__repipe, diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 32323e5d7b25..724ffde8e7d7 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -23,6 +23,7 @@ static const char *perf_event__names[] = { [PERF_RECORD_FORK] = "FORK", [PERF_RECORD_READ] = "READ", [PERF_RECORD_SAMPLE] = "SAMPLE", + [PERF_RECORD_AUX] = "AUX", [PERF_RECORD_HEADER_ATTR] = "ATTR", [PERF_RECORD_HEADER_EVENT_TYPE] = "EVENT_TYPE", [PERF_RECORD_HEADER_TRACING_DATA] = "TRACING_DATA", @@ -695,6 +696,14 @@ int perf_event__process_lost(struct perf_tool *tool __maybe_unused, return machine__process_lost_event(machine, event, sample); } +int perf_event__process_aux(struct perf_tool *tool __maybe_unused, + union perf_event *event, + struct perf_sample *sample __maybe_unused, + struct machine *machine) +{ + return machine__process_aux_event(machine, event); +} + size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp) { return fprintf(fp, " %d/%d: [%#" PRIx64 "(%#" PRIx64 ") @ %#" PRIx64 "]: %c %s\n", @@ -758,6 +767,15 @@ int perf_event__process_exit(struct perf_tool *tool __maybe_unused, return machine__process_exit_event(machine, event, sample); } +size_t perf_event__fprintf_aux(union perf_event *event, FILE *fp) +{ + return fprintf(fp, " offset: %#"PRIx64" size: %#"PRIx64" flags: %#"PRIx64" [%s%s]\n", + event->aux.aux_offset, event->aux.aux_size, + event->aux.flags, + event->aux.flags & PERF_AUX_FLAG_TRUNCATED ? "T" : "", + event->aux.flags & PERF_AUX_FLAG_OVERWRITE ? "O" : ""); +} + size_t perf_event__fprintf(union perf_event *event, FILE *fp) { size_t ret = fprintf(fp, "PERF_RECORD_%s", @@ -777,6 +795,9 @@ size_t perf_event__fprintf(union perf_event *event, FILE *fp) case PERF_RECORD_MMAP2: ret += perf_event__fprintf_mmap2(event, fp); break; + case PERF_RECORD_AUX: + ret += perf_event__fprintf_aux(event, fp); + break; default: ret += fprintf(fp, "\n"); } diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index 80e9f5969a39..b3c350ed4768 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h @@ -323,6 +323,13 @@ struct auxtrace_error_event { char msg[MAX_AUXTRACE_ERROR_MSG]; }; +struct aux_event { + struct perf_event_header header; + u64 aux_offset; + u64 aux_size; + u64 flags; +}; + union perf_event { struct perf_event_header header; struct mmap_event mmap; @@ -341,6 +348,7 @@ union perf_event { struct auxtrace_info_event auxtrace_info; struct auxtrace_event auxtrace; struct auxtrace_error_event auxtrace_error; + struct aux_event aux; }; void perf_event__print_totals(void); @@ -376,6 +384,10 @@ int perf_event__process_lost(struct perf_tool *tool, union perf_event *event, struct perf_sample *sample, struct machine *machine); +int perf_event__process_aux(struct perf_tool *tool, + union perf_event *event, + struct perf_sample *sample, + struct machine *machine); int perf_event__process_mmap(struct perf_tool *tool, union perf_event *event, struct perf_sample *sample, @@ -433,6 +445,7 @@ size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp); size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp); size_t perf_event__fprintf_mmap2(union perf_event *event, FILE *fp); size_t perf_event__fprintf_task(union perf_event *event, FILE *fp); +size_t perf_event__fprintf_aux(union perf_event *event, FILE *fp); size_t perf_event__fprintf(union perf_event *event, FILE *fp); u64 kallsyms__get_function_start(const char *kallsyms_filename, diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index 527e032e24f6..a7ad51100b55 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c @@ -486,6 +486,14 @@ machine__module_dso(struct machine *machine, struct kmod_path *m, return dso; } +int machine__process_aux_event(struct machine *machine __maybe_unused, + union perf_event *event) +{ + if (dump_trace) + perf_event__fprintf_aux(event, stdout); + return 0; +} + struct map *machine__new_module(struct machine *machine, u64 start, const char *filename) { @@ -1331,6 +1339,8 @@ int machine__process_event(struct machine *machine, union perf_event *event, ret = machine__process_exit_event(machine, event, sample); break; case PERF_RECORD_LOST: ret = machine__process_lost_event(machine, event, sample); break; + case PERF_RECORD_AUX: + ret = machine__process_aux_event(machine, event); break; default: ret = -1; break; diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h index 6d64cedb9d1e..fc5432aa66b5 100644 --- a/tools/perf/util/machine.h +++ b/tools/perf/util/machine.h @@ -81,6 +81,8 @@ int machine__process_fork_event(struct machine *machine, union perf_event *event struct perf_sample *sample); int machine__process_lost_event(struct machine *machine, union perf_event *event, struct perf_sample *sample); +int machine__process_aux_event(struct machine *machine, + union perf_event *event); int machine__process_mmap_event(struct machine *machine, union perf_event *event, struct perf_sample *sample); int machine__process_mmap2_event(struct machine *machine, union perf_event *event, diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index b6972b118bc2..0b4646cd5245 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -325,6 +325,8 @@ void perf_tool__fill_defaults(struct perf_tool *tool) tool->exit = process_event_stub; if (tool->lost == NULL) tool->lost = perf_event__process_lost; + if (tool->aux == NULL) + tool->aux = perf_event__process_aux; if (tool->read == NULL) tool->read = process_event_sample_stub; if (tool->throttle == NULL) @@ -443,6 +445,16 @@ static void perf_event__read_swap(union perf_event *event, bool sample_id_all) swap_sample_id_all(event, &event->read + 1); } +static void perf_event__aux_swap(union perf_event *event, bool sample_id_all) +{ + event->aux.aux_offset = bswap_64(event->aux.aux_offset); + event->aux.aux_size = bswap_64(event->aux.aux_size); + event->aux.flags = bswap_64(event->aux.flags); + + if (sample_id_all) + swap_sample_id_all(event, &event->aux + 1); +} + static void perf_event__throttle_swap(union perf_event *event, bool sample_id_all) { @@ -580,6 +592,7 @@ static perf_event__swap_op perf_event__swap_ops[] = { [PERF_RECORD_THROTTLE] = perf_event__throttle_swap, [PERF_RECORD_UNTHROTTLE] = perf_event__throttle_swap, [PERF_RECORD_SAMPLE] = perf_event__all64_swap, + [PERF_RECORD_AUX] = perf_event__aux_swap, [PERF_RECORD_HEADER_ATTR] = perf_event__hdr_attr_swap, [PERF_RECORD_HEADER_EVENT_TYPE] = perf_event__event_type_swap, [PERF_RECORD_HEADER_TRACING_DATA] = perf_event__tracing_data_swap, @@ -1029,6 +1042,8 @@ static int machines__deliver_event(struct machines *machines, return tool->throttle(tool, event, sample, machine); case PERF_RECORD_UNTHROTTLE: return tool->unthrottle(tool, event, sample, machine); + case PERF_RECORD_AUX: + return tool->aux(tool, event, sample, machine); default: ++evlist->stats.nr_unknown_events; return -1; diff --git a/tools/perf/util/tool.h b/tools/perf/util/tool.h index 20afe19a8eb0..8288caf0836e 100644 --- a/tools/perf/util/tool.h +++ b/tools/perf/util/tool.h @@ -43,6 +43,7 @@ struct perf_tool { fork, exit, lost, + aux, throttle, unthrottle; event_attr_op attr; -- cgit v1.2.3 From 0ad21f6869222fd7fd7c63f02febea082e801fc2 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Thu, 30 Apr 2015 17:37:30 +0300 Subject: perf tools: Add support for PERF_RECORD_ITRACE_START Add support for the PERF_RECORD_ITRACE_START event type. This event can be used to determine the pid and tid that are running when Instruction Tracing starts. Generally that information would come from a sched_switch event but, at the start, no sched_switch events may yet have been recorded. Signed-off-by: Adrian Hunter Acked-by: Jiri Olsa Cc: David Ahern Cc: Frederic Weisbecker Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1430404667-10593-8-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-inject.c | 1 + tools/perf/util/event.c | 18 ++++++++++++++++++ tools/perf/util/event.h | 11 +++++++++++ tools/perf/util/machine.c | 11 +++++++++++ tools/perf/util/machine.h | 2 ++ tools/perf/util/session.c | 15 +++++++++++++++ tools/perf/util/tool.h | 1 + 7 files changed, 59 insertions(+) (limited to 'tools/perf/util/session.c') diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c index 3e8f730c7dee..d6a47e854b2b 100644 --- a/tools/perf/builtin-inject.c +++ b/tools/perf/builtin-inject.c @@ -559,6 +559,7 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused) .exit = perf_event__repipe, .lost = perf_event__repipe, .aux = perf_event__repipe, + .itrace_start = perf_event__repipe, .read = perf_event__repipe_sample, .throttle = perf_event__repipe, .unthrottle = perf_event__repipe, diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 724ffde8e7d7..db526091f580 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -24,6 +24,7 @@ static const char *perf_event__names[] = { [PERF_RECORD_READ] = "READ", [PERF_RECORD_SAMPLE] = "SAMPLE", [PERF_RECORD_AUX] = "AUX", + [PERF_RECORD_ITRACE_START] = "ITRACE_START", [PERF_RECORD_HEADER_ATTR] = "ATTR", [PERF_RECORD_HEADER_EVENT_TYPE] = "EVENT_TYPE", [PERF_RECORD_HEADER_TRACING_DATA] = "TRACING_DATA", @@ -704,6 +705,14 @@ int perf_event__process_aux(struct perf_tool *tool __maybe_unused, return machine__process_aux_event(machine, event); } +int perf_event__process_itrace_start(struct perf_tool *tool __maybe_unused, + union perf_event *event, + struct perf_sample *sample __maybe_unused, + struct machine *machine) +{ + return machine__process_itrace_start_event(machine, event); +} + size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp) { return fprintf(fp, " %d/%d: [%#" PRIx64 "(%#" PRIx64 ") @ %#" PRIx64 "]: %c %s\n", @@ -776,6 +785,12 @@ size_t perf_event__fprintf_aux(union perf_event *event, FILE *fp) event->aux.flags & PERF_AUX_FLAG_OVERWRITE ? "O" : ""); } +size_t perf_event__fprintf_itrace_start(union perf_event *event, FILE *fp) +{ + return fprintf(fp, " pid: %u tid: %u\n", + event->itrace_start.pid, event->itrace_start.tid); +} + size_t perf_event__fprintf(union perf_event *event, FILE *fp) { size_t ret = fprintf(fp, "PERF_RECORD_%s", @@ -798,6 +813,9 @@ size_t perf_event__fprintf(union perf_event *event, FILE *fp) case PERF_RECORD_AUX: ret += perf_event__fprintf_aux(event, fp); break; + case PERF_RECORD_ITRACE_START: + ret += perf_event__fprintf_itrace_start(event, fp); + break; default: ret += fprintf(fp, "\n"); } diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index b3c350ed4768..7eecd5e23d77 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h @@ -330,6 +330,11 @@ struct aux_event { u64 flags; }; +struct itrace_start_event { + struct perf_event_header header; + u32 pid, tid; +}; + union perf_event { struct perf_event_header header; struct mmap_event mmap; @@ -349,6 +354,7 @@ union perf_event { struct auxtrace_event auxtrace; struct auxtrace_error_event auxtrace_error; struct aux_event aux; + struct itrace_start_event itrace_start; }; void perf_event__print_totals(void); @@ -388,6 +394,10 @@ int perf_event__process_aux(struct perf_tool *tool, union perf_event *event, struct perf_sample *sample, struct machine *machine); +int perf_event__process_itrace_start(struct perf_tool *tool, + union perf_event *event, + struct perf_sample *sample, + struct machine *machine); int perf_event__process_mmap(struct perf_tool *tool, union perf_event *event, struct perf_sample *sample, @@ -446,6 +456,7 @@ size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp); size_t perf_event__fprintf_mmap2(union perf_event *event, FILE *fp); size_t perf_event__fprintf_task(union perf_event *event, FILE *fp); size_t perf_event__fprintf_aux(union perf_event *event, FILE *fp); +size_t perf_event__fprintf_itrace_start(union perf_event *event, FILE *fp); size_t perf_event__fprintf(union perf_event *event, FILE *fp); u64 kallsyms__get_function_start(const char *kallsyms_filename, diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index a7ad51100b55..2f471105efb1 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c @@ -494,6 +494,14 @@ int machine__process_aux_event(struct machine *machine __maybe_unused, return 0; } +int machine__process_itrace_start_event(struct machine *machine __maybe_unused, + union perf_event *event) +{ + if (dump_trace) + perf_event__fprintf_itrace_start(event, stdout); + return 0; +} + struct map *machine__new_module(struct machine *machine, u64 start, const char *filename) { @@ -1341,6 +1349,9 @@ int machine__process_event(struct machine *machine, union perf_event *event, ret = machine__process_lost_event(machine, event, sample); break; case PERF_RECORD_AUX: ret = machine__process_aux_event(machine, event); break; + case PERF_RECORD_ITRACE_START: + ret = machine__process_itrace_start_event(machine, event); + break; default: ret = -1; break; diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h index fc5432aa66b5..1d992961d5d1 100644 --- a/tools/perf/util/machine.h +++ b/tools/perf/util/machine.h @@ -83,6 +83,8 @@ int machine__process_lost_event(struct machine *machine, union perf_event *event struct perf_sample *sample); int machine__process_aux_event(struct machine *machine, union perf_event *event); +int machine__process_itrace_start_event(struct machine *machine, + union perf_event *event); int machine__process_mmap_event(struct machine *machine, union perf_event *event, struct perf_sample *sample); int machine__process_mmap2_event(struct machine *machine, union perf_event *event, diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 0b4646cd5245..e722107f932a 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -327,6 +327,8 @@ void perf_tool__fill_defaults(struct perf_tool *tool) tool->lost = perf_event__process_lost; if (tool->aux == NULL) tool->aux = perf_event__process_aux; + if (tool->itrace_start == NULL) + tool->itrace_start = perf_event__process_itrace_start; if (tool->read == NULL) tool->read = process_event_sample_stub; if (tool->throttle == NULL) @@ -455,6 +457,16 @@ static void perf_event__aux_swap(union perf_event *event, bool sample_id_all) swap_sample_id_all(event, &event->aux + 1); } +static void perf_event__itrace_start_swap(union perf_event *event, + bool sample_id_all) +{ + event->itrace_start.pid = bswap_32(event->itrace_start.pid); + event->itrace_start.tid = bswap_32(event->itrace_start.tid); + + if (sample_id_all) + swap_sample_id_all(event, &event->itrace_start + 1); +} + static void perf_event__throttle_swap(union perf_event *event, bool sample_id_all) { @@ -593,6 +605,7 @@ static perf_event__swap_op perf_event__swap_ops[] = { [PERF_RECORD_UNTHROTTLE] = perf_event__throttle_swap, [PERF_RECORD_SAMPLE] = perf_event__all64_swap, [PERF_RECORD_AUX] = perf_event__aux_swap, + [PERF_RECORD_ITRACE_START] = perf_event__itrace_start_swap, [PERF_RECORD_HEADER_ATTR] = perf_event__hdr_attr_swap, [PERF_RECORD_HEADER_EVENT_TYPE] = perf_event__event_type_swap, [PERF_RECORD_HEADER_TRACING_DATA] = perf_event__tracing_data_swap, @@ -1044,6 +1057,8 @@ static int machines__deliver_event(struct machines *machines, return tool->unthrottle(tool, event, sample, machine); case PERF_RECORD_AUX: return tool->aux(tool, event, sample, machine); + case PERF_RECORD_ITRACE_START: + return tool->itrace_start(tool, event, sample, machine); default: ++evlist->stats.nr_unknown_events; return -1; diff --git a/tools/perf/util/tool.h b/tools/perf/util/tool.h index 8288caf0836e..7f282ad1d2bd 100644 --- a/tools/perf/util/tool.h +++ b/tools/perf/util/tool.h @@ -44,6 +44,7 @@ struct perf_tool { exit, lost, aux, + itrace_start, throttle, unthrottle; event_attr_op attr; -- cgit v1.2.3