Commit 46bc29b9 authored by Adrian Hunter's avatar Adrian Hunter Committed by Arnaldo Carvalho de Melo
Browse files

perf tools: Add time conversion event



Intel PT uses the time members from the perf_event_mmap_page to convert
between TSC and perf time.

Due to a lack of foresight when Intel PT was implemented, those time
members were recorded in the (implementation dependent) AUXTRACE_INFO
event, the structure of which is generally inaccessible outside of the
Intel PT decoder.  However now the conversion between TSC and perf time
is needed when processing a jitdump file when Intel PT has been used for
tracing.

So add a user event to record the time members.  'perf record' will
synthesize the event if the information is available.  And session
processing will put a copy of the event on the session so that tools
like 'perf inject' can easily access it.

Signed-off-by: default avatarAdrian Hunter <adrian.hunter@intel.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/r/1457426324-30158-1-git-send-email-adrian.hunter@intel.com


Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent 39878d49
Loading
Loading
Loading
Loading
+31 −0
Original line number Diff line number Diff line
@@ -46,3 +46,34 @@ u64 rdtsc(void)

	return low | ((u64)high) << 32;
}

int perf_event__synth_time_conv(const struct perf_event_mmap_page *pc,
				struct perf_tool *tool,
				perf_event__handler_t process,
				struct machine *machine)
{
	union perf_event event = {
		.time_conv = {
			.header = {
				.type = PERF_RECORD_TIME_CONV,
				.size = sizeof(struct time_conv_event),
			},
		},
	};
	struct perf_tsc_conversion tc;
	int err;

	err = perf_read_tsc_conversion(pc, &tc);
	if (err == -EOPNOTSUPP)
		return 0;
	if (err)
		return err;

	pr_debug2("Synthesizing TSC conversion information\n");

	event.time_conv.time_mult  = tc.time_mult;
	event.time_conv.time_shift = tc.time_shift;
	event.time_conv.time_zero  = tc.time_zero;

	return process(tool, &event, NULL, machine);
}
+1 −0
Original line number Diff line number Diff line
@@ -748,6 +748,7 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
			.auxtrace_info	= perf_event__repipe_op2_synth,
			.auxtrace	= perf_event__repipe_auxtrace,
			.auxtrace_error	= perf_event__repipe_op2_synth,
			.time_conv	= perf_event__repipe_op2_synth,
			.finished_round	= perf_event__repipe_oe_synth,
			.build_id	= perf_event__repipe_op2_synth,
			.id_index	= perf_event__repipe_op2_synth,
+15 −0
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@
#include "util/data.h"
#include "util/perf_regs.h"
#include "util/auxtrace.h"
#include "util/tsc.h"
#include "util/parse-branch-options.h"
#include "util/parse-regs-options.h"
#include "util/llvm-utils.h"
@@ -512,6 +513,15 @@ static void workload_exec_failed_signal(int signo __maybe_unused,

static void snapshot_sig_handler(int sig);

int __weak
perf_event__synth_time_conv(const struct perf_event_mmap_page *pc __maybe_unused,
			    struct perf_tool *tool __maybe_unused,
			    perf_event__handler_t process __maybe_unused,
			    struct machine *machine __maybe_unused)
{
	return 0;
}

static int record__synthesize(struct record *rec)
{
	struct perf_session *session = rec->session;
@@ -549,6 +559,11 @@ static int record__synthesize(struct record *rec)
		}
	}

	err = perf_event__synth_time_conv(rec->evlist->mmap[0].base, tool,
					  process_synthesized_event, machine);
	if (err)
		goto out;

	if (rec->opts.full_auxtrace) {
		err = perf_event__synthesize_auxtrace_info(rec->itr, tool,
					session, process_synthesized_event);
+1 −0
Original line number Diff line number Diff line
@@ -45,6 +45,7 @@ static const char *perf_event__names[] = {
	[PERF_RECORD_STAT]			= "STAT",
	[PERF_RECORD_STAT_ROUND]		= "STAT_ROUND",
	[PERF_RECORD_EVENT_UPDATE]		= "EVENT_UPDATE",
	[PERF_RECORD_TIME_CONV]			= "TIME_CONV",
};

const char *perf_event__name(unsigned int id)
+9 −0
Original line number Diff line number Diff line
@@ -233,6 +233,7 @@ enum perf_user_event_type { /* above any possible kernel type */
	PERF_RECORD_STAT			= 76,
	PERF_RECORD_STAT_ROUND			= 77,
	PERF_RECORD_EVENT_UPDATE		= 78,
	PERF_RECORD_TIME_CONV			= 79,
	PERF_RECORD_HEADER_MAX
};

@@ -469,6 +470,13 @@ struct stat_round_event {
	u64				time;
};

struct time_conv_event {
	struct perf_event_header header;
	u64 time_shift;
	u64 time_mult;
	u64 time_zero;
};

union perf_event {
	struct perf_event_header	header;
	struct mmap_event		mmap;
@@ -497,6 +505,7 @@ union perf_event {
	struct stat_config_event	stat_config;
	struct stat_event		stat;
	struct stat_round_event		stat_round;
	struct time_conv_event		time_conv;
};

void perf_event__print_totals(void);
Loading