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

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: default avatarAdrian Hunter <adrian.hunter@intel.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Jiri Olsa <jolsa@redhat.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/1428594864-29309-9-git-send-email-adrian.hunter@intel.comSigned-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent e9bf54d2
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include <linux/types.h> #include <linux/types.h>
#include "../perf.h" #include "../perf.h"
#include "session.h"
union perf_event; union perf_event;
struct perf_session; struct perf_session;
...@@ -31,6 +32,24 @@ struct perf_tool; ...@@ -31,6 +32,24 @@ struct perf_tool;
struct record_opts; struct record_opts;
struct auxtrace_info_event; 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. * struct auxtrace_mmap - records an mmap of the auxtrace buffer.
* @base: address of mapped area * @base: address of mapped area
...@@ -168,4 +187,40 @@ int perf_event__synthesize_auxtrace_info(struct auxtrace_record *itr, ...@@ -168,4 +187,40 @@ int perf_event__synthesize_auxtrace_info(struct auxtrace_record *itr,
struct perf_session *session, struct perf_session *session,
perf_event__handler_t process); 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 #endif
...@@ -15,12 +15,13 @@ ...@@ -15,12 +15,13 @@
#include "cpumap.h" #include "cpumap.h"
#include "perf_regs.h" #include "perf_regs.h"
#include "asm/bug.h" #include "asm/bug.h"
#include "auxtrace.h"
static int machines__deliver_event(struct machines *machines, static int perf_session__deliver_event(struct perf_session *session,
struct perf_evlist *evlist,
union perf_event *event, union perf_event *event,
struct perf_sample *sample, struct perf_sample *sample,
struct perf_tool *tool, u64 file_offset); struct perf_tool *tool,
u64 file_offset);
static int perf_session__open(struct perf_session *session) static int perf_session__open(struct perf_session *session)
{ {
...@@ -105,8 +106,8 @@ static int ordered_events__deliver_event(struct ordered_events *oe, ...@@ -105,8 +106,8 @@ static int ordered_events__deliver_event(struct ordered_events *oe,
return ret; return ret;
} }
return machines__deliver_event(&session->machines, session->evlist, event->event, return perf_session__deliver_event(session, event->event, &sample,
&sample, session->tool, event->file_offset); session->tool, event->file_offset);
} }
struct perf_session *perf_session__new(struct perf_data_file *file, 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) ...@@ -185,6 +186,7 @@ static void perf_session_env__delete(struct perf_session_env *env)
void perf_session__delete(struct perf_session *session) void perf_session__delete(struct perf_session *session)
{ {
auxtrace__free(session);
perf_session__destroy_kernel_maps(session); perf_session__destroy_kernel_maps(session);
perf_session__delete_threads(session); perf_session__delete_threads(session);
perf_session_env__delete(&session->header.env); perf_session_env__delete(&session->header.env);
...@@ -1030,6 +1032,24 @@ static int machines__deliver_event(struct machines *machines, ...@@ -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, static s64 perf_session__process_user_event(struct perf_session *session,
union perf_event *event, union perf_event *event,
u64 file_offset) u64 file_offset)
...@@ -1190,8 +1210,8 @@ static s64 perf_session__process_event(struct perf_session *session, ...@@ -1190,8 +1210,8 @@ static s64 perf_session__process_event(struct perf_session *session,
return ret; return ret;
} }
return machines__deliver_event(&session->machines, evlist, event, return perf_session__deliver_event(session, event, &sample, tool,
&sample, tool, file_offset); file_offset);
} }
void perf_event_header__bswap(struct perf_event_header *hdr) void perf_event_header__bswap(struct perf_event_header *hdr)
...@@ -1350,10 +1370,14 @@ static int __perf_session__process_pipe_events(struct perf_session *session) ...@@ -1350,10 +1370,14 @@ static int __perf_session__process_pipe_events(struct perf_session *session)
done: done:
/* do the final flush for ordered samples */ /* do the final flush for ordered samples */
err = ordered_events__flush(oe, OE_FLUSH__FINAL); err = ordered_events__flush(oe, OE_FLUSH__FINAL);
if (err)
goto out_err;
err = auxtrace__flush_events(session, tool);
out_err: out_err:
free(buf); free(buf);
perf_session__warn_about_errors(session); perf_session__warn_about_errors(session);
ordered_events__free(&session->ordered_events); ordered_events__free(&session->ordered_events);
auxtrace__free_events(session);
return err; return err;
} }
...@@ -1496,10 +1520,14 @@ static int __perf_session__process_events(struct perf_session *session, ...@@ -1496,10 +1520,14 @@ static int __perf_session__process_events(struct perf_session *session,
out: out:
/* do the final flush for ordered samples */ /* do the final flush for ordered samples */
err = ordered_events__flush(oe, OE_FLUSH__FINAL); err = ordered_events__flush(oe, OE_FLUSH__FINAL);
if (err)
goto out_err;
err = auxtrace__flush_events(session, tool);
out_err: out_err:
ui_progress__finish(); ui_progress__finish();
perf_session__warn_about_errors(session); perf_session__warn_about_errors(session);
ordered_events__free(&session->ordered_events); ordered_events__free(&session->ordered_events);
auxtrace__free_events(session);
session->one_mmap = false; session->one_mmap = false;
return err; return err;
} }
...@@ -1582,7 +1610,13 @@ size_t perf_session__fprintf_dsos_buildid(struct perf_session *session, FILE *fp ...@@ -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 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); ret += events_stats__fprintf(&session->evlist->stats, fp);
return ret; return ret;
......
...@@ -15,10 +15,13 @@ ...@@ -15,10 +15,13 @@
struct ip_callchain; struct ip_callchain;
struct thread; struct thread;
struct auxtrace;
struct perf_session { struct perf_session {
struct perf_header header; struct perf_header header;
struct machines machines; struct machines machines;
struct perf_evlist *evlist; struct perf_evlist *evlist;
struct auxtrace *auxtrace;
struct trace_event tevent; struct trace_event tevent;
bool repipe; bool repipe;
bool one_mmap; bool one_mmap;
......
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