]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - tools/perf/util/cs-etm.c
perf cs-etm: Move thread to traceid_queue
[linux.git] / tools / perf / util / cs-etm.c
index de488b43f440ff03517cfe841835479f72815271..0d51d6d9a594e721cb94dc923b284aa0ece573b8 100644 (file)
@@ -60,24 +60,29 @@ struct cs_etm_auxtrace {
        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 thread *thread;
+       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_auxtrace *etm;
-       struct thread *thread;
        struct cs_etm_decoder *decoder;
        struct auxtrace_buffer *buffer;
-       union perf_event *event_buf;
        unsigned int queue_nr;
        pid_t pid, tid;
-       int cpu;
        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;
        size_t buf_len, buf_used;
+       struct cs_etm_traceid_queue *traceid_queues;
 };
 
 static int cs_etm__update_queues(struct cs_etm_auxtrace *etm);
@@ -125,6 +130,122 @@ int cs_etm__get_cpu(u8 trace_chan_id, int *cpu)
        return 0;
 }
 
+static void cs_etm__clear_packet_queue(struct cs_etm_packet_queue *queue)
+{
+       int i;
+
+       queue->head = 0;
+       queue->tail = 0;
+       queue->packet_count = 0;
+       for (i = 0; i < CS_ETM_PACKET_MAX_BUFFER; i++) {
+               queue->packet_buffer[i].isa = CS_ETM_ISA_UNKNOWN;
+               queue->packet_buffer[i].start_addr = CS_ETM_INVAL_ADDR;
+               queue->packet_buffer[i].end_addr = CS_ETM_INVAL_ADDR;
+               queue->packet_buffer[i].instr_count = 0;
+               queue->packet_buffer[i].last_instr_taken_branch = false;
+               queue->packet_buffer[i].last_instr_size = 0;
+               queue->packet_buffer[i].last_instr_type = 0;
+               queue->packet_buffer[i].last_instr_subtype = 0;
+               queue->packet_buffer[i].last_instr_cond = 0;
+               queue->packet_buffer[i].flags = 0;
+               queue->packet_buffer[i].exception_number = UINT32_MAX;
+               queue->packet_buffer[i].trace_chan_id = UINT8_MAX;
+               queue->packet_buffer[i].cpu = INT_MIN;
+       }
+}
+
+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
+*cs_etm__etmq_get_packet_queue(struct cs_etm_queue *etmq, u8 trace_chan_id)
+{
+       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)
 {
        const char *color = PERF_COLOR_BLUE;
@@ -294,13 +415,14 @@ static void cs_etm__free_queue(void *priv)
        if (!etmq)
                return;
 
-       thread__zput(etmq->thread);
+       thread__zput(etmq->traceid_queues->thread);
        cs_etm_decoder__free(etmq->decoder);
-       zfree(&etmq->event_buf);
-       zfree(&etmq->last_branch);
-       zfree(&etmq->last_branch_rb);
-       zfree(&etmq->prev_packet);
-       zfree(&etmq->packet);
+       zfree(&etmq->traceid_queues->event_buf);
+       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);
 }
 
@@ -381,7 +503,7 @@ static u32 cs_etm__mem_access(struct cs_etm_queue *etmq, u64 address,
        machine = etmq->etm->machine;
        cpumode = cs_etm__cpu_mode(etmq, address);
 
-       thread = etmq->thread;
+       thread = etmq->traceid_queues->thread;
        if (!thread) {
                if (cpumode != PERF_RECORD_MISC_KERNEL)
                        return 0;
@@ -412,37 +534,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_trace_params  *t_params = NULL;
        struct cs_etm_queue *etmq;
-       size_t szp = sizeof(struct cs_etm_packet);
 
        etmq = zalloc(sizeof(*etmq));
        if (!etmq)
                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 */
        t_params = zalloc(sizeof(*t_params) * etm->num_cpu);
 
@@ -477,12 +573,6 @@ static struct cs_etm_queue *cs_etm__alloc_queue(struct cs_etm_auxtrace *etm)
 out_free_decoder:
        cs_etm_decoder__free(etmq->decoder);
 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);
 
        return NULL;
@@ -508,11 +598,9 @@ static int cs_etm__setup_queue(struct cs_etm_auxtrace *etm,
        queue->priv = etmq;
        etmq->etm = etm;
        etmq->queue_nr = queue_nr;
-       etmq->cpu = queue->cpu;
        etmq->tid = queue->tid;
        etmq->pid = -1;
        etmq->offset = 0;
-       etmq->period_instructions = 0;
 
 out:
        return ret;
@@ -545,10 +633,12 @@ static int cs_etm__update_queues(struct cs_etm_auxtrace *etm)
        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_dst = etmq->last_branch;
+       struct branch_stack *bs_src = tidq->last_branch_rb;
+       struct branch_stack *bs_dst = tidq->last_branch;
        size_t nr = 0;
 
        /*
@@ -568,9 +658,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
         * 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],
-              &bs_src->entries[etmq->last_branch_pos],
+              &bs_src->entries[tidq->last_branch_pos],
               sizeof(struct branch_entry) * nr);
 
        /*
@@ -583,14 +673,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) {
                memcpy(&bs_dst->entries[nr],
                       &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;
-       etmq->last_branch_rb->nr = 0;
+       tidq->last_branch_pos = 0;
+       tidq->last_branch_rb->nr = 0;
 }
 
 static inline int cs_etm__t32_instr_size(struct cs_etm_queue *etmq,
@@ -643,9 +734,10 @@ static inline u64 cs_etm__instr_addr(struct cs_etm_queue *etmq,
        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;
 
        /*
@@ -654,14 +746,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
         * insert position back to the end of the buffer.
         */
-       if (!etmq->last_branch_pos)
-               etmq->last_branch_pos = etmq->etm->synth_opts.last_branch_sz;
+       if (!tidq->last_branch_pos)
+               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->from = cs_etm__last_executed_instr(etmq->prev_packet);
-       be->to   = cs_etm__first_executed_instr(etmq->packet);
+       be       = &bs->entries[tidq->last_branch_pos];
+       be->from = cs_etm__last_executed_instr(tidq->prev_packet);
+       be->to   = cs_etm__first_executed_instr(tidq->packet);
        /* No support for mispredict */
        be->flags.mispred = 0;
        be->flags.predicted = 1;
@@ -727,29 +819,30 @@ cs_etm__get_trace(struct cs_etm_queue *etmq)
 static void cs_etm__set_pid_tid_cpu(struct cs_etm_auxtrace *etm,
                                    struct auxtrace_queue *queue)
 {
+       struct cs_etm_traceid_queue *tidq;
        struct cs_etm_queue *etmq = queue->priv;
 
+       tidq = cs_etm__etmq_get_traceid_queue(etmq, CS_ETM_PER_THREAD_TRACEID);
+
        /* CPU-wide tracing isn't supported yet */
        if (queue->tid == -1)
                return;
 
-       if ((!etmq->thread) && (etmq->tid != -1))
-               etmq->thread = machine__find_thread(etm->machine, -1,
+       if ((!tidq->thread) && (etmq->tid != -1))
+               tidq->thread = machine__find_thread(etm->machine, -1,
                                                    etmq->tid);
 
-       if (etmq->thread) {
-               etmq->pid = etmq->thread->pid_;
-               if (queue->cpu == -1)
-                       etmq->cpu = etmq->thread->cpu;
-       }
+       if (tidq->thread)
+               etmq->pid = tidq->thread->pid_;
 }
 
 static int cs_etm__synth_instruction_sample(struct cs_etm_queue *etmq,
+                                           struct cs_etm_traceid_queue *tidq,
                                            u64 addr, u64 period)
 {
        int ret = 0;
        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,};
 
        event->sample.header.type = PERF_RECORD_SAMPLE;
@@ -762,14 +855,14 @@ static int cs_etm__synth_instruction_sample(struct cs_etm_queue *etmq,
        sample.id = etmq->etm->instructions_id;
        sample.stream_id = etmq->etm->instructions_id;
        sample.period = period;
-       sample.cpu = etmq->packet->cpu;
-       sample.flags = etmq->prev_packet->flags;
+       sample.cpu = tidq->packet->cpu;
+       sample.flags = tidq->prev_packet->flags;
        sample.insn_len = 1;
        sample.cpumode = event->sample.header.misc;
 
        if (etm->synth_opts.last_branch) {
-               cs_etm__copy_last_branch_rb(etmq);
-               sample.branch_stack = etmq->last_branch;
+               cs_etm__copy_last_branch_rb(etmq, tidq);
+               sample.branch_stack = tidq->last_branch;
        }
 
        if (etm->synth_opts.inject) {
@@ -787,7 +880,7 @@ static int cs_etm__synth_instruction_sample(struct cs_etm_queue *etmq,
                        ret);
 
        if (etm->synth_opts.last_branch)
-               cs_etm__reset_last_branch_rb(etmq);
+               cs_etm__reset_last_branch_rb(tidq);
 
        return ret;
 }
@@ -796,19 +889,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
  * 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;
        struct cs_etm_auxtrace *etm = etmq->etm;
        struct perf_sample sample = {.ip = 0,};
-       union perf_event *event = etmq->event_buf;
+       union perf_event *event = tidq->event_buf;
        struct dummy_branch_stack {
                u64                     nr;
                struct branch_entry     entries;
        } dummy_bs;
        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.misc = cs_etm__cpu_mode(etmq, ip);
@@ -817,12 +911,12 @@ static int cs_etm__synth_branch_sample(struct cs_etm_queue *etmq)
        sample.ip = ip;
        sample.pid = etmq->pid;
        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.stream_id = etmq->etm->branches_id;
        sample.period = 1;
-       sample.cpu = etmq->packet->cpu;
-       sample.flags = etmq->prev_packet->flags;
+       sample.cpu = tidq->packet->cpu;
+       sample.flags = tidq->prev_packet->flags;
        sample.cpumode = event->sample.header.misc;
 
        /*
@@ -965,33 +1059,34 @@ static int cs_etm__synth_events(struct cs_etm_auxtrace *etm,
        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_packet *tmp;
        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
         * PREV_PACKET is a branch.
         */
        if (etm->synth_opts.last_branch &&
-           etmq->prev_packet->sample_type == CS_ETM_RANGE &&
-           etmq->prev_packet->last_instr_taken_branch)
-               cs_etm__update_last_branch_rb(etmq);
+           tidq->prev_packet->sample_type == CS_ETM_RANGE &&
+           tidq->prev_packet->last_instr_taken_branch)
+               cs_etm__update_last_branch_rb(etmq, tidq);
 
        if (etm->sample_instructions &&
-           etmq->period_instructions >= etm->instructions_sample_period) {
+           tidq->period_instructions >= etm->instructions_sample_period) {
                /*
                 * Emit instruction sample periodically
                 * TODO: allow period to be defined in cycles and clock time
                 */
 
                /* 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;
 
                /*
@@ -1000,31 +1095,31 @@ static int cs_etm__sample(struct cs_etm_queue *etmq)
                 * executed, but PC has not advanced to next instruction)
                 */
                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(
-                       etmq, addr, etm->instructions_sample_period);
+                       etmq, tidq, addr, etm->instructions_sample_period);
                if (ret)
                        return ret;
 
                /* Carry remaining instructions into next sample period */
-               etmq->period_instructions = instrs_over;
+               tidq->period_instructions = instrs_over;
        }
 
        if (etm->sample_branches) {
                bool generate_sample = false;
 
                /* 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 for branch taken packet */
-               if (etmq->prev_packet->sample_type == CS_ETM_RANGE &&
-                   etmq->prev_packet->last_instr_taken_branch)
+               if (tidq->prev_packet->sample_type == CS_ETM_RANGE &&
+                   tidq->prev_packet->last_instr_taken_branch)
                        generate_sample = true;
 
                if (generate_sample) {
-                       ret = cs_etm__synth_branch_sample(etmq);
+                       ret = cs_etm__synth_branch_sample(etmq, tidq);
                        if (ret)
                                return ret;
                }
@@ -1035,15 +1130,15 @@ static int cs_etm__sample(struct cs_etm_queue *etmq)
                 * Swap PACKET with PREV_PACKET: PACKET becomes PREV_PACKET for
                 * the next incoming packet.
                 */
-               tmp = etmq->packet;
-               etmq->packet = etmq->prev_packet;
-               etmq->prev_packet = tmp;
+               tmp = tidq->packet;
+               tidq->packet = tidq->prev_packet;
+               tidq->prev_packet = tmp;
        }
 
        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
@@ -1056,24 +1151,25 @@ static int cs_etm__exception(struct cs_etm_queue *etmq)
         * swap PACKET with PREV_PACKET.  This keeps PREV_PACKET to be useful
         * for generating instruction and branch samples.
         */
-       if (etmq->prev_packet->sample_type == CS_ETM_RANGE)
-               etmq->prev_packet->last_instr_taken_branch = true;
+       if (tidq->prev_packet->sample_type == CS_ETM_RANGE)
+               tidq->prev_packet->last_instr_taken_branch = true;
 
        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;
        struct cs_etm_auxtrace *etm = etmq->etm;
        struct cs_etm_packet *tmp;
 
        /* 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;
 
        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
                 * circular buffer at the end of the trace.
@@ -1081,21 +1177,21 @@ static int cs_etm__flush(struct cs_etm_queue *etmq)
                 * Use the address of the end of the last reported execution
                 * 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(
-                       etmq, addr,
-                       etmq->period_instructions);
+                       etmq, tidq, addr,
+                       tidq->period_instructions);
                if (err)
                        return err;
 
-               etmq->period_instructions = 0;
+               tidq->period_instructions = 0;
 
        }
 
        if (etm->sample_branches &&
-           etmq->prev_packet->sample_type == CS_ETM_RANGE) {
-               err = cs_etm__synth_branch_sample(etmq);
+           tidq->prev_packet->sample_type == CS_ETM_RANGE) {
+               err = cs_etm__synth_branch_sample(etmq, tidq);
                if (err)
                        return err;
        }
@@ -1106,15 +1202,16 @@ static int cs_etm__flush(struct cs_etm_queue *etmq)
                 * Swap PACKET with PREV_PACKET: PACKET becomes PREV_PACKET for
                 * the next incoming packet.
                 */
-               tmp = etmq->packet;
-               etmq->packet = etmq->prev_packet;
-               etmq->prev_packet = tmp;
+               tmp = tidq->packet;
+               tidq->packet = tidq->prev_packet;
+               tidq->prev_packet = tmp;
        }
 
        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;
 
@@ -1128,20 +1225,20 @@ static int cs_etm__end_block(struct cs_etm_queue *etmq)
         * the trace.
         */
        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
                 * 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(
-                       etmq, addr,
-                       etmq->period_instructions);
+                       etmq, tidq, addr,
+                       tidq->period_instructions);
                if (err)
                        return err;
 
-               etmq->period_instructions = 0;
+               tidq->period_instructions = 0;
        }
 
        return 0;
@@ -1240,10 +1337,11 @@ static bool cs_etm__is_svc_instr(struct cs_etm_queue *etmq,
        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 *prev_packet = etmq->prev_packet;
+       struct cs_etm_packet *packet = tidq->packet;
+       struct cs_etm_packet *prev_packet = tidq->prev_packet;
 
        if (magic == __perf_cs_etmv3_magic)
                if (packet->exception_number == CS_ETMV3_EXC_SVC)
@@ -1264,9 +1362,10 @@ static bool cs_etm__is_syscall(struct cs_etm_queue *etmq, u64 magic)
        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 (packet->exception_number == CS_ETMV3_EXC_DEBUG_HALT ||
@@ -1289,10 +1388,12 @@ static bool cs_etm__is_async_exception(struct cs_etm_queue *etmq, u64 magic)
        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 *prev_packet = etmq->prev_packet;
+       struct cs_etm_packet *packet = tidq->packet;
+       struct cs_etm_packet *prev_packet = tidq->prev_packet;
 
        if (magic == __perf_cs_etmv3_magic)
                if (packet->exception_number == CS_ETMV3_EXC_SMC ||
@@ -1335,10 +1436,11 @@ static bool cs_etm__is_sync_exception(struct cs_etm_queue *etmq, u64 magic)
        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 *prev_packet = etmq->prev_packet;
+       struct cs_etm_packet *packet = tidq->packet;
+       struct cs_etm_packet *prev_packet = tidq->prev_packet;
        u64 magic;
        int ret;
 
@@ -1440,7 +1542,7 @@ static int cs_etm__set_sample_flags(struct cs_etm_queue *etmq)
                        return ret;
 
                /* 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 |
                                        PERF_IP_FLAG_CALL |
                                        PERF_IP_FLAG_SYSCALLRET;
@@ -1448,7 +1550,7 @@ static int cs_etm__set_sample_flags(struct cs_etm_queue *etmq)
                 * The exceptions are triggered by external signals from bus,
                 * 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 |
                                        PERF_IP_FLAG_CALL |
                                        PERF_IP_FLAG_ASYNC |
@@ -1457,7 +1559,7 @@ static int cs_etm__set_sample_flags(struct cs_etm_queue *etmq)
                 * Otherwise, exception is caused by trap, instruction &
                 * 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 |
                                        PERF_IP_FLAG_CALL |
                                        PERF_IP_FLAG_INTERRUPT;
@@ -1539,68 +1641,72 @@ static int cs_etm__decode_data_block(struct cs_etm_queue *etmq)
        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;
+       struct cs_etm_packet_queue *packet_queue;
 
-               /* Process each packet in this chunk */
-               while (1) {
-                       ret = cs_etm_decoder__get_packet(etmq->decoder,
-                                                        etmq->packet);
-                       if (ret <= 0)
-                               /*
-                                * Stop processing this chunk on
-                                * end of data or error
-                                */
-                               break;
+       packet_queue = &tidq->packet_queue;
 
+       /* Process each packet in this chunk */
+       while (1) {
+               ret = cs_etm_decoder__get_packet(packet_queue,
+                                                tidq->packet);
+               if (ret <= 0)
                        /*
-                        * Since packet addresses are swapped in packet
-                        * handling within below switch() statements,
-                        * thus setting sample flags must be called
-                        * prior to switch() statement to use address
-                        * information before packets swapping.
+                        * Stop processing this chunk on
+                        * end of data or error
                         */
-                       ret = cs_etm__set_sample_flags(etmq);
-                       if (ret < 0)
-                               break;
-
-                       switch (etmq->packet->sample_type) {
-                       case CS_ETM_RANGE:
-                               /*
-                                * If the packet contains an instruction
-                                * range, generate instruction sequence
-                                * events.
-                                */
-                               cs_etm__sample(etmq);
-                               break;
-                       case CS_ETM_EXCEPTION:
-                       case CS_ETM_EXCEPTION_RET:
-                               /*
-                                * If the exception packet is coming,
-                                * make sure the previous instruction
-                                * range packet to be handled properly.
-                                */
-                               cs_etm__exception(etmq);
-                               break;
-                       case CS_ETM_DISCONTINUITY:
-                               /*
-                                * Discontinuity in trace, flush
-                                * previous branch stack
-                                */
-                               cs_etm__flush(etmq);
-                               break;
-                       case CS_ETM_EMPTY:
-                               /*
-                                * Should not receive empty packet,
-                                * report error.
-                                */
-                               pr_err("CS ETM Trace: empty packet\n");
-                               return -EINVAL;
-                       default:
-                               break;
-                       }
+                       break;
+
+               /*
+                * Since packet addresses are swapped in packet
+                * handling within below switch() statements,
+                * thus setting sample flags must be called
+                * prior to switch() statement to use address
+                * information before packets swapping.
+                */
+               ret = cs_etm__set_sample_flags(etmq, tidq);
+               if (ret < 0)
+                       break;
+
+               switch (tidq->packet->sample_type) {
+               case CS_ETM_RANGE:
+                       /*
+                        * If the packet contains an instruction
+                        * range, generate instruction sequence
+                        * events.
+                        */
+                       cs_etm__sample(etmq, tidq);
+                       break;
+               case CS_ETM_EXCEPTION:
+               case CS_ETM_EXCEPTION_RET:
+                       /*
+                        * If the exception packet is coming,
+                        * make sure the previous instruction
+                        * range packet to be handled properly.
+                        */
+                       cs_etm__exception(tidq);
+                       break;
+               case CS_ETM_DISCONTINUITY:
+                       /*
+                        * Discontinuity in trace, flush
+                        * previous branch stack
+                        */
+                       cs_etm__flush(etmq, tidq);
+                       break;
+               case CS_ETM_EMPTY:
+                       /*
+                        * Should not receive empty packet,
+                        * report error.
+                        */
+                       pr_err("CS ETM Trace: empty packet\n");
+                       return -EINVAL;
+               default:
+                       break;
                }
+       }
 
        return ret;
 }
@@ -1608,6 +1714,11 @@ static int cs_etm__process_decoder_queue(struct cs_etm_queue *etmq)
 static int cs_etm__run_decoder(struct cs_etm_queue *etmq)
 {
        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 */
        while (1) {
@@ -1626,13 +1737,13 @@ static int cs_etm__run_decoder(struct cs_etm_queue *etmq)
                         * an error occurs other than hoping the next one will
                         * be better.
                         */
-                       err = cs_etm__process_decoder_queue(etmq);
+                       err = cs_etm__process_traceid_queue(etmq, tidq);
 
                } while (etmq->buf_len);
 
                if (err == 0)
                        /* Flush any remaining branch stack entries */
-                       err = cs_etm__end_block(etmq);
+                       err = cs_etm__end_block(etmq, tidq);
        }
 
        return err;
@@ -1657,6 +1768,65 @@ static int cs_etm__process_timeless_queues(struct cs_etm_auxtrace *etm,
        return 0;
 }
 
+static int cs_etm__process_itrace_start(struct cs_etm_auxtrace *etm,
+                                       union perf_event *event)
+{
+       struct thread *th;
+
+       if (etm->timeless_decoding)
+               return 0;
+
+       /*
+        * Add the tid/pid to the log so that we can get a match when
+        * we get a contextID from the decoder.
+        */
+       th = machine__findnew_thread(etm->machine,
+                                    event->itrace_start.pid,
+                                    event->itrace_start.tid);
+       if (!th)
+               return -ENOMEM;
+
+       thread__put(th);
+
+       return 0;
+}
+
+static int cs_etm__process_switch_cpu_wide(struct cs_etm_auxtrace *etm,
+                                          union perf_event *event)
+{
+       struct thread *th;
+       bool out = event->header.misc & PERF_RECORD_MISC_SWITCH_OUT;
+
+       /*
+        * Context switch in per-thread mode are irrelevant since perf
+        * will start/stop tracing as the process is scheduled.
+        */
+       if (etm->timeless_decoding)
+               return 0;
+
+       /*
+        * SWITCH_IN events carry the next process to be switched out while
+        * SWITCH_OUT events carry the process to be switched in.  As such
+        * we don't care about IN events.
+        */
+       if (!out)
+               return 0;
+
+       /*
+        * Add the tid/pid to the log so that we can get a match when
+        * we get a contextID from the decoder.
+        */
+       th = machine__findnew_thread(etm->machine,
+                                    event->context_switch.next_prev_pid,
+                                    event->context_switch.next_prev_tid);
+       if (!th)
+               return -ENOMEM;
+
+       thread__put(th);
+
+       return 0;
+}
+
 static int cs_etm__process_event(struct perf_session *session,
                                 union perf_event *event,
                                 struct perf_sample *sample,
@@ -1694,6 +1864,11 @@ static int cs_etm__process_event(struct perf_session *session,
                return cs_etm__process_timeless_queues(etm,
                                                       event->fork.tid);
 
+       if (event->header.type == PERF_RECORD_ITRACE_START)
+               return cs_etm__process_itrace_start(etm, event);
+       else if (event->header.type == PERF_RECORD_SWITCH_CPU_WIDE)
+               return cs_etm__process_switch_cpu_wide(etm, event);
+
        return 0;
 }