Skip to contentSkip to conversation

perf tools: Add Intel PT support for jitdump

PATCH In review Adrian Hunter 4 participants 31 messages Mar 3, 2016 – Apr 6, 2016 perf events

lore
Share & tools
lore

Adrian Hunter

author reviewer
#0 lore raw

cover perf tools: Add Intel PT support for jitdump

Hi

In order to use Intel PT with jitdump, changes are needed because Intel PT uses TSC as a timestamp not the monotonic clock.

These patches enable TSC to be used which allows the following using a simple HelloWorld java app:

perf record -e intel_pt//u -o java.perf.data java -agentpath:/home/ahunter/git/linux-perf/tools/perf/jvmti/libjvmti.so HelloWorldApp

perf inject -i java.perf.data --jit -o java.perf.data.jitted

perf report -i java.perf.data.jitted

perf script -i java.perf.data.jitted | less

Note, there will be some decoder errors because not all the generated code is reported to the agent.

Lazily, there is also an unrelated patch:

perf tools: Use 64-bit shifts with (TSC) time conversion"

Adrian Hunter (8):
perf inject: Hit all DSOs for AUX data in JIT and other cases perf session: Simplify tool stubs
perf tools: Add time conversion event
perf jit: Let jit_process() return errors
perf jit: Move clockid validation
perf jit: Add support for using TSC as a timestamp perf intel-pt/bts: Define JITDUMP_USE_ARCH_TIMESTAMP perf tools: Use 64-bit shifts with (TSC) time conversion

 tools/perf/arch/x86/tests/rdpmc.c    |  2 +-
 tools/perf/arch/x86/util/intel-bts.c |  5 +++
 tools/perf/arch/x86/util/intel-pt.c  |  5 +++
 tools/perf/arch/x86/util/tsc.c       | 31 +++++++++++++++++
 tools/perf/builtin-inject.c          | 53 ++++++++++++-----------------
 tools/perf/builtin-record.c          | 15 +++++++++
 tools/perf/jvmti/jvmti_agent.c       | 43 ++++++++++++++++++++++--
 tools/perf/util/event.c              |  1 +
 tools/perf/util/event.h              |  9 +++++
 tools/perf/util/jitdump.c            | 64 ++++++++++++++++++++++++++++++++----
 tools/perf/util/jitdump.h            |  3 ++
 tools/perf/util/session.c            | 46 ++++++++------------------
 tools/perf/util/session.h            |  1 +
 tools/perf/util/tool.h               |  1 +
 tools/perf/util/tsc.c                |  2 +-
 tools/perf/util/tsc.h                | 10 ++++++
 16 files changed, 216 insertions(+), 75 deletions(-)

Regards
Adrian

author reviewer
#1 lore raw

PATCH 1/8 perf inject: Hit all DSOs for AUX data in JIT and other cases

Currently, when injecting build ids, if there is AUX data then 'perf inject' hits all DSOs because it is not known which DSOs the trace data would hit.

That needs to be done for JIT injection also, and in fact there is no reason to distinguish what kind of injection is being done. That is, any time there is AUX data and the HEADER_BUID_ID feature flag is set, and the AUX data is not being processed, then hit all DSOs. This patch does that.

---
 tools/perf/builtin-inject.c | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)
tools/perf/builtin-inject.c +8 -4
index b38445f08c2f..c6a4f2f94ab1 100644
@@ -679,12 +679,16 @@ static int __cmd_inject(struct perf_inject *inject)
 	ret = perf_session__process_events(session);
 
 	if (!file_out->is_pipe) {
-		if (inject->build_ids) {
+		if (inject->build_ids)
 			perf_header__set_feat(&session->header,
 					      HEADER_BUILD_ID);
-			if (inject->have_auxtrace)
-				dsos__hit_all(session);
-		}
+		/*
+		 * Keep all buildids when there is unprocessed AUX data because
+		 * it is not known which ones the AUX trace hits.
+		 */
+		if (perf_header__has_feat(&session->header, HEADER_BUILD_ID) &&
+		    inject->have_auxtrace && !inject->itrace_synth_opts.set)
+			dsos__hit_all(session);
 		/*
 		 * The AUX areas have been removed and replaced with
 		 * synthesized hardware events, so clear the feature flag and
Signature · 1 line
1.9.1
#2 lore raw

[tip:perf/core] perf inject: Hit all DSOs for AUX data in JIT and other cases

perf inject: Hit all DSOs for AUX data in JIT and other cases
Commit-ID:  640dad47988ec4b734d71934be103bb6e931279f
Gitweb:     http://git.kernel.org/tip/640dad47988ec4b734d71934be103bb6e931279f
Author:     Adrian Hunter <[email protected]>
AuthorDate: Mon, 7 Mar 2016 16:44:38 -0300
Committer:  Ingo Molnar <[email protected]>
CommitDate: Tue, 8 Mar 2016 10:11:16 +0100

perf inject: Hit all DSOs for AUX data in JIT and other cases

Currently, when injecting build ids, if there is AUX data then 'perf inject' hits all DSOs because it is not known which DSOs the trace data would hit.

That needs to be done for JIT injection also, and in fact there is no reason to distinguish what kind of injection is being done. That is, any time there is AUX data and the HEADER_BUID_ID feature flag is set, and the AUX data is not being processed, then hit all DSOs. This patch does that.

---
 tools/perf/builtin-inject.c | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)
tools/perf/builtin-inject.c +8 -4
index b38445f..c6a4f2f 100644
@@ -679,12 +679,16 @@ static int __cmd_inject(struct perf_inject *inject)
 	ret = perf_session__process_events(session);
 
 	if (!file_out->is_pipe) {
-		if (inject->build_ids) {
+		if (inject->build_ids)
 			perf_header__set_feat(&session->header,
 					      HEADER_BUILD_ID);
-			if (inject->have_auxtrace)
-				dsos__hit_all(session);
-		}
+		/*
+		 * Keep all buildids when there is unprocessed AUX data because
+		 * it is not known which ones the AUX trace hits.
+		 */
+		if (perf_header__has_feat(&session->header, HEADER_BUILD_ID) &&
+		    inject->have_auxtrace && !inject->itrace_synth_opts.set)
+			dsos__hit_all(session);
 		/*
 		 * The AUX areas have been removed and replaced with
 		 * synthesized hardware events, so clear the feature flag and
author reviewer
#3 lore raw

PATCH 2/8 perf session: Simplify tool stubs

In reply to Adrian Hunter

From: Adrian Hunter <[email protected]>

Some of the stubs are identical so just have one function for them.

---
 tools/perf/util/session.c | 40 +++++++---------------------------------
 1 file changed, 7 insertions(+), 33 deletions(-)
tools/perf/util/session.c +7 -33
index 40b7a0d0905b..60b3593d210d 100644
@@ -240,14 +240,6 @@ static int process_event_stub(struct perf_tool *tool __maybe_unused,
 	return 0;
 }
 
-static int process_build_id_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 process_finished_round_stub(struct perf_tool *tool __maybe_unused,
 				       union perf_event *event __maybe_unused,
 				       struct ordered_events *oe __maybe_unused)
@@ -260,23 +252,6 @@ static int process_finished_round(struct perf_tool *tool,
 				  union perf_event *event,
 				  struct ordered_events *oe);
 
-static int process_id_index_stub(struct perf_tool *tool __maybe_unused,
-				 union perf_event *event __maybe_unused,
-				 struct perf_session *perf_session
-				 __maybe_unused)
-{
-	dump_printf(": unhandled!\n");
-	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];
@@ -303,10 +278,9 @@ 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)
+static int process_event_op2_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;
@@ -410,7 +384,7 @@ void perf_tool__fill_defaults(struct perf_tool *tool)
 	if (tool->tracing_data == NULL)
 		tool->tracing_data = process_event_synth_tracing_data_stub;
 	if (tool->build_id == NULL)
-		tool->build_id = process_build_id_stub;
+		tool->build_id = process_event_op2_stub;
 	if (tool->finished_round == NULL) {
 		if (tool->ordered_events)
 			tool->finished_round = process_finished_round;
@@ -418,13 +392,13 @@ void perf_tool__fill_defaults(struct perf_tool *tool)
 			tool->finished_round = process_finished_round_stub;
 	}
 	if (tool->id_index == NULL)
-		tool->id_index = process_id_index_stub;
+		tool->id_index = process_event_op2_stub;
 	if (tool->auxtrace_info == NULL)
-		tool->auxtrace_info = process_event_auxtrace_info_stub;
+		tool->auxtrace_info = process_event_op2_stub;
 	if (tool->auxtrace == NULL)
 		tool->auxtrace = process_event_auxtrace_stub;
 	if (tool->auxtrace_error == NULL)
-		tool->auxtrace_error = process_event_auxtrace_error_stub;
+		tool->auxtrace_error = process_event_op2_stub;
 	if (tool->thread_map == NULL)
 		tool->thread_map = process_event_thread_map_stub;
 	if (tool->cpu_map == NULL)
Signature · 1 line
1.9.1
author reviewer
#4 lore raw

PATCH v2 2/8 perf session: Simplify tool stubs

Some of the stubs are identical so just have one function for them.

---

Changes in V2:

Fixed "From" and "Signed-off-by" email addresses

 tools/perf/util/session.c | 40 +++++++---------------------------------
 1 file changed, 7 insertions(+), 33 deletions(-)
tools/perf/util/session.c +7 -33
index 40b7a0d0905b..60b3593d210d 100644
@@ -240,14 +240,6 @@ static int process_event_stub(struct perf_tool *tool __maybe_unused,
 	return 0;
 }
 
-static int process_build_id_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 process_finished_round_stub(struct perf_tool *tool __maybe_unused,
 				       union perf_event *event __maybe_unused,
 				       struct ordered_events *oe __maybe_unused)
@@ -260,23 +252,6 @@ static int process_finished_round(struct perf_tool *tool,
 				  union perf_event *event,
 				  struct ordered_events *oe);
 
-static int process_id_index_stub(struct perf_tool *tool __maybe_unused,
-				 union perf_event *event __maybe_unused,
-				 struct perf_session *perf_session
-				 __maybe_unused)
-{
-	dump_printf(": unhandled!\n");
-	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];
@@ -303,10 +278,9 @@ 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)
+static int process_event_op2_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;
@@ -410,7 +384,7 @@ void perf_tool__fill_defaults(struct perf_tool *tool)
 	if (tool->tracing_data == NULL)
 		tool->tracing_data = process_event_synth_tracing_data_stub;
 	if (tool->build_id == NULL)
-		tool->build_id = process_build_id_stub;
+		tool->build_id = process_event_op2_stub;
 	if (tool->finished_round == NULL) {
 		if (tool->ordered_events)
 			tool->finished_round = process_finished_round;
@@ -418,13 +392,13 @@ void perf_tool__fill_defaults(struct perf_tool *tool)
 			tool->finished_round = process_finished_round_stub;
 	}
 	if (tool->id_index == NULL)
-		tool->id_index = process_id_index_stub;
+		tool->id_index = process_event_op2_stub;
 	if (tool->auxtrace_info == NULL)
-		tool->auxtrace_info = process_event_auxtrace_info_stub;
+		tool->auxtrace_info = process_event_op2_stub;
 	if (tool->auxtrace == NULL)
 		tool->auxtrace = process_event_auxtrace_stub;
 	if (tool->auxtrace_error == NULL)
-		tool->auxtrace_error = process_event_auxtrace_error_stub;
+		tool->auxtrace_error = process_event_op2_stub;
 	if (tool->thread_map == NULL)
 		tool->thread_map = process_event_thread_map_stub;
 	if (tool->cpu_map == NULL)
Signature · 1 line
1.9.1
#5 lore raw

[tip:perf/core] perf session: Simplify tool stubs

In reply to Adrian Hunter
perf session: Simplify tool stubs
Commit-ID:  5fb0ac16c5091f48eecf1a77e461f6957a463d61
Gitweb:     http://git.kernel.org/tip/5fb0ac16c5091f48eecf1a77e461f6957a463d61
Author:     Adrian Hunter <[email protected]>
AuthorDate: Mon, 7 Mar 2016 16:44:39 -0300
Committer:  Ingo Molnar <[email protected]>
CommitDate: Tue, 8 Mar 2016 10:11:17 +0100

perf session: Simplify tool stubs

Some of the stubs are identical so just have one function for them.

---
 tools/perf/util/session.c | 40 +++++++---------------------------------
 1 file changed, 7 insertions(+), 33 deletions(-)
tools/perf/util/session.c +7 -33
index 40b7a0d..60b3593 100644
@@ -240,14 +240,6 @@ static int process_event_stub(struct perf_tool *tool __maybe_unused,
 	return 0;
 }
 
-static int process_build_id_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 process_finished_round_stub(struct perf_tool *tool __maybe_unused,
 				       union perf_event *event __maybe_unused,
 				       struct ordered_events *oe __maybe_unused)
@@ -260,23 +252,6 @@ static int process_finished_round(struct perf_tool *tool,
 				  union perf_event *event,
 				  struct ordered_events *oe);
 
-static int process_id_index_stub(struct perf_tool *tool __maybe_unused,
-				 union perf_event *event __maybe_unused,
-				 struct perf_session *perf_session
-				 __maybe_unused)
-{
-	dump_printf(": unhandled!\n");
-	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];
@@ -303,10 +278,9 @@ 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)
+static int process_event_op2_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;
@@ -410,7 +384,7 @@ void perf_tool__fill_defaults(struct perf_tool *tool)
 	if (tool->tracing_data == NULL)
 		tool->tracing_data = process_event_synth_tracing_data_stub;
 	if (tool->build_id == NULL)
-		tool->build_id = process_build_id_stub;
+		tool->build_id = process_event_op2_stub;
 	if (tool->finished_round == NULL) {
 		if (tool->ordered_events)
 			tool->finished_round = process_finished_round;
@@ -418,13 +392,13 @@ void perf_tool__fill_defaults(struct perf_tool *tool)
 			tool->finished_round = process_finished_round_stub;
 	}
 	if (tool->id_index == NULL)
-		tool->id_index = process_id_index_stub;
+		tool->id_index = process_event_op2_stub;
 	if (tool->auxtrace_info == NULL)
-		tool->auxtrace_info = process_event_auxtrace_info_stub;
+		tool->auxtrace_info = process_event_op2_stub;
 	if (tool->auxtrace == NULL)
 		tool->auxtrace = process_event_auxtrace_stub;
 	if (tool->auxtrace_error == NULL)
-		tool->auxtrace_error = process_event_auxtrace_error_stub;
+		tool->auxtrace_error = process_event_op2_stub;
 	if (tool->thread_map == NULL)
 		tool->thread_map = process_event_thread_map_stub;
 	if (tool->cpu_map == NULL)
author reviewer
#6 lore raw

PATCH 3/8 perf tools: Add time conversion event

In reply to Adrian Hunter

From: Adrian Hunter <[email protected]>

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.

---
 tools/perf/arch/x86/util/tsc.c | 31 +++++++++++++++++++++++++++++++
 tools/perf/builtin-inject.c    |  1 +
 tools/perf/builtin-record.c    | 15 +++++++++++++++
 tools/perf/util/event.c        |  1 +
 tools/perf/util/event.h        |  9 +++++++++
 tools/perf/util/session.c      |  6 ++++++
 tools/perf/util/session.h      |  1 +
 tools/perf/util/tool.h         |  1 +
 tools/perf/util/tsc.h          | 10 ++++++++++
 9 files changed, 75 insertions(+)
tools/perf/arch/x86/util/tsc.c +31 -0
index fd2868490d00..70ff7c14bea6 100644
@@ -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);
+}
tools/perf/builtin-inject.c +1 -0
index c6a4f2f94ab1..29dfe68b2fb1 100644
@@ -761,6 +761,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,
tools/perf/builtin-record.c +15 -0
index 515510ecc76a..410035c6e300 100644
@@ -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);
tools/perf/util/event.c +1 -0
index 7bad5c3fa7b7..025509129cda 100644
@@ -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)
tools/perf/util/event.h +9 -0
index b7ffb7ee9971..f1dafa05e8bf 100644
@@ -232,6 +232,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
 };
 
@@ -468,6 +469,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;
@@ -496,6 +504,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);
tools/perf/util/session.c +6 -0
index 60b3593d210d..ee1778a9c0c7 100644
@@ -409,6 +409,8 @@ void perf_tool__fill_defaults(struct perf_tool *tool)
 		tool->stat = process_stat_stub;
 	if (tool->stat_round == NULL)
 		tool->stat_round = process_stat_round_stub;
+	if (tool->time_conv == NULL)
+		tool->time_conv = process_event_op2_stub;
 }
 
 static void swap_sample_id_all(union perf_event *event, void *data)
@@ -794,6 +796,7 @@ static perf_event__swap_op perf_event__swap_ops[] = {
 	[PERF_RECORD_STAT]		  = perf_event__stat_swap,
 	[PERF_RECORD_STAT_ROUND]	  = perf_event__stat_round_swap,
 	[PERF_RECORD_EVENT_UPDATE]	  = perf_event__event_update_swap,
+	[PERF_RECORD_TIME_CONV]		  = perf_event__all64_swap,
 	[PERF_RECORD_HEADER_MAX]	  = NULL,
 };
 
@@ -1342,6 +1345,9 @@ static s64 perf_session__process_user_event(struct perf_session *session,
 		return tool->stat(tool, event, session);
 	case PERF_RECORD_STAT_ROUND:
 		return tool->stat_round(tool, event, session);
+	case PERF_RECORD_TIME_CONV:
+		session->time_conv = event->time_conv;
+		return tool->time_conv(tool, event, session);
 	default:
 		return -EINVAL;
 	}
tools/perf/util/session.h +1 -0
index 5f792e35d4c1..f96fc9e8c52e 100644
@@ -26,6 +26,7 @@ struct perf_session {
 	struct itrace_synth_opts *itrace_synth_opts;
 	struct list_head	auxtrace_index;
 	struct trace_event	tevent;
+	struct time_conv_event	time_conv;
 	bool			repipe;
 	bool			one_mmap;
 	void			*one_mmap_addr;
tools/perf/util/tool.h +1 -0
index 55de4cffcd4e..ac2590a3de2d 100644
@@ -57,6 +57,7 @@ struct perf_tool {
 			id_index,
 			auxtrace_info,
 			auxtrace_error,
+			time_conv,
 			thread_map,
 			cpu_map,
 			stat_config,
tools/perf/util/tsc.h +10 -0
index a8b78f1b3243..280ddc067556 100644
@@ -3,10 +3,20 @@
 
 #include <linux/types.h>
 
+#include "event.h"
 #include "../arch/x86/util/tsc.h"
 
 u64 perf_time_to_tsc(u64 ns, struct perf_tsc_conversion *tc);
 u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc);
 u64 rdtsc(void);
 
+struct perf_event_mmap_page;
+struct perf_tool;
+struct machine;
+
+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);
+
 #endif
Signature · 1 line
1.9.1
author reviewer
#7 lore raw

PATCH v2 3/8 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.

---

Changes in V2:

Fixed "From" and "Signed-off-by" email addresses

 tools/perf/arch/x86/util/tsc.c | 31 +++++++++++++++++++++++++++++++
 tools/perf/builtin-inject.c    |  1 +
 tools/perf/builtin-record.c    | 15 +++++++++++++++
 tools/perf/util/event.c        |  1 +
 tools/perf/util/event.h        |  9 +++++++++
 tools/perf/util/session.c      |  6 ++++++
 tools/perf/util/session.h      |  1 +
 tools/perf/util/tool.h         |  1 +
 tools/perf/util/tsc.h          | 10 ++++++++++
 9 files changed, 75 insertions(+)
tools/perf/arch/x86/util/tsc.c +31 -0
index fd2868490d00..70ff7c14bea6 100644
@@ -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);
+}
tools/perf/builtin-inject.c +1 -0
index c6a4f2f94ab1..29dfe68b2fb1 100644
@@ -761,6 +761,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,
tools/perf/builtin-record.c +15 -0
index 515510ecc76a..410035c6e300 100644
@@ -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);
tools/perf/util/event.c +1 -0
index 7bad5c3fa7b7..025509129cda 100644
@@ -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)
tools/perf/util/event.h +9 -0
index b7ffb7ee9971..f1dafa05e8bf 100644
@@ -232,6 +232,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
 };
 
@@ -468,6 +469,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;
@@ -496,6 +504,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);
tools/perf/util/session.c +6 -0
index 60b3593d210d..ee1778a9c0c7 100644
@@ -409,6 +409,8 @@ void perf_tool__fill_defaults(struct perf_tool *tool)
 		tool->stat = process_stat_stub;
 	if (tool->stat_round == NULL)
 		tool->stat_round = process_stat_round_stub;
+	if (tool->time_conv == NULL)
+		tool->time_conv = process_event_op2_stub;
 }
 
 static void swap_sample_id_all(union perf_event *event, void *data)
@@ -794,6 +796,7 @@ static perf_event__swap_op perf_event__swap_ops[] = {
 	[PERF_RECORD_STAT]		  = perf_event__stat_swap,
 	[PERF_RECORD_STAT_ROUND]	  = perf_event__stat_round_swap,
 	[PERF_RECORD_EVENT_UPDATE]	  = perf_event__event_update_swap,
+	[PERF_RECORD_TIME_CONV]		  = perf_event__all64_swap,
 	[PERF_RECORD_HEADER_MAX]	  = NULL,
 };
 
@@ -1342,6 +1345,9 @@ static s64 perf_session__process_user_event(struct perf_session *session,
 		return tool->stat(tool, event, session);
 	case PERF_RECORD_STAT_ROUND:
 		return tool->stat_round(tool, event, session);
+	case PERF_RECORD_TIME_CONV:
+		session->time_conv = event->time_conv;
+		return tool->time_conv(tool, event, session);
 	default:
 		return -EINVAL;
 	}
tools/perf/util/session.h +1 -0
index 5f792e35d4c1..f96fc9e8c52e 100644
@@ -26,6 +26,7 @@ struct perf_session {
 	struct itrace_synth_opts *itrace_synth_opts;
 	struct list_head	auxtrace_index;
 	struct trace_event	tevent;
+	struct time_conv_event	time_conv;
 	bool			repipe;
 	bool			one_mmap;
 	void			*one_mmap_addr;
tools/perf/util/tool.h +1 -0
index 55de4cffcd4e..ac2590a3de2d 100644
@@ -57,6 +57,7 @@ struct perf_tool {
 			id_index,
 			auxtrace_info,
 			auxtrace_error,
+			time_conv,
 			thread_map,
 			cpu_map,
 			stat_config,
tools/perf/util/tsc.h +10 -0
index a8b78f1b3243..280ddc067556 100644
@@ -3,10 +3,20 @@
 
 #include <linux/types.h>
 
+#include "event.h"
 #include "../arch/x86/util/tsc.h"
 
 u64 perf_time_to_tsc(u64 ns, struct perf_tsc_conversion *tc);
 u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc);
 u64 rdtsc(void);
 
+struct perf_event_mmap_page;
+struct perf_tool;
+struct machine;
+
+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);
+
 #endif
Signature · 1 line
1.9.1
author reviewer
#8 lore raw

Re: [PATCH V2 3/8] perf tools: Add time conversion event

Quoted 11 lines · Adrian Hunter

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.

Quoted 6 lines

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.

This patch (patch 3) and the V2 versions of patches 6 and 7 i.e.

[PATCH V2 3/8] perf tools: Add time conversion event [PATCH V2 6/8] perf jit: Add support for using TSC as a timestamp [PATCH V2 7/8] perf intel-pt/bts: Define JITDUMP_USE_ARCH_TIMESTAMP

still apply. Do you have any comments?

Quoted 235 lines

---

Changes in V2:

Fixed "From" and "Signed-off-by" email addresses

 tools/perf/arch/x86/util/tsc.c | 31 +++++++++++++++++++++++++++++++
 tools/perf/builtin-inject.c    |  1 +
 tools/perf/builtin-record.c    | 15 +++++++++++++++
 tools/perf/util/event.c        |  1 +
 tools/perf/util/event.h        |  9 +++++++++
 tools/perf/util/session.c      |  6 ++++++
 tools/perf/util/session.h      |  1 +
 tools/perf/util/tool.h         |  1 +
 tools/perf/util/tsc.h          | 10 ++++++++++
 9 files changed, 75 insertions(+)
tools/perf/arch/x86/util/tsc.c +31 -0
index fd2868490d00..70ff7c14bea6 100644
@@ -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);
+}
tools/perf/builtin-inject.c +1 -0
index c6a4f2f94ab1..29dfe68b2fb1 100644
@@ -761,6 +761,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,
tools/perf/builtin-record.c +15 -0
index 515510ecc76a..410035c6e300 100644
@@ -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);
tools/perf/util/event.c +1 -0
index 7bad5c3fa7b7..025509129cda 100644
@@ -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)
tools/perf/util/event.h +9 -0
index b7ffb7ee9971..f1dafa05e8bf 100644
@@ -232,6 +232,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
 };
 
@@ -468,6 +469,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;
@@ -496,6 +504,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);
tools/perf/util/session.c +6 -0
index 60b3593d210d..ee1778a9c0c7 100644
@@ -409,6 +409,8 @@ void perf_tool__fill_defaults(struct perf_tool *tool)
 		tool->stat = process_stat_stub;
 	if (tool->stat_round == NULL)
 		tool->stat_round = process_stat_round_stub;
+	if (tool->time_conv == NULL)
+		tool->time_conv = process_event_op2_stub;
 }
 
 static void swap_sample_id_all(union perf_event *event, void *data)
@@ -794,6 +796,7 @@ static perf_event__swap_op perf_event__swap_ops[] = {
 	[PERF_RECORD_STAT]		  = perf_event__stat_swap,
 	[PERF_RECORD_STAT_ROUND]	  = perf_event__stat_round_swap,
 	[PERF_RECORD_EVENT_UPDATE]	  = perf_event__event_update_swap,
+	[PERF_RECORD_TIME_CONV]		  = perf_event__all64_swap,
 	[PERF_RECORD_HEADER_MAX]	  = NULL,
 };
 
@@ -1342,6 +1345,9 @@ static s64 perf_session__process_user_event(struct perf_session *session,
 		return tool->stat(tool, event, session);
 	case PERF_RECORD_STAT_ROUND:
 		return tool->stat_round(tool, event, session);
+	case PERF_RECORD_TIME_CONV:
+		session->time_conv = event->time_conv;
+		return tool->time_conv(tool, event, session);
 	default:
 		return -EINVAL;
 	}
tools/perf/util/session.h +1 -0
index 5f792e35d4c1..f96fc9e8c52e 100644
@@ -26,6 +26,7 @@ struct perf_session {
 	struct itrace_synth_opts *itrace_synth_opts;
 	struct list_head	auxtrace_index;
 	struct trace_event	tevent;
+	struct time_conv_event	time_conv;
 	bool			repipe;
 	bool			one_mmap;
 	void			*one_mmap_addr;
tools/perf/util/tool.h +1 -0
index 55de4cffcd4e..ac2590a3de2d 100644
@@ -57,6 +57,7 @@ struct perf_tool {
 			id_index,
 			auxtrace_info,
 			auxtrace_error,
+			time_conv,
 			thread_map,
 			cpu_map,
 			stat_config,
tools/perf/util/tsc.h +10 -0
index a8b78f1b3243..280ddc067556 100644
@@ -3,10 +3,20 @@
 
 #include <linux/types.h>
 
+#include "event.h"
 #include "../arch/x86/util/tsc.h"
 
 u64 perf_time_to_tsc(u64 ns, struct perf_tsc_conversion *tc);
 u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc);
 u64 rdtsc(void);
 
+struct perf_event_mmap_page;
+struct perf_tool;
+struct machine;
+
+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);
+
 #endif
#9 lore raw

Re: [PATCH V2 3/8] perf tools: Add time conversion event

Em Thu, Mar 31, 2016 at 09:33:04AM +0300, Adrian Hunter escreveu:

Quoted 19 lines · Adrian Hunter
Quoted 11 lines

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.

Quoted 6 lines

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.

Quoted 7 lines

This patch (patch 3) and the V2 versions of patches 6 and 7 i.e.

[PATCH V2 3/8] perf tools: Add time conversion event [PATCH V2 6/8] perf jit: Add support for using TSC as a timestamp [PATCH V2 7/8] perf intel-pt/bts: Define JITDUMP_USE_ARCH_TIMESTAMP

still apply. Do you have any comments?

I was waiting for Stephane to say something, but judging from the fact that this is just making existing infrastructure to be available more widely, I am applying it.

- Arnaldo

Quoted 235 lines
Quoted 235 lines

---

Changes in V2:

Fixed "From" and "Signed-off-by" email addresses

 tools/perf/arch/x86/util/tsc.c | 31 +++++++++++++++++++++++++++++++
 tools/perf/builtin-inject.c    |  1 +
 tools/perf/builtin-record.c    | 15 +++++++++++++++
 tools/perf/util/event.c        |  1 +
 tools/perf/util/event.h        |  9 +++++++++
 tools/perf/util/session.c      |  6 ++++++
 tools/perf/util/session.h      |  1 +
 tools/perf/util/tool.h         |  1 +
 tools/perf/util/tsc.h          | 10 ++++++++++
 9 files changed, 75 insertions(+)
tools/perf/arch/x86/util/tsc.c +31 -0
index fd2868490d00..70ff7c14bea6 100644
@@ -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);
+}
tools/perf/builtin-inject.c +1 -0
index c6a4f2f94ab1..29dfe68b2fb1 100644
@@ -761,6 +761,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,
tools/perf/builtin-record.c +15 -0
index 515510ecc76a..410035c6e300 100644
@@ -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);
tools/perf/util/event.c +1 -0
index 7bad5c3fa7b7..025509129cda 100644
@@ -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)
tools/perf/util/event.h +9 -0
index b7ffb7ee9971..f1dafa05e8bf 100644
@@ -232,6 +232,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
 };
 
@@ -468,6 +469,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;
@@ -496,6 +504,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);
tools/perf/util/session.c +6 -0
index 60b3593d210d..ee1778a9c0c7 100644
@@ -409,6 +409,8 @@ void perf_tool__fill_defaults(struct perf_tool *tool)
 		tool->stat = process_stat_stub;
 	if (tool->stat_round == NULL)
 		tool->stat_round = process_stat_round_stub;
+	if (tool->time_conv == NULL)
+		tool->time_conv = process_event_op2_stub;
 }
 
 static void swap_sample_id_all(union perf_event *event, void *data)
@@ -794,6 +796,7 @@ static perf_event__swap_op perf_event__swap_ops[] = {
 	[PERF_RECORD_STAT]		  = perf_event__stat_swap,
 	[PERF_RECORD_STAT_ROUND]	  = perf_event__stat_round_swap,
 	[PERF_RECORD_EVENT_UPDATE]	  = perf_event__event_update_swap,
+	[PERF_RECORD_TIME_CONV]		  = perf_event__all64_swap,
 	[PERF_RECORD_HEADER_MAX]	  = NULL,
 };
 
@@ -1342,6 +1345,9 @@ static s64 perf_session__process_user_event(struct perf_session *session,
 		return tool->stat(tool, event, session);
 	case PERF_RECORD_STAT_ROUND:
 		return tool->stat_round(tool, event, session);
+	case PERF_RECORD_TIME_CONV:
+		session->time_conv = event->time_conv;
+		return tool->time_conv(tool, event, session);
 	default:
 		return -EINVAL;
 	}
tools/perf/util/session.h +1 -0
index 5f792e35d4c1..f96fc9e8c52e 100644
@@ -26,6 +26,7 @@ struct perf_session {
 	struct itrace_synth_opts *itrace_synth_opts;
 	struct list_head	auxtrace_index;
 	struct trace_event	tevent;
+	struct time_conv_event	time_conv;
 	bool			repipe;
 	bool			one_mmap;
 	void			*one_mmap_addr;
tools/perf/util/tool.h +1 -0
index 55de4cffcd4e..ac2590a3de2d 100644
@@ -57,6 +57,7 @@ struct perf_tool {
 			id_index,
 			auxtrace_info,
 			auxtrace_error,
+			time_conv,
 			thread_map,
 			cpu_map,
 			stat_config,
tools/perf/util/tsc.h +10 -0
index a8b78f1b3243..280ddc067556 100644
@@ -3,10 +3,20 @@
 
 #include <linux/types.h>
 
+#include "event.h"
 #include "../arch/x86/util/tsc.h"
 
 u64 perf_time_to_tsc(u64 ns, struct perf_tsc_conversion *tc);
 u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc);
 u64 rdtsc(void);
 
+struct perf_event_mmap_page;
+struct perf_tool;
+struct machine;
+
+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);
+
 #endif
#10 lore raw

[tip:perf/core] perf tools: Add time conversion event

In reply to Adrian Hunter
perf tools: Add time conversion event
Commit-ID:  46bc29b970f0011a9099077f1db8f3540aa829fe
Gitweb:     http://git.kernel.org/tip/46bc29b970f0011a9099077f1db8f3540aa829fe
Author:     Adrian Hunter <[email protected]>
AuthorDate: Tue, 8 Mar 2016 10:38:44 +0200
Committer:  Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Thu, 31 Mar 2016 10:52:24 -0300

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.

---
 tools/perf/arch/x86/util/tsc.c | 31 +++++++++++++++++++++++++++++++
 tools/perf/builtin-inject.c    |  1 +
 tools/perf/builtin-record.c    | 15 +++++++++++++++
 tools/perf/util/event.c        |  1 +
 tools/perf/util/event.h        |  9 +++++++++
 tools/perf/util/session.c      |  6 ++++++
 tools/perf/util/session.h      |  1 +
 tools/perf/util/tool.h         |  1 +
 tools/perf/util/tsc.h          | 10 ++++++++++
 9 files changed, 75 insertions(+)
tools/perf/arch/x86/util/tsc.c +31 -0
index fd28684..70ff7c1 100644
@@ -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);
+}
tools/perf/builtin-inject.c +1 -0
index d1a2d10..e5afa8f 100644
@@ -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,
tools/perf/builtin-record.c +15 -0
index 515510e..410035c 100644
@@ -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);
tools/perf/util/event.c +1 -0
index dad55d0..b689590 100644
@@ -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)
tools/perf/util/event.h +9 -0
index 6bb1c92..8d363d5 100644
@@ -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);
tools/perf/util/session.c +6 -0
index 4abd85c..ef37055 100644
@@ -409,6 +409,8 @@ void perf_tool__fill_defaults(struct perf_tool *tool)
 		tool->stat = process_stat_stub;
 	if (tool->stat_round == NULL)
 		tool->stat_round = process_stat_round_stub;
+	if (tool->time_conv == NULL)
+		tool->time_conv = process_event_op2_stub;
 }
 
 static void swap_sample_id_all(union perf_event *event, void *data)
@@ -794,6 +796,7 @@ static perf_event__swap_op perf_event__swap_ops[] = {
 	[PERF_RECORD_STAT]		  = perf_event__stat_swap,
 	[PERF_RECORD_STAT_ROUND]	  = perf_event__stat_round_swap,
 	[PERF_RECORD_EVENT_UPDATE]	  = perf_event__event_update_swap,
+	[PERF_RECORD_TIME_CONV]		  = perf_event__all64_swap,
 	[PERF_RECORD_HEADER_MAX]	  = NULL,
 };
 
@@ -1341,6 +1344,9 @@ static s64 perf_session__process_user_event(struct perf_session *session,
 		return tool->stat(tool, event, session);
 	case PERF_RECORD_STAT_ROUND:
 		return tool->stat_round(tool, event, session);
+	case PERF_RECORD_TIME_CONV:
+		session->time_conv = event->time_conv;
+		return tool->time_conv(tool, event, session);
 	default:
 		return -EINVAL;
 	}
tools/perf/util/session.h +1 -0
index 5f792e3..f96fc9e8c 100644
@@ -26,6 +26,7 @@ struct perf_session {
 	struct itrace_synth_opts *itrace_synth_opts;
 	struct list_head	auxtrace_index;
 	struct trace_event	tevent;
+	struct time_conv_event	time_conv;
 	bool			repipe;
 	bool			one_mmap;
 	void			*one_mmap_addr;
tools/perf/util/tool.h +1 -0
index 55de4cf..ac2590a 100644
@@ -57,6 +57,7 @@ struct perf_tool {
 			id_index,
 			auxtrace_info,
 			auxtrace_error,
+			time_conv,
 			thread_map,
 			cpu_map,
 			stat_config,
tools/perf/util/tsc.h +10 -0
index a8b78f1..280ddc0 100644
@@ -3,10 +3,20 @@
 
 #include <linux/types.h>
 
+#include "event.h"
 #include "../arch/x86/util/tsc.h"
 
 u64 perf_time_to_tsc(u64 ns, struct perf_tsc_conversion *tc);
 u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc);
 u64 rdtsc(void);
 
+struct perf_event_mmap_page;
+struct perf_tool;
+struct machine;
+
+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);
+
 #endif
author reviewer
#11 lore raw

PATCH 4/8 perf jit: Let jit_process() return errors

In reply to Adrian Hunter

In preparation for moving clockid validation into jit_process().

Previously a return value of zero meant the processing had been done and non-zero meant either the processing was not done (i.e. not the jitdump file mmap event) or an error occurred.

Change it so that zero means the processing was not done, one means the processing was done and successful, and negative values are an error.

---
 tools/perf/builtin-inject.c | 16 ++++++++++++----
 tools/perf/util/jitdump.c   |  6 ++++--
 2 files changed, 16 insertions(+), 6 deletions(-)
tools/perf/builtin-inject.c +12 -4
index 29dfe68b2fb1..1635533921e8 100644
@@ -253,12 +253,16 @@ static int perf_event__jit_repipe_mmap(struct perf_tool *tool,
 {
 	struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
 	u64 n = 0;
+	int ret;
 
 	/*
 	 * if jit marker, then inject jit mmaps and generate ELF images
 	 */
-	if (!jit_process(inject->session, &inject->output, machine,
-			 event->mmap.filename, sample->pid, &n)) {
+	ret = jit_process(inject->session, &inject->output, machine,
+			  event->mmap.filename, sample->pid, &n);
+	if (ret < 0)
+		return ret;
+	if (ret) {
 		inject->bytes_written += n;
 		return 0;
 	}
@@ -287,12 +291,16 @@ static int perf_event__jit_repipe_mmap2(struct perf_tool *tool,
 {
 	struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
 	u64 n = 0;
+	int ret;
 
 	/*
 	 * if jit marker, then inject jit mmaps and generate ELF images
 	 */
-	if (!jit_process(inject->session, &inject->output, machine,
-			  event->mmap2.filename, sample->pid, &n)) {
+	ret = jit_process(inject->session, &inject->output, machine,
+			  event->mmap2.filename, sample->pid, &n);
+	if (ret < 0)
+		return ret;
+	if (ret) {
 		inject->bytes_written += n;
 		return 0;
 	}
tools/perf/util/jitdump.c +4 -2
index 99fa5eee9fe0..bd9e44f9fff2 100644
@@ -647,7 +647,7 @@ jit_process(struct perf_session *session,
 	 * first, detect marker mmap (i.e., the jitdump mmap)
 	 */
 	if (jit_detect(filename, pid))
-		return -1;
+		return 0;
 
 	memset(&jd, 0, sizeof(jd));
 
@@ -665,8 +665,10 @@ jit_process(struct perf_session *session,
 	*nbytes = 0;
 
 	ret = jit_inject(&jd, filename);
-	if (!ret)
+	if (!ret) {
 		*nbytes = jd.bytes_written;
+		ret = 1;
+	}
 
 	return ret;
 }
Signature · 1 line
1.9.1
#12 lore raw

[tip:perf/core] perf jit: Let jit_process() return errors

perf jit: Let jit_process() return errors
Commit-ID:  570735b33d122bcb259ef67c6aa63e5609af5752
Gitweb:     http://git.kernel.org/tip/570735b33d122bcb259ef67c6aa63e5609af5752
Author:     Adrian Hunter <[email protected]>
AuthorDate: Mon, 7 Mar 2016 16:44:40 -0300
Committer:  Ingo Molnar <[email protected]>
CommitDate: Tue, 8 Mar 2016 10:11:17 +0100

perf jit: Let jit_process() return errors

In preparation for moving clockid validation into jit_process().

Previously a return value of zero meant the processing had been done and non-zero meant either the processing was not done (i.e. not the jitdump file mmap event) or an error occurred.

Change it so that zero means the processing was not done, one means the processing was done and successful, and negative values are an error.

---
 tools/perf/builtin-inject.c | 16 ++++++++++++----
 tools/perf/util/jitdump.c   |  6 ++++--
 2 files changed, 16 insertions(+), 6 deletions(-)
tools/perf/builtin-inject.c +12 -4
index c6a4f2f..2512d71 100644
@@ -253,12 +253,16 @@ static int perf_event__jit_repipe_mmap(struct perf_tool *tool,
 {
 	struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
 	u64 n = 0;
+	int ret;
 
 	/*
 	 * if jit marker, then inject jit mmaps and generate ELF images
 	 */
-	if (!jit_process(inject->session, &inject->output, machine,
-			 event->mmap.filename, sample->pid, &n)) {
+	ret = jit_process(inject->session, &inject->output, machine,
+			  event->mmap.filename, sample->pid, &n);
+	if (ret < 0)
+		return ret;
+	if (ret) {
 		inject->bytes_written += n;
 		return 0;
 	}
@@ -287,12 +291,16 @@ static int perf_event__jit_repipe_mmap2(struct perf_tool *tool,
 {
 	struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
 	u64 n = 0;
+	int ret;
 
 	/*
 	 * if jit marker, then inject jit mmaps and generate ELF images
 	 */
-	if (!jit_process(inject->session, &inject->output, machine,
-			  event->mmap2.filename, sample->pid, &n)) {
+	ret = jit_process(inject->session, &inject->output, machine,
+			  event->mmap2.filename, sample->pid, &n);
+	if (ret < 0)
+		return ret;
+	if (ret) {
 		inject->bytes_written += n;
 		return 0;
 	}
tools/perf/util/jitdump.c +4 -2
index 99fa5ee..bd9e44f 100644
@@ -647,7 +647,7 @@ jit_process(struct perf_session *session,
 	 * first, detect marker mmap (i.e., the jitdump mmap)
 	 */
 	if (jit_detect(filename, pid))
-		return -1;
+		return 0;
 
 	memset(&jd, 0, sizeof(jd));
 
@@ -665,8 +665,10 @@ jit_process(struct perf_session *session,
 	*nbytes = 0;
 
 	ret = jit_inject(&jd, filename);
-	if (!ret)
+	if (!ret) {
 		*nbytes = jd.bytes_written;
+		ret = 1;
+	}
 
 	return ret;
 }
author reviewer
#13 lore raw

PATCH 5/8 perf jit: Move clockid validation

In reply to Adrian Hunter

From: Adrian Hunter <[email protected]>

Move clockid validation into jit_process() so it can later be made conditional.

---
 tools/perf/builtin-inject.c | 24 ------------------------
 tools/perf/util/jitdump.c   | 23 +++++++++++++++++++++++
 2 files changed, 23 insertions(+), 24 deletions(-)
tools/perf/builtin-inject.c +0 -24
index 1635533921e8..319b7b4f7743 100644
@@ -729,23 +729,6 @@ static int __cmd_inject(struct perf_inject *inject)
 	return ret;
 }
 
-#ifdef HAVE_LIBELF_SUPPORT
-static int
-jit_validate_events(struct perf_session *session)
-{
-	struct perf_evsel *evsel;
-
-	/*
-	 * check that all events use CLOCK_MONOTONIC
-	 */
-	evlist__for_each(session->evlist, evsel) {
-		if (evsel->attr.use_clockid == 0 || evsel->attr.clockid != CLOCK_MONOTONIC)
-			return -1;
-	}
-	return 0;
-}
-#endif
-
 int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
 {
 	struct perf_inject inject = {
@@ -853,13 +836,6 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
 	}
 #ifdef HAVE_LIBELF_SUPPORT
 	if (inject.jit_mode) {
-		/*
-		 * validate event is using the correct clockid
-		 */
-		if (jit_validate_events(inject.session)) {
-			fprintf(stderr, "error, jitted code must be sampled with perf record -k 1\n");
-			return -1;
-		}
 		inject.tool.mmap2	   = perf_event__jit_repipe_mmap2;
 		inject.tool.mmap	   = perf_event__jit_repipe_mmap;
 		inject.tool.ordered_events = true;
tools/perf/util/jitdump.c +23 -0
index bd9e44f9fff2..cd272cc21e05 100644
@@ -99,6 +99,21 @@ jit_close(struct jit_buf_desc *jd)
 }
 
 static int
+jit_validate_events(struct perf_session *session)
+{
+	struct perf_evsel *evsel;
+
+	/*
+	 * check that all events use CLOCK_MONOTONIC
+	 */
+	evlist__for_each(session->evlist, evsel) {
+		if (evsel->attr.use_clockid == 0 || evsel->attr.clockid != CLOCK_MONOTONIC)
+			return -1;
+	}
+	return 0;
+}
+
+static int
 jit_open(struct jit_buf_desc *jd, const char *name)
 {
 	struct jitheader header;
@@ -157,6 +172,14 @@ jit_open(struct jit_buf_desc *jd, const char *name)
 		goto error;
 	}
 
+	/*
+	 * validate event is using the correct clockid
+	 */
+	if (jit_validate_events(jd->session)) {
+		pr_err("error, jitted code must be sampled with perf record -k 1\n");
+		goto error;
+	}
+
 	bs = header.total_size - sizeof(header);
 
 	if (bs > bsz) {
Signature · 1 line
1.9.1
author reviewer
#14 lore raw

PATCH v2 5/8 perf jit: Move clockid validation

Move clockid validation into jit_process() so it can later be made conditional.

---

Changes in V2:

Fixed "From" and "Signed-off-by" email addresses

 tools/perf/builtin-inject.c | 24 ------------------------
 tools/perf/util/jitdump.c   | 23 +++++++++++++++++++++++
 2 files changed, 23 insertions(+), 24 deletions(-)
tools/perf/builtin-inject.c +0 -24
index 1635533921e8..319b7b4f7743 100644
@@ -729,23 +729,6 @@ static int __cmd_inject(struct perf_inject *inject)
 	return ret;
 }
 
-#ifdef HAVE_LIBELF_SUPPORT
-static int
-jit_validate_events(struct perf_session *session)
-{
-	struct perf_evsel *evsel;
-
-	/*
-	 * check that all events use CLOCK_MONOTONIC
-	 */
-	evlist__for_each(session->evlist, evsel) {
-		if (evsel->attr.use_clockid == 0 || evsel->attr.clockid != CLOCK_MONOTONIC)
-			return -1;
-	}
-	return 0;
-}
-#endif
-
 int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
 {
 	struct perf_inject inject = {
@@ -853,13 +836,6 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
 	}
 #ifdef HAVE_LIBELF_SUPPORT
 	if (inject.jit_mode) {
-		/*
-		 * validate event is using the correct clockid
-		 */
-		if (jit_validate_events(inject.session)) {
-			fprintf(stderr, "error, jitted code must be sampled with perf record -k 1\n");
-			return -1;
-		}
 		inject.tool.mmap2	   = perf_event__jit_repipe_mmap2;
 		inject.tool.mmap	   = perf_event__jit_repipe_mmap;
 		inject.tool.ordered_events = true;
tools/perf/util/jitdump.c +23 -0
index bd9e44f9fff2..cd272cc21e05 100644
@@ -99,6 +99,21 @@ jit_close(struct jit_buf_desc *jd)
 }
 
 static int
+jit_validate_events(struct perf_session *session)
+{
+	struct perf_evsel *evsel;
+
+	/*
+	 * check that all events use CLOCK_MONOTONIC
+	 */
+	evlist__for_each(session->evlist, evsel) {
+		if (evsel->attr.use_clockid == 0 || evsel->attr.clockid != CLOCK_MONOTONIC)
+			return -1;
+	}
+	return 0;
+}
+
+static int
 jit_open(struct jit_buf_desc *jd, const char *name)
 {
 	struct jitheader header;
@@ -157,6 +172,14 @@ jit_open(struct jit_buf_desc *jd, const char *name)
 		goto error;
 	}
 
+	/*
+	 * validate event is using the correct clockid
+	 */
+	if (jit_validate_events(jd->session)) {
+		pr_err("error, jitted code must be sampled with perf record -k 1\n");
+		goto error;
+	}
+
 	bs = header.total_size - sizeof(header);
 
 	if (bs > bsz) {
Signature · 1 line
1.9.1
#15 lore raw

[tip:perf/core] perf jit: Move clockid validation

In reply to Adrian Hunter
perf jit: Move clockid validation
Commit-ID:  4a018cc47932ef1e68a0600ce3ac100df70fab2a
Gitweb:     http://git.kernel.org/tip/4a018cc47932ef1e68a0600ce3ac100df70fab2a
Author:     Adrian Hunter <[email protected]>
AuthorDate: Mon, 7 Mar 2016 16:44:41 -0300
Committer:  Ingo Molnar <[email protected]>
CommitDate: Tue, 8 Mar 2016 10:11:17 +0100

perf jit: Move clockid validation

Move clockid validation into jit_process() so it can later be made conditional.

---
 tools/perf/builtin-inject.c | 24 ------------------------
 tools/perf/util/jitdump.c   | 23 +++++++++++++++++++++++
 2 files changed, 23 insertions(+), 24 deletions(-)
tools/perf/builtin-inject.c +0 -24
index 2512d71..b288577 100644
@@ -729,23 +729,6 @@ static int __cmd_inject(struct perf_inject *inject)
 	return ret;
 }
 
-#ifdef HAVE_LIBELF_SUPPORT
-static int
-jit_validate_events(struct perf_session *session)
-{
-	struct perf_evsel *evsel;
-
-	/*
-	 * check that all events use CLOCK_MONOTONIC
-	 */
-	evlist__for_each(session->evlist, evsel) {
-		if (evsel->attr.use_clockid == 0 || evsel->attr.clockid != CLOCK_MONOTONIC)
-			return -1;
-	}
-	return 0;
-}
-#endif
-
 int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
 {
 	struct perf_inject inject = {
@@ -852,13 +835,6 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
 	}
 #ifdef HAVE_LIBELF_SUPPORT
 	if (inject.jit_mode) {
-		/*
-		 * validate event is using the correct clockid
-		 */
-		if (jit_validate_events(inject.session)) {
-			fprintf(stderr, "error, jitted code must be sampled with perf record -k 1\n");
-			return -1;
-		}
 		inject.tool.mmap2	   = perf_event__jit_repipe_mmap2;
 		inject.tool.mmap	   = perf_event__jit_repipe_mmap;
 		inject.tool.ordered_events = true;
tools/perf/util/jitdump.c +23 -0
index bd9e44f..cd272cc 100644
@@ -99,6 +99,21 @@ jit_close(struct jit_buf_desc *jd)
 }
 
 static int
+jit_validate_events(struct perf_session *session)
+{
+	struct perf_evsel *evsel;
+
+	/*
+	 * check that all events use CLOCK_MONOTONIC
+	 */
+	evlist__for_each(session->evlist, evsel) {
+		if (evsel->attr.use_clockid == 0 || evsel->attr.clockid != CLOCK_MONOTONIC)
+			return -1;
+	}
+	return 0;
+}
+
+static int
 jit_open(struct jit_buf_desc *jd, const char *name)
 {
 	struct jitheader header;
@@ -157,6 +172,14 @@ jit_open(struct jit_buf_desc *jd, const char *name)
 		goto error;
 	}
 
+	/*
+	 * validate event is using the correct clockid
+	 */
+	if (jit_validate_events(jd->session)) {
+		pr_err("error, jitted code must be sampled with perf record -k 1\n");
+		goto error;
+	}
+
 	bs = header.total_size - sizeof(header);
 
 	if (bs > bsz) {
author reviewer
#16 lore raw

PATCH 6/8 perf jit: Add support for using TSC as a timestamp

In reply to Adrian Hunter

From: Adrian Hunter <[email protected]>

Intel PT uses TSC as a timestamp, so add support for using TSC instead of the monotonic clock. Use of TSC is selected by an environment variable "JITDUMP_USE_ARCH_TIMESTAMP" and flagged in the jitdump file with flag JITDUMP_FLAGS_ARCH_TIMESTAMP.

---
 tools/perf/jvmti/jvmti_agent.c | 43 ++++++++++++++++++++++++++++++++++++++++--
 tools/perf/util/jitdump.c      | 37 +++++++++++++++++++++++++++++++-----
 tools/perf/util/jitdump.h      |  3 +++
 3 files changed, 76 insertions(+), 7 deletions(-)
tools/perf/jvmti/jvmti_agent.c +41 -2
index 6461e02ab940..3573f315f955 100644
@@ -92,6 +92,22 @@ error:
 	return ret;
 }
 
+static int use_arch_timestamp;
+
+static inline uint64_t
+get_arch_timestamp(void)
+{
+#if defined(__i386__) || defined(__x86_64__)
+	unsigned int low, high;
+
+	asm volatile("rdtsc" : "=a" (low), "=d" (high));
+
+	return low | ((uint64_t)high) << 32;
+#else
+	return 0;
+#endif
+}
+
 #define NSEC_PER_SEC	1000000000
 static int perf_clk_id = CLOCK_MONOTONIC;
 
@@ -107,6 +123,9 @@ perf_get_timestamp(void)
 	struct timespec ts;
 	int ret;
 
+	if (use_arch_timestamp)
+		return get_arch_timestamp();
+
 	ret = clock_gettime(perf_clk_id, &ts);
 	if (ret)
 		return 0;
@@ -203,6 +222,17 @@ perf_close_marker_file(void)
 	munmap(marker_addr, pgsz);
 }
 
+static void
+init_arch_timestamp(void)
+{
+	char *str = getenv("JITDUMP_USE_ARCH_TIMESTAMP");
+
+	if (!str || !*str || !strcmp(str, "0"))
+		return;
+
+	use_arch_timestamp = 1;
+}
+
 void *jvmti_open(void)
 {
 	int pad_cnt;
@@ -211,11 +241,17 @@ void *jvmti_open(void)
 	int fd;
 	FILE *fp;
 
+	init_arch_timestamp();
+
 	/*
 	 * check if clockid is supported
 	 */
-	if (!perf_get_timestamp())
-		warnx("jvmti: kernel does not support %d clock id", perf_clk_id);
+	if (!perf_get_timestamp()) {
+		if (use_arch_timestamp)
+			warnx("jvmti: arch timestamp not supported");
+		else
+			warnx("jvmti: kernel does not support %d clock id", perf_clk_id);
+	}
 
 	memset(&header, 0, sizeof(header));
 
@@ -263,6 +299,9 @@ void *jvmti_open(void)
 
 	header.timestamp = perf_get_timestamp();
 
+	if (use_arch_timestamp)
+		header.flags |= JITDUMP_FLAGS_ARCH_TIMESTAMP;
+
 	if (!fwrite(&header, sizeof(header), 1, fp)) {
 		warn("jvmti: cannot write dumpfile header");
 		goto error;
tools/perf/util/jitdump.c +32 -5
index cd272cc21e05..5608179dff34 100644
@@ -17,6 +17,7 @@
 #include "strlist.h"
 #include <elf.h>
 
+#include "tsc.h"
 #include "session.h"
 #include "jit.h"
 #include "jitdump.h"
@@ -33,6 +34,7 @@ struct jit_buf_desc {
 	size_t           bufsize;
 	FILE             *in;
 	bool		 needs_bswap; /* handles cross-endianess */
+	bool		 use_arch_timestamp;
 	void		 *debug_data;
 	size_t		 nr_debug_entries;
 	uint32_t         code_load_count;
@@ -158,13 +160,16 @@ jit_open(struct jit_buf_desc *jd, const char *name)
 		header.flags      = bswap_64(header.flags);
 	}
 
+	jd->use_arch_timestamp = header.flags & JITDUMP_FLAGS_ARCH_TIMESTAMP;
+
 	if (verbose > 2)
-		pr_debug("version=%u\nhdr.size=%u\nts=0x%llx\npid=%d\nelf_mach=%d\n",
+		pr_debug("version=%u\nhdr.size=%u\nts=0x%llx\npid=%d\nelf_mach=%d\nuse_arch_timestamp=%d\n",
 			header.version,
 			header.total_size,
 			(unsigned long long)header.timestamp,
 			header.pid,
-			header.elf_mach);
+			header.elf_mach,
+			jd->use_arch_timestamp);
 
 	if (header.flags & JITDUMP_FLAGS_RESERVED) {
 		pr_err("jitdump file contains invalid or unsupported flags 0x%llx\n",
@@ -172,10 +177,15 @@ jit_open(struct jit_buf_desc *jd, const char *name)
 		goto error;
 	}
 
+	if (jd->use_arch_timestamp && !jd->session->time_conv.time_mult) {
+		pr_err("jitdump file uses arch timestamps but there is no timestamp conversion\n");
+		goto error;
+	}
+
 	/*
 	 * validate event is using the correct clockid
 	 */
-	if (jit_validate_events(jd->session)) {
+	if (!jd->use_arch_timestamp && jit_validate_events(jd->session)) {
 		pr_err("error, jitted code must be sampled with perf record -k 1\n");
 		goto error;
 	}
@@ -329,6 +339,23 @@ jit_inject_event(struct jit_buf_desc *jd, union perf_event *event)
 	return 0;
 }
 
+static uint64_t convert_timestamp(struct jit_buf_desc *jd, uint64_t timestamp)
+{
+	struct perf_tsc_conversion tc;
+
+	if (!jd->use_arch_timestamp)
+		return timestamp;
+
+	tc.time_shift = jd->session->time_conv.time_shift;
+	tc.time_mult  = jd->session->time_conv.time_mult;
+	tc.time_zero  = jd->session->time_conv.time_zero;
+
+	if (!tc.time_mult)
+		return 0;
+
+	return tsc_to_perf_time(timestamp, &tc);
+}
+
 static int jit_repipe_code_load(struct jit_buf_desc *jd, union jr_entry *jr)
 {
 	struct perf_sample sample;
@@ -410,7 +437,7 @@ static int jit_repipe_code_load(struct jit_buf_desc *jd, union jr_entry *jr)
 		id->tid  = tid;
 	}
 	if (jd->sample_type & PERF_SAMPLE_TIME)
-		id->time = jr->load.p.timestamp;
+		id->time = convert_timestamp(jd, jr->load.p.timestamp);
 
 	/*
 	 * create pseudo sample to induce dso hit increment
@@ -498,7 +525,7 @@ static int jit_repipe_code_move(struct jit_buf_desc *jd, union jr_entry *jr)
 		id->tid  = tid;
 	}
 	if (jd->sample_type & PERF_SAMPLE_TIME)
-		id->time = jr->load.p.timestamp;
+		id->time = convert_timestamp(jd, jr->load.p.timestamp);
 
 	/*
 	 * create pseudo sample to induce dso hit increment
tools/perf/util/jitdump.h +3 -0
index b66c1f503d9e..bcacd20d0c1c 100644
@@ -23,9 +23,12 @@
 #define JITHEADER_VERSION 1
 
 enum jitdump_flags_bits {
+	JITDUMP_FLAGS_ARCH_TIMESTAMP_BIT,
 	JITDUMP_FLAGS_MAX_BIT,
 };
 
+#define JITDUMP_FLAGS_ARCH_TIMESTAMP	(1ULL << JITDUMP_FLAGS_ARCH_TIMESTAMP_BIT)
+
 #define JITDUMP_FLAGS_RESERVED (JITDUMP_FLAGS_MAX_BIT < 64 ? \
 				(~((1ULL << JITDUMP_FLAGS_MAX_BIT) - 1)) : 0)
 
Signature · 1 line
1.9.1
author reviewer
#17 lore raw

PATCH v2 6/8 perf jit: Add support for using TSC as a timestamp

Intel PT uses TSC as a timestamp, so add support for using TSC instead of the monotonic clock. Use of TSC is selected by an environment variable "JITDUMP_USE_ARCH_TIMESTAMP" and flagged in the jitdump file with flag JITDUMP_FLAGS_ARCH_TIMESTAMP.

---

Changes in V2:

Fixed "From" and "Signed-off-by" email addresses

 tools/perf/jvmti/jvmti_agent.c | 43 ++++++++++++++++++++++++++++++++++++++++--
 tools/perf/util/jitdump.c      | 37 +++++++++++++++++++++++++++++++-----
 tools/perf/util/jitdump.h      |  3 +++
 3 files changed, 76 insertions(+), 7 deletions(-)
tools/perf/jvmti/jvmti_agent.c +41 -2
index 6461e02ab940..3573f315f955 100644
@@ -92,6 +92,22 @@ error:
 	return ret;
 }
 
+static int use_arch_timestamp;
+
+static inline uint64_t
+get_arch_timestamp(void)
+{
+#if defined(__i386__) || defined(__x86_64__)
+	unsigned int low, high;
+
+	asm volatile("rdtsc" : "=a" (low), "=d" (high));
+
+	return low | ((uint64_t)high) << 32;
+#else
+	return 0;
+#endif
+}
+
 #define NSEC_PER_SEC	1000000000
 static int perf_clk_id = CLOCK_MONOTONIC;
 
@@ -107,6 +123,9 @@ perf_get_timestamp(void)
 	struct timespec ts;
 	int ret;
 
+	if (use_arch_timestamp)
+		return get_arch_timestamp();
+
 	ret = clock_gettime(perf_clk_id, &ts);
 	if (ret)
 		return 0;
@@ -203,6 +222,17 @@ perf_close_marker_file(void)
 	munmap(marker_addr, pgsz);
 }
 
+static void
+init_arch_timestamp(void)
+{
+	char *str = getenv("JITDUMP_USE_ARCH_TIMESTAMP");
+
+	if (!str || !*str || !strcmp(str, "0"))
+		return;
+
+	use_arch_timestamp = 1;
+}
+
 void *jvmti_open(void)
 {
 	int pad_cnt;
@@ -211,11 +241,17 @@ void *jvmti_open(void)
 	int fd;
 	FILE *fp;
 
+	init_arch_timestamp();
+
 	/*
 	 * check if clockid is supported
 	 */
-	if (!perf_get_timestamp())
-		warnx("jvmti: kernel does not support %d clock id", perf_clk_id);
+	if (!perf_get_timestamp()) {
+		if (use_arch_timestamp)
+			warnx("jvmti: arch timestamp not supported");
+		else
+			warnx("jvmti: kernel does not support %d clock id", perf_clk_id);
+	}
 
 	memset(&header, 0, sizeof(header));
 
@@ -263,6 +299,9 @@ void *jvmti_open(void)
 
 	header.timestamp = perf_get_timestamp();
 
+	if (use_arch_timestamp)
+		header.flags |= JITDUMP_FLAGS_ARCH_TIMESTAMP;
+
 	if (!fwrite(&header, sizeof(header), 1, fp)) {
 		warn("jvmti: cannot write dumpfile header");
 		goto error;
tools/perf/util/jitdump.c +32 -5
index cd272cc21e05..5608179dff34 100644
@@ -17,6 +17,7 @@
 #include "strlist.h"
 #include <elf.h>
 
+#include "tsc.h"
 #include "session.h"
 #include "jit.h"
 #include "jitdump.h"
@@ -33,6 +34,7 @@ struct jit_buf_desc {
 	size_t           bufsize;
 	FILE             *in;
 	bool		 needs_bswap; /* handles cross-endianess */
+	bool		 use_arch_timestamp;
 	void		 *debug_data;
 	size_t		 nr_debug_entries;
 	uint32_t         code_load_count;
@@ -158,13 +160,16 @@ jit_open(struct jit_buf_desc *jd, const char *name)
 		header.flags      = bswap_64(header.flags);
 	}
 
+	jd->use_arch_timestamp = header.flags & JITDUMP_FLAGS_ARCH_TIMESTAMP;
+
 	if (verbose > 2)
-		pr_debug("version=%u\nhdr.size=%u\nts=0x%llx\npid=%d\nelf_mach=%d\n",
+		pr_debug("version=%u\nhdr.size=%u\nts=0x%llx\npid=%d\nelf_mach=%d\nuse_arch_timestamp=%d\n",
 			header.version,
 			header.total_size,
 			(unsigned long long)header.timestamp,
 			header.pid,
-			header.elf_mach);
+			header.elf_mach,
+			jd->use_arch_timestamp);
 
 	if (header.flags & JITDUMP_FLAGS_RESERVED) {
 		pr_err("jitdump file contains invalid or unsupported flags 0x%llx\n",
@@ -172,10 +177,15 @@ jit_open(struct jit_buf_desc *jd, const char *name)
 		goto error;
 	}
 
+	if (jd->use_arch_timestamp && !jd->session->time_conv.time_mult) {
+		pr_err("jitdump file uses arch timestamps but there is no timestamp conversion\n");
+		goto error;
+	}
+
 	/*
 	 * validate event is using the correct clockid
 	 */
-	if (jit_validate_events(jd->session)) {
+	if (!jd->use_arch_timestamp && jit_validate_events(jd->session)) {
 		pr_err("error, jitted code must be sampled with perf record -k 1\n");
 		goto error;
 	}
@@ -329,6 +339,23 @@ jit_inject_event(struct jit_buf_desc *jd, union perf_event *event)
 	return 0;
 }
 
+static uint64_t convert_timestamp(struct jit_buf_desc *jd, uint64_t timestamp)
+{
+	struct perf_tsc_conversion tc;
+
+	if (!jd->use_arch_timestamp)
+		return timestamp;
+
+	tc.time_shift = jd->session->time_conv.time_shift;
+	tc.time_mult  = jd->session->time_conv.time_mult;
+	tc.time_zero  = jd->session->time_conv.time_zero;
+
+	if (!tc.time_mult)
+		return 0;
+
+	return tsc_to_perf_time(timestamp, &tc);
+}
+
 static int jit_repipe_code_load(struct jit_buf_desc *jd, union jr_entry *jr)
 {
 	struct perf_sample sample;
@@ -410,7 +437,7 @@ static int jit_repipe_code_load(struct jit_buf_desc *jd, union jr_entry *jr)
 		id->tid  = tid;
 	}
 	if (jd->sample_type & PERF_SAMPLE_TIME)
-		id->time = jr->load.p.timestamp;
+		id->time = convert_timestamp(jd, jr->load.p.timestamp);
 
 	/*
 	 * create pseudo sample to induce dso hit increment
@@ -498,7 +525,7 @@ static int jit_repipe_code_move(struct jit_buf_desc *jd, union jr_entry *jr)
 		id->tid  = tid;
 	}
 	if (jd->sample_type & PERF_SAMPLE_TIME)
-		id->time = jr->load.p.timestamp;
+		id->time = convert_timestamp(jd, jr->load.p.timestamp);
 
 	/*
 	 * create pseudo sample to induce dso hit increment
tools/perf/util/jitdump.h +3 -0
index b66c1f503d9e..bcacd20d0c1c 100644
@@ -23,9 +23,12 @@
 #define JITHEADER_VERSION 1
 
 enum jitdump_flags_bits {
+	JITDUMP_FLAGS_ARCH_TIMESTAMP_BIT,
 	JITDUMP_FLAGS_MAX_BIT,
 };
 
+#define JITDUMP_FLAGS_ARCH_TIMESTAMP	(1ULL << JITDUMP_FLAGS_ARCH_TIMESTAMP_BIT)
+
 #define JITDUMP_FLAGS_RESERVED (JITDUMP_FLAGS_MAX_BIT < 64 ? \
 				(~((1ULL << JITDUMP_FLAGS_MAX_BIT) - 1)) : 0)
 
Signature · 1 line
1.9.1
author reviewer
#18 lore raw

PATCH 7/8 perf intel-pt/bts: Define JITDUMP_USE_ARCH_TIMESTAMP

In reply to Adrian Hunter

From: Adrian Hunter <[email protected]>

For Intel PT / BTS, define the environment variable that selects TSC timestamps in the jitdump file.

---
 tools/perf/arch/x86/util/intel-bts.c | 5 +++++
 tools/perf/arch/x86/util/intel-pt.c  | 5 +++++
 2 files changed, 10 insertions(+)
tools/perf/arch/x86/util/intel-bts.c +5 -0
index d66f9ad4df2e..7dc30637cf66 100644
@@ -438,6 +438,11 @@ struct auxtrace_record *intel_bts_recording_init(int *err)
 	if (!intel_bts_pmu)
 		return NULL;
 
+	if (setenv("JITDUMP_USE_ARCH_TIMESTAMP", "1", 1)) {
+		*err = -errno;
+		return NULL;
+	}
+
 	btsr = zalloc(sizeof(struct intel_bts_recording));
 	if (!btsr) {
 		*err = -ENOMEM;
tools/perf/arch/x86/util/intel-pt.c +5 -0
index a3395179c9ee..a07b9605e93b 100644
@@ -1027,6 +1027,11 @@ struct auxtrace_record *intel_pt_recording_init(int *err)
 	if (!intel_pt_pmu)
 		return NULL;
 
+	if (setenv("JITDUMP_USE_ARCH_TIMESTAMP", "1", 1)) {
+		*err = -errno;
+		return NULL;
+	}
+
 	ptr = zalloc(sizeof(struct intel_pt_recording));
 	if (!ptr) {
 		*err = -ENOMEM;
Signature · 1 line
1.9.1
author reviewer
#19 lore raw

PATCH v2 7/8 perf intel-pt/bts: Define JITDUMP_USE_ARCH_TIMESTAMP

For Intel PT / BTS, define the environment variable that selects TSC timestamps in the jitdump file.

---

Changes in V2:

Fixed "From" and "Signed-off-by" email addresses

 tools/perf/arch/x86/util/intel-bts.c | 5 +++++
 tools/perf/arch/x86/util/intel-pt.c  | 5 +++++
 2 files changed, 10 insertions(+)
tools/perf/arch/x86/util/intel-bts.c +5 -0
index d66f9ad4df2e..7dc30637cf66 100644
@@ -438,6 +438,11 @@ struct auxtrace_record *intel_bts_recording_init(int *err)
 	if (!intel_bts_pmu)
 		return NULL;
 
+	if (setenv("JITDUMP_USE_ARCH_TIMESTAMP", "1", 1)) {
+		*err = -errno;
+		return NULL;
+	}
+
 	btsr = zalloc(sizeof(struct intel_bts_recording));
 	if (!btsr) {
 		*err = -ENOMEM;
tools/perf/arch/x86/util/intel-pt.c +5 -0
index a3395179c9ee..a07b9605e93b 100644
@@ -1027,6 +1027,11 @@ struct auxtrace_record *intel_pt_recording_init(int *err)
 	if (!intel_pt_pmu)
 		return NULL;
 
+	if (setenv("JITDUMP_USE_ARCH_TIMESTAMP", "1", 1)) {
+		*err = -errno;
+		return NULL;
+	}
+
 	ptr = zalloc(sizeof(struct intel_pt_recording));
 	if (!ptr) {
 		*err = -ENOMEM;
Signature · 1 line
1.9.1
#20 lore raw

[tip:perf/core] perf intel-pt/bts: Define JITDUMP_USE_ARCH_TIMESTAMP

perf intel-pt/bts: Define JITDUMP_USE_ARCH_TIMESTAMP
Commit-ID:  bd0c7a54219cc3745ce7f36970d8e5ffb3f8d80e
Gitweb:     http://git.kernel.org/tip/bd0c7a54219cc3745ce7f36970d8e5ffb3f8d80e
Author:     Adrian Hunter <[email protected]>
AuthorDate: Tue, 8 Mar 2016 10:38:53 +0200
Committer:  Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Fri, 1 Apr 2016 18:46:24 -0300

perf intel-pt/bts: Define JITDUMP_USE_ARCH_TIMESTAMP

For Intel PT / BTS, define the environment variable that selects TSC timestamps in the jitdump file.

---
 tools/perf/arch/x86/util/intel-bts.c | 5 +++++
 tools/perf/arch/x86/util/intel-pt.c  | 5 +++++
 2 files changed, 10 insertions(+)
tools/perf/arch/x86/util/intel-bts.c +5 -0
index d66f9ad..7dc3063 100644
@@ -438,6 +438,11 @@ struct auxtrace_record *intel_bts_recording_init(int *err)
 	if (!intel_bts_pmu)
 		return NULL;
 
+	if (setenv("JITDUMP_USE_ARCH_TIMESTAMP", "1", 1)) {
+		*err = -errno;
+		return NULL;
+	}
+
 	btsr = zalloc(sizeof(struct intel_bts_recording));
 	if (!btsr) {
 		*err = -ENOMEM;
tools/perf/arch/x86/util/intel-pt.c +5 -0
index a339517..a07b960 100644
@@ -1027,6 +1027,11 @@ struct auxtrace_record *intel_pt_recording_init(int *err)
 	if (!intel_pt_pmu)
 		return NULL;
 
+	if (setenv("JITDUMP_USE_ARCH_TIMESTAMP", "1", 1)) {
+		*err = -errno;
+		return NULL;
+	}
+
 	ptr = zalloc(sizeof(struct intel_pt_recording));
 	if (!ptr) {
 		*err = -ENOMEM;
author reviewer
#21 lore raw

PATCH 8/8 perf tools: Use 64-bit shifts with (TSC) time conversion

In reply to Adrian Hunter

Commit b9511cd761fa ("perf/x86: Fix time_shift in perf_event_mmap_page") altered the time conversion algorithms documented in the perf_event.h header file, to use 64-bit shifts. That was done to make the code more future-proof (i.e. some time in the future a 32-bit shift could be allowed). Reflect those changes in perf tools.

---
 tools/perf/arch/x86/tests/rdpmc.c | 2 +-
 tools/perf/util/tsc.c             | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)
tools/perf/arch/x86/tests/rdpmc.c +1 -1
index 7945462851a4..72193f19d6d7 100644
@@ -59,7 +59,7 @@ static u64 mmap_read_self(void *addr)
 		u64 quot, rem;
 
 		quot = (cyc >> time_shift);
-		rem = cyc & ((1 << time_shift) - 1);
+		rem = cyc & (((u64)1 << time_shift) - 1);
 		delta = time_offset + quot * time_mult +
 			((rem * time_mult) >> time_shift);
 
tools/perf/util/tsc.c +1 -1
index 4d4210d4e13d..1b741646eed0 100644
@@ -19,7 +19,7 @@ u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc)
 	u64 quot, rem;
 
 	quot = cyc >> tc->time_shift;
-	rem  = cyc & ((1 << tc->time_shift) - 1);
+	rem  = cyc & (((u64)1 << tc->time_shift) - 1);
 	return tc->time_zero + quot * tc->time_mult +
 	       ((rem * tc->time_mult) >> tc->time_shift);
 }
Signature · 1 line
1.9.1
#22 lore raw

[tip:perf/core] perf tools: Use 64-bit shifts with (TSC) time conversion

perf tools: Use 64-bit shifts with (TSC) time conversion
Commit-ID:  a23f96ee4d51ebd50b83ce0dbb5d04898fb8e3cb
Gitweb:     http://git.kernel.org/tip/a23f96ee4d51ebd50b83ce0dbb5d04898fb8e3cb
Author:     Adrian Hunter <[email protected]>
AuthorDate: Mon, 7 Mar 2016 16:44:42 -0300
Committer:  Ingo Molnar <[email protected]>
CommitDate: Tue, 8 Mar 2016 10:11:18 +0100

perf tools: Use 64-bit shifts with (TSC) time conversion

Commit b9511cd761fa ("perf/x86: Fix time_shift in perf_event_mmap_page") altered the time conversion algorithms documented in the perf_event.h header file, to use 64-bit shifts. That was done to make the code more future-proof (i.e. some time in the future a 32-bit shift could be allowed). Reflect those changes in perf tools.

---
 tools/perf/arch/x86/tests/rdpmc.c | 2 +-
 tools/perf/util/tsc.c             | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)
tools/perf/arch/x86/tests/rdpmc.c +1 -1
index 7945462..72193f1 100644
@@ -59,7 +59,7 @@ static u64 mmap_read_self(void *addr)
 		u64 quot, rem;
 
 		quot = (cyc >> time_shift);
-		rem = cyc & ((1 << time_shift) - 1);
+		rem = cyc & (((u64)1 << time_shift) - 1);
 		delta = time_offset + quot * time_mult +
 			((rem * time_mult) >> time_shift);
 
tools/perf/util/tsc.c +1 -1
index 4d4210d..1b74164 100644
@@ -19,7 +19,7 @@ u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc)
 	u64 quot, rem;
 
 	quot = cyc >> tc->time_shift;
-	rem  = cyc & ((1 << tc->time_shift) - 1);
+	rem  = cyc & (((u64)1 << tc->time_shift) - 1);
 	return tc->time_zero + quot * tc->time_mult +
 	       ((rem * tc->time_mult) >> tc->time_shift);
 }
author reviewer
#23 lore raw
In reply to Adrian Hunter

Hi

I have just sent V2 of patches 2, 3, 5, 6, 7 because the email address was wrong in the "From" and "Signed-off-by".

I realize you have already processed some of the patches. Very sorry for the inconvenience.

Regards
Adrian

#24 lore raw

PATCH 1/1 perf tools: Fix build errors on tsc functions for archs other than x86

Build errors on aarch64:

libperf.a(libperf-in.o): In function `convert_timestamp':
util/jitdump.c:356: undefined reference to `tsc_to_perf_time'
collect2: error: ld returned 1 exit status Makefile.perf:347: recipe for target 'perf' failed make[1]: *** [perf] Error 1
Makefile:68: recipe for target 'all' failed
make: *** [all] Error 2

Since tsc conversion functions were moved out from arch dir, move 'tsc.h' out from x86 dir to make it possible to compile for other archs.

---
 tools/perf/arch/x86/util/tsc.c |  1 -
 tools/perf/arch/x86/util/tsc.h | 17 -----------------
 tools/perf/util/Build          |  3 +--
 tools/perf/util/tsc.h          | 11 ++++++++++-
 4 files changed, 11 insertions(+), 21 deletions(-)
 delete mode 100644 tools/perf/arch/x86/util/tsc.h
tools/perf/arch/x86/util/tsc.c +0 -1
index 70ff7c1..357f1b1 100644
@@ -7,7 +7,6 @@
 #include <linux/types.h>
 #include "../../util/debug.h"
 #include "../../util/tsc.h"
-#include "tsc.h"
 
 int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc,
 			     struct perf_tsc_conversion *tc)
tools/perf/arch/x86/util/tsc.h deleted +0 -17
deleted file mode 100644
index 2edc4d3..0000000
@@ -1,17 +0,0 @@
-#ifndef TOOLS_PERF_ARCH_X86_UTIL_TSC_H__
-#define TOOLS_PERF_ARCH_X86_UTIL_TSC_H__
-
-#include <linux/types.h>
-
-struct perf_tsc_conversion {
-	u16 time_shift;
-	u32 time_mult;
-	u64 time_zero;
-};
-
-struct perf_event_mmap_page;
-
-int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc,
-			     struct perf_tsc_conversion *tc);
-
-#endif /* TOOLS_PERF_ARCH_X86_UTIL_TSC_H__ */
tools/perf/util/Build +1 -2
index da48fd8..85ceff3 100644
@@ -69,8 +69,7 @@ libperf-y += stat-shadow.o
 libperf-y += record.o
 libperf-y += srcline.o
 libperf-y += data.o
-libperf-$(CONFIG_X86) += tsc.o
-libperf-$(CONFIG_AUXTRACE) += tsc.o
+libperf-y += tsc.o
 libperf-y += cloexec.o
 libperf-y += thread-stack.o
 libperf-$(CONFIG_AUXTRACE) += auxtrace.o
tools/perf/util/tsc.h +10 -1
index 280ddc0..d5b11e2 100644
@@ -4,7 +4,16 @@
 #include <linux/types.h>
 
 #include "event.h"
-#include "../arch/x86/util/tsc.h"
+
+struct perf_tsc_conversion {
+	u16 time_shift;
+	u32 time_mult;
+	u64 time_zero;
+};
+struct perf_event_mmap_page;
+
+int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc,
+			     struct perf_tsc_conversion *tc);
 
 u64 perf_time_to_tsc(u64 ns, struct perf_tsc_conversion *tc);
 u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc);
Signature · 1 line
1.8.5.2
author reviewer Acked-by on v1 1/1
#25 lore raw

Re: [PATCH] perf tools: Fix build errors on tsc functions for archs other than x86

Quoted 9 lines · He Kuang

Build errors on aarch64:

libperf.a(libperf-in.o): In function `convert_timestamp':
util/jitdump.c:356: undefined reference to `tsc_to_perf_time'
collect2: error: ld returned 1 exit status Makefile.perf:347: recipe for target 'perf' failed make[1]: *** [perf] Error 1
Makefile:68: recipe for target 'all' failed
make: *** [all] Error 2

Sorry about that :-(

Quoted 3 lines

Since tsc conversion functions were moved out from arch dir, move 'tsc.h' out from x86 dir to make it possible to compile for other archs.

So this is the case where data can be collected on x86 and then processed on another arch.

Originally, it wasn't wanted to be compiled in:

	http://marc.info/?l=linux-kernel&m=142445842131011

But that has been causing problems:

	http://marc.info/?l=linux-kernel&m=144109627003194

So this seems better.

Quoted 2 lines
Quoted 80 lines
---
 tools/perf/arch/x86/util/tsc.c |  1 -
 tools/perf/arch/x86/util/tsc.h | 17 -----------------
 tools/perf/util/Build          |  3 +--
 tools/perf/util/tsc.h          | 11 ++++++++++-
 4 files changed, 11 insertions(+), 21 deletions(-)
 delete mode 100644 tools/perf/arch/x86/util/tsc.h
tools/perf/arch/x86/util/tsc.c +0 -1
index 70ff7c1..357f1b1 100644
@@ -7,7 +7,6 @@
 #include <linux/types.h>
 #include "../../util/debug.h"
 #include "../../util/tsc.h"
-#include "tsc.h"
 
 int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc,
 			     struct perf_tsc_conversion *tc)
tools/perf/arch/x86/util/tsc.h deleted +0 -17
deleted file mode 100644
index 2edc4d3..0000000
@@ -1,17 +0,0 @@
-#ifndef TOOLS_PERF_ARCH_X86_UTIL_TSC_H__
-#define TOOLS_PERF_ARCH_X86_UTIL_TSC_H__
-
-#include <linux/types.h>
-
-struct perf_tsc_conversion {
-	u16 time_shift;
-	u32 time_mult;
-	u64 time_zero;
-};
-
-struct perf_event_mmap_page;
-
-int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc,
-			     struct perf_tsc_conversion *tc);
-
-#endif /* TOOLS_PERF_ARCH_X86_UTIL_TSC_H__ */
tools/perf/util/Build +1 -2
index da48fd8..85ceff3 100644
@@ -69,8 +69,7 @@ libperf-y += stat-shadow.o
 libperf-y += record.o
 libperf-y += srcline.o
 libperf-y += data.o
-libperf-$(CONFIG_X86) += tsc.o
-libperf-$(CONFIG_AUXTRACE) += tsc.o
+libperf-y += tsc.o
 libperf-y += cloexec.o
 libperf-y += thread-stack.o
 libperf-$(CONFIG_AUXTRACE) += auxtrace.o
tools/perf/util/tsc.h +10 -1
index 280ddc0..d5b11e2 100644
@@ -4,7 +4,16 @@
 #include <linux/types.h>
 
 #include "event.h"
-#include "../arch/x86/util/tsc.h"
+
+struct perf_tsc_conversion {
+	u16 time_shift;
+	u32 time_mult;
+	u64 time_zero;
+};
+struct perf_event_mmap_page;
+
+int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc,
+			     struct perf_tsc_conversion *tc);
 
 u64 perf_time_to_tsc(u64 ns, struct perf_tsc_conversion *tc);
 u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc);
#26 lore raw

Re: [PATCH] perf tools: Fix build errors on tsc functions for archs other than x86

In reply to He Kuang

Em Fri, Apr 01, 2016 at 03:49:32AM +0000, He Kuang escreveu:

Quoted 9 lines

Build errors on aarch64:

libperf.a(libperf-in.o): In function `convert_timestamp':
util/jitdump.c:356: undefined reference to `tsc_to_perf_time'
collect2: error: ld returned 1 exit status Makefile.perf:347: recipe for target 'perf' failed make[1]: *** [perf] Error 1
Makefile:68: recipe for target 'all' failed
make: *** [all] Error 2

Got it, my cross-compile environment for aarch64 doesn't build jitdump.c because it needs a package I haven't found in ubuntu:

config/Makefile:416: No libcrypto.h found, disables jitted code injection, please install libssl-devel or libssl-dev
minimal-ubuntu-x-arm64: Ok

BTW, He, what environment do you use to build for arm64, is it a cross compile one? Yocto?

- Arnaldo

Quoted 85 lines

Since tsc conversion functions were moved out from arch dir, move 'tsc.h' out from x86 dir to make it possible to compile for other archs.

---
 tools/perf/arch/x86/util/tsc.c |  1 -
 tools/perf/arch/x86/util/tsc.h | 17 -----------------
 tools/perf/util/Build          |  3 +--
 tools/perf/util/tsc.h          | 11 ++++++++++-
 4 files changed, 11 insertions(+), 21 deletions(-)
 delete mode 100644 tools/perf/arch/x86/util/tsc.h
tools/perf/arch/x86/util/tsc.c +0 -1
index 70ff7c1..357f1b1 100644
@@ -7,7 +7,6 @@
 #include <linux/types.h>
 #include "../../util/debug.h"
 #include "../../util/tsc.h"
-#include "tsc.h"
 
 int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc,
 			     struct perf_tsc_conversion *tc)
tools/perf/arch/x86/util/tsc.h deleted +0 -17
deleted file mode 100644
index 2edc4d3..0000000
@@ -1,17 +0,0 @@
-#ifndef TOOLS_PERF_ARCH_X86_UTIL_TSC_H__
-#define TOOLS_PERF_ARCH_X86_UTIL_TSC_H__
-
-#include <linux/types.h>
-
-struct perf_tsc_conversion {
-	u16 time_shift;
-	u32 time_mult;
-	u64 time_zero;
-};
-
-struct perf_event_mmap_page;
-
-int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc,
-			     struct perf_tsc_conversion *tc);
-
-#endif /* TOOLS_PERF_ARCH_X86_UTIL_TSC_H__ */
tools/perf/util/Build +1 -2
index da48fd8..85ceff3 100644
@@ -69,8 +69,7 @@ libperf-y += stat-shadow.o
 libperf-y += record.o
 libperf-y += srcline.o
 libperf-y += data.o
-libperf-$(CONFIG_X86) += tsc.o
-libperf-$(CONFIG_AUXTRACE) += tsc.o
+libperf-y += tsc.o
 libperf-y += cloexec.o
 libperf-y += thread-stack.o
 libperf-$(CONFIG_AUXTRACE) += auxtrace.o
tools/perf/util/tsc.h +10 -1
index 280ddc0..d5b11e2 100644
@@ -4,7 +4,16 @@
 #include <linux/types.h>
 
 #include "event.h"
-#include "../arch/x86/util/tsc.h"
+
+struct perf_tsc_conversion {
+	u16 time_shift;
+	u32 time_mult;
+	u64 time_zero;
+};
+struct perf_event_mmap_page;
+
+int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc,
+			     struct perf_tsc_conversion *tc);
 
 u64 perf_time_to_tsc(u64 ns, struct perf_tsc_conversion *tc);
 u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc);
Signature · 1 line
1.8.5.2
#27 lore raw

Re: [PATCH] perf tools: Fix build errors on tsc functions for archs other than x86

hi,

Quoted 10 lines · Arnaldo Carvalho de Melo

Em Fri, Apr 01, 2016 at 03:49:32AM +0000, He Kuang escreveu:

Quoted 9 lines

Build errors on aarch64:

libperf.a(libperf-in.o): In function `convert_timestamp':
util/jitdump.c:356: undefined reference to `tsc_to_perf_time'
collect2: error: ld returned 1 exit status Makefile.perf:347: recipe for target 'perf' failed make[1]: *** [perf] Error 1
Makefile:68: recipe for target 'all' failed
make: *** [all] Error 2

Quoted 8 lines

Got it, my cross-compile environment for aarch64 doesn't build jitdump.c because it needs a package I haven't found in ubuntu:

config/Makefile:416: No libcrypto.h found, disables jitted code injection, please install libssl-devel or libssl-dev
minimal-ubuntu-x-arm64: Ok

BTW, He, what environment do you use to build for arm64, is it a cross compile one? Yocto?

I use buildroot, though my colleague prefers yocto(oxygen).

In my environment, libcrypto is on.
... libcrypto: [ on ]

Quoted 90 lines

- Arnaldo

Quoted 85 lines

Since tsc conversion functions were moved out from arch dir, move 'tsc.h' out from x86 dir to make it possible to compile for other archs.

---
  tools/perf/arch/x86/util/tsc.c |  1 -
  tools/perf/arch/x86/util/tsc.h | 17 -----------------
  tools/perf/util/Build          |  3 +--
  tools/perf/util/tsc.h          | 11 ++++++++++-
  4 files changed, 11 insertions(+), 21 deletions(-)

delete mode 100644 tools/perf/arch/x86/util/tsc.h

tools/perf/arch/x86/util/tsc.c +0 -1
index 70ff7c1..357f1b1 100644
@@ -7,7 +7,6 @@
  #include <linux/types.h>
  #include "../../util/debug.h"
  #include "../../util/tsc.h"
-#include "tsc.h"
 
  int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc,
  			     struct perf_tsc_conversion *tc)
tools/perf/arch/x86/util/tsc.h deleted +0 -17
deleted file mode 100644
index 2edc4d3..0000000
@@ -1,17 +0,0 @@
-#ifndef TOOLS_PERF_ARCH_X86_UTIL_TSC_H__
-#define TOOLS_PERF_ARCH_X86_UTIL_TSC_H__
-
-#include <linux/types.h>
-
-struct perf_tsc_conversion {
-	u16 time_shift;
-	u32 time_mult;
-	u64 time_zero;
-};
-
-struct perf_event_mmap_page;
-
-int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc,
-			     struct perf_tsc_conversion *tc);
-
-#endif /* TOOLS_PERF_ARCH_X86_UTIL_TSC_H__ */
tools/perf/util/Build +1 -2
index da48fd8..85ceff3 100644
@@ -69,8 +69,7 @@ libperf-y += stat-shadow.o
  libperf-y += record.o
  libperf-y += srcline.o
  libperf-y += data.o
-libperf-$(CONFIG_X86) += tsc.o
-libperf-$(CONFIG_AUXTRACE) += tsc.o
+libperf-y += tsc.o
  libperf-y += cloexec.o
  libperf-y += thread-stack.o
  libperf-$(CONFIG_AUXTRACE) += auxtrace.o
tools/perf/util/tsc.h +10 -1
index 280ddc0..d5b11e2 100644
@@ -4,7 +4,16 @@
  #include <linux/types.h>
 
  #include "event.h"
-#include "../arch/x86/util/tsc.h"
+
+struct perf_tsc_conversion {
+	u16 time_shift;
+	u32 time_mult;
+	u64 time_zero;
+};
+struct perf_event_mmap_page;
+
+int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc,
+			     struct perf_tsc_conversion *tc);
 
  u64 perf_time_to_tsc(u64 ns, struct perf_tsc_conversion *tc);
  u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc);
Signature · 1 line
1.8.5.2
#28 lore raw

Re: [PATCH] perf tools: Fix build errors on tsc functions for archs other than x86

In reply to Arnaldo Carvalho de Melo

Em Fri, Apr 01, 2016 at 10:13:12AM -0300, Arnaldo Carvalho de Melo escreveu:

Quoted 11 lines

Em Fri, Apr 01, 2016 at 03:49:32AM +0000, He Kuang escreveu:

Quoted 9 lines

Build errors on aarch64:

libperf.a(libperf-in.o): In function `convert_timestamp':
util/jitdump.c:356: undefined reference to `tsc_to_perf_time'
collect2: error: ld returned 1 exit status Makefile.perf:347: recipe for target 'perf' failed make[1]: *** [perf] Error 1
Makefile:68: recipe for target 'all' failed
make: *** [all] Error 2

Quoted 8 lines

Got it, my cross-compile environment for aarch64 doesn't build jitdump.c because it needs a package I haven't found in ubuntu:

config/Makefile:416: No libcrypto.h found, disables jitted code injection, please install libssl-devel or libssl-dev
minimal-ubuntu-x-arm64: Ok

BTW, He, what environment do you use to build for arm64, is it a cross compile one? Yocto?

Adrian, BTW, Ok with this? I'm adding a:

Fixes d3e58a3b8b3b ("perf jit: Add support for using TSC as a timestamp")

And would appreciate your Acked-by.

Thanks,

- Arnaldo

author reviewer Acked-by
#29 lore raw

Re: [PATCH] perf tools: Fix build errors on tsc functions for archs other than x86

Quoted 18 lines · Arnaldo Carvalho de Melo

Em Fri, Apr 01, 2016 at 10:13:12AM -0300, Arnaldo Carvalho de Melo escreveu:

Quoted 17 lines

Em Fri, Apr 01, 2016 at 03:49:32AM +0000, He Kuang escreveu:

Quoted 9 lines

Build errors on aarch64:

libperf.a(libperf-in.o): In function `convert_timestamp':
util/jitdump.c:356: undefined reference to `tsc_to_perf_time'
collect2: error: ld returned 1 exit status Makefile.perf:347: recipe for target 'perf' failed make[1]: *** [perf] Error 1
Makefile:68: recipe for target 'all' failed
make: *** [all] Error 2

Got it, my cross-compile environment for aarch64 doesn't build jitdump.c because it needs a package I haven't found in ubuntu:

config/Makefile:416: No libcrypto.h found, disables jitted code injection, please install libssl-devel or libssl-dev
minimal-ubuntu-x-arm64: Ok

Quoted 8 lines
Quoted 2 lines

BTW, He, what environment do you use to build for arm64, is it a cross compile one? Yocto?

Adrian, BTW, Ok with this? I'm adding a:

Fixes d3e58a3b8b3b ("perf jit: Add support for using TSC as a timestamp")

And would appreciate your Acked-by.

Sure, already did in http://marc.info/?l=linux-kernel&m=145949505329251

#30 lore raw

[tip:perf/core] perf jit: Add support for using TSC as a timestamp

In reply to He Kuang
perf jit: Add support for using TSC as a timestamp
Commit-ID:  2a28e23049af99e1c810111ef5e56455cafeda45
Gitweb:     http://git.kernel.org/tip/2a28e23049af99e1c810111ef5e56455cafeda45
Author:     Adrian Hunter <[email protected]>
AuthorDate: Tue, 8 Mar 2016 10:38:50 +0200
Committer:  Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Fri, 1 Apr 2016 18:42:55 -0300

perf jit: Add support for using TSC as a timestamp

Intel PT uses TSC as a timestamp, so add support for using TSC instead of the monotonic clock. Use of TSC is selected by an environment variable "JITDUMP_USE_ARCH_TIMESTAMP" and flagged in the jitdump file with flag JITDUMP_FLAGS_ARCH_TIMESTAMP.

Cc Alexander Shishkin <[email protected]>
Cc He Kuang <[email protected]>
Cc Jiri Olsa <[email protected]>
Cc Josh Poimboeuf <[email protected]>
Cc Peter Zijlstra <[email protected]>
Cc Stephane Eranian <[email protected]>
Cc Sukadev Bhattiprolu <[email protected]>
Cc Wang Nan <[email protected]>
[ Added the fixup from He Kuang to make it build on other arches, ]
[ such as aarch64, to avoid inserting this bisectiong breakage upstream ]
---
 tools/perf/arch/x86/util/tsc.c |  1 -
 tools/perf/arch/x86/util/tsc.h | 17 -----------------
 tools/perf/jvmti/jvmti_agent.c | 43 ++++++++++++++++++++++++++++++++++++++++--
 tools/perf/util/Build          |  3 +--
 tools/perf/util/jitdump.c      | 37 +++++++++++++++++++++++++++++++-----
 tools/perf/util/jitdump.h      |  3 +++
 tools/perf/util/tsc.h          | 11 ++++++++++-
 7 files changed, 87 insertions(+), 28 deletions(-)
tools/perf/arch/x86/util/tsc.c +0 -1
index 70ff7c1..357f1b1 100644
@@ -7,7 +7,6 @@
 #include <linux/types.h>
 #include "../../util/debug.h"
 #include "../../util/tsc.h"
-#include "tsc.h"
 
 int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc,
 			     struct perf_tsc_conversion *tc)
tools/perf/arch/x86/util/tsc.h deleted +0 -17
deleted file mode 100644
index 2edc4d3..0000000
@@ -1,17 +0,0 @@
-#ifndef TOOLS_PERF_ARCH_X86_UTIL_TSC_H__
-#define TOOLS_PERF_ARCH_X86_UTIL_TSC_H__
-
-#include <linux/types.h>
-
-struct perf_tsc_conversion {
-	u16 time_shift;
-	u32 time_mult;
-	u64 time_zero;
-};
-
-struct perf_event_mmap_page;
-
-int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc,
-			     struct perf_tsc_conversion *tc);
-
-#endif /* TOOLS_PERF_ARCH_X86_UTIL_TSC_H__ */
tools/perf/jvmti/jvmti_agent.c +41 -2

76 lines not on this page · raw message

tools/perf/util/Build +1 -2
index da48fd8..85ceff3 100644
@@ -69,8 +69,7 @@ libperf-y += stat-shadow.o
 libperf-y += record.o
 libperf-y += srcline.o
 libperf-y += data.o
-libperf-$(CONFIG_X86) += tsc.o
-libperf-$(CONFIG_AUXTRACE) += tsc.o
+libperf-y += tsc.o
 libperf-y += cloexec.o
 libperf-y += thread-stack.o
 libperf-$(CONFIG_AUXTRACE) += auxtrace.o
tools/perf/util/jitdump.c +32 -5
index ad0c0bb..52fcef3 100644
@@ -17,6 +17,7 @@
 #include "strlist.h"
 #include <elf.h>
 
+#include "tsc.h"
 #include "session.h"
 #include "jit.h"
 #include "jitdump.h"
@@ -33,6 +34,7 @@ struct jit_buf_desc {
 	size_t           bufsize;
 	FILE             *in;
 	bool		 needs_bswap; /* handles cross-endianess */
+	bool		 use_arch_timestamp;
 	void		 *debug_data;
 	size_t		 nr_debug_entries;
 	uint32_t         code_load_count;
@@ -158,13 +160,16 @@ jit_open(struct jit_buf_desc *jd, const char *name)
 		header.flags      = bswap_64(header.flags);
 	}
 
+	jd->use_arch_timestamp = header.flags & JITDUMP_FLAGS_ARCH_TIMESTAMP;
+
 	if (verbose > 2)
-		pr_debug("version=%u\nhdr.size=%u\nts=0x%llx\npid=%d\nelf_mach=%d\n",
+		pr_debug("version=%u\nhdr.size=%u\nts=0x%llx\npid=%d\nelf_mach=%d\nuse_arch_timestamp=%d\n",
 			header.version,
 			header.total_size,
 			(unsigned long long)header.timestamp,
 			header.pid,
-			header.elf_mach);
+			header.elf_mach,
+			jd->use_arch_timestamp);
 
 	if (header.flags & JITDUMP_FLAGS_RESERVED) {
 		pr_err("jitdump file contains invalid or unsupported flags 0x%llx\n",
@@ -172,10 +177,15 @@ jit_open(struct jit_buf_desc *jd, const char *name)
 		goto error;
 	}
 
+	if (jd->use_arch_timestamp && !jd->session->time_conv.time_mult) {
+		pr_err("jitdump file uses arch timestamps but there is no timestamp conversion\n");
+		goto error;
+	}
+
 	/*
 	 * validate event is using the correct clockid
 	 */
-	if (jit_validate_events(jd->session)) {
+	if (!jd->use_arch_timestamp && jit_validate_events(jd->session)) {
 		pr_err("error, jitted code must be sampled with perf record -k 1\n");
 		goto error;
 	}
@@ -329,6 +339,23 @@ jit_inject_event(struct jit_buf_desc *jd, union perf_event *event)
 	return 0;
 }
 
+static uint64_t convert_timestamp(struct jit_buf_desc *jd, uint64_t timestamp)
+{
+	struct perf_tsc_conversion tc;
+
+	if (!jd->use_arch_timestamp)
+		return timestamp;
+
+	tc.time_shift = jd->session->time_conv.time_shift;
+	tc.time_mult  = jd->session->time_conv.time_mult;
+	tc.time_zero  = jd->session->time_conv.time_zero;
+
+	if (!tc.time_mult)
+		return 0;
+
+	return tsc_to_perf_time(timestamp, &tc);
+}
+
 static int jit_repipe_code_load(struct jit_buf_desc *jd, union jr_entry *jr)
 {
 	struct perf_sample sample;
@@ -410,7 +437,7 @@ static int jit_repipe_code_load(struct jit_buf_desc *jd, union jr_entry *jr)
 		id->tid  = tid;
 	}
 	if (jd->sample_type & PERF_SAMPLE_TIME)
-		id->time = jr->load.p.timestamp;
+		id->time = convert_timestamp(jd, jr->load.p.timestamp);
 
 	/*
 	 * create pseudo sample to induce dso hit increment
@@ -499,7 +526,7 @@ static int jit_repipe_code_move(struct jit_buf_desc *jd, union jr_entry *jr)
 		id->tid  = tid;
 	}
 	if (jd->sample_type & PERF_SAMPLE_TIME)
-		id->time = jr->load.p.timestamp;
+		id->time = convert_timestamp(jd, jr->load.p.timestamp);
 
 	/*
 	 * create pseudo sample to induce dso hit increment
tools/perf/util/jitdump.h +3 -0
index b66c1f5..bcacd20 100644
@@ -23,9 +23,12 @@
 #define JITHEADER_VERSION 1
 
 enum jitdump_flags_bits {
+	JITDUMP_FLAGS_ARCH_TIMESTAMP_BIT,
 	JITDUMP_FLAGS_MAX_BIT,
 };
 
+#define JITDUMP_FLAGS_ARCH_TIMESTAMP	(1ULL << JITDUMP_FLAGS_ARCH_TIMESTAMP_BIT)
+
 #define JITDUMP_FLAGS_RESERVED (JITDUMP_FLAGS_MAX_BIT < 64 ? \
 				(~((1ULL << JITDUMP_FLAGS_MAX_BIT) - 1)) : 0)
 
tools/perf/util/tsc.h +10 -1
index 280ddc0..d5b11e2 100644
@@ -4,7 +4,16 @@
 #include <linux/types.h>
 
 #include "event.h"
-#include "../arch/x86/util/tsc.h"
+
+struct perf_tsc_conversion {
+	u16 time_shift;
+	u32 time_mult;
+	u64 time_zero;
+};
+struct perf_event_mmap_page;
+
+int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc,
+			     struct perf_tsc_conversion *tc);
 
 u64 perf_time_to_tsc(u64 ns, struct perf_tsc_conversion *tc);
 u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc);