aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf
diff options
context:
space:
mode:
authorRobert Walker <robert.walker@arm.com>2018-02-14 06:24:40 -0500
committerArnaldo Carvalho de Melo <acme@redhat.com>2018-02-16 12:55:45 -0500
commit256e751cac78739a4de2232450d3681b68b5845e (patch)
treec55385eb57df392c84ef5a8f2d830d08213ab37a /tools/perf
parente573e978fb12e16094c0b39fad3dc4e6b4803c2c (diff)
perf inject: Emit instruction records on ETM trace discontinuity
There may be discontinuities in the ETM trace stream due to overflows or ETM configuration for selective trace. This patch emits an instruction sample with the pending branch stack when a TRACE ON packet occurs indicating a discontinuity in the trace data. A new packet type CS_ETM_TRACE_ON is added, which is emitted by the low level decoder when a TRACE ON occurs. The higher level decoder flushes the branch stack when this packet is emitted. Signed-off-by: Robert Walker <robert.walker@arm.com> Acked-by: Mathieu 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-3-git-send-email-robert.walker@arm.com Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools/perf')
-rw-r--r--tools/perf/util/cs-etm-decoder/cs-etm-decoder.c9
-rw-r--r--tools/perf/util/cs-etm-decoder/cs-etm-decoder.h1
-rw-r--r--tools/perf/util/cs-etm.c80
3 files changed, 67 insertions, 23 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 8ff69dfd725a..640af88331b4 100644
--- a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c
+++ b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.c
@@ -328,7 +328,14 @@ cs_etm_decoder__buffer_range(struct cs_etm_decoder *decoder,
328 } 328 }
329 329
330 return ret; 330 return ret;
331}
331 332
333static ocsd_datapath_resp_t
334cs_etm_decoder__buffer_trace_on(struct cs_etm_decoder *decoder,
335 const uint8_t trace_chan_id)
336{
337 return cs_etm_decoder__buffer_packet(decoder, trace_chan_id,
338 CS_ETM_TRACE_ON);
332} 339}
333 340
334static ocsd_datapath_resp_t cs_etm_decoder__gen_trace_elem_printer( 341static ocsd_datapath_resp_t cs_etm_decoder__gen_trace_elem_printer(
@@ -347,6 +354,8 @@ static ocsd_datapath_resp_t cs_etm_decoder__gen_trace_elem_printer(
347 decoder->trace_on = false; 354 decoder->trace_on = false;
348 break; 355 break;
349 case OCSD_GEN_TRC_ELEM_TRACE_ON: 356 case OCSD_GEN_TRC_ELEM_TRACE_ON:
357 resp = cs_etm_decoder__buffer_trace_on(decoder,
358 trace_chan_id);
350 decoder->trace_on = true; 359 decoder->trace_on = true;
351 break; 360 break;
352 case OCSD_GEN_TRC_ELEM_INSTR_RANGE: 361 case OCSD_GEN_TRC_ELEM_INSTR_RANGE:
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 a4fdd285b145..743f5f444304 100644
--- a/tools/perf/util/cs-etm-decoder/cs-etm-decoder.h
+++ b/tools/perf/util/cs-etm-decoder/cs-etm-decoder.h
@@ -24,6 +24,7 @@ struct cs_etm_buffer {
24 24
25enum cs_etm_sample_type { 25enum cs_etm_sample_type {
26 CS_ETM_RANGE = 1 << 0, 26 CS_ETM_RANGE = 1 << 0,
27 CS_ETM_TRACE_ON = 1 << 1,
27}; 28};
28 29
29struct cs_etm_packet { 30struct cs_etm_packet {
diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c
index 6e595d96c04d..1b0d422373be 100644
--- a/tools/perf/util/cs-etm.c
+++ b/tools/perf/util/cs-etm.c
@@ -867,6 +867,7 @@ static int cs_etm__sample(struct cs_etm_queue *etmq)
867 */ 867 */
868 if (etm->synth_opts.last_branch && 868 if (etm->synth_opts.last_branch &&
869 etmq->prev_packet && 869 etmq->prev_packet &&
870 etmq->prev_packet->sample_type == CS_ETM_RANGE &&
870 etmq->prev_packet->last_instr_taken_branch) 871 etmq->prev_packet->last_instr_taken_branch)
871 cs_etm__update_last_branch_rb(etmq); 872 cs_etm__update_last_branch_rb(etmq);
872 873
@@ -920,6 +921,40 @@ static int cs_etm__sample(struct cs_etm_queue *etmq)
920 return 0; 921 return 0;
921} 922}
922 923
924static int cs_etm__flush(struct cs_etm_queue *etmq)
925{
926 int err = 0;
927 struct cs_etm_packet *tmp;
928
929 if (etmq->etm->synth_opts.last_branch &&
930 etmq->prev_packet &&
931 etmq->prev_packet->sample_type == CS_ETM_RANGE) {
932 /*
933 * Generate a last branch event for the branches left in the
934 * circular buffer at the end of the trace.
935 *
936 * Use the address of the end of the last reported execution
937 * range
938 */
939 u64 addr = cs_etm__last_executed_instr(etmq->prev_packet);
940
941 err = cs_etm__synth_instruction_sample(
942 etmq, addr,
943 etmq->period_instructions);
944 etmq->period_instructions = 0;
945
946 /*
947 * Swap PACKET with PREV_PACKET: PACKET becomes PREV_PACKET for
948 * the next incoming packet.
949 */
950 tmp = etmq->packet;
951 etmq->packet = etmq->prev_packet;
952 etmq->prev_packet = tmp;
953 }
954
955 return err;
956}
957
923static int cs_etm__run_decoder(struct cs_etm_queue *etmq) 958static int cs_etm__run_decoder(struct cs_etm_queue *etmq)
924{ 959{
925 struct cs_etm_auxtrace *etm = etmq->etm; 960 struct cs_etm_auxtrace *etm = etmq->etm;
@@ -971,32 +1006,31 @@ static int cs_etm__run_decoder(struct cs_etm_queue *etmq)
971 */ 1006 */
972 break; 1007 break;
973 1008
974 /* 1009 switch (etmq->packet->sample_type) {
975 * If the packet contains an instruction 1010 case CS_ETM_RANGE:
976 * range, generate instruction sequence 1011 /*
977 * events. 1012 * If the packet contains an instruction
978 */ 1013 * range, generate instruction sequence
979 if (etmq->packet->sample_type & CS_ETM_RANGE) 1014 * events.
980 err = cs_etm__sample(etmq); 1015 */
1016 cs_etm__sample(etmq);
1017 break;
1018 case CS_ETM_TRACE_ON:
1019 /*
1020 * Discontinuity in trace, flush
1021 * previous branch stack
1022 */
1023 cs_etm__flush(etmq);
1024 break;
1025 default:
1026 break;
1027 }
981 } 1028 }
982 } while (buffer.len > buffer_used); 1029 } while (buffer.len > buffer_used);
983 1030
984 /* 1031 if (err == 0)
985 * Generate a last branch event for the branches left in 1032 /* Flush any remaining branch stack entries */
986 * the circular buffer at the end of the trace. 1033 err = cs_etm__flush(etmq);
987 */
988 if (etm->sample_instructions &&
989 etmq->etm->synth_opts.last_branch) {
990 struct branch_stack *bs = etmq->last_branch_rb;
991 struct branch_entry *be =
992 &bs->entries[etmq->last_branch_pos];
993
994 err = cs_etm__synth_instruction_sample(
995 etmq, be->to, etmq->period_instructions);
996 if (err)
997 return err;
998 }
999
1000 } 1034 }
1001 1035
1002 return err; 1036 return err;