Merge remote-tracking branch 'torvalds/master' into perf/core
[linux-2.6-microblaze.git] / tools / perf / util / cs-etm.c
index 7e63e7d..64536a6 100644 (file)
@@ -38,8 +38,6 @@
 #include <tools/libc_compat.h>
 #include "util/synthetic-events.h"
 
-#define MAX_TIMESTAMP (~0ULL)
-
 struct cs_etm_auxtrace {
        struct auxtrace auxtrace;
        struct auxtrace_queues queues;
@@ -56,6 +54,7 @@ struct cs_etm_auxtrace {
        u8 sample_instructions;
 
        int num_cpu;
+       u64 latest_kernel_timestamp;
        u32 auxtrace_type;
        u64 branches_sample_type;
        u64 branches_id;
@@ -86,7 +85,7 @@ struct cs_etm_queue {
        struct cs_etm_decoder *decoder;
        struct auxtrace_buffer *buffer;
        unsigned int queue_nr;
-       u8 pending_timestamp;
+       u8 pending_timestamp_chan_id;
        u64 offset;
        const unsigned char *buf;
        size_t buf_len, buf_used;
@@ -208,7 +207,7 @@ void cs_etm__etmq_set_traceid_queue_timestamp(struct cs_etm_queue *etmq,
         * be more than one channel per cs_etm_queue, we need to specify
         * what traceID queue needs servicing.
         */
-       etmq->pending_timestamp = trace_chan_id;
+       etmq->pending_timestamp_chan_id = trace_chan_id;
 }
 
 static u64 cs_etm__etmq_get_timestamp(struct cs_etm_queue *etmq,
@@ -216,22 +215,22 @@ static u64 cs_etm__etmq_get_timestamp(struct cs_etm_queue *etmq,
 {
        struct cs_etm_packet_queue *packet_queue;
 
-       if (!etmq->pending_timestamp)
+       if (!etmq->pending_timestamp_chan_id)
                return 0;
 
        if (trace_chan_id)
-               *trace_chan_id = etmq->pending_timestamp;
+               *trace_chan_id = etmq->pending_timestamp_chan_id;
 
        packet_queue = cs_etm__etmq_get_packet_queue(etmq,
-                                                    etmq->pending_timestamp);
+                                                    etmq->pending_timestamp_chan_id);
        if (!packet_queue)
                return 0;
 
        /* Acknowledge pending status */
-       etmq->pending_timestamp = 0;
+       etmq->pending_timestamp_chan_id = 0;
 
        /* See function cs_etm_decoder__do_{hard|soft}_timestamp() */
-       return packet_queue->timestamp;
+       return packet_queue->cs_timestamp;
 }
 
 static void cs_etm__clear_packet_queue(struct cs_etm_packet_queue *queue)
@@ -814,7 +813,7 @@ static int cs_etm__setup_queue(struct cs_etm_auxtrace *etm,
        int ret = 0;
        unsigned int cs_queue_nr;
        u8 trace_chan_id;
-       u64 timestamp;
+       u64 cs_timestamp;
        struct cs_etm_queue *etmq = queue->priv;
 
        if (list_empty(&queue->head) || etmq)
@@ -854,7 +853,7 @@ static int cs_etm__setup_queue(struct cs_etm_auxtrace *etm,
 
                /*
                 * Run decoder on the trace block.  The decoder will stop when
-                * encountering a timestamp, a full packet queue or the end of
+                * encountering a CS timestamp, a full packet queue or the end of
                 * trace for that block.
                 */
                ret = cs_etm__decode_data_block(etmq);
@@ -865,10 +864,10 @@ static int cs_etm__setup_queue(struct cs_etm_auxtrace *etm,
                 * Function cs_etm_decoder__do_{hard|soft}_timestamp() does all
                 * the timestamp calculation for us.
                 */
-               timestamp = cs_etm__etmq_get_timestamp(etmq, &trace_chan_id);
+               cs_timestamp = cs_etm__etmq_get_timestamp(etmq, &trace_chan_id);
 
                /* We found a timestamp, no need to continue. */
-               if (timestamp)
+               if (cs_timestamp)
                        break;
 
                /*
@@ -892,7 +891,7 @@ static int cs_etm__setup_queue(struct cs_etm_auxtrace *etm,
         * queue and will be processed in cs_etm__process_queues().
         */
        cs_queue_nr = TO_CS_QUEUE_NR(queue_nr, trace_chan_id);
-       ret = auxtrace_heap__add(&etm->heap, cs_queue_nr, timestamp);
+       ret = auxtrace_heap__add(&etm->heap, cs_queue_nr, cs_timestamp);
 out:
        return ret;
 }
@@ -1194,6 +1193,8 @@ static int cs_etm__synth_instruction_sample(struct cs_etm_queue *etmq,
        event->sample.header.misc = cs_etm__cpu_mode(etmq, addr);
        event->sample.header.size = sizeof(struct perf_event_header);
 
+       if (!etm->timeless_decoding)
+               sample.time = etm->latest_kernel_timestamp;
        sample.ip = addr;
        sample.pid = tidq->pid;
        sample.tid = tidq->tid;
@@ -1250,6 +1251,8 @@ static int cs_etm__synth_branch_sample(struct cs_etm_queue *etmq,
        event->sample.header.misc = cs_etm__cpu_mode(etmq, ip);
        event->sample.header.size = sizeof(struct perf_event_header);
 
+       if (!etm->timeless_decoding)
+               sample.time = etm->latest_kernel_timestamp;
        sample.ip = ip;
        sample.pid = tidq->pid;
        sample.tid = tidq->tid;
@@ -2221,7 +2224,7 @@ static int cs_etm__process_queues(struct cs_etm_auxtrace *etm)
        int ret = 0;
        unsigned int cs_queue_nr, queue_nr;
        u8 trace_chan_id;
-       u64 timestamp;
+       u64 cs_timestamp;
        struct auxtrace_queue *queue;
        struct cs_etm_queue *etmq;
        struct cs_etm_traceid_queue *tidq;
@@ -2283,9 +2286,9 @@ refetch:
                if (ret)
                        goto out;
 
-               timestamp = cs_etm__etmq_get_timestamp(etmq, &trace_chan_id);
+               cs_timestamp = cs_etm__etmq_get_timestamp(etmq, &trace_chan_id);
 
-               if (!timestamp) {
+               if (!cs_timestamp) {
                        /*
                         * Function cs_etm__decode_data_block() returns when
                         * there is no more traces to decode in the current
@@ -2308,7 +2311,7 @@ refetch:
                 * this queue/traceID.
                 */
                cs_queue_nr = TO_CS_QUEUE_NR(queue_nr, trace_chan_id);
-               ret = auxtrace_heap__add(&etm->heap, cs_queue_nr, timestamp);
+               ret = auxtrace_heap__add(&etm->heap, cs_queue_nr, cs_timestamp);
        }
 
 out:
@@ -2380,7 +2383,7 @@ static int cs_etm__process_event(struct perf_session *session,
                                 struct perf_tool *tool)
 {
        int err = 0;
-       u64 timestamp;
+       u64 sample_kernel_timestamp;
        struct cs_etm_auxtrace *etm = container_of(session->auxtrace,
                                                   struct cs_etm_auxtrace,
                                                   auxtrace);
@@ -2394,11 +2397,11 @@ static int cs_etm__process_event(struct perf_session *session,
        }
 
        if (sample->time && (sample->time != (u64) -1))
-               timestamp = sample->time;
+               sample_kernel_timestamp = sample->time;
        else
-               timestamp = 0;
+               sample_kernel_timestamp = 0;
 
-       if (timestamp || etm->timeless_decoding) {
+       if (sample_kernel_timestamp || etm->timeless_decoding) {
                err = cs_etm__update_queues(etm);
                if (err)
                        return err;
@@ -2414,9 +2417,15 @@ static int cs_etm__process_event(struct perf_session *session,
        else if (event->header.type == PERF_RECORD_SWITCH_CPU_WIDE)
                return cs_etm__process_switch_cpu_wide(etm, event);
 
-       if (!etm->timeless_decoding &&
-           event->header.type == PERF_RECORD_AUX)
+       if (!etm->timeless_decoding && event->header.type == PERF_RECORD_AUX) {
+               /*
+                * Record the latest kernel timestamp available in the header
+                * for samples so that synthesised samples occur from this point
+                * onwards.
+                */
+               etm->latest_kernel_timestamp = sample_kernel_timestamp;
                return cs_etm__process_queues(etm);
+       }
 
        return 0;
 }
@@ -2464,6 +2473,10 @@ static bool cs_etm__is_timeless_decoding(struct cs_etm_auxtrace *etm)
        struct evlist *evlist = etm->session->evlist;
        bool timeless_decoding = true;
 
+       /* Override timeless mode with user input from --itrace=Z */
+       if (etm->synth_opts.timeless_decoding)
+               return true;
+
        /*
         * Circle through the list of event and complain if we find one
         * with the time bit set.
@@ -2810,6 +2823,14 @@ int cs_etm__process_auxtrace_info(union perf_event *event,
        if (err)
                goto err_free_etm;
 
+       if (session->itrace_synth_opts->set) {
+               etm->synth_opts = *session->itrace_synth_opts;
+       } else {
+               itrace_synth_opts__set_default(&etm->synth_opts,
+                               session->itrace_synth_opts->default_no_sample);
+               etm->synth_opts.callchain = false;
+       }
+
        etm->session = session;
        etm->machine = &session->machines.host;
 
@@ -2854,14 +2875,6 @@ int cs_etm__process_auxtrace_info(union perf_event *event,
                return 0;
        }
 
-       if (session->itrace_synth_opts->set) {
-               etm->synth_opts = *session->itrace_synth_opts;
-       } else {
-               itrace_synth_opts__set_default(&etm->synth_opts,
-                               session->itrace_synth_opts->default_no_sample);
-               etm->synth_opts.callchain = false;
-       }
-
        err = cs_etm__synth_events(etm, session);
        if (err)
                goto err_delete_thread;