提交 c7bfa2fd 编写于 作者: M Mathieu Poirier 提交者: Arnaldo Carvalho de Melo

perf cs-etm: Introduce the concept of trace ID queues

In an ideal world there is one CPU per cs_etm_queue and as such, one
trace ID per cs_etm_queue.  In the real world CoreSight topologies allow
multiple CPUs to use the same sink, which translates to multiple trace
IDs per cs_etm_queue.

To deal with this a new cs_etm_traceid_queue structure is introduced to
enclose all the information related to a single trace ID, allowing a
cs_etm_queue to handle traces generated by any number of CPUs.
Signed-off-by: NMathieu Poirier <mathieu.poirier@linaro.org>
Tested-by: NLeo 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-10-mathieu.poirier@linaro.orgSigned-off-by: NArnaldo Carvalho de Melo <acme@redhat.com>
上级 882f4874
...@@ -413,8 +413,8 @@ static ocsd_datapath_resp_t cs_etm_decoder__gen_trace_elem_printer( ...@@ -413,8 +413,8 @@ static ocsd_datapath_resp_t cs_etm_decoder__gen_trace_elem_printer(
struct cs_etm_queue *etmq = decoder->data; struct cs_etm_queue *etmq = decoder->data;
struct cs_etm_packet_queue *packet_queue; struct cs_etm_packet_queue *packet_queue;
/* First get the packet queue */ /* First get the packet queue for this traceID */
packet_queue = cs_etm__etmq_get_packet_queue(etmq); packet_queue = cs_etm__etmq_get_packet_queue(etmq, trace_chan_id);
if (!packet_queue) if (!packet_queue)
return OCSD_RESP_FATAL_SYS_ERR; return OCSD_RESP_FATAL_SYS_ERR;
......
...@@ -60,25 +60,30 @@ struct cs_etm_auxtrace { ...@@ -60,25 +60,30 @@ struct cs_etm_auxtrace {
unsigned int pmu_type; unsigned int pmu_type;
}; };
struct cs_etm_traceid_queue {
u8 trace_chan_id;
u64 period_instructions;
size_t last_branch_pos;
union perf_event *event_buf;
struct branch_stack *last_branch;
struct branch_stack *last_branch_rb;
struct cs_etm_packet *prev_packet;
struct cs_etm_packet *packet;
struct cs_etm_packet_queue packet_queue;
};
struct cs_etm_queue { struct cs_etm_queue {
struct cs_etm_auxtrace *etm; struct cs_etm_auxtrace *etm;
struct thread *thread; struct thread *thread;
struct cs_etm_decoder *decoder; struct cs_etm_decoder *decoder;
struct auxtrace_buffer *buffer; struct auxtrace_buffer *buffer;
union perf_event *event_buf;
unsigned int queue_nr; unsigned int queue_nr;
pid_t pid, tid; pid_t pid, tid;
int cpu; int cpu;
u64 offset; u64 offset;
u64 period_instructions;
struct branch_stack *last_branch;
struct branch_stack *last_branch_rb;
size_t last_branch_pos;
struct cs_etm_packet *prev_packet;
struct cs_etm_packet *packet;
const unsigned char *buf; const unsigned char *buf;
size_t buf_len, buf_used; size_t buf_len, buf_used;
struct cs_etm_packet_queue packet_queue; 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);
...@@ -150,10 +155,96 @@ static void cs_etm__clear_packet_queue(struct cs_etm_packet_queue *queue) ...@@ -150,10 +155,96 @@ static void cs_etm__clear_packet_queue(struct cs_etm_packet_queue *queue)
} }
} }
static int cs_etm__init_traceid_queue(struct cs_etm_queue *etmq,
struct cs_etm_traceid_queue *tidq,
u8 trace_chan_id)
{
int rc = -ENOMEM;
struct cs_etm_auxtrace *etm = etmq->etm;
cs_etm__clear_packet_queue(&tidq->packet_queue);
tidq->trace_chan_id = trace_chan_id;
tidq->packet = zalloc(sizeof(struct cs_etm_packet));
if (!tidq->packet)
goto out;
tidq->prev_packet = zalloc(sizeof(struct cs_etm_packet));
if (!tidq->prev_packet)
goto out_free;
if (etm->synth_opts.last_branch) {
size_t sz = sizeof(struct branch_stack);
sz += etm->synth_opts.last_branch_sz *
sizeof(struct branch_entry);
tidq->last_branch = zalloc(sz);
if (!tidq->last_branch)
goto out_free;
tidq->last_branch_rb = zalloc(sz);
if (!tidq->last_branch_rb)
goto out_free;
}
tidq->event_buf = malloc(PERF_SAMPLE_MAX_SIZE);
if (!tidq->event_buf)
goto out_free;
return 0;
out_free:
zfree(&tidq->last_branch_rb);
zfree(&tidq->last_branch);
zfree(&tidq->prev_packet);
zfree(&tidq->packet);
out:
return rc;
}
static struct cs_etm_traceid_queue
*cs_etm__etmq_get_traceid_queue(struct cs_etm_queue *etmq, u8 trace_chan_id)
{
struct cs_etm_traceid_queue *tidq;
struct cs_etm_auxtrace *etm = etmq->etm;
if (!etm->timeless_decoding)
return NULL;
tidq = etmq->traceid_queues;
if (tidq)
return tidq;
tidq = malloc(sizeof(*tidq));
if (!tidq)
return NULL;
memset(tidq, 0, sizeof(*tidq));
if (cs_etm__init_traceid_queue(etmq, tidq, trace_chan_id))
goto out_free;
etmq->traceid_queues = tidq;
return etmq->traceid_queues;
out_free:
free(tidq);
return NULL;
}
struct cs_etm_packet_queue struct cs_etm_packet_queue
*cs_etm__etmq_get_packet_queue(struct cs_etm_queue *etmq) *cs_etm__etmq_get_packet_queue(struct cs_etm_queue *etmq, u8 trace_chan_id)
{ {
return &etmq->packet_queue; struct cs_etm_traceid_queue *tidq;
tidq = cs_etm__etmq_get_traceid_queue(etmq, trace_chan_id);
if (tidq)
return &tidq->packet_queue;
return NULL;
} }
static void cs_etm__packet_dump(const char *pkt_string) static void cs_etm__packet_dump(const char *pkt_string)
...@@ -327,11 +418,12 @@ static void cs_etm__free_queue(void *priv) ...@@ -327,11 +418,12 @@ static void cs_etm__free_queue(void *priv)
thread__zput(etmq->thread); thread__zput(etmq->thread);
cs_etm_decoder__free(etmq->decoder); cs_etm_decoder__free(etmq->decoder);
zfree(&etmq->event_buf); zfree(&etmq->traceid_queues->event_buf);
zfree(&etmq->last_branch); zfree(&etmq->traceid_queues->last_branch);
zfree(&etmq->last_branch_rb); zfree(&etmq->traceid_queues->last_branch_rb);
zfree(&etmq->prev_packet); zfree(&etmq->traceid_queues->prev_packet);
zfree(&etmq->packet); zfree(&etmq->traceid_queues->packet);
zfree(&etmq->traceid_queues);
free(etmq); free(etmq);
} }
...@@ -443,37 +535,11 @@ static struct cs_etm_queue *cs_etm__alloc_queue(struct cs_etm_auxtrace *etm) ...@@ -443,37 +535,11 @@ static struct cs_etm_queue *cs_etm__alloc_queue(struct cs_etm_auxtrace *etm)
struct cs_etm_decoder_params d_params; struct cs_etm_decoder_params d_params;
struct cs_etm_trace_params *t_params = NULL; struct cs_etm_trace_params *t_params = NULL;
struct cs_etm_queue *etmq; struct cs_etm_queue *etmq;
size_t szp = sizeof(struct cs_etm_packet);
etmq = zalloc(sizeof(*etmq)); etmq = zalloc(sizeof(*etmq));
if (!etmq) if (!etmq)
return NULL; return NULL;
etmq->packet = zalloc(szp);
if (!etmq->packet)
goto out_free;
etmq->prev_packet = zalloc(szp);
if (!etmq->prev_packet)
goto out_free;
if (etm->synth_opts.last_branch) {
size_t sz = sizeof(struct branch_stack);
sz += etm->synth_opts.last_branch_sz *
sizeof(struct branch_entry);
etmq->last_branch = zalloc(sz);
if (!etmq->last_branch)
goto out_free;
etmq->last_branch_rb = zalloc(sz);
if (!etmq->last_branch_rb)
goto out_free;
}
etmq->event_buf = malloc(PERF_SAMPLE_MAX_SIZE);
if (!etmq->event_buf)
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);
...@@ -508,12 +574,6 @@ static struct cs_etm_queue *cs_etm__alloc_queue(struct cs_etm_auxtrace *etm) ...@@ -508,12 +574,6 @@ 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:
zfree(&t_params);
zfree(&etmq->event_buf);
zfree(&etmq->last_branch);
zfree(&etmq->last_branch_rb);
zfree(&etmq->prev_packet);
zfree(&etmq->packet);
free(etmq); free(etmq);
return NULL; return NULL;
...@@ -543,8 +603,6 @@ static int cs_etm__setup_queue(struct cs_etm_auxtrace *etm, ...@@ -543,8 +603,6 @@ static int cs_etm__setup_queue(struct cs_etm_auxtrace *etm,
etmq->tid = queue->tid; etmq->tid = queue->tid;
etmq->pid = -1; etmq->pid = -1;
etmq->offset = 0; etmq->offset = 0;
etmq->period_instructions = 0;
cs_etm__clear_packet_queue(&etmq->packet_queue);
out: out:
return ret; return ret;
...@@ -577,10 +635,12 @@ static int cs_etm__update_queues(struct cs_etm_auxtrace *etm) ...@@ -577,10 +635,12 @@ static int cs_etm__update_queues(struct cs_etm_auxtrace *etm)
return 0; return 0;
} }
static inline void cs_etm__copy_last_branch_rb(struct cs_etm_queue *etmq) static inline
void cs_etm__copy_last_branch_rb(struct cs_etm_queue *etmq,
struct cs_etm_traceid_queue *tidq)
{ {
struct branch_stack *bs_src = etmq->last_branch_rb; struct branch_stack *bs_src = tidq->last_branch_rb;
struct branch_stack *bs_dst = etmq->last_branch; struct branch_stack *bs_dst = tidq->last_branch;
size_t nr = 0; size_t nr = 0;
/* /*
...@@ -600,9 +660,9 @@ static inline void cs_etm__copy_last_branch_rb(struct cs_etm_queue *etmq) ...@@ -600,9 +660,9 @@ static inline void cs_etm__copy_last_branch_rb(struct cs_etm_queue *etmq)
* two steps. First, copy the branches from the most recently inserted * two steps. First, copy the branches from the most recently inserted
* branch ->last_branch_pos until the end of bs_src->entries buffer. * branch ->last_branch_pos until the end of bs_src->entries buffer.
*/ */
nr = etmq->etm->synth_opts.last_branch_sz - etmq->last_branch_pos; nr = etmq->etm->synth_opts.last_branch_sz - tidq->last_branch_pos;
memcpy(&bs_dst->entries[0], memcpy(&bs_dst->entries[0],
&bs_src->entries[etmq->last_branch_pos], &bs_src->entries[tidq->last_branch_pos],
sizeof(struct branch_entry) * nr); sizeof(struct branch_entry) * nr);
/* /*
...@@ -615,14 +675,15 @@ static inline void cs_etm__copy_last_branch_rb(struct cs_etm_queue *etmq) ...@@ -615,14 +675,15 @@ static inline void cs_etm__copy_last_branch_rb(struct cs_etm_queue *etmq)
if (bs_src->nr >= etmq->etm->synth_opts.last_branch_sz) { if (bs_src->nr >= etmq->etm->synth_opts.last_branch_sz) {
memcpy(&bs_dst->entries[nr], memcpy(&bs_dst->entries[nr],
&bs_src->entries[0], &bs_src->entries[0],
sizeof(struct branch_entry) * etmq->last_branch_pos); sizeof(struct branch_entry) * tidq->last_branch_pos);
} }
} }
static inline void cs_etm__reset_last_branch_rb(struct cs_etm_queue *etmq) static inline
void cs_etm__reset_last_branch_rb(struct cs_etm_traceid_queue *tidq)
{ {
etmq->last_branch_pos = 0; tidq->last_branch_pos = 0;
etmq->last_branch_rb->nr = 0; tidq->last_branch_rb->nr = 0;
} }
static inline int cs_etm__t32_instr_size(struct cs_etm_queue *etmq, static inline int cs_etm__t32_instr_size(struct cs_etm_queue *etmq,
...@@ -675,9 +736,10 @@ static inline u64 cs_etm__instr_addr(struct cs_etm_queue *etmq, ...@@ -675,9 +736,10 @@ static inline u64 cs_etm__instr_addr(struct cs_etm_queue *etmq,
return packet->start_addr + offset * 4; return packet->start_addr + offset * 4;
} }
static void cs_etm__update_last_branch_rb(struct cs_etm_queue *etmq) static void cs_etm__update_last_branch_rb(struct cs_etm_queue *etmq,
struct cs_etm_traceid_queue *tidq)
{ {
struct branch_stack *bs = etmq->last_branch_rb; struct branch_stack *bs = tidq->last_branch_rb;
struct branch_entry *be; struct branch_entry *be;
/* /*
...@@ -686,14 +748,14 @@ static void cs_etm__update_last_branch_rb(struct cs_etm_queue *etmq) ...@@ -686,14 +748,14 @@ static void cs_etm__update_last_branch_rb(struct cs_etm_queue *etmq)
* buffer down. After writing the first element of the stack, move the * buffer down. After writing the first element of the stack, move the
* insert position back to the end of the buffer. * insert position back to the end of the buffer.
*/ */
if (!etmq->last_branch_pos) if (!tidq->last_branch_pos)
etmq->last_branch_pos = etmq->etm->synth_opts.last_branch_sz; tidq->last_branch_pos = etmq->etm->synth_opts.last_branch_sz;
etmq->last_branch_pos -= 1; tidq->last_branch_pos -= 1;
be = &bs->entries[etmq->last_branch_pos]; be = &bs->entries[tidq->last_branch_pos];
be->from = cs_etm__last_executed_instr(etmq->prev_packet); be->from = cs_etm__last_executed_instr(tidq->prev_packet);
be->to = cs_etm__first_executed_instr(etmq->packet); be->to = cs_etm__first_executed_instr(tidq->packet);
/* No support for mispredict */ /* No support for mispredict */
be->flags.mispred = 0; be->flags.mispred = 0;
be->flags.predicted = 1; be->flags.predicted = 1;
...@@ -777,11 +839,12 @@ static void cs_etm__set_pid_tid_cpu(struct cs_etm_auxtrace *etm, ...@@ -777,11 +839,12 @@ static void cs_etm__set_pid_tid_cpu(struct cs_etm_auxtrace *etm,
} }
static int cs_etm__synth_instruction_sample(struct cs_etm_queue *etmq, static int cs_etm__synth_instruction_sample(struct cs_etm_queue *etmq,
struct cs_etm_traceid_queue *tidq,
u64 addr, u64 period) u64 addr, u64 period)
{ {
int ret = 0; int ret = 0;
struct cs_etm_auxtrace *etm = etmq->etm; struct cs_etm_auxtrace *etm = etmq->etm;
union perf_event *event = etmq->event_buf; union perf_event *event = tidq->event_buf;
struct perf_sample sample = {.ip = 0,}; struct perf_sample sample = {.ip = 0,};
event->sample.header.type = PERF_RECORD_SAMPLE; event->sample.header.type = PERF_RECORD_SAMPLE;
...@@ -794,14 +857,14 @@ static int cs_etm__synth_instruction_sample(struct cs_etm_queue *etmq, ...@@ -794,14 +857,14 @@ static int cs_etm__synth_instruction_sample(struct cs_etm_queue *etmq,
sample.id = etmq->etm->instructions_id; sample.id = etmq->etm->instructions_id;
sample.stream_id = etmq->etm->instructions_id; sample.stream_id = etmq->etm->instructions_id;
sample.period = period; sample.period = period;
sample.cpu = etmq->packet->cpu; sample.cpu = tidq->packet->cpu;
sample.flags = etmq->prev_packet->flags; sample.flags = tidq->prev_packet->flags;
sample.insn_len = 1; sample.insn_len = 1;
sample.cpumode = event->sample.header.misc; sample.cpumode = event->sample.header.misc;
if (etm->synth_opts.last_branch) { if (etm->synth_opts.last_branch) {
cs_etm__copy_last_branch_rb(etmq); cs_etm__copy_last_branch_rb(etmq, tidq);
sample.branch_stack = etmq->last_branch; sample.branch_stack = tidq->last_branch;
} }
if (etm->synth_opts.inject) { if (etm->synth_opts.inject) {
...@@ -819,7 +882,7 @@ static int cs_etm__synth_instruction_sample(struct cs_etm_queue *etmq, ...@@ -819,7 +882,7 @@ static int cs_etm__synth_instruction_sample(struct cs_etm_queue *etmq,
ret); ret);
if (etm->synth_opts.last_branch) if (etm->synth_opts.last_branch)
cs_etm__reset_last_branch_rb(etmq); cs_etm__reset_last_branch_rb(tidq);
return ret; return ret;
} }
...@@ -828,19 +891,20 @@ static int cs_etm__synth_instruction_sample(struct cs_etm_queue *etmq, ...@@ -828,19 +891,20 @@ static int cs_etm__synth_instruction_sample(struct cs_etm_queue *etmq,
* The cs etm packet encodes an instruction range between a branch target * The cs etm packet encodes an instruction range between a branch target
* and the next taken branch. Generate sample accordingly. * and the next taken branch. Generate sample accordingly.
*/ */
static int cs_etm__synth_branch_sample(struct cs_etm_queue *etmq) static int cs_etm__synth_branch_sample(struct cs_etm_queue *etmq,
struct cs_etm_traceid_queue *tidq)
{ {
int ret = 0; int ret = 0;
struct cs_etm_auxtrace *etm = etmq->etm; struct cs_etm_auxtrace *etm = etmq->etm;
struct perf_sample sample = {.ip = 0,}; struct perf_sample sample = {.ip = 0,};
union perf_event *event = etmq->event_buf; union perf_event *event = tidq->event_buf;
struct dummy_branch_stack { struct dummy_branch_stack {
u64 nr; u64 nr;
struct branch_entry entries; struct branch_entry entries;
} dummy_bs; } dummy_bs;
u64 ip; u64 ip;
ip = cs_etm__last_executed_instr(etmq->prev_packet); ip = cs_etm__last_executed_instr(tidq->prev_packet);
event->sample.header.type = PERF_RECORD_SAMPLE; event->sample.header.type = PERF_RECORD_SAMPLE;
event->sample.header.misc = cs_etm__cpu_mode(etmq, ip); event->sample.header.misc = cs_etm__cpu_mode(etmq, ip);
...@@ -849,12 +913,12 @@ static int cs_etm__synth_branch_sample(struct cs_etm_queue *etmq) ...@@ -849,12 +913,12 @@ static int cs_etm__synth_branch_sample(struct cs_etm_queue *etmq)
sample.ip = ip; sample.ip = ip;
sample.pid = etmq->pid; sample.pid = etmq->pid;
sample.tid = etmq->tid; sample.tid = etmq->tid;
sample.addr = cs_etm__first_executed_instr(etmq->packet); sample.addr = cs_etm__first_executed_instr(tidq->packet);
sample.id = etmq->etm->branches_id; sample.id = etmq->etm->branches_id;
sample.stream_id = etmq->etm->branches_id; sample.stream_id = etmq->etm->branches_id;
sample.period = 1; sample.period = 1;
sample.cpu = etmq->packet->cpu; sample.cpu = tidq->packet->cpu;
sample.flags = etmq->prev_packet->flags; sample.flags = tidq->prev_packet->flags;
sample.cpumode = event->sample.header.misc; sample.cpumode = event->sample.header.misc;
/* /*
...@@ -997,33 +1061,34 @@ static int cs_etm__synth_events(struct cs_etm_auxtrace *etm, ...@@ -997,33 +1061,34 @@ static int cs_etm__synth_events(struct cs_etm_auxtrace *etm,
return 0; return 0;
} }
static int cs_etm__sample(struct cs_etm_queue *etmq) static int cs_etm__sample(struct cs_etm_queue *etmq,
struct cs_etm_traceid_queue *tidq)
{ {
struct cs_etm_auxtrace *etm = etmq->etm; struct cs_etm_auxtrace *etm = etmq->etm;
struct cs_etm_packet *tmp; struct cs_etm_packet *tmp;
int ret; int ret;
u64 instrs_executed = etmq->packet->instr_count; u64 instrs_executed = tidq->packet->instr_count;
etmq->period_instructions += instrs_executed; tidq->period_instructions += instrs_executed;
/* /*
* Record a branch when the last instruction in * Record a branch when the last instruction in
* PREV_PACKET is a branch. * PREV_PACKET is a branch.
*/ */
if (etm->synth_opts.last_branch && if (etm->synth_opts.last_branch &&
etmq->prev_packet->sample_type == CS_ETM_RANGE && tidq->prev_packet->sample_type == CS_ETM_RANGE &&
etmq->prev_packet->last_instr_taken_branch) tidq->prev_packet->last_instr_taken_branch)
cs_etm__update_last_branch_rb(etmq); cs_etm__update_last_branch_rb(etmq, tidq);
if (etm->sample_instructions && if (etm->sample_instructions &&
etmq->period_instructions >= etm->instructions_sample_period) { tidq->period_instructions >= etm->instructions_sample_period) {
/* /*
* Emit instruction sample periodically * Emit instruction sample periodically
* TODO: allow period to be defined in cycles and clock time * TODO: allow period to be defined in cycles and clock time
*/ */
/* Get number of instructions executed after the sample point */ /* Get number of instructions executed after the sample point */
u64 instrs_over = etmq->period_instructions - u64 instrs_over = tidq->period_instructions -
etm->instructions_sample_period; etm->instructions_sample_period;
/* /*
...@@ -1032,31 +1097,31 @@ static int cs_etm__sample(struct cs_etm_queue *etmq) ...@@ -1032,31 +1097,31 @@ static int cs_etm__sample(struct cs_etm_queue *etmq)
* executed, but PC has not advanced to next instruction) * executed, but PC has not advanced to next instruction)
*/ */
u64 offset = (instrs_executed - instrs_over - 1); u64 offset = (instrs_executed - instrs_over - 1);
u64 addr = cs_etm__instr_addr(etmq, etmq->packet, offset); u64 addr = cs_etm__instr_addr(etmq, tidq->packet, offset);
ret = cs_etm__synth_instruction_sample( ret = cs_etm__synth_instruction_sample(
etmq, addr, etm->instructions_sample_period); etmq, tidq, addr, etm->instructions_sample_period);
if (ret) if (ret)
return ret; return ret;
/* Carry remaining instructions into next sample period */ /* Carry remaining instructions into next sample period */
etmq->period_instructions = instrs_over; tidq->period_instructions = instrs_over;
} }
if (etm->sample_branches) { if (etm->sample_branches) {
bool generate_sample = false; bool generate_sample = false;
/* Generate sample for tracing on packet */ /* Generate sample for tracing on packet */
if (etmq->prev_packet->sample_type == CS_ETM_DISCONTINUITY) if (tidq->prev_packet->sample_type == CS_ETM_DISCONTINUITY)
generate_sample = true; generate_sample = true;
/* Generate sample for branch taken packet */ /* Generate sample for branch taken packet */
if (etmq->prev_packet->sample_type == CS_ETM_RANGE && if (tidq->prev_packet->sample_type == CS_ETM_RANGE &&
etmq->prev_packet->last_instr_taken_branch) tidq->prev_packet->last_instr_taken_branch)
generate_sample = true; generate_sample = true;
if (generate_sample) { if (generate_sample) {
ret = cs_etm__synth_branch_sample(etmq); ret = cs_etm__synth_branch_sample(etmq, tidq);
if (ret) if (ret)
return ret; return ret;
} }
...@@ -1067,15 +1132,15 @@ static int cs_etm__sample(struct cs_etm_queue *etmq) ...@@ -1067,15 +1132,15 @@ static int cs_etm__sample(struct cs_etm_queue *etmq)
* Swap PACKET with PREV_PACKET: PACKET becomes PREV_PACKET for * Swap PACKET with PREV_PACKET: PACKET becomes PREV_PACKET for
* the next incoming packet. * the next incoming packet.
*/ */
tmp = etmq->packet; tmp = tidq->packet;
etmq->packet = etmq->prev_packet; tidq->packet = tidq->prev_packet;
etmq->prev_packet = tmp; tidq->prev_packet = tmp;
} }
return 0; return 0;
} }
static int cs_etm__exception(struct cs_etm_queue *etmq) static int cs_etm__exception(struct cs_etm_traceid_queue *tidq)
{ {
/* /*
* When the exception packet is inserted, whether the last instruction * When the exception packet is inserted, whether the last instruction
...@@ -1088,24 +1153,25 @@ static int cs_etm__exception(struct cs_etm_queue *etmq) ...@@ -1088,24 +1153,25 @@ static int cs_etm__exception(struct cs_etm_queue *etmq)
* swap PACKET with PREV_PACKET. This keeps PREV_PACKET to be useful * swap PACKET with PREV_PACKET. This keeps PREV_PACKET to be useful
* for generating instruction and branch samples. * for generating instruction and branch samples.
*/ */
if (etmq->prev_packet->sample_type == CS_ETM_RANGE) if (tidq->prev_packet->sample_type == CS_ETM_RANGE)
etmq->prev_packet->last_instr_taken_branch = true; tidq->prev_packet->last_instr_taken_branch = true;
return 0; return 0;
} }
static int cs_etm__flush(struct cs_etm_queue *etmq) static int cs_etm__flush(struct cs_etm_queue *etmq,
struct cs_etm_traceid_queue *tidq)
{ {
int err = 0; int err = 0;
struct cs_etm_auxtrace *etm = etmq->etm; struct cs_etm_auxtrace *etm = etmq->etm;
struct cs_etm_packet *tmp; struct cs_etm_packet *tmp;
/* Handle start tracing packet */ /* Handle start tracing packet */
if (etmq->prev_packet->sample_type == CS_ETM_EMPTY) if (tidq->prev_packet->sample_type == CS_ETM_EMPTY)
goto swap_packet; goto swap_packet;
if (etmq->etm->synth_opts.last_branch && if (etmq->etm->synth_opts.last_branch &&
etmq->prev_packet->sample_type == CS_ETM_RANGE) { tidq->prev_packet->sample_type == CS_ETM_RANGE) {
/* /*
* Generate a last branch event for the branches left in the * Generate a last branch event for the branches left in the
* circular buffer at the end of the trace. * circular buffer at the end of the trace.
...@@ -1113,21 +1179,21 @@ static int cs_etm__flush(struct cs_etm_queue *etmq) ...@@ -1113,21 +1179,21 @@ static int cs_etm__flush(struct cs_etm_queue *etmq)
* Use the address of the end of the last reported execution * Use the address of the end of the last reported execution
* range * range
*/ */
u64 addr = cs_etm__last_executed_instr(etmq->prev_packet); u64 addr = cs_etm__last_executed_instr(tidq->prev_packet);
err = cs_etm__synth_instruction_sample( err = cs_etm__synth_instruction_sample(
etmq, addr, etmq, tidq, addr,
etmq->period_instructions); tidq->period_instructions);
if (err) if (err)
return err; return err;
etmq->period_instructions = 0; tidq->period_instructions = 0;
} }
if (etm->sample_branches && if (etm->sample_branches &&
etmq->prev_packet->sample_type == CS_ETM_RANGE) { tidq->prev_packet->sample_type == CS_ETM_RANGE) {
err = cs_etm__synth_branch_sample(etmq); err = cs_etm__synth_branch_sample(etmq, tidq);
if (err) if (err)
return err; return err;
} }
...@@ -1138,15 +1204,16 @@ static int cs_etm__flush(struct cs_etm_queue *etmq) ...@@ -1138,15 +1204,16 @@ static int cs_etm__flush(struct cs_etm_queue *etmq)
* Swap PACKET with PREV_PACKET: PACKET becomes PREV_PACKET for * Swap PACKET with PREV_PACKET: PACKET becomes PREV_PACKET for
* the next incoming packet. * the next incoming packet.
*/ */
tmp = etmq->packet; tmp = tidq->packet;
etmq->packet = etmq->prev_packet; tidq->packet = tidq->prev_packet;
etmq->prev_packet = tmp; tidq->prev_packet = tmp;
} }
return err; return err;
} }
static int cs_etm__end_block(struct cs_etm_queue *etmq) static int cs_etm__end_block(struct cs_etm_queue *etmq,
struct cs_etm_traceid_queue *tidq)
{ {
int err; int err;
...@@ -1160,20 +1227,20 @@ static int cs_etm__end_block(struct cs_etm_queue *etmq) ...@@ -1160,20 +1227,20 @@ static int cs_etm__end_block(struct cs_etm_queue *etmq)
* the trace. * the trace.
*/ */
if (etmq->etm->synth_opts.last_branch && if (etmq->etm->synth_opts.last_branch &&
etmq->prev_packet->sample_type == CS_ETM_RANGE) { tidq->prev_packet->sample_type == CS_ETM_RANGE) {
/* /*
* Use the address of the end of the last reported execution * Use the address of the end of the last reported execution
* range. * range.
*/ */
u64 addr = cs_etm__last_executed_instr(etmq->prev_packet); u64 addr = cs_etm__last_executed_instr(tidq->prev_packet);
err = cs_etm__synth_instruction_sample( err = cs_etm__synth_instruction_sample(
etmq, addr, etmq, tidq, addr,
etmq->period_instructions); tidq->period_instructions);
if (err) if (err)
return err; return err;
etmq->period_instructions = 0; tidq->period_instructions = 0;
} }
return 0; return 0;
...@@ -1272,10 +1339,11 @@ static bool cs_etm__is_svc_instr(struct cs_etm_queue *etmq, ...@@ -1272,10 +1339,11 @@ static bool cs_etm__is_svc_instr(struct cs_etm_queue *etmq,
return false; return false;
} }
static bool cs_etm__is_syscall(struct cs_etm_queue *etmq, u64 magic) static bool cs_etm__is_syscall(struct cs_etm_queue *etmq,
struct cs_etm_traceid_queue *tidq, u64 magic)
{ {
struct cs_etm_packet *packet = etmq->packet; struct cs_etm_packet *packet = tidq->packet;
struct cs_etm_packet *prev_packet = etmq->prev_packet; struct cs_etm_packet *prev_packet = tidq->prev_packet;
if (magic == __perf_cs_etmv3_magic) if (magic == __perf_cs_etmv3_magic)
if (packet->exception_number == CS_ETMV3_EXC_SVC) if (packet->exception_number == CS_ETMV3_EXC_SVC)
...@@ -1296,9 +1364,10 @@ static bool cs_etm__is_syscall(struct cs_etm_queue *etmq, u64 magic) ...@@ -1296,9 +1364,10 @@ static bool cs_etm__is_syscall(struct cs_etm_queue *etmq, u64 magic)
return false; return false;
} }
static bool cs_etm__is_async_exception(struct cs_etm_queue *etmq, u64 magic) static bool cs_etm__is_async_exception(struct cs_etm_traceid_queue *tidq,
u64 magic)
{ {
struct cs_etm_packet *packet = etmq->packet; struct cs_etm_packet *packet = tidq->packet;
if (magic == __perf_cs_etmv3_magic) if (magic == __perf_cs_etmv3_magic)
if (packet->exception_number == CS_ETMV3_EXC_DEBUG_HALT || if (packet->exception_number == CS_ETMV3_EXC_DEBUG_HALT ||
...@@ -1321,10 +1390,12 @@ static bool cs_etm__is_async_exception(struct cs_etm_queue *etmq, u64 magic) ...@@ -1321,10 +1390,12 @@ static bool cs_etm__is_async_exception(struct cs_etm_queue *etmq, u64 magic)
return false; return false;
} }
static bool cs_etm__is_sync_exception(struct cs_etm_queue *etmq, u64 magic) static bool cs_etm__is_sync_exception(struct cs_etm_queue *etmq,
struct cs_etm_traceid_queue *tidq,
u64 magic)
{ {
struct cs_etm_packet *packet = etmq->packet; struct cs_etm_packet *packet = tidq->packet;
struct cs_etm_packet *prev_packet = etmq->prev_packet; struct cs_etm_packet *prev_packet = tidq->prev_packet;
if (magic == __perf_cs_etmv3_magic) if (magic == __perf_cs_etmv3_magic)
if (packet->exception_number == CS_ETMV3_EXC_SMC || if (packet->exception_number == CS_ETMV3_EXC_SMC ||
...@@ -1367,10 +1438,11 @@ static bool cs_etm__is_sync_exception(struct cs_etm_queue *etmq, u64 magic) ...@@ -1367,10 +1438,11 @@ static bool cs_etm__is_sync_exception(struct cs_etm_queue *etmq, u64 magic)
return false; return false;
} }
static int cs_etm__set_sample_flags(struct cs_etm_queue *etmq) static int cs_etm__set_sample_flags(struct cs_etm_queue *etmq,
struct cs_etm_traceid_queue *tidq)
{ {
struct cs_etm_packet *packet = etmq->packet; struct cs_etm_packet *packet = tidq->packet;
struct cs_etm_packet *prev_packet = etmq->prev_packet; struct cs_etm_packet *prev_packet = tidq->prev_packet;
u64 magic; u64 magic;
int ret; int ret;
...@@ -1472,7 +1544,7 @@ static int cs_etm__set_sample_flags(struct cs_etm_queue *etmq) ...@@ -1472,7 +1544,7 @@ static int cs_etm__set_sample_flags(struct cs_etm_queue *etmq)
return ret; return ret;
/* The exception is for system call. */ /* The exception is for system call. */
if (cs_etm__is_syscall(etmq, magic)) if (cs_etm__is_syscall(etmq, tidq, magic))
packet->flags = PERF_IP_FLAG_BRANCH | packet->flags = PERF_IP_FLAG_BRANCH |
PERF_IP_FLAG_CALL | PERF_IP_FLAG_CALL |
PERF_IP_FLAG_SYSCALLRET; PERF_IP_FLAG_SYSCALLRET;
...@@ -1480,7 +1552,7 @@ static int cs_etm__set_sample_flags(struct cs_etm_queue *etmq) ...@@ -1480,7 +1552,7 @@ static int cs_etm__set_sample_flags(struct cs_etm_queue *etmq)
* The exceptions are triggered by external signals from bus, * The exceptions are triggered by external signals from bus,
* interrupt controller, debug module, PE reset or halt. * interrupt controller, debug module, PE reset or halt.
*/ */
else if (cs_etm__is_async_exception(etmq, magic)) else if (cs_etm__is_async_exception(tidq, magic))
packet->flags = PERF_IP_FLAG_BRANCH | packet->flags = PERF_IP_FLAG_BRANCH |
PERF_IP_FLAG_CALL | PERF_IP_FLAG_CALL |
PERF_IP_FLAG_ASYNC | PERF_IP_FLAG_ASYNC |
...@@ -1489,7 +1561,7 @@ static int cs_etm__set_sample_flags(struct cs_etm_queue *etmq) ...@@ -1489,7 +1561,7 @@ static int cs_etm__set_sample_flags(struct cs_etm_queue *etmq)
* Otherwise, exception is caused by trap, instruction & * Otherwise, exception is caused by trap, instruction &
* data fault, or alignment errors. * data fault, or alignment errors.
*/ */
else if (cs_etm__is_sync_exception(etmq, magic)) else if (cs_etm__is_sync_exception(etmq, tidq, magic))
packet->flags = PERF_IP_FLAG_BRANCH | packet->flags = PERF_IP_FLAG_BRANCH |
PERF_IP_FLAG_CALL | PERF_IP_FLAG_CALL |
PERF_IP_FLAG_INTERRUPT; PERF_IP_FLAG_INTERRUPT;
...@@ -1571,17 +1643,18 @@ static int cs_etm__decode_data_block(struct cs_etm_queue *etmq) ...@@ -1571,17 +1643,18 @@ static int cs_etm__decode_data_block(struct cs_etm_queue *etmq)
return ret; return ret;
} }
static int cs_etm__process_decoder_queue(struct cs_etm_queue *etmq) static int cs_etm__process_traceid_queue(struct cs_etm_queue *etmq,
struct cs_etm_traceid_queue *tidq)
{ {
int ret; int ret;
struct cs_etm_packet_queue *packet_queue; struct cs_etm_packet_queue *packet_queue;
packet_queue = cs_etm__etmq_get_packet_queue(etmq); packet_queue = &tidq->packet_queue;
/* Process each packet in this chunk */ /* Process each packet in this chunk */
while (1) { while (1) {
ret = cs_etm_decoder__get_packet(packet_queue, ret = cs_etm_decoder__get_packet(packet_queue,
etmq->packet); tidq->packet);
if (ret <= 0) if (ret <= 0)
/* /*
* Stop processing this chunk on * Stop processing this chunk on
...@@ -1596,18 +1669,18 @@ static int cs_etm__process_decoder_queue(struct cs_etm_queue *etmq) ...@@ -1596,18 +1669,18 @@ static int cs_etm__process_decoder_queue(struct cs_etm_queue *etmq)
* prior to switch() statement to use address * prior to switch() statement to use address
* information before packets swapping. * information before packets swapping.
*/ */
ret = cs_etm__set_sample_flags(etmq); ret = cs_etm__set_sample_flags(etmq, tidq);
if (ret < 0) if (ret < 0)
break; break;
switch (etmq->packet->sample_type) { switch (tidq->packet->sample_type) {
case CS_ETM_RANGE: case CS_ETM_RANGE:
/* /*
* If the packet contains an instruction * If the packet contains an instruction
* range, generate instruction sequence * range, generate instruction sequence
* events. * events.
*/ */
cs_etm__sample(etmq); cs_etm__sample(etmq, tidq);
break; break;
case CS_ETM_EXCEPTION: case CS_ETM_EXCEPTION:
case CS_ETM_EXCEPTION_RET: case CS_ETM_EXCEPTION_RET:
...@@ -1616,14 +1689,14 @@ static int cs_etm__process_decoder_queue(struct cs_etm_queue *etmq) ...@@ -1616,14 +1689,14 @@ static int cs_etm__process_decoder_queue(struct cs_etm_queue *etmq)
* make sure the previous instruction * make sure the previous instruction
* range packet to be handled properly. * range packet to be handled properly.
*/ */
cs_etm__exception(etmq); cs_etm__exception(tidq);
break; break;
case CS_ETM_DISCONTINUITY: case CS_ETM_DISCONTINUITY:
/* /*
* Discontinuity in trace, flush * Discontinuity in trace, flush
* previous branch stack * previous branch stack
*/ */
cs_etm__flush(etmq); cs_etm__flush(etmq, tidq);
break; break;
case CS_ETM_EMPTY: case CS_ETM_EMPTY:
/* /*
...@@ -1643,6 +1716,11 @@ static int cs_etm__process_decoder_queue(struct cs_etm_queue *etmq) ...@@ -1643,6 +1716,11 @@ static int cs_etm__process_decoder_queue(struct cs_etm_queue *etmq)
static int cs_etm__run_decoder(struct cs_etm_queue *etmq) static int cs_etm__run_decoder(struct cs_etm_queue *etmq)
{ {
int err = 0; int err = 0;
struct cs_etm_traceid_queue *tidq;
tidq = cs_etm__etmq_get_traceid_queue(etmq, CS_ETM_PER_THREAD_TRACEID);
if (!tidq)
return -EINVAL;
/* Go through each buffer in the queue and decode them one by one */ /* Go through each buffer in the queue and decode them one by one */
while (1) { while (1) {
...@@ -1661,13 +1739,13 @@ static int cs_etm__run_decoder(struct cs_etm_queue *etmq) ...@@ -1661,13 +1739,13 @@ static int cs_etm__run_decoder(struct cs_etm_queue *etmq)
* an error occurs other than hoping the next one will * an error occurs other than hoping the next one will
* be better. * be better.
*/ */
err = cs_etm__process_decoder_queue(etmq); err = cs_etm__process_traceid_queue(etmq, tidq);
} while (etmq->buf_len); } while (etmq->buf_len);
if (err == 0) if (err == 0)
/* Flush any remaining branch stack entries */ /* Flush any remaining branch stack entries */
err = cs_etm__end_block(etmq); err = cs_etm__end_block(etmq, tidq);
} }
return err; return err;
......
...@@ -136,6 +136,16 @@ struct cs_etm_packet { ...@@ -136,6 +136,16 @@ struct cs_etm_packet {
#define CS_ETM_PACKET_MAX_BUFFER 1024 #define CS_ETM_PACKET_MAX_BUFFER 1024
/*
* When working with per-thread scenarios the process under trace can
* be scheduled on any CPU and as such, more than one traceID may be
* associated with the same process. Since a traceID of '0' is illegal
* as per the CoreSight architecture, use that specific value to
* identify the queue where all packets (with any traceID) are
* aggregated.
*/
#define CS_ETM_PER_THREAD_TRACEID 0
struct cs_etm_packet_queue { struct cs_etm_packet_queue {
u32 packet_count; u32 packet_count;
u32 head; u32 head;
...@@ -172,7 +182,7 @@ int cs_etm__process_auxtrace_info(union perf_event *event, ...@@ -172,7 +182,7 @@ int cs_etm__process_auxtrace_info(union perf_event *event,
struct perf_session *session); struct perf_session *session);
int cs_etm__get_cpu(u8 trace_chan_id, int *cpu); int cs_etm__get_cpu(u8 trace_chan_id, int *cpu);
struct cs_etm_packet_queue struct cs_etm_packet_queue
*cs_etm__etmq_get_packet_queue(struct cs_etm_queue *etmq); *cs_etm__etmq_get_packet_queue(struct cs_etm_queue *etmq, u8 trace_chan_id);
#else #else
static inline int static inline int
cs_etm__process_auxtrace_info(union perf_event *event __maybe_unused, cs_etm__process_auxtrace_info(union perf_event *event __maybe_unused,
...@@ -188,7 +198,8 @@ static inline int cs_etm__get_cpu(u8 trace_chan_id __maybe_unused, ...@@ -188,7 +198,8 @@ static inline int cs_etm__get_cpu(u8 trace_chan_id __maybe_unused,
} }
static inline struct cs_etm_packet_queue *cs_etm__etmq_get_packet_queue( static inline struct cs_etm_packet_queue *cs_etm__etmq_get_packet_queue(
struct cs_etm_queue *etmq __maybe_unused) struct cs_etm_queue *etmq __maybe_unused,
u8 trace_chan_id __maybe_unused)
{ {
return NULL; return NULL;
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册