Each decoded trace sample encodes the execution of a sequence of instructions between to "waypoints", typically a branch target and the next taken branch. This sample has to be converted into a perf sample struct before it can be passed on to the perf subsystem.
This patch adds two functions that take a decoded trace packet and populate the perf sample structure and pass it on to perf session event processing. It also adds a function in the decoder library interface to return a decoded trace packet.
Signed-off-by: Tor Jeremiassen tor@ti.com --- tools/perf/util/cs-etm-decoder/cs-etm-decoder.c | 21 ++++++++ tools/perf/util/cs-etm-decoder/cs-etm-decoder.h | 3 ++ tools/perf/util/cs-etm.c | 64 +++++++++++++++++++++++++ tools/perf/util/cs-etm.h | 2 + 4 files changed, 90 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 cfd18ec..e46ce59 100644 --- a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c +++ b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c @@ -86,6 +86,27 @@ int cs_etm_decoder__add_mem_access_cb(struct cs_etm_decoder *decoder, return 0; }
+int cs_etm_decoder__get_packet(struct cs_etm_decoder *decoder, + struct cs_etm_packet *packet) +{ + if (!decoder) + return -CS_ETM_ERR_PARAM; + + if (decoder->packet_count == 0) + return -CS_ETM_ERR_NODATA; + + if (!packet) + return -CS_ETM_ERR_PARAM; + + *packet = decoder->packet_buffer[decoder->head]; + + decoder->head = (decoder->head + 1) & (MAX_BUFFER - 1); + + decoder->packet_count--; + + return 0; +} + const struct cs_etm_state * cs_etm_decoder__process_data_block(struct cs_etm_decoder *decoder, uint64_t indx, const uint8_t *buf, 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 b53dbed..259059b 100644 --- a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.h +++ b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.h @@ -126,6 +126,9 @@ int cs_etm_decoder__add_mem_access_cb(struct cs_etm_decoder *decoder, uint64_t start, uint64_t end, cs_etm_mem_cb_type cb_func);
+int cs_etm_decoder__get_packet(struct cs_etm_decoder *decoder, + struct cs_etm_packet *packet); + int cs_etm_decoder__create_etmv4i_decoder(struct cs_etm_decoder_params *d_params, struct cs_etm_trace_params *t_params, diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c index 0516301..72c4c9d 100644 --- a/tools/perf/util/cs-etm.c +++ b/tools/perf/util/cs-etm.c @@ -334,6 +334,70 @@ static int cs_etm__setup_queues(struct cs_etm_auxtrace *etm) return 0; }
+/* + * The cs etm packet encodes an instruction range between a branch target + * and the next taken branch. Generate sample accordingly. + */ +static int cs_etm__synth_instruction_sample(struct cs_etm_queue *etmq, + struct cs_etm_packet *packet) +{ + int ret = 0; + struct cs_etm_auxtrace *etm = etmq->etm; + union perf_event *event = etmq->event_buf; + struct perf_sample sample = {.ip = 0,}; + uint64_t start_addr = packet->start_addr; + uint64_t end_addr = packet->end_addr; + + event->sample.header.type = PERF_RECORD_SAMPLE; + event->sample.header.misc = PERF_RECORD_MISC_USER; + event->sample.header.size = sizeof(struct perf_event_header); + + sample.ip = start_addr; + sample.pid = etmq->pid; + sample.tid = etmq->tid; + sample.addr = end_addr; + sample.id = etmq->etm->instructions_id; + sample.stream_id = etmq->etm->instructions_id; + /* approximate the period to be the number of words in the range */ + sample.period = (end_addr - start_addr) >> 2; + sample.cpu = packet->cpu; + sample.flags = 0; + sample.insn_len = 1; + sample.cpumode = event->header.misc; + + ret = perf_session__deliver_synth_event(etm->session, event, &sample); + + if (ret) + pr_err( + "CS ETM Trace: failed to deliver instruction event, error %d\n", + ret); + + return ret; +} + +int cs_etm__sample(struct cs_etm_queue *etmq) +{ + struct cs_etm_packet packet; + int err; + + err = cs_etm_decoder__get_packet(etmq->decoder, &packet); + /* if there is no sample, it returns err = -1, no real error */ + if (err) + return err; + + /* + * if the packet contains an instruction range, generate + * an instruction sequence event + */ + if (packet.sample_type & CS_ETM_RANGE) { + err = cs_etm__synth_instruction_sample(etmq, &packet); + if (err) + return err; + } + + return 0; +} + int cs_etm__update_queues(struct cs_etm_auxtrace *etm) { if (etm->queues.new_data) { diff --git a/tools/perf/util/cs-etm.h b/tools/perf/util/cs-etm.h index d1cb049..aa7e0d4 100644 --- a/tools/perf/util/cs-etm.h +++ b/tools/perf/util/cs-etm.h @@ -108,4 +108,6 @@ struct cs_etm_queue *cs_etm__alloc_queue(struct cs_etm_auxtrace *etm,
int cs_etm__update_queues(struct cs_etm_auxtrace *etm);
+int cs_etm__sample(struct cs_etm_queue *etmq); + #endif