Re: [PATCH v3 07/10] pert tools: Add queue management functionality
From: Mathieu Poirier
Date: Mon Jan 22 2018 - 15:15:07 EST
On 22 January 2018 at 10:25, Robert Walker <robert.walker@xxxxxxx> wrote:
>
>
> On 01/17/2018 05:52 PM, Mathieu Poirier wrote:
>>
>> Add functionatlity to setup trace queues so that traces associated with
>> CoreSight auxtrace events found in the perf.data file can be classified
>> properly. The decoder and memory callback associated with each queue are
>> then used to decode the traces that have been assigned to that queue.
>>
>> Co-authored-by: Tor Jeremiassen <tor@xxxxxx>
>> Signed-off-by: Mathieu Poirier <mathieu.poirier@xxxxxxxxxx>
>> ---
>> tools/perf/util/cs-etm.c | 208
>> ++++++++++++++++++++++++++++++++++++++++++++++-
>> 1 file changed, 204 insertions(+), 4 deletions(-)
>>
>> diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c
>> index cad429ce3c00..83eb676274b5 100644
>> --- a/tools/perf/util/cs-etm.c
>> +++ b/tools/perf/util/cs-etm.c
>> @@ -196,15 +196,215 @@ static void cs_etm__free(struct perf_session
>> *session)
>> zfree(&aux);
>> }
>> +static u32 cs_etm__mem_access(struct cs_etm_queue *etmq, u64 address,
>> + size_t size, u8 *buffer)
>> +{
>> + u8 cpumode;
>> + u64 offset;
>> + int len;
>> + struct thread *thread;
>> + struct machine *machine;
>> + struct addr_location al;
>> +
>> + if (!etmq)
>> + return -1;
>> +
>> + machine = etmq->etm->machine;
>> + if (address >= etmq->etm->kernel_start)
>> + cpumode = PERF_RECORD_MISC_KERNEL;
>> + else
>> + cpumode = PERF_RECORD_MISC_USER;
>> +
>> + thread = etmq->thread;
>> + if (!thread) {
>> + if (cpumode != PERF_RECORD_MISC_KERNEL)
>> + return -EINVAL;
>> + thread = etmq->etm->unknown_thread;
>> + }
>> +
>> + thread__find_addr_map(thread, cpumode, MAP__FUNCTION, address,
>> &al);
>> +
>> + if (!al.map || !al.map->dso)
>> + return 0;
>> +
>> + if (al.map->dso->data.status == DSO_DATA_STATUS_ERROR &&
>> + dso__data_status_seen(al.map->dso,
>> DSO_DATA_STATUS_SEEN_ITRACE))
>> + return 0;
>> +
>> + offset = al.map->map_ip(al.map, address);
>> +
>> + map__load(al.map);
>> +
>> + len = dso__data_read_offset(al.map->dso, machine, offset, buffer,
>> size);
>> +
>> + if (len <= 0)
>> + return 0;
>> +
>> + return len;
>> +}
>> +
>> +static struct cs_etm_queue *cs_etm__alloc_queue(struct cs_etm_auxtrace
>> *etm,
>> + unsigned int queue_nr)
>> +{
>> + int i;
>> + struct cs_etm_decoder_params d_params;
>> + struct cs_etm_trace_params *t_params;
>> + struct cs_etm_queue *etmq;
>> +
>> + etmq = zalloc(sizeof(*etmq));
>> + if (!etmq)
>> + return NULL;
>> +
>> + etmq->event_buf = malloc(PERF_SAMPLE_MAX_SIZE);
>
>
> Should this and the other members of etmq alloc'd in this function be free'd
> in cs_etm__free_queue() as they were in the original version at
> https://github.com/Linaro/perf-opencsd/ ? I can't see them getting freed
> anywhere else.
Quite right - it got lost in the refactoring. Thanks for pointing this out.
Mathieu
>
>> + if (!etmq->event_buf)
>> + goto out_free;
>> +
>> + etmq->etm = etm;
>> + etmq->queue_nr = queue_nr;
>> + etmq->pid = -1;
>> + etmq->tid = -1;
>> + etmq->cpu = -1;
>> +
>> + /* Use metadata to fill in trace parameters for trace decoder */
>> + t_params = zalloc(sizeof(*t_params) * etm->num_cpu);
>> +
>> + if (!t_params)
>> + goto out_free;
>> +
>> + for (i = 0; i < etm->num_cpu; i++) {
>> + t_params[i].protocol = CS_ETM_PROTO_ETMV4i;
>> + t_params[i].etmv4.reg_idr0 =
>> etm->metadata[i][CS_ETMV4_TRCIDR0];
>> + t_params[i].etmv4.reg_idr1 =
>> etm->metadata[i][CS_ETMV4_TRCIDR1];
>> + t_params[i].etmv4.reg_idr2 =
>> etm->metadata[i][CS_ETMV4_TRCIDR2];
>> + t_params[i].etmv4.reg_idr8 =
>> etm->metadata[i][CS_ETMV4_TRCIDR8];
>> + t_params[i].etmv4.reg_configr =
>> +
>> etm->metadata[i][CS_ETMV4_TRCCONFIGR];
>> + t_params[i].etmv4.reg_traceidr =
>> +
>> etm->metadata[i][CS_ETMV4_TRCTRACEIDR];
>> + }
>> +
>> + /* Set decoder parameters to simply print the trace packets */
>> + d_params.packet_printer = cs_etm__packet_dump;
>> + d_params.operation = CS_ETM_OPERATION_DECODE;
>> + d_params.formatted = true;
>> + d_params.fsyncs = false;
>> + d_params.hsyncs = false;
>> + d_params.frame_aligned = true;
>> + d_params.data = etmq;
>> +
>> + etmq->decoder = cs_etm_decoder__new(etm->num_cpu, &d_params,
>> t_params);
>> +
>> + zfree(&t_params);
>> +
>> + if (!etmq->decoder)
>> + goto out_free;
>> +
>> + /*
>> + * Register a function to handle all memory accesses required by
>> + * the trace decoder library.
>> + */
>> + if (cs_etm_decoder__add_mem_access_cb(etmq->decoder,
>> + 0x0L, ((u64) -1L),
>> + cs_etm__mem_access))
>> + goto out_free_decoder;
>> +
>> + etmq->offset = 0;
>> +
>> + return etmq;
>> +
>> +out_free_decoder:
>> + cs_etm_decoder__free(etmq->decoder);
>> +out_free:
>> + zfree(&etmq->event_buf);
>> + free(etmq);
>> +
>> + return NULL;
>> +}
>> +
>> +static int cs_etm__setup_queue(struct cs_etm_auxtrace *etm,
>> + struct auxtrace_queue *queue,
>> + unsigned int queue_nr)
>> +{
>> + struct cs_etm_queue *etmq = queue->priv;
>> +
>> + if (list_empty(&queue->head) || etmq)
>> + return 0;
>> +
>> + etmq = cs_etm__alloc_queue(etm, queue_nr);
>> +
>> + if (!etmq)
>> + return -ENOMEM;
>> +
>> + queue->priv = etmq;
>> +
>> + if (queue->cpu != -1)
>> + etmq->cpu = queue->cpu;
>> +
>> + etmq->tid = queue->tid;
>> +
>> + return 0;
>> +}
>> +
>> +static int cs_etm__setup_queues(struct cs_etm_auxtrace *etm)
>> +{
>> + unsigned int i;
>> + int ret;
>> +
>> + for (i = 0; i < etm->queues.nr_queues; i++) {
>> + ret = cs_etm__setup_queue(etm,
>> &etm->queues.queue_array[i], i);
>> + if (ret)
>> + return ret;
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +static int cs_etm__update_queues(struct cs_etm_auxtrace *etm)
>> +{
>> + if (etm->queues.new_data) {
>> + etm->queues.new_data = false;
>> + return cs_etm__setup_queues(etm);
>> + }
>> +
>> + return 0;
>> +}
>> +
>> static int cs_etm__process_event(struct perf_session *session,
>> union perf_event *event,
>> struct perf_sample *sample,
>> struct perf_tool *tool)
>> {
>> - (void) session;
>> - (void) event;
>> - (void) sample;
>> - (void) tool;
>> + int err = 0;
>> + u64 timestamp;
>> + struct cs_etm_auxtrace *etm = container_of(session->auxtrace,
>> + struct cs_etm_auxtrace,
>> + auxtrace);
>> +
>> + /* Keep compiler happy */
>> + (void)event;
>> +
>> + if (dump_trace)
>> + return 0;
>> +
>> + if (!tool->ordered_events) {
>> + pr_err("CoreSight ETM Trace requires ordered events\n");
>> + return -EINVAL;
>> + }
>> +
>> + if (!etm->timeless_decoding)
>> + return -EINVAL;
>> +
>> + if (sample->time && (sample->time != (u64) -1))
>> + timestamp = sample->time;
>> + else
>> + timestamp = 0;
>> +
>> + if (timestamp || etm->timeless_decoding) {
>> + err = cs_etm__update_queues(etm);
>> + if (err)
>> + return err;
>> + }
>> +
>> return 0;
>> }
>>