Hi Leo, On Tue, 11 Dec 2018 at 15:08, leo.yan@linaro.org wrote:
Hi Mathieu, Mike,
On Tue, Dec 11, 2018 at 11:01:11PM +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 and exception return packet.
Since the exception packet contains the exception number, according this number value this patch divide exception types into three classes:
The first type of exception is caused by external logics like bus, interrupt controller, debug module or PE reset or halt; this is corresponding to flags "bcyi" which defined in documentation perf-script.txt;
The second type is for system call, this is set as "bcs" by following definition in the documentation;
The third type is for CPU trap, data and instruction prefetch abort, alignment abort; usually these exceptions are synchronous for CPU, so set them as "bci" type.
As the exception return packet doesn't contain valid exception number, the exception number is recorded in cs_etm_queue struct from the previous exception packet and this value will be reused by exception return packet. To avoid to use stale exception number, the exception number will be reset to UINT_MAX after handling exception return packet or there have one discontinuity packet is coming.
Neither exception packet nor exception return packet is standalone packet which can be used to generate samples; essentially they must affiliate with instruction range packets for samples generation. The previous instruction range packet sample flags are assigned with its following exception packet or exception return packet.
This patch seris is sent to you and CoreSight mailing list for internal review before send to LKML. I still have several questions want to check with you firstly, so please see below comments.
Also very welcome comment and suggestion.
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 then use corresponding exception numbers for the specific ETM version.
Should I divide this into two patches, one is for ETMv3 and another is for ETMv4?
Signed-off-by: Leo Yan leo.yan@linaro.org
tools/perf/util/cs-etm.c | 127 +++++++++++++++++++++++++++++++++++++++++++++++ tools/perf/util/cs-etm.h | 36 ++++++++++++++ 2 files changed, 163 insertions(+)
diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c index bc8a4bc..0c917b1 100644 --- a/tools/perf/util/cs-etm.c +++ b/tools/perf/util/cs-etm.c @@ -73,6 +73,7 @@ struct cs_etm_queue { u64 timestamp; u64 offset; u64 period_instructions;
u32 exc_num; struct branch_stack *last_branch; struct branch_stack *last_branch_rb; size_t last_branch_pos;
@@ -1108,6 +1109,73 @@ static int cs_etm__end_block(struct cs_etm_queue *etmq) return 0; }
+static bool cs_etm__is_syscall(struct cs_etm_queue *etmq) +{
struct cs_etm_auxtrace *etm = etmq->etm;
int cpu = etmq->packet->cpu;
if (etm->metadata[cpu][CS_ETM_MAGIC] == __perf_cs_etmv3_magic)
if (etmq->exc_num == CS_ETMV3_EXC_SVC)
return true;
if (etm->metadata[cpu][CS_ETM_MAGIC] == __perf_cs_etmv4_magic)
if (etmq->exc_num == CS_ETMV4_EXC_CALL)
return true;
return false;
+}
+static bool cs_etm__is_async_exception(struct cs_etm_queue *etmq) +{
struct cs_etm_auxtrace *etm = etmq->etm;
int cpu = etmq->packet->cpu;
if (etm->metadata[cpu][CS_ETM_MAGIC] == __perf_cs_etmv3_magic)
if (etmq->exc_num == CS_ETMV3_EXC_DEBUG_HALT ||
etmq->exc_num == CS_ETMV3_EXC_ASYNC_DATA_ABORT ||
etmq->exc_num == CS_ETMV3_EXC_PE_RESET ||
etmq->exc_num == CS_ETMV3_EXC_IRQ ||
etmq->exc_num == CS_ETMV3_EXC_FIQ)
return true;
if (etm->metadata[cpu][CS_ETM_MAGIC] == __perf_cs_etmv4_magic)
if (etmq->exc_num == CS_ETMV4_EXC_RESET ||
etmq->exc_num == CS_ETMV4_EXC_DEBUG_HALT ||
etmq->exc_num == CS_ETMV4_EXC_SYSTEM_ERROR ||
etmq->exc_num == CS_ETMV4_EXC_INST_DEBUG ||
etmq->exc_num == CS_ETMV4_EXC_DATA_DEBUG ||
etmq->exc_num == CS_ETMV4_EXC_IRQ ||
etmq->exc_num == CS_ETMV4_EXC_FIQ)
return true;
return false;
+}
+static bool cs_etm__is_sync_exception(struct cs_etm_queue *etmq) +{
struct cs_etm_auxtrace *etm = etmq->etm;
int cpu = etmq->packet->cpu;
if (etm->metadata[cpu][CS_ETM_MAGIC] == __perf_cs_etmv3_magic)
if (etmq->exc_num == CS_ETMV3_EXC_SMC ||
etmq->exc_num == CS_ETMV3_EXC_HYP ||
etmq->exc_num == CS_ETMV3_EXC_JAZELLE ||
etmq->exc_num == CS_ETMV3_EXC_UNDEFINED_INSTR ||
etmq->exc_num == CS_ETMV3_EXC_PREFETCH_ABORT ||
etmq->exc_num == CS_ETMV3_EXC_DATA_FAULT ||
etmq->exc_num == CS_ETMV3_EXC_GENERIC)
return true;
Mike, could you help confirm what's the exception type for CS_ETMV3_EXC_JAZELLE/CS_ETMV3_EXC_UNDEFINED_INSTR/CS_ETMV3_EXC_GENERIC?
Are they synchronous exceptions?
Thanks, Leo Yan
if (etm->metadata[cpu][CS_ETM_MAGIC] == __perf_cs_etmv4_magic)
if (etmq->exc_num == CS_ETMV4_EXC_TRAP ||
etmq->exc_num == CS_ETMV4_EXC_ALIGNMENT ||
etmq->exc_num == CS_ETMV4_EXC_INST_FAULT ||
etmq->exc_num == CS_ETMV4_EXC_DATA_FAULT)
return true;
return false;
+}
static void cs_etm__set_sample_flags(struct cs_etm_queue *etmq) { struct cs_etm_packet *packet = etmq->packet; @@ -1192,9 +1260,67 @@ static void cs_etm__set_sample_flags(struct cs_etm_queue *etmq) if (prev_packet->sample_type == CS_ETM_RANGE) prev_packet->flags |= PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_TRACE_END;
etmq->exc_num = UINT_MAX; break; case CS_ETM_EXCEPTION:
etmq->exc_num = packet->exc_num;
/* The exception is for system call. */
if (cs_etm__is_syscall(etmq))
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))
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))
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:
if (cs_etm__is_syscall(etmq))
packet->flags = PERF_IP_FLAG_BRANCH |
PERF_IP_FLAG_RETURN |
PERF_IP_FLAG_SYSCALLRET;
else
packet->flags = PERF_IP_FLAG_BRANCH |
PERF_IP_FLAG_RETURN |
PERF_IP_FLAG_INTERRUPT;
/*
* 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.
*/
if (prev_packet->sample_type == CS_ETM_RANGE)
prev_packet->flags = packet->flags;
etmq->exc_num = UINT_MAX;
break; case CS_ETM_EMPTY: default: break;
@@ -1553,6 +1679,7 @@ int cs_etm__process_auxtrace_info(union perf_event *event, err = -ENOMEM; goto err_free_metadata; }
for (k = 0; k < CS_ETMV4_PRIV_MAX; k++) metadata[j][k] = ptr[i + k];
diff --git a/tools/perf/util/cs-etm.h b/tools/perf/util/cs-etm.h index 37f8d48..fa46ff6 100644 --- a/tools/perf/util/cs-etm.h +++ b/tools/perf/util/cs-etm.h @@ -39,6 +39,26 @@ enum { CS_ETM_PRIV_MAX, };
+/* ETMv3 exception number */ +enum {
CS_ETMV3_EXC_NONE,
CS_ETMV3_EXC_DEBUG_HALT,
CS_ETMV3_EXC_SMC,
CS_ETMV3_EXC_HYP,
CS_ETMV3_EXC_ASYNC_DATA_ABORT,
CS_ETMV3_EXC_JAZELLE,
CS_ETMV3_EXC_RESERVED1,
CS_ETMV3_EXC_RESERVED2,
CS_ETMV3_EXC_PE_RESET,
CS_ETMV3_EXC_UNDEFINED_INSTR,
CS_ETMV3_EXC_SVC,
CS_ETMV3_EXC_PREFETCH_ABORT,
CS_ETMV3_EXC_DATA_FAULT,
CS_ETMV3_EXC_GENERIC,
CS_ETMV3_EXC_IRQ,
CS_ETMV3_EXC_FIQ,
+};
/* ETMv4 metadata */ enum { /* Dynamic, configurable parameters */ @@ -53,6 +73,22 @@ enum { CS_ETMV4_PRIV_MAX, };
+/* ETMv4 exception number */ +enum {
CS_ETMV4_EXC_RESET,
CS_ETMV4_EXC_DEBUG_HALT,
CS_ETMV4_EXC_CALL,
CS_ETMV4_EXC_TRAP,
CS_ETMV4_EXC_SYSTEM_ERROR,
CS_ETMV4_EXC_INST_DEBUG,
CS_ETMV4_EXC_DATA_DEBUG,
CS_ETMV4_EXC_ALIGNMENT,
CS_ETMV4_EXC_INST_FAULT,
CS_ETMV4_EXC_DATA_FAULT,
CS_ETMV4_EXC_IRQ,
CS_ETMV4_EXC_FIQ,
+};
This enum needs correcting to cover the reserved values so that the enum values match up for the actual exception number value. Additionally there are implementation defined exceptions after FIQ that could occur on custom devices.
Regards
Mike
/* RB tree for quick conversion between traceID and CPUs */ struct intlist *traceid_list;
-- 2.7.4