This makes it easier to support multiple threads without creating a decode tree for every CPU for every thread. It also fixes the CPU field of synthesised samples being incorrect when the CPU can't be retrieved using the trace ID in unformatted mode.
It also simplifies by removing a special case in the decode path for per-thread mode. Per-thread mode is now decoded in exactly the same way as per-CPU (apart from pre-initialising the context).
Signed-off-by: James Clark james.clark@linaro.org --- tools/perf/util/cs-etm.c | 40 ++++++++++++++++++++++++++++++---------- 1 file changed, 30 insertions(+), 10 deletions(-)
diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c index 509ec014b276..f19aa4f787fa 100644 --- a/tools/perf/util/cs-etm.c +++ b/tools/perf/util/cs-etm.c @@ -296,9 +296,6 @@ static int cs_etm__map_trace_id(struct cs_etm_queue *etmq, u8 trace_chan_id,
static struct cs_etm_queue *cs_etm__get_queue(struct cs_etm_auxtrace *etm, int cpu) { - if (etm->per_thread_decoding) - return etm->queues.queue_array[0].priv; - if (cpu < 0 || cpu >= (int)etm->queues.nr_queues) return NULL;
@@ -436,11 +433,7 @@ static int cs_etm__map_unformatted_trace_ids(struct cs_etm_auxtrace *etm) return -EINVAL; }
- if (etm->per_thread_decoding) - cpu_data = etm->metadata[0]; - else - cpu_data = get_cpu_data(etm, queue->cpu); - + cpu_data = get_cpu_data(etm, queue->cpu); if (!cpu_data) { pr_err("CS_ETM: Unformatted queue missing CPU metadata\n"); return -EINVAL; @@ -1301,7 +1294,7 @@ static int cs_etm__setup_queue(struct cs_etm_auxtrace *etm, queue->priv = etmq; etmq->etm = etm; etmq->queue_nr = queue_nr; - queue->cpu = queue_nr; /* Placeholder, may be reset to -1 in per-thread mode */ + queue->cpu = queue_nr; etmq->offset = 0; etmq->sink_id = SINK_UNSET;
@@ -2187,6 +2180,7 @@ static void cs_etm__flush_all_stack(struct cs_etm_queue *etmq) */ static int cs_etm__get_data_block(struct cs_etm_queue *etmq) { + struct cs_etm_auxtrace *etm = etmq->etm; int ret;
/* The current block is not finished */ @@ -2215,6 +2209,29 @@ static int cs_etm__get_data_block(struct cs_etm_queue *etmq) */ cs_etm__flush_all_stack(etmq);
+ /* + * Per-thread mode still uses a queue for each CPU, but that CPU can run + * different threads. When the TID from the AUX record on a CPU changes, + * re-initialize the thread using the AUX record/buffer fragment TID so + * we can start decoding even if the context ID packet was cropped or + * they're disabled. + */ + if (etm->per_thread_decoding) { + struct cs_etm_traceid_queue *tidq = cs_etm__etmq_get_traceid_queue(etmq, + CS_ETM_PER_THREAD_TRACEID); + + if (thread__tid(tidq->decode_thread) != etmq->buffer->tid) { + thread__zput(tidq->frontend_thread); + thread__zput(tidq->decode_thread); + tidq->frontend_thread = machine__findnew_thread( + &etm->session->machines.host, -1, + etmq->buffer->tid); + tidq->decode_thread = machine__findnew_thread( + &etm->session->machines.host, -1, + etmq->buffer->tid); + } + } + return 1; }
@@ -3288,7 +3305,9 @@ static int cs_etm__queue_aux_fragment(struct perf_session *session, off_t file_o
if (aux_offset >= auxtrace_event->offset && aux_offset + aux_size <= auxtrace_event->offset + auxtrace_event->size) { - struct cs_etm_queue *etmq = cs_etm__get_queue(etm, auxtrace_event->cpu); + /* Old per-thread files have no CPU (before v6.4) */ + int queue_idx = sample->cpu == (u32)-1 ? 0 : sample->cpu; + struct cs_etm_queue *etmq = cs_etm__get_queue(etm, queue_idx);
if (!etmq) return -EINVAL; @@ -3301,6 +3320,7 @@ static int cs_etm__queue_aux_fragment(struct perf_session *session, off_t file_o auxtrace_fragment.auxtrace.size = aux_size; auxtrace_fragment.auxtrace.offset = aux_offset; auxtrace_fragment.auxtrace.idx = etmq->queue_nr; + auxtrace_fragment.auxtrace.cpu = etmq->queue_nr; file_offset += aux_offset - auxtrace_event->offset + auxtrace_event->header.size;
pr_debug3("CS ETM: Queue buffer size: %#"PRI_lx64" offset: %#"PRI_lx64