Commit e573e978 authored by Robert Walker's avatar Robert Walker Committed by Arnaldo Carvalho de Melo

perf cs-etm: Inject capabilitity for CoreSight traces

Added user space perf functionality to translate CoreSight traces into
instruction events with branch stack.

To invoke the new functionality, use the perf inject tool with
--itrace=il. For example, to translate the ETM trace from perf.data into
last branch records in a new inj.data file:

    $ perf inject --itrace=i100000il128 -i perf.data -o perf.data.new

The 'i' parameter to itrace generates periodic instruction events.  The
period between instruction events can be specified as a number of
instructions suffixed by i (default 100000).

The parameter to 'l' specifies the number of entries in the branch stack
attached to instruction events.

The 'b' parameter to itrace generates events on taken branches.

This patch also fixes the contents of the branch events used in perf
report - previously branch events were generated for each contiguous
range of instructions executed.  These are fixed to generate branch
events between the last address of a range ending in an executed branch
instruction and the start address of the next range.

Based on patches by Sebastian Pop <s.pop@samsung.com> with additional fixes
and support for specifying the instruction period.
Originally-by: default avatarSebastian Pop <s.pop@samsung.com>
Signed-off-by: default avatarRobert Walker <robert.walker@arm.com>
Acked-by: default avatarMathieu Poirier <mathieu.poirier@linaro.org>
Cc: coresight@lists.linaro.org
Cc: linux-arm-kernel@lists.infradead.org
Link: http://lkml.kernel.org/r/1518607481-4059-2-git-send-email-robert.walker@arm.comSigned-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent 7e99b197
...@@ -78,6 +78,8 @@ int cs_etm_decoder__reset(struct cs_etm_decoder *decoder) ...@@ -78,6 +78,8 @@ int cs_etm_decoder__reset(struct cs_etm_decoder *decoder)
{ {
ocsd_datapath_resp_t dp_ret; ocsd_datapath_resp_t dp_ret;
decoder->prev_return = OCSD_RESP_CONT;
dp_ret = ocsd_dt_process_data(decoder->dcd_tree, OCSD_OP_RESET, dp_ret = ocsd_dt_process_data(decoder->dcd_tree, OCSD_OP_RESET,
0, 0, NULL, NULL); 0, 0, NULL, NULL);
if (OCSD_DATA_RESP_IS_FATAL(dp_ret)) if (OCSD_DATA_RESP_IS_FATAL(dp_ret))
...@@ -253,16 +255,16 @@ static void cs_etm_decoder__clear_buffer(struct cs_etm_decoder *decoder) ...@@ -253,16 +255,16 @@ static void cs_etm_decoder__clear_buffer(struct cs_etm_decoder *decoder)
decoder->packet_count = 0; decoder->packet_count = 0;
for (i = 0; i < MAX_BUFFER; i++) { for (i = 0; i < MAX_BUFFER; i++) {
decoder->packet_buffer[i].start_addr = 0xdeadbeefdeadbeefUL; decoder->packet_buffer[i].start_addr = 0xdeadbeefdeadbeefUL;
decoder->packet_buffer[i].end_addr = 0xdeadbeefdeadbeefUL; decoder->packet_buffer[i].end_addr = 0xdeadbeefdeadbeefUL;
decoder->packet_buffer[i].exc = false; decoder->packet_buffer[i].last_instr_taken_branch = false;
decoder->packet_buffer[i].exc_ret = false; decoder->packet_buffer[i].exc = false;
decoder->packet_buffer[i].cpu = INT_MIN; decoder->packet_buffer[i].exc_ret = false;
decoder->packet_buffer[i].cpu = INT_MIN;
} }
} }
static ocsd_datapath_resp_t static ocsd_datapath_resp_t
cs_etm_decoder__buffer_packet(struct cs_etm_decoder *decoder, cs_etm_decoder__buffer_packet(struct cs_etm_decoder *decoder,
const ocsd_generic_trace_elem *elem,
const u8 trace_chan_id, const u8 trace_chan_id,
enum cs_etm_sample_type sample_type) enum cs_etm_sample_type sample_type)
{ {
...@@ -278,18 +280,16 @@ cs_etm_decoder__buffer_packet(struct cs_etm_decoder *decoder, ...@@ -278,18 +280,16 @@ cs_etm_decoder__buffer_packet(struct cs_etm_decoder *decoder,
return OCSD_RESP_FATAL_SYS_ERR; return OCSD_RESP_FATAL_SYS_ERR;
et = decoder->tail; et = decoder->tail;
et = (et + 1) & (MAX_BUFFER - 1);
decoder->tail = et;
decoder->packet_count++;
decoder->packet_buffer[et].sample_type = sample_type; decoder->packet_buffer[et].sample_type = sample_type;
decoder->packet_buffer[et].start_addr = elem->st_addr;
decoder->packet_buffer[et].end_addr = elem->en_addr;
decoder->packet_buffer[et].exc = false; decoder->packet_buffer[et].exc = false;
decoder->packet_buffer[et].exc_ret = false; decoder->packet_buffer[et].exc_ret = false;
decoder->packet_buffer[et].cpu = *((int *)inode->priv); decoder->packet_buffer[et].cpu = *((int *)inode->priv);
decoder->packet_buffer[et].start_addr = 0xdeadbeefdeadbeefUL;
/* Wrap around if need be */ decoder->packet_buffer[et].end_addr = 0xdeadbeefdeadbeefUL;
et = (et + 1) & (MAX_BUFFER - 1);
decoder->tail = et;
decoder->packet_count++;
if (decoder->packet_count == MAX_BUFFER - 1) if (decoder->packet_count == MAX_BUFFER - 1)
return OCSD_RESP_WAIT; return OCSD_RESP_WAIT;
...@@ -297,6 +297,40 @@ cs_etm_decoder__buffer_packet(struct cs_etm_decoder *decoder, ...@@ -297,6 +297,40 @@ cs_etm_decoder__buffer_packet(struct cs_etm_decoder *decoder,
return OCSD_RESP_CONT; return OCSD_RESP_CONT;
} }
static ocsd_datapath_resp_t
cs_etm_decoder__buffer_range(struct cs_etm_decoder *decoder,
const ocsd_generic_trace_elem *elem,
const uint8_t trace_chan_id)
{
int ret = 0;
struct cs_etm_packet *packet;
ret = cs_etm_decoder__buffer_packet(decoder, trace_chan_id,
CS_ETM_RANGE);
if (ret != OCSD_RESP_CONT && ret != OCSD_RESP_WAIT)
return ret;
packet = &decoder->packet_buffer[decoder->tail];
packet->start_addr = elem->st_addr;
packet->end_addr = elem->en_addr;
switch (elem->last_i_type) {
case OCSD_INSTR_BR:
case OCSD_INSTR_BR_INDIRECT:
packet->last_instr_taken_branch = elem->last_instr_exec;
break;
case OCSD_INSTR_ISB:
case OCSD_INSTR_DSB_DMB:
case OCSD_INSTR_OTHER:
default:
packet->last_instr_taken_branch = false;
break;
}
return ret;
}
static ocsd_datapath_resp_t cs_etm_decoder__gen_trace_elem_printer( static ocsd_datapath_resp_t cs_etm_decoder__gen_trace_elem_printer(
const void *context, const void *context,
const ocsd_trc_index_t indx __maybe_unused, const ocsd_trc_index_t indx __maybe_unused,
...@@ -316,9 +350,8 @@ static ocsd_datapath_resp_t cs_etm_decoder__gen_trace_elem_printer( ...@@ -316,9 +350,8 @@ static ocsd_datapath_resp_t cs_etm_decoder__gen_trace_elem_printer(
decoder->trace_on = true; decoder->trace_on = true;
break; break;
case OCSD_GEN_TRC_ELEM_INSTR_RANGE: case OCSD_GEN_TRC_ELEM_INSTR_RANGE:
resp = cs_etm_decoder__buffer_packet(decoder, elem, resp = cs_etm_decoder__buffer_range(decoder, elem,
trace_chan_id, trace_chan_id);
CS_ETM_RANGE);
break; break;
case OCSD_GEN_TRC_ELEM_EXCEPTION: case OCSD_GEN_TRC_ELEM_EXCEPTION:
decoder->packet_buffer[decoder->tail].exc = true; decoder->packet_buffer[decoder->tail].exc = true;
......
...@@ -30,6 +30,7 @@ struct cs_etm_packet { ...@@ -30,6 +30,7 @@ struct cs_etm_packet {
enum cs_etm_sample_type sample_type; enum cs_etm_sample_type sample_type;
u64 start_addr; u64 start_addr;
u64 end_addr; u64 end_addr;
u8 last_instr_taken_branch;
u8 exc; u8 exc;
u8 exc_ret; u8 exc_ret;
int cpu; int cpu;
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment