This patch deals with timestamp packets received from the decoding library in order to give the front end packet processing loop a handle on the time instruction conveyed by range packets have been executed at.
Signed-off-by: Mathieu Poirier mathieu.poirier@linaro.org --- tools/perf/util/cs-etm-decoder/cs-etm-decoder.c | 104 +++++++++++++++++++++++- tools/perf/util/cs-etm-decoder/cs-etm-decoder.h | 1 + 2 files changed, 104 insertions(+), 1 deletion(-)
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 3e69abbfa2c5..016180de40f1 100644 --- a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c +++ b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c @@ -39,8 +39,11 @@ struct cs_etm_decoder { cs_etm_mem_cb_type mem_access; ocsd_datapath_resp_t prev_return; u32 packet_count; + u32 instr_count; u32 head; u32 tail; + u64 start_timestamp; + u64 end_timestamp; struct cs_etm_packet packet_buffer[MAX_BUFFER]; };
@@ -321,6 +324,7 @@ cs_etm_decoder__buffer_range(struct cs_etm_decoder *decoder,
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: @@ -334,6 +338,18 @@ cs_etm_decoder__buffer_range(struct cs_etm_decoder *decoder, break; }
+ /* + * At the beginning of a trace session or trace discontinuity, the + * tracers will generate a timestamp packet _after_ a range packet + * has been generated. In order to know when traces started to be + * executed we need to keep track of the amount of instructions that + * were processed. That way when the timestamp packet gets generated + * we can _estimate_ the start time by substracting the number of + * instructions that were executed from the timestamp value. + * Timestamp estimation is done in cs_etm_decoder__buffer_timestamp(). + */ + decoder->instr_count += elem->num_instr_range; + return ret; }
@@ -376,6 +392,54 @@ cs_etm_decoder__set_tid(struct cs_etm_decoder *decoder, return ret; }
+static void +cs_etm_decoder__reset_time_statistics(struct cs_etm_decoder *decoder) +{ + decoder->instr_count = 0; + decoder->start_timestamp = 0; + decoder->end_timestamp = 0; +} + +static ocsd_datapath_resp_t +cs_etm_decoder__update_time_statistics(struct cs_etm_decoder *decoder, + const ocsd_generic_trace_elem *elem) +{ + /* + * At the beginning of traces or upon trace discontinuity the time + * instructions started to be generated is not known since timestamp + * packets are generated _after_ a range packet. As such estimate + * the start timestamp by substracting the amount of instructions + * encountered in the range packet(s) from the current timestamp. + * + * There are also cases where we get a timestamp when no instructions + * have been received, ex. when the PE takes an exception or returns + * from one. In this case @instr_count is zero and the algorithm + * below works since statistics are reset in function + * cs_etm_decoder__gen_trace_elem_printer(). + */ + if (!decoder->start_timestamp) + decoder->start_timestamp = elem->timestamp - + decoder->instr_count; + else + decoder->start_timestamp = decoder->end_timestamp; + + /* + * @instr_count represent the amount of instructions executed + * since the last timestamp. + */ + decoder->instr_count = 0; + + /* + * Since timestamp packets are generated after range packets, the + * timestamp in this packet becomes the time at which instructions + * in the coming range packets began to execute. + */ + decoder->end_timestamp = elem->timestamp; + + /* Halt processing until we are being told to proceed */ + return OCSD_RESP_WAIT; +} + static ocsd_datapath_resp_t cs_etm_decoder__gen_trace_elem_printer( const void *context, const ocsd_trc_index_t indx __maybe_unused, @@ -390,8 +454,12 @@ static ocsd_datapath_resp_t cs_etm_decoder__gen_trace_elem_printer( break; case OCSD_GEN_TRC_ELEM_NO_SYNC: decoder->trace_on = false; + cs_etm_decoder__reset_time_statistics(decoder); break; case OCSD_GEN_TRC_ELEM_TRACE_ON: + /* A discontinuity has been observed, reset statistics. */ + cs_etm_decoder__reset_time_statistics(decoder); + resp = cs_etm_decoder__buffer_trace_on(decoder, trace_chan_id); decoder->trace_on = true; @@ -401,18 +469,32 @@ static ocsd_datapath_resp_t cs_etm_decoder__gen_trace_elem_printer( trace_chan_id); break; case OCSD_GEN_TRC_ELEM_EXCEPTION: + /* A timestamp is generated after a PE takes an exception */ + cs_etm_decoder__reset_time_statistics(decoder); decoder->packet_buffer[decoder->tail].exc = true; break; case OCSD_GEN_TRC_ELEM_EXCEPTION_RET: + /* + * A timestamp is generated when a PE returns + * from an exception. + */ + cs_etm_decoder__reset_time_statistics(decoder); decoder->packet_buffer[decoder->tail].exc_ret = true; break; case OCSD_GEN_TRC_ELEM_PE_CONTEXT: + /* + * The context information has changed, better reset the + * time statistics. + */ + cs_etm_decoder__reset_time_statistics(decoder); resp = cs_etm_decoder__set_tid(decoder, elem, trace_chan_id); break; + case OCSD_GEN_TRC_ELEM_TIMESTAMP: + resp = cs_etm_decoder__update_time_statistics(decoder, elem); + break; case OCSD_GEN_TRC_ELEM_EO_TRACE: case OCSD_GEN_TRC_ELEM_ADDR_NACC: - case OCSD_GEN_TRC_ELEM_TIMESTAMP: case OCSD_GEN_TRC_ELEM_CYCLE_COUNT: case OCSD_GEN_TRC_ELEM_ADDR_UNKNOWN: case OCSD_GEN_TRC_ELEM_EVENT: @@ -582,6 +664,18 @@ int cs_etm_decoder__process_data_block(struct cs_etm_decoder *decoder, decoder->prev_return = cur; *consumed = processed;
+ /* + * If we are at the end of this block and @instr_count isn't 0, + * we have processed range packet(s) but haven't received a timestamp + * for them. As such estimate one so that the front end packet + * processing loop isn't impacted. + */ + if (processed == len && decoder->instr_count) { + decoder->start_timestamp = decoder->end_timestamp; + decoder->end_timestamp += decoder->instr_count; + decoder->instr_count = 0; + } + return ret; }
@@ -594,3 +688,11 @@ void cs_etm_decoder__free(struct cs_etm_decoder *decoder) decoder->dcd_tree = NULL; free(decoder); } + +u64 cs_etm_decoder__get_timestamp(struct cs_etm_decoder *decoder) +{ + if (!decoder) + return 0; + + return decoder->start_timestamp; +} 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 a61a8f75a135..1f560545f135 100644 --- a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.h +++ b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.h @@ -99,5 +99,6 @@ int cs_etm_decoder__get_packet(struct cs_etm_decoder *decoder, struct cs_etm_packet *packet);
int cs_etm_decoder__reset(struct cs_etm_decoder *decoder); +u64 cs_etm_decoder__get_timestamp(struct cs_etm_decoder *decoder);
#endif /* INCLUDE__CS_ETM_DECODER_H__ */