Commit c152d4d4 authored by Mathieu Poirier's avatar Mathieu Poirier Committed by Arnaldo Carvalho de Melo

perf cs-etm: Add support for multiple traceID queues

When operating in CPU-wide trace mode with a source/sink topology of N:1
packets with multiple traceID will end up in the same cs_etm_queue.  In
order to properly decode packets they need to be split in different
queues, i.e one queue per traceID.

As such add support for multiple traceID per cs_etm_queue by adding a
new cs_etm_traceid_queue every time a new traceID is discovered in the
trace stream.
Signed-off-by: default avatarMathieu Poirier <mathieu.poirier@linaro.org>
Tested-by: default avatarLeo Yan <leo.yan@linaro.org>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Suzuki Poulouse <suzuki.poulose@arm.com>
Cc: coresight@lists.linaro.org
Cc: linux-arm-kernel@lists.infradead.org
Link: http://lkml.kernel.org/r/20190524173508.29044-15-mathieu.poirier@linaro.orgSigned-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent af21577c
...@@ -413,6 +413,9 @@ ifdef CORESIGHT ...@@ -413,6 +413,9 @@ ifdef CORESIGHT
$(call feature_check,libopencsd) $(call feature_check,libopencsd)
ifeq ($(feature-libopencsd), 1) ifeq ($(feature-libopencsd), 1)
CFLAGS += -DHAVE_CSTRACE_SUPPORT $(LIBOPENCSD_CFLAGS) CFLAGS += -DHAVE_CSTRACE_SUPPORT $(LIBOPENCSD_CFLAGS)
ifeq ($(feature-reallocarray), 0)
CFLAGS += -DCOMPAT_NEED_REALLOCARRAY
endif
LDFLAGS += $(LIBOPENCSD_LDFLAGS) LDFLAGS += $(LIBOPENCSD_LDFLAGS)
EXTLIBS += $(OPENCSDLIBS) EXTLIBS += $(OPENCSDLIBS)
$(call detected,CONFIG_LIBOPENCSD) $(call detected,CONFIG_LIBOPENCSD)
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#include "thread.h" #include "thread.h"
#include "thread_map.h" #include "thread_map.h"
#include "thread-stack.h" #include "thread-stack.h"
#include <tools/libc_compat.h>
#include "util.h" #include "util.h"
#define MAX_TIMESTAMP (~0ULL) #define MAX_TIMESTAMP (~0ULL)
...@@ -82,7 +83,9 @@ struct cs_etm_queue { ...@@ -82,7 +83,9 @@ struct cs_etm_queue {
u64 offset; u64 offset;
const unsigned char *buf; const unsigned char *buf;
size_t buf_len, buf_used; size_t buf_len, buf_used;
struct cs_etm_traceid_queue *traceid_queues; /* Conversion between traceID and index in traceid_queues array */
struct intlist *traceid_queues_list;
struct cs_etm_traceid_queue **traceid_queues;
}; };
static int cs_etm__update_queues(struct cs_etm_auxtrace *etm); static int cs_etm__update_queues(struct cs_etm_auxtrace *etm);
...@@ -208,31 +211,71 @@ static int cs_etm__init_traceid_queue(struct cs_etm_queue *etmq, ...@@ -208,31 +211,71 @@ static int cs_etm__init_traceid_queue(struct cs_etm_queue *etmq,
static struct cs_etm_traceid_queue static struct cs_etm_traceid_queue
*cs_etm__etmq_get_traceid_queue(struct cs_etm_queue *etmq, u8 trace_chan_id) *cs_etm__etmq_get_traceid_queue(struct cs_etm_queue *etmq, u8 trace_chan_id)
{ {
struct cs_etm_traceid_queue *tidq; int idx;
struct int_node *inode;
struct intlist *traceid_queues_list;
struct cs_etm_traceid_queue *tidq, **traceid_queues;
struct cs_etm_auxtrace *etm = etmq->etm; struct cs_etm_auxtrace *etm = etmq->etm;
if (!etm->timeless_decoding) if (etm->timeless_decoding)
return NULL; trace_chan_id = CS_ETM_PER_THREAD_TRACEID;
tidq = etmq->traceid_queues; traceid_queues_list = etmq->traceid_queues_list;
if (tidq) /*
return tidq; * Check if the traceid_queue exist for this traceID by looking
* in the queue list.
*/
inode = intlist__find(traceid_queues_list, trace_chan_id);
if (inode) {
idx = (int)(intptr_t)inode->priv;
return etmq->traceid_queues[idx];
}
/* We couldn't find a traceid_queue for this traceID, allocate one */
tidq = malloc(sizeof(*tidq)); tidq = malloc(sizeof(*tidq));
if (!tidq) if (!tidq)
return NULL; return NULL;
memset(tidq, 0, sizeof(*tidq)); memset(tidq, 0, sizeof(*tidq));
/* Get a valid index for the new traceid_queue */
idx = intlist__nr_entries(traceid_queues_list);
/* Memory for the inode is free'ed in cs_etm_free_traceid_queues () */
inode = intlist__findnew(traceid_queues_list, trace_chan_id);
if (!inode)
goto out_free;
/* Associate this traceID with this index */
inode->priv = (void *)(intptr_t)idx;
if (cs_etm__init_traceid_queue(etmq, tidq, trace_chan_id)) if (cs_etm__init_traceid_queue(etmq, tidq, trace_chan_id))
goto out_free; goto out_free;
etmq->traceid_queues = tidq; /* Grow the traceid_queues array by one unit */
traceid_queues = etmq->traceid_queues;
traceid_queues = reallocarray(traceid_queues,
idx + 1,
sizeof(*traceid_queues));
/*
* On failure reallocarray() returns NULL and the original block of
* memory is left untouched.
*/
if (!traceid_queues)
goto out_free;
traceid_queues[idx] = tidq;
etmq->traceid_queues = traceid_queues;
return etmq->traceid_queues; return etmq->traceid_queues[idx];
out_free: out_free:
/*
* Function intlist__remove() removes the inode from the list
* and delete the memory associated to it.
*/
intlist__remove(traceid_queues_list, inode);
free(tidq); free(tidq);
return NULL; return NULL;
...@@ -412,6 +455,44 @@ static int cs_etm__flush_events(struct perf_session *session, ...@@ -412,6 +455,44 @@ static int cs_etm__flush_events(struct perf_session *session,
return cs_etm__process_timeless_queues(etm, -1); return cs_etm__process_timeless_queues(etm, -1);
} }
static void cs_etm__free_traceid_queues(struct cs_etm_queue *etmq)
{
int idx;
uintptr_t priv;
struct int_node *inode, *tmp;
struct cs_etm_traceid_queue *tidq;
struct intlist *traceid_queues_list = etmq->traceid_queues_list;
intlist__for_each_entry_safe(inode, tmp, traceid_queues_list) {
priv = (uintptr_t)inode->priv;
idx = priv;
/* Free this traceid_queue from the array */
tidq = etmq->traceid_queues[idx];
thread__zput(tidq->thread);
zfree(&tidq->event_buf);
zfree(&tidq->last_branch);
zfree(&tidq->last_branch_rb);
zfree(&tidq->prev_packet);
zfree(&tidq->packet);
zfree(&tidq);
/*
* Function intlist__remove() removes the inode from the list
* and delete the memory associated to it.
*/
intlist__remove(traceid_queues_list, inode);
}
/* Then the RB tree itself */
intlist__delete(traceid_queues_list);
etmq->traceid_queues_list = NULL;
/* finally free the traceid_queues array */
free(etmq->traceid_queues);
etmq->traceid_queues = NULL;
}
static void cs_etm__free_queue(void *priv) static void cs_etm__free_queue(void *priv)
{ {
struct cs_etm_queue *etmq = priv; struct cs_etm_queue *etmq = priv;
...@@ -419,14 +500,8 @@ static void cs_etm__free_queue(void *priv) ...@@ -419,14 +500,8 @@ static void cs_etm__free_queue(void *priv)
if (!etmq) if (!etmq)
return; return;
thread__zput(etmq->traceid_queues->thread);
cs_etm_decoder__free(etmq->decoder); cs_etm_decoder__free(etmq->decoder);
zfree(&etmq->traceid_queues->event_buf); cs_etm__free_traceid_queues(etmq);
zfree(&etmq->traceid_queues->last_branch);
zfree(&etmq->traceid_queues->last_branch_rb);
zfree(&etmq->traceid_queues->prev_packet);
zfree(&etmq->traceid_queues->packet);
zfree(&etmq->traceid_queues);
free(etmq); free(etmq);
} }
...@@ -497,19 +572,21 @@ static u32 cs_etm__mem_access(struct cs_etm_queue *etmq, u8 trace_chan_id, ...@@ -497,19 +572,21 @@ static u32 cs_etm__mem_access(struct cs_etm_queue *etmq, u8 trace_chan_id,
u8 cpumode; u8 cpumode;
u64 offset; u64 offset;
int len; int len;
struct thread *thread; struct thread *thread;
struct machine *machine; struct machine *machine;
struct addr_location al; struct addr_location al;
struct cs_etm_traceid_queue *tidq;
(void)trace_chan_id;
if (!etmq) if (!etmq)
return 0; return 0;
machine = etmq->etm->machine; machine = etmq->etm->machine;
cpumode = cs_etm__cpu_mode(etmq, address); cpumode = cs_etm__cpu_mode(etmq, address);
tidq = cs_etm__etmq_get_traceid_queue(etmq, trace_chan_id);
if (!tidq)
return 0;
thread = etmq->traceid_queues->thread; thread = tidq->thread;
if (!thread) { if (!thread) {
if (cpumode != PERF_RECORD_MISC_KERNEL) if (cpumode != PERF_RECORD_MISC_KERNEL)
return 0; return 0;
...@@ -545,6 +622,10 @@ static struct cs_etm_queue *cs_etm__alloc_queue(struct cs_etm_auxtrace *etm) ...@@ -545,6 +622,10 @@ static struct cs_etm_queue *cs_etm__alloc_queue(struct cs_etm_auxtrace *etm)
if (!etmq) if (!etmq)
return NULL; return NULL;
etmq->traceid_queues_list = intlist__new(NULL);
if (!etmq->traceid_queues_list)
goto out_free;
/* Use metadata to fill in trace parameters for trace decoder */ /* Use metadata to fill in trace parameters for trace decoder */
t_params = zalloc(sizeof(*t_params) * etm->num_cpu); t_params = zalloc(sizeof(*t_params) * etm->num_cpu);
...@@ -579,6 +660,7 @@ static struct cs_etm_queue *cs_etm__alloc_queue(struct cs_etm_auxtrace *etm) ...@@ -579,6 +660,7 @@ static struct cs_etm_queue *cs_etm__alloc_queue(struct cs_etm_auxtrace *etm)
out_free_decoder: out_free_decoder:
cs_etm_decoder__free(etmq->decoder); cs_etm_decoder__free(etmq->decoder);
out_free: out_free:
intlist__delete(etmq->traceid_queues_list);
free(etmq); free(etmq);
return NULL; return NULL;
...@@ -1280,8 +1362,9 @@ static bool cs_etm__is_svc_instr(struct cs_etm_queue *etmq, u8 trace_chan_id, ...@@ -1280,8 +1362,9 @@ static bool cs_etm__is_svc_instr(struct cs_etm_queue *etmq, u8 trace_chan_id,
struct cs_etm_packet *packet, struct cs_etm_packet *packet,
u64 end_addr) u64 end_addr)
{ {
u16 instr16; /* Initialise to keep compiler happy */
u32 instr32; u16 instr16 = 0;
u32 instr32 = 0;
u64 addr; u64 addr;
switch (packet->isa) { switch (packet->isa) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment