linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v6 0/8] perf cs-etm: Add support for sample flags
@ 2019-01-19  1:43 Leo Yan
  2019-01-19  1:43 ` [PATCH v6 1/8] perf cs-etm: Add last instruction information in packet Leo Yan
                   ` (8 more replies)
  0 siblings, 9 replies; 21+ messages in thread
From: Leo Yan @ 2019-01-19  1:43 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo, Mathieu Poirier, Suzuki K Poulose,
	Alexander Shishkin, Jiri Olsa, Namhyung Kim, Mike Leach,
	Robert Walker, linux-arm-kernel, linux-kernel, Coresight ML
  Cc: Leo Yan

This patch seris adds support for sample flags so can facilitate perf
to print sample flags for branch instruction.

Patch 0001 is used to save last branch information in packet structure,
this includes instruction type, subtype and condition flag to help
making decision for which branch instruction it is.  It passes related
information from decoder layer to cs-etm.c, so we use cs-etm.c as a
central place to set sample flags.

Patch 0002 is used to set sample flags for instruction range packet.

Patch 0003 is used to set sample flags for trace discontinuity packet.

Patches 0004/0005/0006 are preparation for exception packet handling:
Patch 0004 addes exception number in packet; pacth 0005/0006 is to use
traceID/metadata tuple to access metadata pointer based on traceID, this
can help decide if the CPU is connected with ETMv3 or ETMv4, ETMv3 and
ETMv4 have totally different definition for exception numbers.

Patch 0007 sets sample flags for exception packet; patch 0008 support
sample flags for exception return packet.

This patch series is applied on the acme's perf core branch with the
with latest commit 02bb912ae451 ("perf tools: Replace automatic const
char[] variables by statics").

After applying this patch series, we can verify sample flags with below
command:

  # perf script -F,-time,+flags,+ip,+sym,+dso,+addr,+symoff -k vmlinux

Changes from v5:
* Addressed Rob's suggestion to add specification info for exception
  number encoding;
* Added Rob's review tag in patch 0007.

Changes from v4:
* Fixed typos in comments, and removed redundant info from commit log;
* Addressed Mathieu's suggestion to add helper functions for metadata
  fields (CS_ETM_CPU and CS_ETM_MAGIC) accessing;
* Addressed Mathieu's suggestion to include headers with alphabetical
  order.

Changes from v3:
* Fixed typos in commit logs;
* Rearranged fields in cs_etm_packet by grouping with same variable
  types;
* Fixed ETMv4 exception number which pointed by Mike;
* Fixed ETMv4 SVC / SMC / HVC in the same CALL, by checking svc
  instruction to distinguish them;
* Refine ETMv4 return exception packet handling.

Changes from v2:
* Addressed Mathieu's suggestion to split one big patch to 3 small
  patches for setting sample flags, one is for instruction range
  packet, one is for discontinuity packet and one is for exception
  packet.
* Added supporting for ETMv3 exception packet.
* Followed Mathieu's suggestion to move all sample flags handling
  from decoder layer to cs-etm.c, thus it has enough info to set flags
  based on trace context in single place.

Changes from v1:
* Moved exception packets handling patches into patch series 'perf
  cs-etm: Correct packets handling'.
* Added sample flags fixing up for TRACE_OFF packet.
* Created a new function which is used to maintain flags fixing up.


Leo Yan (8):
  perf cs-etm: Add last instruction information in packet
  perf cs-etm: Set sample flags for instruction range packet
  perf cs-etm: Set sample flags for trace discontinuity
  perf cs-etm: Add exception number in exception packet
  perf cs-etm: Change tuple from traceID-CPU# to traceID-metadata
  perf cs-etm: Add traceID in packet
  perf cs-etm: Set sample flags for exception packet
  perf cs-etm: Set sample flags for exception return packet

 .../perf/util/cs-etm-decoder/cs-etm-decoder.c |  41 +-
 .../perf/util/cs-etm-decoder/cs-etm-decoder.h |   6 +
 tools/perf/util/cs-etm.c                      | 405 +++++++++++++++++-
 tools/perf/util/cs-etm.h                      |  48 ++-
 4 files changed, 482 insertions(+), 18 deletions(-)

-- 
2.17.1


^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH v6 1/8] perf cs-etm: Add last instruction information in packet
  2019-01-19  1:43 [PATCH v6 0/8] perf cs-etm: Add support for sample flags Leo Yan
@ 2019-01-19  1:43 ` Leo Yan
  2019-01-23 21:03   ` Mathieu Poirier
  2019-01-19  1:43 ` [PATCH v6 2/8] perf cs-etm: Set sample flags for instruction range packet Leo Yan
                   ` (7 subsequent siblings)
  8 siblings, 1 reply; 21+ messages in thread
From: Leo Yan @ 2019-01-19  1:43 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo, Mathieu Poirier, Suzuki K Poulose,
	Alexander Shishkin, Jiri Olsa, Namhyung Kim, Mike Leach,
	Robert Walker, linux-arm-kernel, linux-kernel, Coresight ML
  Cc: Leo Yan

Decoder provides last instruction related information, these information
can be used for trace analysis; specifically we can get to know what
kind of branch instruction has been executed, mainly the information
are contained in three element fields:

  last_i_type: this is significant type for waypoint calculation, it
  indicates the last instruction is one of immediate branch instruction,
  indirect branch instruction, instruction barrier (ISB), or data
  barrier (DSB/DMB).

  last_i_subtype: this is used for instruction sub type, it can be
  branch with link, ARMv8 return instruction, ARMv8 eret instruction
  (return from exception), or ARMv7 instruction which could imply
  return (e.g. MOV PC, LR; POP { ,PC}).

  last_instr_cond: it indicates if the last instruction was conditional.

But these three fields are not saved into cs_etm_packet struct, thus
cs-etm layer don't know related information and cannot generate sample
flags for branch instructions.

This patch add corresponding three new fields in cs_etm_packet struct
and save related value into the packet structure, it is preparation for
supporting sample flags.

Signed-off-by: Leo Yan <leo.yan@linaro.org>
---
 tools/perf/util/cs-etm-decoder/cs-etm-decoder.c | 9 +++++++++
 tools/perf/util/cs-etm-decoder/cs-etm-decoder.h | 3 +++
 2 files changed, 12 insertions(+)

diff --git a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c
index 8c155575c6c5..8a19310500d9 100644
--- a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c
+++ b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c
@@ -290,6 +290,9 @@ static void cs_etm_decoder__clear_buffer(struct cs_etm_decoder *decoder)
 		decoder->packet_buffer[i].instr_count = 0;
 		decoder->packet_buffer[i].last_instr_taken_branch = false;
 		decoder->packet_buffer[i].last_instr_size = 0;
+		decoder->packet_buffer[i].last_instr_type = 0;
+		decoder->packet_buffer[i].last_instr_subtype = 0;
+		decoder->packet_buffer[i].last_instr_cond = 0;
 		decoder->packet_buffer[i].cpu = INT_MIN;
 	}
 }
@@ -323,6 +326,9 @@ cs_etm_decoder__buffer_packet(struct cs_etm_decoder *decoder,
 	decoder->packet_buffer[et].instr_count = 0;
 	decoder->packet_buffer[et].last_instr_taken_branch = false;
 	decoder->packet_buffer[et].last_instr_size = 0;
+	decoder->packet_buffer[et].last_instr_type = 0;
+	decoder->packet_buffer[et].last_instr_subtype = 0;
+	decoder->packet_buffer[et].last_instr_cond = 0;
 
 	if (decoder->packet_count == MAX_BUFFER - 1)
 		return OCSD_RESP_WAIT;
@@ -366,6 +372,9 @@ cs_etm_decoder__buffer_range(struct cs_etm_decoder *decoder,
 	packet->start_addr = elem->st_addr;
 	packet->end_addr = elem->en_addr;
 	packet->instr_count = elem->num_instr_range;
+	packet->last_instr_type = elem->last_i_type;
+	packet->last_instr_subtype = elem->last_i_subtype;
+	packet->last_instr_cond = elem->last_instr_cond;
 
 	switch (elem->last_i_type) {
 	case OCSD_INSTR_BR:
diff --git a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.h b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.h
index a6407d41598f..7cdd6a9c68a7 100644
--- a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.h
+++ b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.h
@@ -43,6 +43,9 @@ struct cs_etm_packet {
 	u64 start_addr;
 	u64 end_addr;
 	u32 instr_count;
+	u32 last_instr_type;
+	u32 last_instr_subtype;
+	u8 last_instr_cond;
 	u8 last_instr_taken_branch;
 	u8 last_instr_size;
 	int cpu;
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v6 2/8] perf cs-etm: Set sample flags for instruction range packet
  2019-01-19  1:43 [PATCH v6 0/8] perf cs-etm: Add support for sample flags Leo Yan
  2019-01-19  1:43 ` [PATCH v6 1/8] perf cs-etm: Add last instruction information in packet Leo Yan
@ 2019-01-19  1:43 ` Leo Yan
  2019-01-23 21:03   ` Mathieu Poirier
  2019-01-19  1:43 ` [PATCH v6 3/8] perf cs-etm: Set sample flags for trace discontinuity Leo Yan
                   ` (6 subsequent siblings)
  8 siblings, 1 reply; 21+ messages in thread
From: Leo Yan @ 2019-01-19  1:43 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo, Mathieu Poirier, Suzuki K Poulose,
	Alexander Shishkin, Jiri Olsa, Namhyung Kim, Mike Leach,
	Robert Walker, linux-arm-kernel, linux-kernel, Coresight ML
  Cc: Leo Yan

The perf sample data contains flags to indicate the hardware trace data
is belonging to which type branch instruction, thus this can be used to
print out the human readable string.  Arm CoreSight ETM sample data is
missed to set flags and it is always set to zeros, this results in perf
tool skips to print string for instruction types.

This patch is to set branch instruction flags for instruction range
packet.

Signed-off-by: Leo Yan <leo.yan@linaro.org>
---
 .../perf/util/cs-etm-decoder/cs-etm-decoder.c |  2 +
 .../perf/util/cs-etm-decoder/cs-etm-decoder.h |  1 +
 tools/perf/util/cs-etm.c                      | 90 ++++++++++++++++++-
 3 files changed, 91 insertions(+), 2 deletions(-)

diff --git a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c
index 8a19310500d9..e98ee49a1527 100644
--- a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c
+++ b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c
@@ -293,6 +293,7 @@ static void cs_etm_decoder__clear_buffer(struct cs_etm_decoder *decoder)
 		decoder->packet_buffer[i].last_instr_type = 0;
 		decoder->packet_buffer[i].last_instr_subtype = 0;
 		decoder->packet_buffer[i].last_instr_cond = 0;
+		decoder->packet_buffer[i].flags = 0;
 		decoder->packet_buffer[i].cpu = INT_MIN;
 	}
 }
@@ -329,6 +330,7 @@ cs_etm_decoder__buffer_packet(struct cs_etm_decoder *decoder,
 	decoder->packet_buffer[et].last_instr_type = 0;
 	decoder->packet_buffer[et].last_instr_subtype = 0;
 	decoder->packet_buffer[et].last_instr_cond = 0;
+	decoder->packet_buffer[et].flags = 0;
 
 	if (decoder->packet_count == MAX_BUFFER - 1)
 		return OCSD_RESP_WAIT;
diff --git a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.h b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.h
index 7cdd6a9c68a7..23600e57a215 100644
--- a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.h
+++ b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.h
@@ -45,6 +45,7 @@ struct cs_etm_packet {
 	u32 instr_count;
 	u32 last_instr_type;
 	u32 last_instr_subtype;
+	u32 flags;
 	u8 last_instr_cond;
 	u8 last_instr_taken_branch;
 	u8 last_instr_size;
diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c
index 27a374ddf661..d05cac5295f1 100644
--- a/tools/perf/util/cs-etm.c
+++ b/tools/perf/util/cs-etm.c
@@ -12,6 +12,7 @@
 #include <linux/log2.h>
 #include <linux/types.h>
 
+#include <opencsd/ocsd_if_types.h>
 #include <stdlib.h>
 
 #include "auxtrace.h"
@@ -719,7 +720,7 @@ static int cs_etm__synth_instruction_sample(struct cs_etm_queue *etmq,
 	sample.stream_id = etmq->etm->instructions_id;
 	sample.period = period;
 	sample.cpu = etmq->packet->cpu;
-	sample.flags = 0;
+	sample.flags = etmq->prev_packet->flags;
 	sample.insn_len = 1;
 	sample.cpumode = event->sample.header.misc;
 
@@ -778,7 +779,7 @@ static int cs_etm__synth_branch_sample(struct cs_etm_queue *etmq)
 	sample.stream_id = etmq->etm->branches_id;
 	sample.period = 1;
 	sample.cpu = etmq->packet->cpu;
-	sample.flags = 0;
+	sample.flags = etmq->prev_packet->flags;
 	sample.cpumode = event->sample.header.misc;
 
 	/*
@@ -1107,6 +1108,80 @@ static int cs_etm__end_block(struct cs_etm_queue *etmq)
 	return 0;
 }
 
+static int cs_etm__set_sample_flags(struct cs_etm_queue *etmq)
+{
+	struct cs_etm_packet *packet = etmq->packet;
+
+	switch (packet->sample_type) {
+	case CS_ETM_RANGE:
+		/*
+		 * Immediate branch instruction without neither link nor
+		 * return flag, it's normal branch instruction within
+		 * the function.
+		 */
+		if (packet->last_instr_type == OCSD_INSTR_BR &&
+		    packet->last_instr_subtype == OCSD_S_INSTR_NONE) {
+			packet->flags = PERF_IP_FLAG_BRANCH;
+
+			if (packet->last_instr_cond)
+				packet->flags |= PERF_IP_FLAG_CONDITIONAL;
+		}
+
+		/*
+		 * Immediate branch instruction with link (e.g. BL), this is
+		 * branch instruction for function call.
+		 */
+		if (packet->last_instr_type == OCSD_INSTR_BR &&
+		    packet->last_instr_subtype == OCSD_S_INSTR_BR_LINK)
+			packet->flags = PERF_IP_FLAG_BRANCH |
+					PERF_IP_FLAG_CALL;
+
+		/*
+		 * Indirect branch instruction with link (e.g. BLR), this is
+		 * branch instruction for function call.
+		 */
+		if (packet->last_instr_type == OCSD_INSTR_BR_INDIRECT &&
+		    packet->last_instr_subtype == OCSD_S_INSTR_BR_LINK)
+			packet->flags = PERF_IP_FLAG_BRANCH |
+					PERF_IP_FLAG_CALL;
+
+		/*
+		 * Indirect branch instruction with subtype of
+		 * OCSD_S_INSTR_V7_IMPLIED_RET, this is explicit hint for
+		 * function return for A32/T32.
+		 */
+		if (packet->last_instr_type == OCSD_INSTR_BR_INDIRECT &&
+		    packet->last_instr_subtype == OCSD_S_INSTR_V7_IMPLIED_RET)
+			packet->flags = PERF_IP_FLAG_BRANCH |
+					PERF_IP_FLAG_RETURN;
+
+		/*
+		 * Indirect branch instruction without link (e.g. BR), usually
+		 * this is used for function return, especially for functions
+		 * within dynamic link lib.
+		 */
+		if (packet->last_instr_type == OCSD_INSTR_BR_INDIRECT &&
+		    packet->last_instr_subtype == OCSD_S_INSTR_NONE)
+			packet->flags = PERF_IP_FLAG_BRANCH |
+					PERF_IP_FLAG_RETURN;
+
+		/* Return instruction for function return. */
+		if (packet->last_instr_type == OCSD_INSTR_BR_INDIRECT &&
+		    packet->last_instr_subtype == OCSD_S_INSTR_V8_RET)
+			packet->flags = PERF_IP_FLAG_BRANCH |
+					PERF_IP_FLAG_RETURN;
+		break;
+	case CS_ETM_DISCONTINUITY:
+	case CS_ETM_EXCEPTION:
+	case CS_ETM_EXCEPTION_RET:
+	case CS_ETM_EMPTY:
+	default:
+		break;
+	}
+
+	return 0;
+}
+
 static int cs_etm__run_decoder(struct cs_etm_queue *etmq)
 {
 	struct cs_etm_auxtrace *etm = etmq->etm;
@@ -1158,6 +1233,17 @@ static int cs_etm__run_decoder(struct cs_etm_queue *etmq)
 					 */
 					break;
 
+				/*
+				 * Since packet addresses are swapped in packet
+				 * handling within below switch() statements,
+				 * thus setting sample flags must be called
+				 * prior to switch() statement to use address
+				 * information before packets swapping.
+				 */
+				err = cs_etm__set_sample_flags(etmq);
+				if (err < 0)
+					break;
+
 				switch (etmq->packet->sample_type) {
 				case CS_ETM_RANGE:
 					/*
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v6 3/8] perf cs-etm: Set sample flags for trace discontinuity
  2019-01-19  1:43 [PATCH v6 0/8] perf cs-etm: Add support for sample flags Leo Yan
  2019-01-19  1:43 ` [PATCH v6 1/8] perf cs-etm: Add last instruction information in packet Leo Yan
  2019-01-19  1:43 ` [PATCH v6 2/8] perf cs-etm: Set sample flags for instruction range packet Leo Yan
@ 2019-01-19  1:43 ` Leo Yan
  2019-01-23 21:04   ` Mathieu Poirier
  2019-01-19  1:43 ` [PATCH v6 4/8] perf cs-etm: Add exception number in exception packet Leo Yan
                   ` (5 subsequent siblings)
  8 siblings, 1 reply; 21+ messages in thread
From: Leo Yan @ 2019-01-19  1:43 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo, Mathieu Poirier, Suzuki K Poulose,
	Alexander Shishkin, Jiri Olsa, Namhyung Kim, Mike Leach,
	Robert Walker, linux-arm-kernel, linux-kernel, Coresight ML
  Cc: Leo Yan

In the middle of trace stream, it might be interrupted thus the trace
data is not continuous, the trace stream firstly is ended for previous
trace block and restarted for next block.

To display related information for showing trace is restarted, this
patch set sample flags for trace discontinuity:

- If one discontinuity packet is coming, append flag
  PERF_IP_FLAG_TRACE_END to the previous packet to indicate the trace
  has been ended;
- If one instruction packet is following discontinuity packet, this
  instruction packet is the first one packet to restarting trace.  So
  set flag PERF_IP_FLAG_TRACE_START to discontinuity packet, this flag
  will be used to generate sample when connect with the sequential
  instruction packet.

Signed-off-by: Leo Yan <leo.yan@linaro.org>
---
 tools/perf/util/cs-etm.c | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c
index d05cac5295f1..1aa29633ce77 100644
--- a/tools/perf/util/cs-etm.c
+++ b/tools/perf/util/cs-etm.c
@@ -1111,6 +1111,7 @@ static int cs_etm__end_block(struct cs_etm_queue *etmq)
 static int cs_etm__set_sample_flags(struct cs_etm_queue *etmq)
 {
 	struct cs_etm_packet *packet = etmq->packet;
+	struct cs_etm_packet *prev_packet = etmq->prev_packet;
 
 	switch (packet->sample_type) {
 	case CS_ETM_RANGE:
@@ -1170,8 +1171,26 @@ static int cs_etm__set_sample_flags(struct cs_etm_queue *etmq)
 		    packet->last_instr_subtype == OCSD_S_INSTR_V8_RET)
 			packet->flags = PERF_IP_FLAG_BRANCH |
 					PERF_IP_FLAG_RETURN;
+
+		/*
+		 * Decoder might insert a discontinuity in the middle of
+		 * instruction packets, fixup prev_packet with flag
+		 * PERF_IP_FLAG_TRACE_BEGIN to indicate restarting trace.
+		 */
+		if (prev_packet->sample_type == CS_ETM_DISCONTINUITY)
+			prev_packet->flags |= PERF_IP_FLAG_BRANCH |
+					      PERF_IP_FLAG_TRACE_BEGIN;
 		break;
 	case CS_ETM_DISCONTINUITY:
+		/*
+		 * The trace is discontinuous, if the previous packet is
+		 * instruction packet, set flag PERF_IP_FLAG_TRACE_END
+		 * for previous packet.
+		 */
+		if (prev_packet->sample_type == CS_ETM_RANGE)
+			prev_packet->flags |= PERF_IP_FLAG_BRANCH |
+					      PERF_IP_FLAG_TRACE_END;
+		break;
 	case CS_ETM_EXCEPTION:
 	case CS_ETM_EXCEPTION_RET:
 	case CS_ETM_EMPTY:
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v6 4/8] perf cs-etm: Add exception number in exception packet
  2019-01-19  1:43 [PATCH v6 0/8] perf cs-etm: Add support for sample flags Leo Yan
                   ` (2 preceding siblings ...)
  2019-01-19  1:43 ` [PATCH v6 3/8] perf cs-etm: Set sample flags for trace discontinuity Leo Yan
@ 2019-01-19  1:43 ` Leo Yan
  2019-01-23 21:05   ` Mathieu Poirier
  2019-01-19  1:43 ` [PATCH v6 5/8] perf cs-etm: Change tuple from traceID-CPU# to traceID-metadata Leo Yan
                   ` (4 subsequent siblings)
  8 siblings, 1 reply; 21+ messages in thread
From: Leo Yan @ 2019-01-19  1:43 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo, Mathieu Poirier, Suzuki K Poulose,
	Alexander Shishkin, Jiri Olsa, Namhyung Kim, Mike Leach,
	Robert Walker, linux-arm-kernel, linux-kernel, Coresight ML
  Cc: Leo Yan

When an exception packet comes, it contains the information for
exception number; the exception number indicates the exception types,
so from it we can know if the exception is taken for interrupt,
system call or other traps, etc.

This patch simply adds a field in cs_etm_packet struct, it records
exception number for exception packet that will then be used to
properly identify exception types to the perf synthesize mechanic.

Signed-off-by: Leo Yan <leo.yan@linaro.org>
---
 .../perf/util/cs-etm-decoder/cs-etm-decoder.c | 20 +++++++++++++++----
 .../perf/util/cs-etm-decoder/cs-etm-decoder.h |  1 +
 2 files changed, 17 insertions(+), 4 deletions(-)

diff --git a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c
index e98ee49a1527..294efa76c9e3 100644
--- a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c
+++ b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c
@@ -294,6 +294,7 @@ static void cs_etm_decoder__clear_buffer(struct cs_etm_decoder *decoder)
 		decoder->packet_buffer[i].last_instr_subtype = 0;
 		decoder->packet_buffer[i].last_instr_cond = 0;
 		decoder->packet_buffer[i].flags = 0;
+		decoder->packet_buffer[i].exception_number = UINT32_MAX;
 		decoder->packet_buffer[i].cpu = INT_MIN;
 	}
 }
@@ -331,6 +332,7 @@ cs_etm_decoder__buffer_packet(struct cs_etm_decoder *decoder,
 	decoder->packet_buffer[et].last_instr_subtype = 0;
 	decoder->packet_buffer[et].last_instr_cond = 0;
 	decoder->packet_buffer[et].flags = 0;
+	decoder->packet_buffer[et].exception_number = UINT32_MAX;
 
 	if (decoder->packet_count == MAX_BUFFER - 1)
 		return OCSD_RESP_WAIT;
@@ -406,10 +408,20 @@ cs_etm_decoder__buffer_discontinuity(struct cs_etm_decoder *decoder,
 
 static ocsd_datapath_resp_t
 cs_etm_decoder__buffer_exception(struct cs_etm_decoder *decoder,
+				 const ocsd_generic_trace_elem *elem,
 				 const uint8_t trace_chan_id)
-{
-	return cs_etm_decoder__buffer_packet(decoder, trace_chan_id,
-					     CS_ETM_EXCEPTION);
+{	int ret = 0;
+	struct cs_etm_packet *packet;
+
+	ret = cs_etm_decoder__buffer_packet(decoder, trace_chan_id,
+					    CS_ETM_EXCEPTION);
+	if (ret != OCSD_RESP_CONT && ret != OCSD_RESP_WAIT)
+		return ret;
+
+	packet = &decoder->packet_buffer[decoder->tail];
+	packet->exception_number = elem->exception_number;
+
+	return ret;
 }
 
 static ocsd_datapath_resp_t
@@ -443,7 +455,7 @@ static ocsd_datapath_resp_t cs_etm_decoder__gen_trace_elem_printer(
 						    trace_chan_id);
 		break;
 	case OCSD_GEN_TRC_ELEM_EXCEPTION:
-		resp = cs_etm_decoder__buffer_exception(decoder,
+		resp = cs_etm_decoder__buffer_exception(decoder, elem,
 							trace_chan_id);
 		break;
 	case OCSD_GEN_TRC_ELEM_EXCEPTION_RET:
diff --git a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.h b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.h
index 23600e57a215..012b4728a46f 100644
--- a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.h
+++ b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.h
@@ -46,6 +46,7 @@ struct cs_etm_packet {
 	u32 last_instr_type;
 	u32 last_instr_subtype;
 	u32 flags;
+	u32 exception_number;
 	u8 last_instr_cond;
 	u8 last_instr_taken_branch;
 	u8 last_instr_size;
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v6 5/8] perf cs-etm: Change tuple from traceID-CPU# to traceID-metadata
  2019-01-19  1:43 [PATCH v6 0/8] perf cs-etm: Add support for sample flags Leo Yan
                   ` (3 preceding siblings ...)
  2019-01-19  1:43 ` [PATCH v6 4/8] perf cs-etm: Add exception number in exception packet Leo Yan
@ 2019-01-19  1:43 ` Leo Yan
  2019-01-23 21:13   ` Mathieu Poirier
  2019-01-19  1:43 ` [PATCH v6 6/8] perf cs-etm: Add traceID in packet Leo Yan
                   ` (3 subsequent siblings)
  8 siblings, 1 reply; 21+ messages in thread
From: Leo Yan @ 2019-01-19  1:43 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo, Mathieu Poirier, Suzuki K Poulose,
	Alexander Shishkin, Jiri Olsa, Namhyung Kim, Mike Leach,
	Robert Walker, linux-arm-kernel, linux-kernel, Coresight ML
  Cc: Leo Yan

If packet processing wants to know the packet is bound with which ETM
version, it needs to access metadata to decide that based on metadata
magic number; but we cannot simply to use CPU logic ID number as index
to access metadata sequential array, especially when system have
hotplugged off CPUs, the metadata array are only allocated for online
CPUs but not offline CPUs, so the CPU logic number doesn't match with
its index in the array.

For this reason, a reliable way for accessing metadata array is to use
traceID to find associated metadata; by accessing metadata content we
can know not only the CPU number but also for ETM version, which can be
used for sequential change for setting sample flags for exception
packets.

This patch is to change tuple from traceID-CPU# to traceID-metadata,
thus it can use the tuple to retrieve metadata pointer according to
traceID.

For safe accessing metadata fields, this patch provides helper function
cs_etm__get_cpu() which is used to return CPU number according to
traceID; cs_etm_decoder__buffer_packet() is the first consumer for this
helper function.

Signed-off-by: Leo Yan <leo.yan@linaro.org>
---
 .../perf/util/cs-etm-decoder/cs-etm-decoder.c |  8 ++--
 tools/perf/util/cs-etm.c                      | 37 ++++++++++++++++---
 tools/perf/util/cs-etm.h                      |  4 +-
 3 files changed, 37 insertions(+), 12 deletions(-)

diff --git a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c
index 294efa76c9e3..cdd38ffd10d2 100644
--- a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c
+++ b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c
@@ -305,14 +305,12 @@ cs_etm_decoder__buffer_packet(struct cs_etm_decoder *decoder,
 			      enum cs_etm_sample_type sample_type)
 {
 	u32 et = 0;
-	struct int_node *inode = NULL;
+	int cpu;
 
 	if (decoder->packet_count >= MAX_BUFFER - 1)
 		return OCSD_RESP_FATAL_SYS_ERR;
 
-	/* Search the RB tree for the cpu associated with this traceID */
-	inode = intlist__find(traceid_list, trace_chan_id);
-	if (!inode)
+	if (cs_etm__get_cpu(trace_chan_id, &cpu) < 0)
 		return OCSD_RESP_FATAL_SYS_ERR;
 
 	et = decoder->tail;
@@ -322,7 +320,7 @@ cs_etm_decoder__buffer_packet(struct cs_etm_decoder *decoder,
 
 	decoder->packet_buffer[et].sample_type = sample_type;
 	decoder->packet_buffer[et].isa = CS_ETM_ISA_UNKNOWN;
-	decoder->packet_buffer[et].cpu = *((int *)inode->priv);
+	decoder->packet_buffer[et].cpu = cpu;
 	decoder->packet_buffer[et].start_addr = CS_ETM_INVAL_ADDR;
 	decoder->packet_buffer[et].end_addr = CS_ETM_INVAL_ADDR;
 	decoder->packet_buffer[et].instr_count = 0;
diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c
index 1aa29633ce77..e89989fe0a5c 100644
--- a/tools/perf/util/cs-etm.c
+++ b/tools/perf/util/cs-etm.c
@@ -97,6 +97,20 @@ static u32 cs_etm__get_v7_protocol_version(u32 etmidr)
 	return CS_ETM_PROTO_ETMV3;
 }
 
+int cs_etm__get_cpu(u8 trace_chan_id, int *cpu)
+{
+	struct int_node *inode;
+	u64 *metadata;
+
+	inode = intlist__find(traceid_list, trace_chan_id);
+	if (!inode)
+		return -EINVAL;
+
+	metadata = inode->priv;
+	*cpu = (int)metadata[CS_ETM_CPU];
+	return 0;
+}
+
 static void cs_etm__packet_dump(const char *pkt_string)
 {
 	const char *color = PERF_COLOR_BLUE;
@@ -252,7 +266,7 @@ static void cs_etm__free(struct perf_session *session)
 	cs_etm__free_events(session);
 	session->auxtrace = NULL;
 
-	/* First remove all traceID/CPU# nodes for the RB tree */
+	/* First remove all traceID/metadata nodes for the RB tree */
 	intlist__for_each_entry_safe(inode, tmp, traceid_list)
 		intlist__remove(traceid_list, inode);
 	/* Then the RB tree itself */
@@ -1519,9 +1533,20 @@ int cs_etm__process_auxtrace_info(union perf_event *event,
 				    0xffffffff);
 
 	/*
-	 * Create an RB tree for traceID-CPU# tuple. Since the conversion has
-	 * to be made for each packet that gets decoded, optimizing access in
-	 * anything other than a sequential array is worth doing.
+	 * Create an RB tree for traceID-metadata tuple.
+	 *
+	 * The conversion between traceID and CPU logic ID number has to
+	 * be made for each packet that gets decoded: firstly retrieve
+	 * metadata pointer from trace ID by using traceID-metadata tuple,
+	 * then read CPU logic ID number in metadata.
+	 *
+	 * It's not safe to directly use CPU logic ID number as index to
+	 * access metadata sequential array, e.g. when system have
+	 * hotplugged out CPUs, the metadata array are only allocated for
+	 * online CPUs but not offline CPUs, thus the CPU logic number is
+	 * not consistent with its index in the arrary.  For this reason,
+	 * we need to fallback to use TraceID-metadata tuple as a reliable
+	 * method to access metadata.
 	 */
 	traceid_list = intlist__new(NULL);
 	if (!traceid_list) {
@@ -1587,8 +1612,8 @@ int cs_etm__process_auxtrace_info(union perf_event *event,
 			err = -EINVAL;
 			goto err_free_metadata;
 		}
-		/* All good, associate the traceID with the CPU# */
-		inode->priv = &metadata[j][CS_ETM_CPU];
+		/* All good, associate the traceID with the metadata pointer */
+		inode->priv = metadata[j];
 	}
 
 	/*
diff --git a/tools/perf/util/cs-etm.h b/tools/perf/util/cs-etm.h
index 37f8d48179ca..5d70d10f3907 100644
--- a/tools/perf/util/cs-etm.h
+++ b/tools/perf/util/cs-etm.h
@@ -53,7 +53,7 @@ enum {
 	CS_ETMV4_PRIV_MAX,
 };
 
-/* RB tree for quick conversion between traceID and CPUs */
+/* RB tree for quick conversion between traceID and metadata pointers */
 struct intlist *traceid_list;
 
 #define KiB(x) ((x) * 1024)
@@ -78,4 +78,6 @@ cs_etm__process_auxtrace_info(union perf_event *event __maybe_unused,
 }
 #endif
 
+int cs_etm__get_cpu(u8 trace_chan_id, int *cpu);
+
 #endif
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v6 6/8] perf cs-etm: Add traceID in packet
  2019-01-19  1:43 [PATCH v6 0/8] perf cs-etm: Add support for sample flags Leo Yan
                   ` (4 preceding siblings ...)
  2019-01-19  1:43 ` [PATCH v6 5/8] perf cs-etm: Change tuple from traceID-CPU# to traceID-metadata Leo Yan
@ 2019-01-19  1:43 ` Leo Yan
  2019-01-23 21:23   ` Mathieu Poirier
  2019-01-19  1:43 ` [PATCH v6 7/8] perf cs-etm: Set sample flags for exception packet Leo Yan
                   ` (2 subsequent siblings)
  8 siblings, 1 reply; 21+ messages in thread
From: Leo Yan @ 2019-01-19  1:43 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo, Mathieu Poirier, Suzuki K Poulose,
	Alexander Shishkin, Jiri Olsa, Namhyung Kim, Mike Leach,
	Robert Walker, linux-arm-kernel, linux-kernel, Coresight ML
  Cc: Leo Yan

Add traceID in packet, thus we can use traceID to retrieve metadata
pointer from traceID-metadata tuple.

Signed-off-by: Leo Yan <leo.yan@linaro.org>
---
 tools/perf/util/cs-etm-decoder/cs-etm-decoder.c | 2 ++
 tools/perf/util/cs-etm-decoder/cs-etm-decoder.h | 1 +
 2 files changed, 3 insertions(+)

diff --git a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c
index cdd38ffd10d2..ba4c623cd8de 100644
--- a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c
+++ b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c
@@ -295,6 +295,7 @@ static void cs_etm_decoder__clear_buffer(struct cs_etm_decoder *decoder)
 		decoder->packet_buffer[i].last_instr_cond = 0;
 		decoder->packet_buffer[i].flags = 0;
 		decoder->packet_buffer[i].exception_number = UINT32_MAX;
+		decoder->packet_buffer[i].trace_chan_id = UINT8_MAX;
 		decoder->packet_buffer[i].cpu = INT_MIN;
 	}
 }
@@ -331,6 +332,7 @@ cs_etm_decoder__buffer_packet(struct cs_etm_decoder *decoder,
 	decoder->packet_buffer[et].last_instr_cond = 0;
 	decoder->packet_buffer[et].flags = 0;
 	decoder->packet_buffer[et].exception_number = UINT32_MAX;
+	decoder->packet_buffer[et].trace_chan_id = trace_chan_id;
 
 	if (decoder->packet_count == MAX_BUFFER - 1)
 		return OCSD_RESP_WAIT;
diff --git a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.h b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.h
index 012b4728a46f..7e6a8850be4a 100644
--- a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.h
+++ b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.h
@@ -50,6 +50,7 @@ struct cs_etm_packet {
 	u8 last_instr_cond;
 	u8 last_instr_taken_branch;
 	u8 last_instr_size;
+	u8 trace_chan_id;
 	int cpu;
 };
 
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v6 7/8] perf cs-etm: Set sample flags for exception packet
  2019-01-19  1:43 [PATCH v6 0/8] perf cs-etm: Add support for sample flags Leo Yan
                   ` (5 preceding siblings ...)
  2019-01-19  1:43 ` [PATCH v6 6/8] perf cs-etm: Add traceID in packet Leo Yan
@ 2019-01-19  1:43 ` Leo Yan
  2019-01-23 21:39   ` Mathieu Poirier
  2019-01-19  1:43 ` [PATCH v6 8/8] perf cs-etm: Set sample flags for exception return packet Leo Yan
  2019-01-24  0:22 ` [PATCH v6 0/8] perf cs-etm: Add support for sample flags Mathieu Poirier
  8 siblings, 1 reply; 21+ messages in thread
From: Leo Yan @ 2019-01-19  1:43 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo, Mathieu Poirier, Suzuki K Poulose,
	Alexander Shishkin, Jiri Olsa, Namhyung Kim, Mike Leach,
	Robert Walker, linux-arm-kernel, linux-kernel, Coresight ML
  Cc: Leo Yan

The exception taken and returning are typical flow for instruction jump
but it needs to be handled with exception packets. This patch is to set
sample flags for exception packet.

Since the exception packet contains the exception number, according to
the exception number this patch makes decision for belonging to which
exception types.

The decoder have defined different exception number for ETMv3 and ETMv4
separately, hence this patch needs firstly decide the ETM version by
using the metadata magic number, and this patch adds helper function
cs_etm__get_magic() for easily getting magic number.

Based on different ETM version, the exception packet contains the
exception number, according to the exception number this patch makes
decision for the exception belonging to which exception types.

In this patch, it introduces helper function cs_etm__is_svc_instr();
for ETMv4 CS_ETMV4_EXC_CALL covers SVC, SMC and HVC cases in the
single exception number, thus need to use cs_etm__is_svc_instr() to
decide an exception taken for system call.

Reviewed-by: Robert Walker <robert.walker@arm.com>
Signed-off-by: Leo Yan <leo.yan@linaro.org>
---
 tools/perf/util/cs-etm.c | 215 +++++++++++++++++++++++++++++++++++++++
 tools/perf/util/cs-etm.h |  44 ++++++++
 2 files changed, 259 insertions(+)

diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c
index e89989fe0a5c..052805de6513 100644
--- a/tools/perf/util/cs-etm.c
+++ b/tools/perf/util/cs-etm.c
@@ -97,6 +97,20 @@ static u32 cs_etm__get_v7_protocol_version(u32 etmidr)
 	return CS_ETM_PROTO_ETMV3;
 }
 
+static int cs_etm__get_magic(u8 trace_chan_id, u64 *magic)
+{
+	struct int_node *inode;
+	u64 *metadata;
+
+	inode = intlist__find(traceid_list, trace_chan_id);
+	if (!inode)
+		return -EINVAL;
+
+	metadata = inode->priv;
+	*magic = metadata[CS_ETM_MAGIC];
+	return 0;
+}
+
 int cs_etm__get_cpu(u8 trace_chan_id, int *cpu)
 {
 	struct int_node *inode;
@@ -1122,10 +1136,174 @@ static int cs_etm__end_block(struct cs_etm_queue *etmq)
 	return 0;
 }
 
+static bool cs_etm__is_svc_instr(struct cs_etm_queue *etmq,
+				 struct cs_etm_packet *packet,
+				 u64 end_addr)
+{
+	u16 instr16;
+	u32 instr32;
+	u64 addr;
+
+	switch (packet->isa) {
+	case CS_ETM_ISA_T32:
+		/*
+		 * The SVC of T32 is defined in ARM DDI 0487D.a, F5.1.247:
+		 *
+		 *  b'15         b'8
+		 * +-----------------+--------+
+		 * | 1 1 0 1 1 1 1 1 |  imm8  |
+		 * +-----------------+--------+
+		 *
+		 * According to the specifiction, it only defines SVC for T32
+		 * with 16 bits instruction and has no definition for 32bits;
+		 * so below only read 2 bytes as instruction size for T32.
+		 */
+		addr = end_addr - 2;
+		cs_etm__mem_access(etmq, addr, sizeof(instr16), (u8 *)&instr16);
+		if ((instr16 & 0xFF00) == 0xDF00)
+			return true;
+
+		break;
+	case CS_ETM_ISA_A32:
+		/*
+		 * The SVC of A32 is defined in ARM DDI 0487D.a, F5.1.247:
+		 *
+		 *  b'31 b'28 b'27 b'24
+		 * +---------+---------+-------------------------+
+		 * |  !1111  | 1 1 1 1 |        imm24            |
+		 * +---------+---------+-------------------------+
+		 */
+		addr = end_addr - 4;
+		cs_etm__mem_access(etmq, addr, sizeof(instr32), (u8 *)&instr32);
+		if ((instr32 & 0x0F000000) == 0x0F000000 &&
+		    (instr32 & 0xF0000000) != 0xF0000000)
+			return true;
+
+		break;
+	case CS_ETM_ISA_A64:
+		/*
+		 * The SVC of A64 is defined in ARM DDI 0487D.a, C6.2.294:
+		 *
+		 *  b'31               b'21           b'4     b'0
+		 * +-----------------------+---------+-----------+
+		 * | 1 1 0 1 0 1 0 0 0 0 0 |  imm16  | 0 0 0 0 1 |
+		 * +-----------------------+---------+-----------+
+		 */
+		addr = end_addr - 4;
+		cs_etm__mem_access(etmq, addr, sizeof(instr32), (u8 *)&instr32);
+		if ((instr32 & 0xFFE0001F) == 0xd4000001)
+			return true;
+
+		break;
+	case CS_ETM_ISA_UNKNOWN:
+	default:
+		break;
+	}
+
+	return false;
+}
+
+static bool cs_etm__is_syscall(struct cs_etm_queue *etmq, u64 magic)
+{
+	struct cs_etm_packet *packet = etmq->packet;
+	struct cs_etm_packet *prev_packet = etmq->prev_packet;
+
+	if (magic == __perf_cs_etmv3_magic)
+		if (packet->exception_number == CS_ETMV3_EXC_SVC)
+			return true;
+
+	/*
+	 * ETMv4 exception type CS_ETMV4_EXC_CALL covers SVC, SMC and
+	 * HVC cases; need to check if it's SVC instruction based on
+	 * packet address.
+	 */
+	if (magic == __perf_cs_etmv4_magic) {
+		if (packet->exception_number == CS_ETMV4_EXC_CALL &&
+		    cs_etm__is_svc_instr(etmq, prev_packet,
+					 prev_packet->end_addr))
+			return true;
+	}
+
+	return false;
+}
+
+static bool cs_etm__is_async_exception(struct cs_etm_queue *etmq, u64 magic)
+{
+	struct cs_etm_packet *packet = etmq->packet;
+
+	if (magic == __perf_cs_etmv3_magic)
+		if (packet->exception_number == CS_ETMV3_EXC_DEBUG_HALT ||
+		    packet->exception_number == CS_ETMV3_EXC_ASYNC_DATA_ABORT ||
+		    packet->exception_number == CS_ETMV3_EXC_PE_RESET ||
+		    packet->exception_number == CS_ETMV3_EXC_IRQ ||
+		    packet->exception_number == CS_ETMV3_EXC_FIQ)
+			return true;
+
+	if (magic == __perf_cs_etmv4_magic)
+		if (packet->exception_number == CS_ETMV4_EXC_RESET ||
+		    packet->exception_number == CS_ETMV4_EXC_DEBUG_HALT ||
+		    packet->exception_number == CS_ETMV4_EXC_SYSTEM_ERROR ||
+		    packet->exception_number == CS_ETMV4_EXC_INST_DEBUG ||
+		    packet->exception_number == CS_ETMV4_EXC_DATA_DEBUG ||
+		    packet->exception_number == CS_ETMV4_EXC_IRQ ||
+		    packet->exception_number == CS_ETMV4_EXC_FIQ)
+			return true;
+
+	return false;
+}
+
+static bool cs_etm__is_sync_exception(struct cs_etm_queue *etmq, u64 magic)
+{
+	struct cs_etm_packet *packet = etmq->packet;
+	struct cs_etm_packet *prev_packet = etmq->prev_packet;
+
+	if (magic == __perf_cs_etmv3_magic)
+		if (packet->exception_number == CS_ETMV3_EXC_SMC ||
+		    packet->exception_number == CS_ETMV3_EXC_HYP ||
+		    packet->exception_number == CS_ETMV3_EXC_JAZELLE_THUMBEE ||
+		    packet->exception_number == CS_ETMV3_EXC_UNDEFINED_INSTR ||
+		    packet->exception_number == CS_ETMV3_EXC_PREFETCH_ABORT ||
+		    packet->exception_number == CS_ETMV3_EXC_DATA_FAULT ||
+		    packet->exception_number == CS_ETMV3_EXC_GENERIC)
+			return true;
+
+	if (magic == __perf_cs_etmv4_magic) {
+		if (packet->exception_number == CS_ETMV4_EXC_TRAP ||
+		    packet->exception_number == CS_ETMV4_EXC_ALIGNMENT ||
+		    packet->exception_number == CS_ETMV4_EXC_INST_FAULT ||
+		    packet->exception_number == CS_ETMV4_EXC_DATA_FAULT)
+			return true;
+
+		/*
+		 * For CS_ETMV4_EXC_CALL, except SVC other instructions
+		 * (SMC, HVC) are taken as sync exceptions.
+		 */
+		if (packet->exception_number == CS_ETMV4_EXC_CALL &&
+		    !cs_etm__is_svc_instr(etmq, prev_packet,
+					  prev_packet->end_addr))
+			return true;
+
+		/*
+		 * ETMv4 has 5 bits for exception number; if the numbers
+		 * are in the range ( CS_ETMV4_EXC_FIQ, CS_ETMV4_EXC_END ]
+		 * they are implementation defined exceptions.
+		 *
+		 * For this case, simply take it as sync exception.
+		 */
+		if (packet->exception_number > CS_ETMV4_EXC_FIQ &&
+		    packet->exception_number <= CS_ETMV4_EXC_END)
+			return true;
+	}
+
+	return false;
+}
+
 static int cs_etm__set_sample_flags(struct cs_etm_queue *etmq)
 {
 	struct cs_etm_packet *packet = etmq->packet;
 	struct cs_etm_packet *prev_packet = etmq->prev_packet;
+	u64 magic;
+	int ret;
 
 	switch (packet->sample_type) {
 	case CS_ETM_RANGE:
@@ -1206,6 +1384,43 @@ static int cs_etm__set_sample_flags(struct cs_etm_queue *etmq)
 					      PERF_IP_FLAG_TRACE_END;
 		break;
 	case CS_ETM_EXCEPTION:
+		ret = cs_etm__get_magic(packet->trace_chan_id, &magic);
+		if (ret)
+			return ret;
+
+		/* The exception is for system call. */
+		if (cs_etm__is_syscall(etmq, magic))
+			packet->flags = PERF_IP_FLAG_BRANCH |
+					PERF_IP_FLAG_CALL |
+					PERF_IP_FLAG_SYSCALLRET;
+		/*
+		 * The exceptions are triggered by external signals from bus,
+		 * interrupt controller, debug module, PE reset or halt.
+		 */
+		else if (cs_etm__is_async_exception(etmq, magic))
+			packet->flags = PERF_IP_FLAG_BRANCH |
+					PERF_IP_FLAG_CALL |
+					PERF_IP_FLAG_ASYNC |
+					PERF_IP_FLAG_INTERRUPT;
+		/*
+		 * Otherwise, exception is caused by trap, instruction &
+		 * data fault, or alignment errors.
+		 */
+		else if (cs_etm__is_sync_exception(etmq, magic))
+			packet->flags = PERF_IP_FLAG_BRANCH |
+					PERF_IP_FLAG_CALL |
+					PERF_IP_FLAG_INTERRUPT;
+
+		/*
+		 * When the exception packet is inserted, since exception
+		 * packet is not used standalone for generating samples
+		 * and it's affiliation to the previous instruction range
+		 * packet; so set previous range packet flags to tell perf
+		 * it is an exception taken branch.
+		 */
+		if (prev_packet->sample_type == CS_ETM_RANGE)
+			prev_packet->flags = packet->flags;
+		break;
 	case CS_ETM_EXCEPTION_RET:
 	case CS_ETM_EMPTY:
 	default:
diff --git a/tools/perf/util/cs-etm.h b/tools/perf/util/cs-etm.h
index 5d70d10f3907..7bd16ea8a62d 100644
--- a/tools/perf/util/cs-etm.h
+++ b/tools/perf/util/cs-etm.h
@@ -53,6 +53,50 @@ enum {
 	CS_ETMV4_PRIV_MAX,
 };
 
+/*
+ * ETMv3 exception encoding number:
+ * See Embedded Trace Macrocell spcification (ARM IHI 0014Q)
+ * table 7-12 Encoding of Exception[3:0] for non-ARMv7-M processors.
+ */
+enum {
+	CS_ETMV3_EXC_NONE = 0,
+	CS_ETMV3_EXC_DEBUG_HALT = 1,
+	CS_ETMV3_EXC_SMC = 2,
+	CS_ETMV3_EXC_HYP = 3,
+	CS_ETMV3_EXC_ASYNC_DATA_ABORT = 4,
+	CS_ETMV3_EXC_JAZELLE_THUMBEE = 5,
+	CS_ETMV3_EXC_PE_RESET = 8,
+	CS_ETMV3_EXC_UNDEFINED_INSTR = 9,
+	CS_ETMV3_EXC_SVC = 10,
+	CS_ETMV3_EXC_PREFETCH_ABORT = 11,
+	CS_ETMV3_EXC_DATA_FAULT = 12,
+	CS_ETMV3_EXC_GENERIC = 13,
+	CS_ETMV3_EXC_IRQ = 14,
+	CS_ETMV3_EXC_FIQ = 15,
+};
+
+/*
+ * ETMv4 exception encoding number:
+ * See ARM Embedded Trace Macrocell Architecture Specification (ARM IHI 0064D)
+ * table 6-12 Possible values for the TYPE field in an Exception instruction
+ * trace packet, for ARMv7-A/R and ARMv8-A/R PEs.
+ */
+enum {
+	CS_ETMV4_EXC_RESET = 0,
+	CS_ETMV4_EXC_DEBUG_HALT = 1,
+	CS_ETMV4_EXC_CALL = 2,
+	CS_ETMV4_EXC_TRAP = 3,
+	CS_ETMV4_EXC_SYSTEM_ERROR = 4,
+	CS_ETMV4_EXC_INST_DEBUG = 6,
+	CS_ETMV4_EXC_DATA_DEBUG = 7,
+	CS_ETMV4_EXC_ALIGNMENT = 10,
+	CS_ETMV4_EXC_INST_FAULT = 11,
+	CS_ETMV4_EXC_DATA_FAULT = 12,
+	CS_ETMV4_EXC_IRQ = 14,
+	CS_ETMV4_EXC_FIQ = 15,
+	CS_ETMV4_EXC_END = 31,
+};
+
 /* RB tree for quick conversion between traceID and metadata pointers */
 struct intlist *traceid_list;
 
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v6 8/8] perf cs-etm: Set sample flags for exception return packet
  2019-01-19  1:43 [PATCH v6 0/8] perf cs-etm: Add support for sample flags Leo Yan
                   ` (6 preceding siblings ...)
  2019-01-19  1:43 ` [PATCH v6 7/8] perf cs-etm: Set sample flags for exception packet Leo Yan
@ 2019-01-19  1:43 ` Leo Yan
  2019-01-23 21:51   ` Mathieu Poirier
  2019-01-24  0:22 ` [PATCH v6 0/8] perf cs-etm: Add support for sample flags Mathieu Poirier
  8 siblings, 1 reply; 21+ messages in thread
From: Leo Yan @ 2019-01-19  1:43 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo, Mathieu Poirier, Suzuki K Poulose,
	Alexander Shishkin, Jiri Olsa, Namhyung Kim, Mike Leach,
	Robert Walker, linux-arm-kernel, linux-kernel, Coresight ML
  Cc: Leo Yan

When return from exception, we need to distinguish if it's system call
return or for other type exceptions for setting sample flags.  Due to
the exception return packet doesn't contain exception number, so we
cannot decide sample flags based on exception number.

On the other hand, the exception return packet is followed by an
instruction range packet; this range packet deliveries the start address
after exception handling, we can check if it is a SVC instruction just
before the start address.  If there has one SVC instruction is found
ahead the return address, this means it's an exception return for system
call; otherwise it is an normal return for other exceptions.

This patch is to set sample flags for exception return packet, firstly
it simply set sample flags as PERF_IP_FLAG_INTERRUPT for all exception
returns since at this point it doesn't know what's exactly the exception
type.  We will defer to decide if it's an exception return for system
call when the next instruction range packet comes, it checks if there
has one SVC instruction prior to the start address and if so we will
change sample flags to PERF_IP_FLAG_SYSCALLRET for system call
return.

Signed-off-by: Leo Yan <leo.yan@linaro.org>
---
 tools/perf/util/cs-etm.c | 44 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 44 insertions(+)

diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c
index 052805de6513..7547a7178f46 100644
--- a/tools/perf/util/cs-etm.c
+++ b/tools/perf/util/cs-etm.c
@@ -1372,6 +1372,20 @@ static int cs_etm__set_sample_flags(struct cs_etm_queue *etmq)
 		if (prev_packet->sample_type == CS_ETM_DISCONTINUITY)
 			prev_packet->flags |= PERF_IP_FLAG_BRANCH |
 					      PERF_IP_FLAG_TRACE_BEGIN;
+
+		/*
+		 * If the previous packet is an exception return packet
+		 * and the return address just follows SVC instuction,
+		 * it needs to calibrate the previous packet sample flags
+		 * as PERF_IP_FLAG_SYSCALLRET.
+		 */
+		if (prev_packet->flags == (PERF_IP_FLAG_BRANCH |
+					   PERF_IP_FLAG_RETURN |
+					   PERF_IP_FLAG_INTERRUPT) &&
+		    cs_etm__is_svc_instr(etmq, packet, packet->start_addr))
+			prev_packet->flags = PERF_IP_FLAG_BRANCH |
+					     PERF_IP_FLAG_RETURN |
+					     PERF_IP_FLAG_SYSCALLRET;
 		break;
 	case CS_ETM_DISCONTINUITY:
 		/*
@@ -1422,6 +1436,36 @@ static int cs_etm__set_sample_flags(struct cs_etm_queue *etmq)
 			prev_packet->flags = packet->flags;
 		break;
 	case CS_ETM_EXCEPTION_RET:
+		/*
+		 * When the exception return packet is inserted, since
+		 * exception return packet is not used standalone for
+		 * generating samples and it's affiliation to the previous
+		 * instruction range packet; so set previous range packet
+		 * flags to tell perf it is an exception return branch.
+		 *
+		 * The exception return can be for either system call or
+		 * other exception types; unfortunately the packet doesn't
+		 * contain exception type related info so we cannot decide
+		 * the exception type purely based on exception return packet.
+		 * If we record the exception number from exception packet and
+		 * reuse it for excpetion return packet, this is not reliable
+		 * due the trace can be discontinuity or the interrupt can
+		 * be nested, thus the recorded exception number cannot be
+		 * used for exception return packet for these two cases.
+		 *
+		 * For exception return packet, we only need to distinguish the
+		 * packet is for system call or for other types.  Thus the
+		 * decision can be deferred when receive the next packet which
+		 * contains the return address, based on the return address we
+		 * can read out the previous instruction and check if it's a
+		 * system call instruction and then calibrate the sample flag
+		 * as needed.
+		 */
+		if (prev_packet->sample_type == CS_ETM_RANGE)
+			prev_packet->flags = PERF_IP_FLAG_BRANCH |
+					     PERF_IP_FLAG_RETURN |
+					     PERF_IP_FLAG_INTERRUPT;
+		break;
 	case CS_ETM_EMPTY:
 	default:
 		break;
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 21+ messages in thread

* Re: [PATCH v6 1/8] perf cs-etm: Add last instruction information in packet
  2019-01-19  1:43 ` [PATCH v6 1/8] perf cs-etm: Add last instruction information in packet Leo Yan
@ 2019-01-23 21:03   ` Mathieu Poirier
  0 siblings, 0 replies; 21+ messages in thread
From: Mathieu Poirier @ 2019-01-23 21:03 UTC (permalink / raw)
  To: Leo Yan
  Cc: Arnaldo Carvalho de Melo, Suzuki K Poulose, Alexander Shishkin,
	Jiri Olsa, Namhyung Kim, Mike Leach, Robert Walker,
	linux-arm-kernel, linux-kernel, Coresight ML

On Sat, Jan 19, 2019 at 09:43:40AM +0800, Leo Yan wrote:
> Decoder provides last instruction related information, these information
> can be used for trace analysis; specifically we can get to know what
> kind of branch instruction has been executed, mainly the information
> are contained in three element fields:
> 
>   last_i_type: this is significant type for waypoint calculation, it
>   indicates the last instruction is one of immediate branch instruction,
>   indirect branch instruction, instruction barrier (ISB), or data
>   barrier (DSB/DMB).
> 
>   last_i_subtype: this is used for instruction sub type, it can be
>   branch with link, ARMv8 return instruction, ARMv8 eret instruction
>   (return from exception), or ARMv7 instruction which could imply
>   return (e.g. MOV PC, LR; POP { ,PC}).
> 
>   last_instr_cond: it indicates if the last instruction was conditional.
> 
> But these three fields are not saved into cs_etm_packet struct, thus
> cs-etm layer don't know related information and cannot generate sample
> flags for branch instructions.
> 
> This patch add corresponding three new fields in cs_etm_packet struct
> and save related value into the packet structure, it is preparation for
> supporting sample flags.
> 
> Signed-off-by: Leo Yan <leo.yan@linaro.org>
> ---
>  tools/perf/util/cs-etm-decoder/cs-etm-decoder.c | 9 +++++++++
>  tools/perf/util/cs-etm-decoder/cs-etm-decoder.h | 3 +++
>  2 files changed, 12 insertions(+)
> 
> diff --git a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c
> index 8c155575c6c5..8a19310500d9 100644
> --- a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c
> +++ b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c
> @@ -290,6 +290,9 @@ static void cs_etm_decoder__clear_buffer(struct cs_etm_decoder *decoder)
>  		decoder->packet_buffer[i].instr_count = 0;
>  		decoder->packet_buffer[i].last_instr_taken_branch = false;
>  		decoder->packet_buffer[i].last_instr_size = 0;
> +		decoder->packet_buffer[i].last_instr_type = 0;
> +		decoder->packet_buffer[i].last_instr_subtype = 0;
> +		decoder->packet_buffer[i].last_instr_cond = 0;
>  		decoder->packet_buffer[i].cpu = INT_MIN;
>  	}
>  }
> @@ -323,6 +326,9 @@ cs_etm_decoder__buffer_packet(struct cs_etm_decoder *decoder,
>  	decoder->packet_buffer[et].instr_count = 0;
>  	decoder->packet_buffer[et].last_instr_taken_branch = false;
>  	decoder->packet_buffer[et].last_instr_size = 0;
> +	decoder->packet_buffer[et].last_instr_type = 0;
> +	decoder->packet_buffer[et].last_instr_subtype = 0;
> +	decoder->packet_buffer[et].last_instr_cond = 0;
>  
>  	if (decoder->packet_count == MAX_BUFFER - 1)
>  		return OCSD_RESP_WAIT;
> @@ -366,6 +372,9 @@ cs_etm_decoder__buffer_range(struct cs_etm_decoder *decoder,
>  	packet->start_addr = elem->st_addr;
>  	packet->end_addr = elem->en_addr;
>  	packet->instr_count = elem->num_instr_range;
> +	packet->last_instr_type = elem->last_i_type;
> +	packet->last_instr_subtype = elem->last_i_subtype;
> +	packet->last_instr_cond = elem->last_instr_cond;
>  
>  	switch (elem->last_i_type) {
>  	case OCSD_INSTR_BR:
> diff --git a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.h b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.h
> index a6407d41598f..7cdd6a9c68a7 100644
> --- a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.h
> +++ b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.h
> @@ -43,6 +43,9 @@ struct cs_etm_packet {
>  	u64 start_addr;
>  	u64 end_addr;
>  	u32 instr_count;
> +	u32 last_instr_type;
> +	u32 last_instr_subtype;
> +	u8 last_instr_cond;
>  	u8 last_instr_taken_branch;
>  	u8 last_instr_size;
>  	int cpu;

Reviewed-by: Mathieu Poirier <mathieu.poirier@linaro.org>

> -- 
> 2.17.1
> 

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v6 2/8] perf cs-etm: Set sample flags for instruction range packet
  2019-01-19  1:43 ` [PATCH v6 2/8] perf cs-etm: Set sample flags for instruction range packet Leo Yan
@ 2019-01-23 21:03   ` Mathieu Poirier
  0 siblings, 0 replies; 21+ messages in thread
From: Mathieu Poirier @ 2019-01-23 21:03 UTC (permalink / raw)
  To: Leo Yan
  Cc: Arnaldo Carvalho de Melo, Suzuki K Poulose, Alexander Shishkin,
	Jiri Olsa, Namhyung Kim, Mike Leach, Robert Walker,
	linux-arm-kernel, linux-kernel, Coresight ML

On Sat, Jan 19, 2019 at 09:43:41AM +0800, Leo Yan wrote:
> The perf sample data contains flags to indicate the hardware trace data
> is belonging to which type branch instruction, thus this can be used to
> print out the human readable string.  Arm CoreSight ETM sample data is
> missed to set flags and it is always set to zeros, this results in perf
> tool skips to print string for instruction types.
> 
> This patch is to set branch instruction flags for instruction range
> packet.
> 
> Signed-off-by: Leo Yan <leo.yan@linaro.org>
> ---
>  .../perf/util/cs-etm-decoder/cs-etm-decoder.c |  2 +
>  .../perf/util/cs-etm-decoder/cs-etm-decoder.h |  1 +
>  tools/perf/util/cs-etm.c                      | 90 ++++++++++++++++++-
>  3 files changed, 91 insertions(+), 2 deletions(-)
> 
> diff --git a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c
> index 8a19310500d9..e98ee49a1527 100644
> --- a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c
> +++ b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c
> @@ -293,6 +293,7 @@ static void cs_etm_decoder__clear_buffer(struct cs_etm_decoder *decoder)
>  		decoder->packet_buffer[i].last_instr_type = 0;
>  		decoder->packet_buffer[i].last_instr_subtype = 0;
>  		decoder->packet_buffer[i].last_instr_cond = 0;
> +		decoder->packet_buffer[i].flags = 0;
>  		decoder->packet_buffer[i].cpu = INT_MIN;
>  	}
>  }
> @@ -329,6 +330,7 @@ cs_etm_decoder__buffer_packet(struct cs_etm_decoder *decoder,
>  	decoder->packet_buffer[et].last_instr_type = 0;
>  	decoder->packet_buffer[et].last_instr_subtype = 0;
>  	decoder->packet_buffer[et].last_instr_cond = 0;
> +	decoder->packet_buffer[et].flags = 0;
>  
>  	if (decoder->packet_count == MAX_BUFFER - 1)
>  		return OCSD_RESP_WAIT;
> diff --git a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.h b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.h
> index 7cdd6a9c68a7..23600e57a215 100644
> --- a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.h
> +++ b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.h
> @@ -45,6 +45,7 @@ struct cs_etm_packet {
>  	u32 instr_count;
>  	u32 last_instr_type;
>  	u32 last_instr_subtype;
> +	u32 flags;
>  	u8 last_instr_cond;
>  	u8 last_instr_taken_branch;
>  	u8 last_instr_size;
> diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c
> index 27a374ddf661..d05cac5295f1 100644
> --- a/tools/perf/util/cs-etm.c
> +++ b/tools/perf/util/cs-etm.c
> @@ -12,6 +12,7 @@
>  #include <linux/log2.h>
>  #include <linux/types.h>
>  
> +#include <opencsd/ocsd_if_types.h>
>  #include <stdlib.h>
>  
>  #include "auxtrace.h"
> @@ -719,7 +720,7 @@ static int cs_etm__synth_instruction_sample(struct cs_etm_queue *etmq,
>  	sample.stream_id = etmq->etm->instructions_id;
>  	sample.period = period;
>  	sample.cpu = etmq->packet->cpu;
> -	sample.flags = 0;
> +	sample.flags = etmq->prev_packet->flags;
>  	sample.insn_len = 1;
>  	sample.cpumode = event->sample.header.misc;
>  
> @@ -778,7 +779,7 @@ static int cs_etm__synth_branch_sample(struct cs_etm_queue *etmq)
>  	sample.stream_id = etmq->etm->branches_id;
>  	sample.period = 1;
>  	sample.cpu = etmq->packet->cpu;
> -	sample.flags = 0;
> +	sample.flags = etmq->prev_packet->flags;
>  	sample.cpumode = event->sample.header.misc;
>  
>  	/*
> @@ -1107,6 +1108,80 @@ static int cs_etm__end_block(struct cs_etm_queue *etmq)
>  	return 0;
>  }
>  
> +static int cs_etm__set_sample_flags(struct cs_etm_queue *etmq)
> +{
> +	struct cs_etm_packet *packet = etmq->packet;
> +
> +	switch (packet->sample_type) {
> +	case CS_ETM_RANGE:
> +		/*
> +		 * Immediate branch instruction without neither link nor
> +		 * return flag, it's normal branch instruction within
> +		 * the function.
> +		 */
> +		if (packet->last_instr_type == OCSD_INSTR_BR &&
> +		    packet->last_instr_subtype == OCSD_S_INSTR_NONE) {
> +			packet->flags = PERF_IP_FLAG_BRANCH;
> +
> +			if (packet->last_instr_cond)
> +				packet->flags |= PERF_IP_FLAG_CONDITIONAL;
> +		}
> +
> +		/*
> +		 * Immediate branch instruction with link (e.g. BL), this is
> +		 * branch instruction for function call.
> +		 */
> +		if (packet->last_instr_type == OCSD_INSTR_BR &&
> +		    packet->last_instr_subtype == OCSD_S_INSTR_BR_LINK)
> +			packet->flags = PERF_IP_FLAG_BRANCH |
> +					PERF_IP_FLAG_CALL;
> +
> +		/*
> +		 * Indirect branch instruction with link (e.g. BLR), this is
> +		 * branch instruction for function call.
> +		 */
> +		if (packet->last_instr_type == OCSD_INSTR_BR_INDIRECT &&
> +		    packet->last_instr_subtype == OCSD_S_INSTR_BR_LINK)
> +			packet->flags = PERF_IP_FLAG_BRANCH |
> +					PERF_IP_FLAG_CALL;
> +
> +		/*
> +		 * Indirect branch instruction with subtype of
> +		 * OCSD_S_INSTR_V7_IMPLIED_RET, this is explicit hint for
> +		 * function return for A32/T32.
> +		 */
> +		if (packet->last_instr_type == OCSD_INSTR_BR_INDIRECT &&
> +		    packet->last_instr_subtype == OCSD_S_INSTR_V7_IMPLIED_RET)
> +			packet->flags = PERF_IP_FLAG_BRANCH |
> +					PERF_IP_FLAG_RETURN;
> +
> +		/*
> +		 * Indirect branch instruction without link (e.g. BR), usually
> +		 * this is used for function return, especially for functions
> +		 * within dynamic link lib.
> +		 */
> +		if (packet->last_instr_type == OCSD_INSTR_BR_INDIRECT &&
> +		    packet->last_instr_subtype == OCSD_S_INSTR_NONE)
> +			packet->flags = PERF_IP_FLAG_BRANCH |
> +					PERF_IP_FLAG_RETURN;
> +
> +		/* Return instruction for function return. */
> +		if (packet->last_instr_type == OCSD_INSTR_BR_INDIRECT &&
> +		    packet->last_instr_subtype == OCSD_S_INSTR_V8_RET)
> +			packet->flags = PERF_IP_FLAG_BRANCH |
> +					PERF_IP_FLAG_RETURN;
> +		break;
> +	case CS_ETM_DISCONTINUITY:
> +	case CS_ETM_EXCEPTION:
> +	case CS_ETM_EXCEPTION_RET:
> +	case CS_ETM_EMPTY:
> +	default:
> +		break;
> +	}
> +
> +	return 0;
> +}
> +
>  static int cs_etm__run_decoder(struct cs_etm_queue *etmq)
>  {
>  	struct cs_etm_auxtrace *etm = etmq->etm;
> @@ -1158,6 +1233,17 @@ static int cs_etm__run_decoder(struct cs_etm_queue *etmq)
>  					 */
>  					break;
>  
> +				/*
> +				 * Since packet addresses are swapped in packet
> +				 * handling within below switch() statements,
> +				 * thus setting sample flags must be called
> +				 * prior to switch() statement to use address
> +				 * information before packets swapping.
> +				 */
> +				err = cs_etm__set_sample_flags(etmq);
> +				if (err < 0)
> +					break;
> +
>  				switch (etmq->packet->sample_type) {
>  				case CS_ETM_RANGE:
>  					/*

Reviewed-by: Mathieu Poirier <mathieu.poirier@linaro.org>

> -- 
> 2.17.1
> 

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v6 3/8] perf cs-etm: Set sample flags for trace discontinuity
  2019-01-19  1:43 ` [PATCH v6 3/8] perf cs-etm: Set sample flags for trace discontinuity Leo Yan
@ 2019-01-23 21:04   ` Mathieu Poirier
  0 siblings, 0 replies; 21+ messages in thread
From: Mathieu Poirier @ 2019-01-23 21:04 UTC (permalink / raw)
  To: Leo Yan
  Cc: Arnaldo Carvalho de Melo, Suzuki K Poulose, Alexander Shishkin,
	Jiri Olsa, Namhyung Kim, Mike Leach, Robert Walker,
	linux-arm-kernel, linux-kernel, Coresight ML

On Sat, Jan 19, 2019 at 09:43:42AM +0800, Leo Yan wrote:
> In the middle of trace stream, it might be interrupted thus the trace
> data is not continuous, the trace stream firstly is ended for previous
> trace block and restarted for next block.
> 
> To display related information for showing trace is restarted, this
> patch set sample flags for trace discontinuity:
> 
> - If one discontinuity packet is coming, append flag
>   PERF_IP_FLAG_TRACE_END to the previous packet to indicate the trace
>   has been ended;
> - If one instruction packet is following discontinuity packet, this
>   instruction packet is the first one packet to restarting trace.  So
>   set flag PERF_IP_FLAG_TRACE_START to discontinuity packet, this flag
>   will be used to generate sample when connect with the sequential
>   instruction packet.
> 
> Signed-off-by: Leo Yan <leo.yan@linaro.org>
> ---
>  tools/perf/util/cs-etm.c | 19 +++++++++++++++++++
>  1 file changed, 19 insertions(+)
> 
> diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c
> index d05cac5295f1..1aa29633ce77 100644
> --- a/tools/perf/util/cs-etm.c
> +++ b/tools/perf/util/cs-etm.c
> @@ -1111,6 +1111,7 @@ static int cs_etm__end_block(struct cs_etm_queue *etmq)
>  static int cs_etm__set_sample_flags(struct cs_etm_queue *etmq)
>  {
>  	struct cs_etm_packet *packet = etmq->packet;
> +	struct cs_etm_packet *prev_packet = etmq->prev_packet;
>  
>  	switch (packet->sample_type) {
>  	case CS_ETM_RANGE:
> @@ -1170,8 +1171,26 @@ static int cs_etm__set_sample_flags(struct cs_etm_queue *etmq)
>  		    packet->last_instr_subtype == OCSD_S_INSTR_V8_RET)
>  			packet->flags = PERF_IP_FLAG_BRANCH |
>  					PERF_IP_FLAG_RETURN;
> +
> +		/*
> +		 * Decoder might insert a discontinuity in the middle of
> +		 * instruction packets, fixup prev_packet with flag
> +		 * PERF_IP_FLAG_TRACE_BEGIN to indicate restarting trace.
> +		 */
> +		if (prev_packet->sample_type == CS_ETM_DISCONTINUITY)
> +			prev_packet->flags |= PERF_IP_FLAG_BRANCH |
> +					      PERF_IP_FLAG_TRACE_BEGIN;
>  		break;
>  	case CS_ETM_DISCONTINUITY:
> +		/*
> +		 * The trace is discontinuous, if the previous packet is
> +		 * instruction packet, set flag PERF_IP_FLAG_TRACE_END
> +		 * for previous packet.
> +		 */
> +		if (prev_packet->sample_type == CS_ETM_RANGE)
> +			prev_packet->flags |= PERF_IP_FLAG_BRANCH |
> +					      PERF_IP_FLAG_TRACE_END;
> +		break;
>  	case CS_ETM_EXCEPTION:
>  	case CS_ETM_EXCEPTION_RET:
>  	case CS_ETM_EMPTY:

Reviewed-by: Mathieu Poirier <mathieu.poirier@linaro.org>

> -- 
> 2.17.1
> 

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v6 4/8] perf cs-etm: Add exception number in exception packet
  2019-01-19  1:43 ` [PATCH v6 4/8] perf cs-etm: Add exception number in exception packet Leo Yan
@ 2019-01-23 21:05   ` Mathieu Poirier
  0 siblings, 0 replies; 21+ messages in thread
From: Mathieu Poirier @ 2019-01-23 21:05 UTC (permalink / raw)
  To: Leo Yan
  Cc: Arnaldo Carvalho de Melo, Suzuki K Poulose, Alexander Shishkin,
	Jiri Olsa, Namhyung Kim, Mike Leach, Robert Walker,
	linux-arm-kernel, linux-kernel, Coresight ML

On Sat, Jan 19, 2019 at 09:43:43AM +0800, Leo Yan wrote:
> When an exception packet comes, it contains the information for
> exception number; the exception number indicates the exception types,
> so from it we can know if the exception is taken for interrupt,
> system call or other traps, etc.
> 
> This patch simply adds a field in cs_etm_packet struct, it records
> exception number for exception packet that will then be used to
> properly identify exception types to the perf synthesize mechanic.
> 
> Signed-off-by: Leo Yan <leo.yan@linaro.org>
> ---
>  .../perf/util/cs-etm-decoder/cs-etm-decoder.c | 20 +++++++++++++++----
>  .../perf/util/cs-etm-decoder/cs-etm-decoder.h |  1 +
>  2 files changed, 17 insertions(+), 4 deletions(-)
> 
> diff --git a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c
> index e98ee49a1527..294efa76c9e3 100644
> --- a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c
> +++ b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c
> @@ -294,6 +294,7 @@ static void cs_etm_decoder__clear_buffer(struct cs_etm_decoder *decoder)
>  		decoder->packet_buffer[i].last_instr_subtype = 0;
>  		decoder->packet_buffer[i].last_instr_cond = 0;
>  		decoder->packet_buffer[i].flags = 0;
> +		decoder->packet_buffer[i].exception_number = UINT32_MAX;
>  		decoder->packet_buffer[i].cpu = INT_MIN;
>  	}
>  }
> @@ -331,6 +332,7 @@ cs_etm_decoder__buffer_packet(struct cs_etm_decoder *decoder,
>  	decoder->packet_buffer[et].last_instr_subtype = 0;
>  	decoder->packet_buffer[et].last_instr_cond = 0;
>  	decoder->packet_buffer[et].flags = 0;
> +	decoder->packet_buffer[et].exception_number = UINT32_MAX;
>  
>  	if (decoder->packet_count == MAX_BUFFER - 1)
>  		return OCSD_RESP_WAIT;
> @@ -406,10 +408,20 @@ cs_etm_decoder__buffer_discontinuity(struct cs_etm_decoder *decoder,
>  
>  static ocsd_datapath_resp_t
>  cs_etm_decoder__buffer_exception(struct cs_etm_decoder *decoder,
> +				 const ocsd_generic_trace_elem *elem,
>  				 const uint8_t trace_chan_id)
> -{
> -	return cs_etm_decoder__buffer_packet(decoder, trace_chan_id,
> -					     CS_ETM_EXCEPTION);
> +{	int ret = 0;
> +	struct cs_etm_packet *packet;
> +
> +	ret = cs_etm_decoder__buffer_packet(decoder, trace_chan_id,
> +					    CS_ETM_EXCEPTION);
> +	if (ret != OCSD_RESP_CONT && ret != OCSD_RESP_WAIT)
> +		return ret;
> +
> +	packet = &decoder->packet_buffer[decoder->tail];
> +	packet->exception_number = elem->exception_number;
> +
> +	return ret;
>  }
>  
>  static ocsd_datapath_resp_t
> @@ -443,7 +455,7 @@ static ocsd_datapath_resp_t cs_etm_decoder__gen_trace_elem_printer(
>  						    trace_chan_id);
>  		break;
>  	case OCSD_GEN_TRC_ELEM_EXCEPTION:
> -		resp = cs_etm_decoder__buffer_exception(decoder,
> +		resp = cs_etm_decoder__buffer_exception(decoder, elem,
>  							trace_chan_id);
>  		break;
>  	case OCSD_GEN_TRC_ELEM_EXCEPTION_RET:
> diff --git a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.h b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.h
> index 23600e57a215..012b4728a46f 100644
> --- a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.h
> +++ b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.h
> @@ -46,6 +46,7 @@ struct cs_etm_packet {
>  	u32 last_instr_type;
>  	u32 last_instr_subtype;
>  	u32 flags;
> +	u32 exception_number;
>  	u8 last_instr_cond;
>  	u8 last_instr_taken_branch;
>  	u8 last_instr_size;

Reviewed-by: Mathieu Poirier <mathieu.poirier@linaro.org>

> -- 
> 2.17.1
> 

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v6 5/8] perf cs-etm: Change tuple from traceID-CPU# to traceID-metadata
  2019-01-19  1:43 ` [PATCH v6 5/8] perf cs-etm: Change tuple from traceID-CPU# to traceID-metadata Leo Yan
@ 2019-01-23 21:13   ` Mathieu Poirier
  2019-01-23 23:45     ` Leo Yan
  0 siblings, 1 reply; 21+ messages in thread
From: Mathieu Poirier @ 2019-01-23 21:13 UTC (permalink / raw)
  To: Leo Yan
  Cc: Arnaldo Carvalho de Melo, Suzuki K Poulose, Alexander Shishkin,
	Jiri Olsa, Namhyung Kim, Mike Leach, Robert Walker,
	linux-arm-kernel, linux-kernel, Coresight ML

On Sat, Jan 19, 2019 at 09:43:44AM +0800, Leo Yan wrote:
> If packet processing wants to know the packet is bound with which ETM
> version, it needs to access metadata to decide that based on metadata
> magic number; but we cannot simply to use CPU logic ID number as index
> to access metadata sequential array, especially when system have
> hotplugged off CPUs, the metadata array are only allocated for online
> CPUs but not offline CPUs, so the CPU logic number doesn't match with
> its index in the array.
> 
> For this reason, a reliable way for accessing metadata array is to use
> traceID to find associated metadata; by accessing metadata content we
> can know not only the CPU number but also for ETM version, which can be
> used for sequential change for setting sample flags for exception
> packets.

This paragraph is not needed to understand why this patch is needed.  Please
remove.

> 
> This patch is to change tuple from traceID-CPU# to traceID-metadata,
> thus it can use the tuple to retrieve metadata pointer according to
> traceID.
> 
> For safe accessing metadata fields, this patch provides helper function
> cs_etm__get_cpu() which is used to return CPU number according to
> traceID; cs_etm_decoder__buffer_packet() is the first consumer for this
> helper function.
> 
> Signed-off-by: Leo Yan <leo.yan@linaro.org>
> ---
>  .../perf/util/cs-etm-decoder/cs-etm-decoder.c |  8 ++--
>  tools/perf/util/cs-etm.c                      | 37 ++++++++++++++++---
>  tools/perf/util/cs-etm.h                      |  4 +-
>  3 files changed, 37 insertions(+), 12 deletions(-)
> 
> diff --git a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c
> index 294efa76c9e3..cdd38ffd10d2 100644
> --- a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c
> +++ b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c
> @@ -305,14 +305,12 @@ cs_etm_decoder__buffer_packet(struct cs_etm_decoder *decoder,
>  			      enum cs_etm_sample_type sample_type)
>  {
>  	u32 et = 0;
> -	struct int_node *inode = NULL;
> +	int cpu;
>  
>  	if (decoder->packet_count >= MAX_BUFFER - 1)
>  		return OCSD_RESP_FATAL_SYS_ERR;
>  
> -	/* Search the RB tree for the cpu associated with this traceID */
> -	inode = intlist__find(traceid_list, trace_chan_id);
> -	if (!inode)
> +	if (cs_etm__get_cpu(trace_chan_id, &cpu) < 0)
>  		return OCSD_RESP_FATAL_SYS_ERR;
>  
>  	et = decoder->tail;
> @@ -322,7 +320,7 @@ cs_etm_decoder__buffer_packet(struct cs_etm_decoder *decoder,
>  
>  	decoder->packet_buffer[et].sample_type = sample_type;
>  	decoder->packet_buffer[et].isa = CS_ETM_ISA_UNKNOWN;
> -	decoder->packet_buffer[et].cpu = *((int *)inode->priv);
> +	decoder->packet_buffer[et].cpu = cpu;
>  	decoder->packet_buffer[et].start_addr = CS_ETM_INVAL_ADDR;
>  	decoder->packet_buffer[et].end_addr = CS_ETM_INVAL_ADDR;
>  	decoder->packet_buffer[et].instr_count = 0;
> diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c
> index 1aa29633ce77..e89989fe0a5c 100644
> --- a/tools/perf/util/cs-etm.c
> +++ b/tools/perf/util/cs-etm.c
> @@ -97,6 +97,20 @@ static u32 cs_etm__get_v7_protocol_version(u32 etmidr)
>  	return CS_ETM_PROTO_ETMV3;
>  }
>  
> +int cs_etm__get_cpu(u8 trace_chan_id, int *cpu)
> +{
> +	struct int_node *inode;
> +	u64 *metadata;
> +
> +	inode = intlist__find(traceid_list, trace_chan_id);
> +	if (!inode)
> +		return -EINVAL;
> +
> +	metadata = inode->priv;
> +	*cpu = (int)metadata[CS_ETM_CPU];
> +	return 0;
> +}
> +
>  static void cs_etm__packet_dump(const char *pkt_string)
>  {
>  	const char *color = PERF_COLOR_BLUE;
> @@ -252,7 +266,7 @@ static void cs_etm__free(struct perf_session *session)
>  	cs_etm__free_events(session);
>  	session->auxtrace = NULL;
>  
> -	/* First remove all traceID/CPU# nodes for the RB tree */
> +	/* First remove all traceID/metadata nodes for the RB tree */
>  	intlist__for_each_entry_safe(inode, tmp, traceid_list)
>  		intlist__remove(traceid_list, inode);
>  	/* Then the RB tree itself */
> @@ -1519,9 +1533,20 @@ int cs_etm__process_auxtrace_info(union perf_event *event,
>  				    0xffffffff);
>  
>  	/*
> -	 * Create an RB tree for traceID-CPU# tuple. Since the conversion has
> -	 * to be made for each packet that gets decoded, optimizing access in
> -	 * anything other than a sequential array is worth doing.
> +	 * Create an RB tree for traceID-metadata tuple.
> +	 *
> +	 * The conversion between traceID and CPU logic ID number has to
> +	 * be made for each packet that gets decoded: firstly retrieve
> +	 * metadata pointer from trace ID by using traceID-metadata tuple,
> +	 * then read CPU logic ID number in metadata.
> +	 *
> +	 * It's not safe to directly use CPU logic ID number as index to
> +	 * access metadata sequential array, e.g. when system have
> +	 * hotplugged out CPUs, the metadata array are only allocated for
> +	 * online CPUs but not offline CPUs, thus the CPU logic number is
> +	 * not consistent with its index in the arrary.  For this reason,
> +	 * we need to fallback to use TraceID-metadata tuple as a reliable
> +	 * method to access metadata.

Why adding this long comment?  To me all that is needed is
s/traceID-CPU#/traceID-metadata .

>  	 */
>  	traceid_list = intlist__new(NULL);
>  	if (!traceid_list) {
> @@ -1587,8 +1612,8 @@ int cs_etm__process_auxtrace_info(union perf_event *event,
>  			err = -EINVAL;
>  			goto err_free_metadata;
>  		}
> -		/* All good, associate the traceID with the CPU# */
> -		inode->priv = &metadata[j][CS_ETM_CPU];
> +		/* All good, associate the traceID with the metadata pointer */
> +		inode->priv = metadata[j];
>  	}
>  
>  	/*
> diff --git a/tools/perf/util/cs-etm.h b/tools/perf/util/cs-etm.h
> index 37f8d48179ca..5d70d10f3907 100644
> --- a/tools/perf/util/cs-etm.h
> +++ b/tools/perf/util/cs-etm.h
> @@ -53,7 +53,7 @@ enum {
>  	CS_ETMV4_PRIV_MAX,
>  };
>  
> -/* RB tree for quick conversion between traceID and CPUs */
> +/* RB tree for quick conversion between traceID and metadata pointers */
>  struct intlist *traceid_list;
>  
>  #define KiB(x) ((x) * 1024)
> @@ -78,4 +78,6 @@ cs_etm__process_auxtrace_info(union perf_event *event __maybe_unused,
>  }
>  #endif
>  
> +int cs_etm__get_cpu(u8 trace_chan_id, int *cpu);

This function is part of a public header that can theoretically be included by
any other file.  As such it has to be defined within the HAVE_CSTRACE_SUPPORT
define.

> +
>  #endif
> -- 
> 2.17.1
> 

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v6 6/8] perf cs-etm: Add traceID in packet
  2019-01-19  1:43 ` [PATCH v6 6/8] perf cs-etm: Add traceID in packet Leo Yan
@ 2019-01-23 21:23   ` Mathieu Poirier
  0 siblings, 0 replies; 21+ messages in thread
From: Mathieu Poirier @ 2019-01-23 21:23 UTC (permalink / raw)
  To: Leo Yan
  Cc: Arnaldo Carvalho de Melo, Suzuki K Poulose, Alexander Shishkin,
	Jiri Olsa, Namhyung Kim, Mike Leach, Robert Walker,
	linux-arm-kernel, linux-kernel, Coresight ML

On Sat, Jan 19, 2019 at 09:43:45AM +0800, Leo Yan wrote:
> Add traceID in packet, thus we can use traceID to retrieve metadata
> pointer from traceID-metadata tuple.
> 
> Signed-off-by: Leo Yan <leo.yan@linaro.org>
> ---
>  tools/perf/util/cs-etm-decoder/cs-etm-decoder.c | 2 ++
>  tools/perf/util/cs-etm-decoder/cs-etm-decoder.h | 1 +
>  2 files changed, 3 insertions(+)
> 
> diff --git a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c
> index cdd38ffd10d2..ba4c623cd8de 100644
> --- a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c
> +++ b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c
> @@ -295,6 +295,7 @@ static void cs_etm_decoder__clear_buffer(struct cs_etm_decoder *decoder)
>  		decoder->packet_buffer[i].last_instr_cond = 0;
>  		decoder->packet_buffer[i].flags = 0;
>  		decoder->packet_buffer[i].exception_number = UINT32_MAX;
> +		decoder->packet_buffer[i].trace_chan_id = UINT8_MAX;
>  		decoder->packet_buffer[i].cpu = INT_MIN;
>  	}
>  }
> @@ -331,6 +332,7 @@ cs_etm_decoder__buffer_packet(struct cs_etm_decoder *decoder,
>  	decoder->packet_buffer[et].last_instr_cond = 0;
>  	decoder->packet_buffer[et].flags = 0;
>  	decoder->packet_buffer[et].exception_number = UINT32_MAX;
> +	decoder->packet_buffer[et].trace_chan_id = trace_chan_id;
>  
>  	if (decoder->packet_count == MAX_BUFFER - 1)
>  		return OCSD_RESP_WAIT;
> diff --git a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.h b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.h
> index 012b4728a46f..7e6a8850be4a 100644
> --- a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.h
> +++ b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.h
> @@ -50,6 +50,7 @@ struct cs_etm_packet {
>  	u8 last_instr_cond;
>  	u8 last_instr_taken_branch;
>  	u8 last_instr_size;
> +	u8 trace_chan_id;
>  	int cpu;

Reviewed-by: Mathieu Poirier <mathieu.poirier@linaro.org>

>  };
>  
> -- 
> 2.17.1
> 

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v6 7/8] perf cs-etm: Set sample flags for exception packet
  2019-01-19  1:43 ` [PATCH v6 7/8] perf cs-etm: Set sample flags for exception packet Leo Yan
@ 2019-01-23 21:39   ` Mathieu Poirier
  0 siblings, 0 replies; 21+ messages in thread
From: Mathieu Poirier @ 2019-01-23 21:39 UTC (permalink / raw)
  To: Leo Yan
  Cc: Arnaldo Carvalho de Melo, Suzuki K Poulose, Alexander Shishkin,
	Jiri Olsa, Namhyung Kim, Mike Leach, Robert Walker,
	linux-arm-kernel, linux-kernel, Coresight ML

On Sat, Jan 19, 2019 at 09:43:46AM +0800, Leo Yan wrote:
> The exception taken and returning are typical flow for instruction jump
> but it needs to be handled with exception packets. This patch is to set
> sample flags for exception packet.
> 
> Since the exception packet contains the exception number, according to
> the exception number this patch makes decision for belonging to which
> exception types.
> 
> The decoder have defined different exception number for ETMv3 and ETMv4
> separately, hence this patch needs firstly decide the ETM version by
> using the metadata magic number, and this patch adds helper function
> cs_etm__get_magic() for easily getting magic number.
> 
> Based on different ETM version, the exception packet contains the
> exception number, according to the exception number this patch makes
> decision for the exception belonging to which exception types.
> 
> In this patch, it introduces helper function cs_etm__is_svc_instr();
> for ETMv4 CS_ETMV4_EXC_CALL covers SVC, SMC and HVC cases in the
> single exception number, thus need to use cs_etm__is_svc_instr() to
> decide an exception taken for system call.
> 
> Reviewed-by: Robert Walker <robert.walker@arm.com>
> Signed-off-by: Leo Yan <leo.yan@linaro.org>

This is the other way around, i.e you wrote the code and then Robert reviewed
it.  With this change:

Reviewed-by: Mathieu Poirier <mathieu.poirier@linaro.org>

> ---
>  tools/perf/util/cs-etm.c | 215 +++++++++++++++++++++++++++++++++++++++
>  tools/perf/util/cs-etm.h |  44 ++++++++
>  2 files changed, 259 insertions(+)
> 
> diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c
> index e89989fe0a5c..052805de6513 100644
> --- a/tools/perf/util/cs-etm.c
> +++ b/tools/perf/util/cs-etm.c
> @@ -97,6 +97,20 @@ static u32 cs_etm__get_v7_protocol_version(u32 etmidr)
>  	return CS_ETM_PROTO_ETMV3;
>  }
>  
> +static int cs_etm__get_magic(u8 trace_chan_id, u64 *magic)
> +{
> +	struct int_node *inode;
> +	u64 *metadata;
> +
> +	inode = intlist__find(traceid_list, trace_chan_id);
> +	if (!inode)
> +		return -EINVAL;
> +
> +	metadata = inode->priv;
> +	*magic = metadata[CS_ETM_MAGIC];
> +	return 0;
> +}
> +
>  int cs_etm__get_cpu(u8 trace_chan_id, int *cpu)
>  {
>  	struct int_node *inode;
> @@ -1122,10 +1136,174 @@ static int cs_etm__end_block(struct cs_etm_queue *etmq)
>  	return 0;
>  }
>  
> +static bool cs_etm__is_svc_instr(struct cs_etm_queue *etmq,
> +				 struct cs_etm_packet *packet,
> +				 u64 end_addr)
> +{
> +	u16 instr16;
> +	u32 instr32;
> +	u64 addr;
> +
> +	switch (packet->isa) {
> +	case CS_ETM_ISA_T32:
> +		/*
> +		 * The SVC of T32 is defined in ARM DDI 0487D.a, F5.1.247:
> +		 *
> +		 *  b'15         b'8
> +		 * +-----------------+--------+
> +		 * | 1 1 0 1 1 1 1 1 |  imm8  |
> +		 * +-----------------+--------+
> +		 *
> +		 * According to the specifiction, it only defines SVC for T32
> +		 * with 16 bits instruction and has no definition for 32bits;
> +		 * so below only read 2 bytes as instruction size for T32.
> +		 */
> +		addr = end_addr - 2;
> +		cs_etm__mem_access(etmq, addr, sizeof(instr16), (u8 *)&instr16);
> +		if ((instr16 & 0xFF00) == 0xDF00)
> +			return true;
> +
> +		break;
> +	case CS_ETM_ISA_A32:
> +		/*
> +		 * The SVC of A32 is defined in ARM DDI 0487D.a, F5.1.247:
> +		 *
> +		 *  b'31 b'28 b'27 b'24
> +		 * +---------+---------+-------------------------+
> +		 * |  !1111  | 1 1 1 1 |        imm24            |
> +		 * +---------+---------+-------------------------+
> +		 */
> +		addr = end_addr - 4;
> +		cs_etm__mem_access(etmq, addr, sizeof(instr32), (u8 *)&instr32);
> +		if ((instr32 & 0x0F000000) == 0x0F000000 &&
> +		    (instr32 & 0xF0000000) != 0xF0000000)
> +			return true;
> +
> +		break;
> +	case CS_ETM_ISA_A64:
> +		/*
> +		 * The SVC of A64 is defined in ARM DDI 0487D.a, C6.2.294:
> +		 *
> +		 *  b'31               b'21           b'4     b'0
> +		 * +-----------------------+---------+-----------+
> +		 * | 1 1 0 1 0 1 0 0 0 0 0 |  imm16  | 0 0 0 0 1 |
> +		 * +-----------------------+---------+-----------+
> +		 */
> +		addr = end_addr - 4;
> +		cs_etm__mem_access(etmq, addr, sizeof(instr32), (u8 *)&instr32);
> +		if ((instr32 & 0xFFE0001F) == 0xd4000001)
> +			return true;
> +
> +		break;
> +	case CS_ETM_ISA_UNKNOWN:
> +	default:
> +		break;
> +	}
> +
> +	return false;
> +}
> +
> +static bool cs_etm__is_syscall(struct cs_etm_queue *etmq, u64 magic)
> +{
> +	struct cs_etm_packet *packet = etmq->packet;
> +	struct cs_etm_packet *prev_packet = etmq->prev_packet;
> +
> +	if (magic == __perf_cs_etmv3_magic)
> +		if (packet->exception_number == CS_ETMV3_EXC_SVC)
> +			return true;
> +
> +	/*
> +	 * ETMv4 exception type CS_ETMV4_EXC_CALL covers SVC, SMC and
> +	 * HVC cases; need to check if it's SVC instruction based on
> +	 * packet address.
> +	 */
> +	if (magic == __perf_cs_etmv4_magic) {
> +		if (packet->exception_number == CS_ETMV4_EXC_CALL &&
> +		    cs_etm__is_svc_instr(etmq, prev_packet,
> +					 prev_packet->end_addr))
> +			return true;
> +	}
> +
> +	return false;
> +}
> +
> +static bool cs_etm__is_async_exception(struct cs_etm_queue *etmq, u64 magic)
> +{
> +	struct cs_etm_packet *packet = etmq->packet;
> +
> +	if (magic == __perf_cs_etmv3_magic)
> +		if (packet->exception_number == CS_ETMV3_EXC_DEBUG_HALT ||
> +		    packet->exception_number == CS_ETMV3_EXC_ASYNC_DATA_ABORT ||
> +		    packet->exception_number == CS_ETMV3_EXC_PE_RESET ||
> +		    packet->exception_number == CS_ETMV3_EXC_IRQ ||
> +		    packet->exception_number == CS_ETMV3_EXC_FIQ)
> +			return true;
> +
> +	if (magic == __perf_cs_etmv4_magic)
> +		if (packet->exception_number == CS_ETMV4_EXC_RESET ||
> +		    packet->exception_number == CS_ETMV4_EXC_DEBUG_HALT ||
> +		    packet->exception_number == CS_ETMV4_EXC_SYSTEM_ERROR ||
> +		    packet->exception_number == CS_ETMV4_EXC_INST_DEBUG ||
> +		    packet->exception_number == CS_ETMV4_EXC_DATA_DEBUG ||
> +		    packet->exception_number == CS_ETMV4_EXC_IRQ ||
> +		    packet->exception_number == CS_ETMV4_EXC_FIQ)
> +			return true;
> +
> +	return false;
> +}
> +
> +static bool cs_etm__is_sync_exception(struct cs_etm_queue *etmq, u64 magic)
> +{
> +	struct cs_etm_packet *packet = etmq->packet;
> +	struct cs_etm_packet *prev_packet = etmq->prev_packet;
> +
> +	if (magic == __perf_cs_etmv3_magic)
> +		if (packet->exception_number == CS_ETMV3_EXC_SMC ||
> +		    packet->exception_number == CS_ETMV3_EXC_HYP ||
> +		    packet->exception_number == CS_ETMV3_EXC_JAZELLE_THUMBEE ||
> +		    packet->exception_number == CS_ETMV3_EXC_UNDEFINED_INSTR ||
> +		    packet->exception_number == CS_ETMV3_EXC_PREFETCH_ABORT ||
> +		    packet->exception_number == CS_ETMV3_EXC_DATA_FAULT ||
> +		    packet->exception_number == CS_ETMV3_EXC_GENERIC)
> +			return true;
> +
> +	if (magic == __perf_cs_etmv4_magic) {
> +		if (packet->exception_number == CS_ETMV4_EXC_TRAP ||
> +		    packet->exception_number == CS_ETMV4_EXC_ALIGNMENT ||
> +		    packet->exception_number == CS_ETMV4_EXC_INST_FAULT ||
> +		    packet->exception_number == CS_ETMV4_EXC_DATA_FAULT)
> +			return true;
> +
> +		/*
> +		 * For CS_ETMV4_EXC_CALL, except SVC other instructions
> +		 * (SMC, HVC) are taken as sync exceptions.
> +		 */
> +		if (packet->exception_number == CS_ETMV4_EXC_CALL &&
> +		    !cs_etm__is_svc_instr(etmq, prev_packet,
> +					  prev_packet->end_addr))
> +			return true;
> +
> +		/*
> +		 * ETMv4 has 5 bits for exception number; if the numbers
> +		 * are in the range ( CS_ETMV4_EXC_FIQ, CS_ETMV4_EXC_END ]
> +		 * they are implementation defined exceptions.
> +		 *
> +		 * For this case, simply take it as sync exception.
> +		 */
> +		if (packet->exception_number > CS_ETMV4_EXC_FIQ &&
> +		    packet->exception_number <= CS_ETMV4_EXC_END)
> +			return true;
> +	}
> +
> +	return false;
> +}
> +
>  static int cs_etm__set_sample_flags(struct cs_etm_queue *etmq)
>  {
>  	struct cs_etm_packet *packet = etmq->packet;
>  	struct cs_etm_packet *prev_packet = etmq->prev_packet;
> +	u64 magic;
> +	int ret;
>  
>  	switch (packet->sample_type) {
>  	case CS_ETM_RANGE:
> @@ -1206,6 +1384,43 @@ static int cs_etm__set_sample_flags(struct cs_etm_queue *etmq)
>  					      PERF_IP_FLAG_TRACE_END;
>  		break;
>  	case CS_ETM_EXCEPTION:
> +		ret = cs_etm__get_magic(packet->trace_chan_id, &magic);
> +		if (ret)
> +			return ret;
> +
> +		/* The exception is for system call. */
> +		if (cs_etm__is_syscall(etmq, magic))
> +			packet->flags = PERF_IP_FLAG_BRANCH |
> +					PERF_IP_FLAG_CALL |
> +					PERF_IP_FLAG_SYSCALLRET;
> +		/*
> +		 * The exceptions are triggered by external signals from bus,
> +		 * interrupt controller, debug module, PE reset or halt.
> +		 */
> +		else if (cs_etm__is_async_exception(etmq, magic))
> +			packet->flags = PERF_IP_FLAG_BRANCH |
> +					PERF_IP_FLAG_CALL |
> +					PERF_IP_FLAG_ASYNC |
> +					PERF_IP_FLAG_INTERRUPT;
> +		/*
> +		 * Otherwise, exception is caused by trap, instruction &
> +		 * data fault, or alignment errors.
> +		 */
> +		else if (cs_etm__is_sync_exception(etmq, magic))
> +			packet->flags = PERF_IP_FLAG_BRANCH |
> +					PERF_IP_FLAG_CALL |
> +					PERF_IP_FLAG_INTERRUPT;
> +
> +		/*
> +		 * When the exception packet is inserted, since exception
> +		 * packet is not used standalone for generating samples
> +		 * and it's affiliation to the previous instruction range
> +		 * packet; so set previous range packet flags to tell perf
> +		 * it is an exception taken branch.
> +		 */
> +		if (prev_packet->sample_type == CS_ETM_RANGE)
> +			prev_packet->flags = packet->flags;
> +		break;
>  	case CS_ETM_EXCEPTION_RET:
>  	case CS_ETM_EMPTY:
>  	default:
> diff --git a/tools/perf/util/cs-etm.h b/tools/perf/util/cs-etm.h
> index 5d70d10f3907..7bd16ea8a62d 100644
> --- a/tools/perf/util/cs-etm.h
> +++ b/tools/perf/util/cs-etm.h
> @@ -53,6 +53,50 @@ enum {
>  	CS_ETMV4_PRIV_MAX,
>  };
>  
> +/*
> + * ETMv3 exception encoding number:
> + * See Embedded Trace Macrocell spcification (ARM IHI 0014Q)
> + * table 7-12 Encoding of Exception[3:0] for non-ARMv7-M processors.
> + */
> +enum {
> +	CS_ETMV3_EXC_NONE = 0,
> +	CS_ETMV3_EXC_DEBUG_HALT = 1,
> +	CS_ETMV3_EXC_SMC = 2,
> +	CS_ETMV3_EXC_HYP = 3,
> +	CS_ETMV3_EXC_ASYNC_DATA_ABORT = 4,
> +	CS_ETMV3_EXC_JAZELLE_THUMBEE = 5,
> +	CS_ETMV3_EXC_PE_RESET = 8,
> +	CS_ETMV3_EXC_UNDEFINED_INSTR = 9,
> +	CS_ETMV3_EXC_SVC = 10,
> +	CS_ETMV3_EXC_PREFETCH_ABORT = 11,
> +	CS_ETMV3_EXC_DATA_FAULT = 12,
> +	CS_ETMV3_EXC_GENERIC = 13,
> +	CS_ETMV3_EXC_IRQ = 14,
> +	CS_ETMV3_EXC_FIQ = 15,
> +};
> +
> +/*
> + * ETMv4 exception encoding number:
> + * See ARM Embedded Trace Macrocell Architecture Specification (ARM IHI 0064D)
> + * table 6-12 Possible values for the TYPE field in an Exception instruction
> + * trace packet, for ARMv7-A/R and ARMv8-A/R PEs.
> + */
> +enum {
> +	CS_ETMV4_EXC_RESET = 0,
> +	CS_ETMV4_EXC_DEBUG_HALT = 1,
> +	CS_ETMV4_EXC_CALL = 2,
> +	CS_ETMV4_EXC_TRAP = 3,
> +	CS_ETMV4_EXC_SYSTEM_ERROR = 4,
> +	CS_ETMV4_EXC_INST_DEBUG = 6,
> +	CS_ETMV4_EXC_DATA_DEBUG = 7,
> +	CS_ETMV4_EXC_ALIGNMENT = 10,
> +	CS_ETMV4_EXC_INST_FAULT = 11,
> +	CS_ETMV4_EXC_DATA_FAULT = 12,
> +	CS_ETMV4_EXC_IRQ = 14,
> +	CS_ETMV4_EXC_FIQ = 15,
> +	CS_ETMV4_EXC_END = 31,
> +};
> +
>  /* RB tree for quick conversion between traceID and metadata pointers */
>  struct intlist *traceid_list;
>  
> -- 
> 2.17.1
> 

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v6 8/8] perf cs-etm: Set sample flags for exception return packet
  2019-01-19  1:43 ` [PATCH v6 8/8] perf cs-etm: Set sample flags for exception return packet Leo Yan
@ 2019-01-23 21:51   ` Mathieu Poirier
  2019-01-23 23:36     ` Leo Yan
  0 siblings, 1 reply; 21+ messages in thread
From: Mathieu Poirier @ 2019-01-23 21:51 UTC (permalink / raw)
  To: Leo Yan
  Cc: Arnaldo Carvalho de Melo, Suzuki K Poulose, Alexander Shishkin,
	Jiri Olsa, Namhyung Kim, Mike Leach, Robert Walker,
	linux-arm-kernel, linux-kernel, Coresight ML

On Sat, Jan 19, 2019 at 09:43:47AM +0800, Leo Yan wrote:
> When return from exception, we need to distinguish if it's system call
> return or for other type exceptions for setting sample flags.  Due to
> the exception return packet doesn't contain exception number, so we
> cannot decide sample flags based on exception number.
> 
> On the other hand, the exception return packet is followed by an
> instruction range packet; this range packet deliveries the start address
> after exception handling, we can check if it is a SVC instruction just
> before the start address.  If there has one SVC instruction is found
> ahead the return address, this means it's an exception return for system
> call; otherwise it is an normal return for other exceptions.
> 
> This patch is to set sample flags for exception return packet, firstly
> it simply set sample flags as PERF_IP_FLAG_INTERRUPT for all exception
> returns since at this point it doesn't know what's exactly the exception
> type.  We will defer to decide if it's an exception return for system
> call when the next instruction range packet comes, it checks if there
> has one SVC instruction prior to the start address and if so we will
> change sample flags to PERF_IP_FLAG_SYSCALLRET for system call
> return.
> 
> Signed-off-by: Leo Yan <leo.yan@linaro.org>
> ---
>  tools/perf/util/cs-etm.c | 44 ++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 44 insertions(+)
> 
> diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c
> index 052805de6513..7547a7178f46 100644
> --- a/tools/perf/util/cs-etm.c
> +++ b/tools/perf/util/cs-etm.c
> @@ -1372,6 +1372,20 @@ static int cs_etm__set_sample_flags(struct cs_etm_queue *etmq)
>  		if (prev_packet->sample_type == CS_ETM_DISCONTINUITY)
>  			prev_packet->flags |= PERF_IP_FLAG_BRANCH |
>  					      PERF_IP_FLAG_TRACE_BEGIN;
> +
> +		/*
> +		 * If the previous packet is an exception return packet
> +		 * and the return address just follows SVC instuction,
> +		 * it needs to calibrate the previous packet sample flags
> +		 * as PERF_IP_FLAG_SYSCALLRET.
> +		 */
> +		if (prev_packet->flags == (PERF_IP_FLAG_BRANCH |
> +					   PERF_IP_FLAG_RETURN |
> +					   PERF_IP_FLAG_INTERRUPT) &&

Would it make more sense to just look for prev-packet->sample_type ==
CS_ETM_EXCEPTION_RET ?

> +		    cs_etm__is_svc_instr(etmq, packet, packet->start_addr))
> +			prev_packet->flags = PERF_IP_FLAG_BRANCH |
> +					     PERF_IP_FLAG_RETURN |
> +					     PERF_IP_FLAG_SYSCALLRET;
>  		break;
>  	case CS_ETM_DISCONTINUITY:
>  		/*
> @@ -1422,6 +1436,36 @@ static int cs_etm__set_sample_flags(struct cs_etm_queue *etmq)
>  			prev_packet->flags = packet->flags;
>  		break;
>  	case CS_ETM_EXCEPTION_RET:
> +		/*
> +		 * When the exception return packet is inserted, since
> +		 * exception return packet is not used standalone for
> +		 * generating samples and it's affiliation to the previous
> +		 * instruction range packet; so set previous range packet
> +		 * flags to tell perf it is an exception return branch.
> +		 *
> +		 * The exception return can be for either system call or
> +		 * other exception types; unfortunately the packet doesn't
> +		 * contain exception type related info so we cannot decide
> +		 * the exception type purely based on exception return packet.
> +		 * If we record the exception number from exception packet and
> +		 * reuse it for excpetion return packet, this is not reliable
> +		 * due the trace can be discontinuity or the interrupt can
> +		 * be nested, thus the recorded exception number cannot be
> +		 * used for exception return packet for these two cases.
> +		 *
> +		 * For exception return packet, we only need to distinguish the
> +		 * packet is for system call or for other types.  Thus the
> +		 * decision can be deferred when receive the next packet which
> +		 * contains the return address, based on the return address we
> +		 * can read out the previous instruction and check if it's a
> +		 * system call instruction and then calibrate the sample flag
> +		 * as needed.
> +		 */
> +		if (prev_packet->sample_type == CS_ETM_RANGE)
> +			prev_packet->flags = PERF_IP_FLAG_BRANCH |
> +					     PERF_IP_FLAG_RETURN |
> +					     PERF_IP_FLAG_INTERRUPT;
> +		break;
>  	case CS_ETM_EMPTY:
>  	default:
>  		break;
> -- 
> 2.17.1
> 

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v6 8/8] perf cs-etm: Set sample flags for exception return packet
  2019-01-23 21:51   ` Mathieu Poirier
@ 2019-01-23 23:36     ` Leo Yan
  0 siblings, 0 replies; 21+ messages in thread
From: Leo Yan @ 2019-01-23 23:36 UTC (permalink / raw)
  To: Mathieu Poirier
  Cc: Arnaldo Carvalho de Melo, Suzuki K Poulose, Alexander Shishkin,
	Jiri Olsa, Namhyung Kim, Mike Leach, Robert Walker,
	linux-arm-kernel, linux-kernel, Coresight ML

Hi Mathieu,

On Wed, Jan 23, 2019 at 02:51:14PM -0700, Mathieu Poirier wrote:
> On Sat, Jan 19, 2019 at 09:43:47AM +0800, Leo Yan wrote:
> > When return from exception, we need to distinguish if it's system call
> > return or for other type exceptions for setting sample flags.  Due to
> > the exception return packet doesn't contain exception number, so we
> > cannot decide sample flags based on exception number.
> > 
> > On the other hand, the exception return packet is followed by an
> > instruction range packet; this range packet deliveries the start address
> > after exception handling, we can check if it is a SVC instruction just
> > before the start address.  If there has one SVC instruction is found
> > ahead the return address, this means it's an exception return for system
> > call; otherwise it is an normal return for other exceptions.
> > 
> > This patch is to set sample flags for exception return packet, firstly
> > it simply set sample flags as PERF_IP_FLAG_INTERRUPT for all exception
> > returns since at this point it doesn't know what's exactly the exception
> > type.  We will defer to decide if it's an exception return for system
> > call when the next instruction range packet comes, it checks if there
> > has one SVC instruction prior to the start address and if so we will
> > change sample flags to PERF_IP_FLAG_SYSCALLRET for system call
> > return.
> > 
> > Signed-off-by: Leo Yan <leo.yan@linaro.org>
> > ---
> >  tools/perf/util/cs-etm.c | 44 ++++++++++++++++++++++++++++++++++++++++
> >  1 file changed, 44 insertions(+)
> > 
> > diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c
> > index 052805de6513..7547a7178f46 100644
> > --- a/tools/perf/util/cs-etm.c
> > +++ b/tools/perf/util/cs-etm.c
> > @@ -1372,6 +1372,20 @@ static int cs_etm__set_sample_flags(struct cs_etm_queue *etmq)
> >  		if (prev_packet->sample_type == CS_ETM_DISCONTINUITY)
> >  			prev_packet->flags |= PERF_IP_FLAG_BRANCH |
> >  					      PERF_IP_FLAG_TRACE_BEGIN;
> > +
> > +		/*
> > +		 * If the previous packet is an exception return packet
> > +		 * and the return address just follows SVC instuction,
> > +		 * it needs to calibrate the previous packet sample flags
> > +		 * as PERF_IP_FLAG_SYSCALLRET.
> > +		 */
> > +		if (prev_packet->flags == (PERF_IP_FLAG_BRANCH |
> > +					   PERF_IP_FLAG_RETURN |
> > +					   PERF_IP_FLAG_INTERRUPT) &&
> 
> Would it make more sense to just look for prev-packet->sample_type ==
> CS_ETM_EXCEPTION_RET ?

We cannot check 'prev-packet->sample_type == CS_ETM_EXCEPTION_RET',
since CS_ETM_EXCEPTION_RET is associated to its previous instruction
range packet but not a standalone instruction range packet, we don't
swap for exception and exception return packets, 'prev_packet' is
pointed to the previous instruction range packet at here.

This is why we need to use 'prev_packet->flags' but not
'prev_packet->sample_type' as checking condition.

Thanks,
Leo Yan

> > +		    cs_etm__is_svc_instr(etmq, packet, packet->start_addr))
> > +			prev_packet->flags = PERF_IP_FLAG_BRANCH |
> > +					     PERF_IP_FLAG_RETURN |
> > +					     PERF_IP_FLAG_SYSCALLRET;
> >  		break;
> >  	case CS_ETM_DISCONTINUITY:
> >  		/*
> > @@ -1422,6 +1436,36 @@ static int cs_etm__set_sample_flags(struct cs_etm_queue *etmq)
> >  			prev_packet->flags = packet->flags;
> >  		break;
> >  	case CS_ETM_EXCEPTION_RET:
> > +		/*
> > +		 * When the exception return packet is inserted, since
> > +		 * exception return packet is not used standalone for
> > +		 * generating samples and it's affiliation to the previous
> > +		 * instruction range packet; so set previous range packet
> > +		 * flags to tell perf it is an exception return branch.
> > +		 *
> > +		 * The exception return can be for either system call or
> > +		 * other exception types; unfortunately the packet doesn't
> > +		 * contain exception type related info so we cannot decide
> > +		 * the exception type purely based on exception return packet.
> > +		 * If we record the exception number from exception packet and
> > +		 * reuse it for excpetion return packet, this is not reliable
> > +		 * due the trace can be discontinuity or the interrupt can
> > +		 * be nested, thus the recorded exception number cannot be
> > +		 * used for exception return packet for these two cases.
> > +		 *
> > +		 * For exception return packet, we only need to distinguish the
> > +		 * packet is for system call or for other types.  Thus the
> > +		 * decision can be deferred when receive the next packet which
> > +		 * contains the return address, based on the return address we
> > +		 * can read out the previous instruction and check if it's a
> > +		 * system call instruction and then calibrate the sample flag
> > +		 * as needed.
> > +		 */
> > +		if (prev_packet->sample_type == CS_ETM_RANGE)
> > +			prev_packet->flags = PERF_IP_FLAG_BRANCH |
> > +					     PERF_IP_FLAG_RETURN |
> > +					     PERF_IP_FLAG_INTERRUPT;
> > +		break;
> >  	case CS_ETM_EMPTY:
> >  	default:
> >  		break;
> > -- 
> > 2.17.1
> > 

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v6 5/8] perf cs-etm: Change tuple from traceID-CPU# to traceID-metadata
  2019-01-23 21:13   ` Mathieu Poirier
@ 2019-01-23 23:45     ` Leo Yan
  0 siblings, 0 replies; 21+ messages in thread
From: Leo Yan @ 2019-01-23 23:45 UTC (permalink / raw)
  To: Mathieu Poirier
  Cc: Arnaldo Carvalho de Melo, Suzuki K Poulose, Alexander Shishkin,
	Jiri Olsa, Namhyung Kim, Mike Leach, Robert Walker,
	linux-arm-kernel, linux-kernel, Coresight ML

On Wed, Jan 23, 2019 at 02:13:00PM -0700, Mathieu Poirier wrote:
> On Sat, Jan 19, 2019 at 09:43:44AM +0800, Leo Yan wrote:
> > If packet processing wants to know the packet is bound with which ETM
> > version, it needs to access metadata to decide that based on metadata
> > magic number; but we cannot simply to use CPU logic ID number as index
> > to access metadata sequential array, especially when system have
> > hotplugged off CPUs, the metadata array are only allocated for online
> > CPUs but not offline CPUs, so the CPU logic number doesn't match with
> > its index in the array.
> > 
> > For this reason, a reliable way for accessing metadata array is to use
> > traceID to find associated metadata; by accessing metadata content we
> > can know not only the CPU number but also for ETM version, which can be
> > used for sequential change for setting sample flags for exception
> > packets.
> 
> This paragraph is not needed to understand why this patch is needed.  Please
> remove.

Will do.

> > This patch is to change tuple from traceID-CPU# to traceID-metadata,
> > thus it can use the tuple to retrieve metadata pointer according to
> > traceID.
> > 
> > For safe accessing metadata fields, this patch provides helper function
> > cs_etm__get_cpu() which is used to return CPU number according to
> > traceID; cs_etm_decoder__buffer_packet() is the first consumer for this
> > helper function.
> > 
> > Signed-off-by: Leo Yan <leo.yan@linaro.org>
> > ---
> >  .../perf/util/cs-etm-decoder/cs-etm-decoder.c |  8 ++--
> >  tools/perf/util/cs-etm.c                      | 37 ++++++++++++++++---
> >  tools/perf/util/cs-etm.h                      |  4 +-
> >  3 files changed, 37 insertions(+), 12 deletions(-)
> > 
> > diff --git a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c
> > index 294efa76c9e3..cdd38ffd10d2 100644
> > --- a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c
> > +++ b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c
> > @@ -305,14 +305,12 @@ cs_etm_decoder__buffer_packet(struct cs_etm_decoder *decoder,
> >  			      enum cs_etm_sample_type sample_type)
> >  {
> >  	u32 et = 0;
> > -	struct int_node *inode = NULL;
> > +	int cpu;
> >  
> >  	if (decoder->packet_count >= MAX_BUFFER - 1)
> >  		return OCSD_RESP_FATAL_SYS_ERR;
> >  
> > -	/* Search the RB tree for the cpu associated with this traceID */
> > -	inode = intlist__find(traceid_list, trace_chan_id);
> > -	if (!inode)
> > +	if (cs_etm__get_cpu(trace_chan_id, &cpu) < 0)
> >  		return OCSD_RESP_FATAL_SYS_ERR;
> >  
> >  	et = decoder->tail;
> > @@ -322,7 +320,7 @@ cs_etm_decoder__buffer_packet(struct cs_etm_decoder *decoder,
> >  
> >  	decoder->packet_buffer[et].sample_type = sample_type;
> >  	decoder->packet_buffer[et].isa = CS_ETM_ISA_UNKNOWN;
> > -	decoder->packet_buffer[et].cpu = *((int *)inode->priv);
> > +	decoder->packet_buffer[et].cpu = cpu;
> >  	decoder->packet_buffer[et].start_addr = CS_ETM_INVAL_ADDR;
> >  	decoder->packet_buffer[et].end_addr = CS_ETM_INVAL_ADDR;
> >  	decoder->packet_buffer[et].instr_count = 0;
> > diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c
> > index 1aa29633ce77..e89989fe0a5c 100644
> > --- a/tools/perf/util/cs-etm.c
> > +++ b/tools/perf/util/cs-etm.c
> > @@ -97,6 +97,20 @@ static u32 cs_etm__get_v7_protocol_version(u32 etmidr)
> >  	return CS_ETM_PROTO_ETMV3;
> >  }
> >  
> > +int cs_etm__get_cpu(u8 trace_chan_id, int *cpu)
> > +{
> > +	struct int_node *inode;
> > +	u64 *metadata;
> > +
> > +	inode = intlist__find(traceid_list, trace_chan_id);
> > +	if (!inode)
> > +		return -EINVAL;
> > +
> > +	metadata = inode->priv;
> > +	*cpu = (int)metadata[CS_ETM_CPU];
> > +	return 0;
> > +}
> > +
> >  static void cs_etm__packet_dump(const char *pkt_string)
> >  {
> >  	const char *color = PERF_COLOR_BLUE;
> > @@ -252,7 +266,7 @@ static void cs_etm__free(struct perf_session *session)
> >  	cs_etm__free_events(session);
> >  	session->auxtrace = NULL;
> >  
> > -	/* First remove all traceID/CPU# nodes for the RB tree */
> > +	/* First remove all traceID/metadata nodes for the RB tree */
> >  	intlist__for_each_entry_safe(inode, tmp, traceid_list)
> >  		intlist__remove(traceid_list, inode);
> >  	/* Then the RB tree itself */
> > @@ -1519,9 +1533,20 @@ int cs_etm__process_auxtrace_info(union perf_event *event,
> >  				    0xffffffff);
> >  
> >  	/*
> > -	 * Create an RB tree for traceID-CPU# tuple. Since the conversion has
> > -	 * to be made for each packet that gets decoded, optimizing access in
> > -	 * anything other than a sequential array is worth doing.
> > +	 * Create an RB tree for traceID-metadata tuple.
> > +	 *
> > +	 * The conversion between traceID and CPU logic ID number has to
> > +	 * be made for each packet that gets decoded: firstly retrieve
> > +	 * metadata pointer from trace ID by using traceID-metadata tuple,
> > +	 * then read CPU logic ID number in metadata.
> > +	 *
> > +	 * It's not safe to directly use CPU logic ID number as index to
> > +	 * access metadata sequential array, e.g. when system have
> > +	 * hotplugged out CPUs, the metadata array are only allocated for
> > +	 * online CPUs but not offline CPUs, thus the CPU logic number is
> > +	 * not consistent with its index in the arrary.  For this reason,
> > +	 * we need to fallback to use TraceID-metadata tuple as a reliable
> > +	 * method to access metadata.
> 
> Why adding this long comment?  To me all that is needed is
> s/traceID-CPU#/traceID-metadata .

Here just want to give more information for why we create
traceID-metadata tuple (and hope can give the reason why we need
to use traceID-metadata rather than traceID-CPU# tuple).

If you think it's redundant, will drop it.

> >  	 */
> >  	traceid_list = intlist__new(NULL);
> >  	if (!traceid_list) {
> > @@ -1587,8 +1612,8 @@ int cs_etm__process_auxtrace_info(union perf_event *event,
> >  			err = -EINVAL;
> >  			goto err_free_metadata;
> >  		}
> > -		/* All good, associate the traceID with the CPU# */
> > -		inode->priv = &metadata[j][CS_ETM_CPU];
> > +		/* All good, associate the traceID with the metadata pointer */
> > +		inode->priv = metadata[j];
> >  	}
> >  
> >  	/*
> > diff --git a/tools/perf/util/cs-etm.h b/tools/perf/util/cs-etm.h
> > index 37f8d48179ca..5d70d10f3907 100644
> > --- a/tools/perf/util/cs-etm.h
> > +++ b/tools/perf/util/cs-etm.h
> > @@ -53,7 +53,7 @@ enum {
> >  	CS_ETMV4_PRIV_MAX,
> >  };
> >  
> > -/* RB tree for quick conversion between traceID and CPUs */
> > +/* RB tree for quick conversion between traceID and metadata pointers */
> >  struct intlist *traceid_list;
> >  
> >  #define KiB(x) ((x) * 1024)
> > @@ -78,4 +78,6 @@ cs_etm__process_auxtrace_info(union perf_event *event __maybe_unused,
> >  }
> >  #endif
> >  
> > +int cs_etm__get_cpu(u8 trace_chan_id, int *cpu);
> 
> This function is part of a public header that can theoretically be included by
> any other file.  As such it has to be defined within the HAVE_CSTRACE_SUPPORT
> define.

My stupid.  Will move it into HAVE_CSTRACE_SUPPORT blocks.

Thanks a lot for reviewing.

> > +
> >  #endif
> > -- 
> > 2.17.1
> > 

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v6 0/8] perf cs-etm: Add support for sample flags
  2019-01-19  1:43 [PATCH v6 0/8] perf cs-etm: Add support for sample flags Leo Yan
                   ` (7 preceding siblings ...)
  2019-01-19  1:43 ` [PATCH v6 8/8] perf cs-etm: Set sample flags for exception return packet Leo Yan
@ 2019-01-24  0:22 ` Mathieu Poirier
  2019-01-24  4:00   ` Leo Yan
  8 siblings, 1 reply; 21+ messages in thread
From: Mathieu Poirier @ 2019-01-24  0:22 UTC (permalink / raw)
  To: Leo Yan
  Cc: Arnaldo Carvalho de Melo, Suzuki K Poulose, Alexander Shishkin,
	Jiri Olsa, Namhyung Kim, Mike Leach, Robert Walker,
	linux-arm-kernel, Linux Kernel Mailing List, Coresight ML

On Fri, 18 Jan 2019 at 18:44, Leo Yan <leo.yan@linaro.org> wrote:
>
> This patch seris adds support for sample flags so can facilitate perf
> to print sample flags for branch instruction.
>
> Patch 0001 is used to save last branch information in packet structure,
> this includes instruction type, subtype and condition flag to help
> making decision for which branch instruction it is.  It passes related
> information from decoder layer to cs-etm.c, so we use cs-etm.c as a
> central place to set sample flags.
>
> Patch 0002 is used to set sample flags for instruction range packet.
>
> Patch 0003 is used to set sample flags for trace discontinuity packet.
>
> Patches 0004/0005/0006 are preparation for exception packet handling:
> Patch 0004 addes exception number in packet; pacth 0005/0006 is to use
> traceID/metadata tuple to access metadata pointer based on traceID, this
> can help decide if the CPU is connected with ETMv3 or ETMv4, ETMv3 and
> ETMv4 have totally different definition for exception numbers.
>
> Patch 0007 sets sample flags for exception packet; patch 0008 support
> sample flags for exception return packet.
>
> This patch series is applied on the acme's perf core branch with the
> with latest commit 02bb912ae451 ("perf tools: Replace automatic const
> char[] variables by statics").
>
> After applying this patch series, we can verify sample flags with below
> command:
>
>   # perf script -F,-time,+flags,+ip,+sym,+dso,+addr,+symoff -k vmlinux

Since you are going for another iteration please add a "before" and
"after" example.

Thanks,
Mathieu


>
> Changes from v5:
> * Addressed Rob's suggestion to add specification info for exception
>   number encoding;
> * Added Rob's review tag in patch 0007.
>
> Changes from v4:
> * Fixed typos in comments, and removed redundant info from commit log;
> * Addressed Mathieu's suggestion to add helper functions for metadata
>   fields (CS_ETM_CPU and CS_ETM_MAGIC) accessing;
> * Addressed Mathieu's suggestion to include headers with alphabetical
>   order.
>
> Changes from v3:
> * Fixed typos in commit logs;
> * Rearranged fields in cs_etm_packet by grouping with same variable
>   types;
> * Fixed ETMv4 exception number which pointed by Mike;
> * Fixed ETMv4 SVC / SMC / HVC in the same CALL, by checking svc
>   instruction to distinguish them;
> * Refine ETMv4 return exception packet handling.
>
> Changes from v2:
> * Addressed Mathieu's suggestion to split one big patch to 3 small
>   patches for setting sample flags, one is for instruction range
>   packet, one is for discontinuity packet and one is for exception
>   packet.
> * Added supporting for ETMv3 exception packet.
> * Followed Mathieu's suggestion to move all sample flags handling
>   from decoder layer to cs-etm.c, thus it has enough info to set flags
>   based on trace context in single place.
>
> Changes from v1:
> * Moved exception packets handling patches into patch series 'perf
>   cs-etm: Correct packets handling'.
> * Added sample flags fixing up for TRACE_OFF packet.
> * Created a new function which is used to maintain flags fixing up.
>
>
> Leo Yan (8):
>   perf cs-etm: Add last instruction information in packet
>   perf cs-etm: Set sample flags for instruction range packet
>   perf cs-etm: Set sample flags for trace discontinuity
>   perf cs-etm: Add exception number in exception packet
>   perf cs-etm: Change tuple from traceID-CPU# to traceID-metadata
>   perf cs-etm: Add traceID in packet
>   perf cs-etm: Set sample flags for exception packet
>   perf cs-etm: Set sample flags for exception return packet
>
>  .../perf/util/cs-etm-decoder/cs-etm-decoder.c |  41 +-
>  .../perf/util/cs-etm-decoder/cs-etm-decoder.h |   6 +
>  tools/perf/util/cs-etm.c                      | 405 +++++++++++++++++-
>  tools/perf/util/cs-etm.h                      |  48 ++-
>  4 files changed, 482 insertions(+), 18 deletions(-)
>
> --
> 2.17.1
>

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [PATCH v6 0/8] perf cs-etm: Add support for sample flags
  2019-01-24  0:22 ` [PATCH v6 0/8] perf cs-etm: Add support for sample flags Mathieu Poirier
@ 2019-01-24  4:00   ` Leo Yan
  0 siblings, 0 replies; 21+ messages in thread
From: Leo Yan @ 2019-01-24  4:00 UTC (permalink / raw)
  To: Mathieu Poirier
  Cc: Arnaldo Carvalho de Melo, Suzuki K Poulose, Alexander Shishkin,
	Jiri Olsa, Namhyung Kim, Mike Leach, Robert Walker,
	linux-arm-kernel, Linux Kernel Mailing List, Coresight ML

On Wed, Jan 23, 2019 at 05:22:03PM -0700, Mathieu Poirier wrote:
> On Fri, 18 Jan 2019 at 18:44, Leo Yan <leo.yan@linaro.org> wrote:

[...]

> > After applying this patch series, we can verify sample flags with below
> > command:
> >
> >   # perf script -F,-time,+flags,+ip,+sym,+dso,+addr,+symoff -k vmlinux
> 
> Since you are going for another iteration please add a "before" and
> "after" example.

Sure, will add it.

Thanks,
Leo Yan

^ permalink raw reply	[flat|nested] 21+ messages in thread

end of thread, other threads:[~2019-01-24  4:00 UTC | newest]

Thread overview: 21+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-01-19  1:43 [PATCH v6 0/8] perf cs-etm: Add support for sample flags Leo Yan
2019-01-19  1:43 ` [PATCH v6 1/8] perf cs-etm: Add last instruction information in packet Leo Yan
2019-01-23 21:03   ` Mathieu Poirier
2019-01-19  1:43 ` [PATCH v6 2/8] perf cs-etm: Set sample flags for instruction range packet Leo Yan
2019-01-23 21:03   ` Mathieu Poirier
2019-01-19  1:43 ` [PATCH v6 3/8] perf cs-etm: Set sample flags for trace discontinuity Leo Yan
2019-01-23 21:04   ` Mathieu Poirier
2019-01-19  1:43 ` [PATCH v6 4/8] perf cs-etm: Add exception number in exception packet Leo Yan
2019-01-23 21:05   ` Mathieu Poirier
2019-01-19  1:43 ` [PATCH v6 5/8] perf cs-etm: Change tuple from traceID-CPU# to traceID-metadata Leo Yan
2019-01-23 21:13   ` Mathieu Poirier
2019-01-23 23:45     ` Leo Yan
2019-01-19  1:43 ` [PATCH v6 6/8] perf cs-etm: Add traceID in packet Leo Yan
2019-01-23 21:23   ` Mathieu Poirier
2019-01-19  1:43 ` [PATCH v6 7/8] perf cs-etm: Set sample flags for exception packet Leo Yan
2019-01-23 21:39   ` Mathieu Poirier
2019-01-19  1:43 ` [PATCH v6 8/8] perf cs-etm: Set sample flags for exception return packet Leo Yan
2019-01-23 21:51   ` Mathieu Poirier
2019-01-23 23:36     ` Leo Yan
2019-01-24  0:22 ` [PATCH v6 0/8] perf cs-etm: Add support for sample flags Mathieu Poirier
2019-01-24  4:00   ` Leo Yan

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).