All of lore.kernel.org
 help / color / mirror / Atom feed
From: tip-bot for Mathieu Poirier <tipbot@zytor.com>
To: linux-tip-commits@vger.kernel.org
Cc: peterz@infradead.org, suzuki.poulose@arm.com,
	mathieu.poirier@linaro.org, jolsa@redhat.com,
	namhyung@kernel.org, acme@redhat.com, leo.yan@linaro.org,
	linux-kernel@vger.kernel.org, alexander.shishkin@linux.intel.com,
	mingo@kernel.org, hpa@zytor.com, tglx@linutronix.de
Subject: [tip:perf/core] perf cs-etm: Add support for CPU-wide trace scenarios
Date: Mon, 17 Jun 2019 12:31:20 -0700	[thread overview]
Message-ID: <tip-21fe8dc1191a1528f6732e471f45d370a5c48045@git.kernel.org> (raw)
In-Reply-To: <20190524173508.29044-18-mathieu.poirier@linaro.org>

Commit-ID:  21fe8dc1191a1528f6732e471f45d370a5c48045
Gitweb:     https://git.kernel.org/tip/21fe8dc1191a1528f6732e471f45d370a5c48045
Author:     Mathieu Poirier <mathieu.poirier@linaro.org>
AuthorDate: Fri, 24 May 2019 11:35:08 -0600
Committer:  Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Mon, 10 Jun 2019 15:50:02 -0300

perf cs-etm: Add support for CPU-wide trace scenarios

Add support for CPU-wide trace scenarios by correlating range packets
with timestamp packets.  That way range packets received on different
ETMQ/traceID channels can be processed and synthesized in chronological
order.

Signed-off-by: Mathieu Poirier <mathieu.poirier@linaro.org>
Tested-by: Leo 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-18-mathieu.poirier@linaro.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/util/cs-etm.c | 254 +++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 246 insertions(+), 8 deletions(-)

diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c
index 91496a3a2209..0c7776b51045 100644
--- a/tools/perf/util/cs-etm.c
+++ b/tools/perf/util/cs-etm.c
@@ -90,12 +90,26 @@ struct cs_etm_queue {
 };
 
 static int cs_etm__update_queues(struct cs_etm_auxtrace *etm);
+static int cs_etm__process_queues(struct cs_etm_auxtrace *etm);
 static int cs_etm__process_timeless_queues(struct cs_etm_auxtrace *etm,
 					   pid_t tid);
+static int cs_etm__get_data_block(struct cs_etm_queue *etmq);
+static int cs_etm__decode_data_block(struct cs_etm_queue *etmq);
 
 /* PTMs ETMIDR [11:8] set to b0011 */
 #define ETMIDR_PTM_VERSION 0x00000300
 
+/*
+ * A struct auxtrace_heap_item only has a queue_nr and a timestamp to
+ * work with.  One option is to modify to auxtrace_heap_XYZ() API or simply
+ * encode the etm queue number as the upper 16 bit and the channel as
+ * the lower 16 bit.
+ */
+#define TO_CS_QUEUE_NR(queue_nr, trace_id_chan)	\
+		      (queue_nr << 16 | trace_chan_id)
+#define TO_QUEUE_NR(cs_queue_nr) (cs_queue_nr >> 16)
+#define TO_TRACE_CHAN_ID(cs_queue_nr) (cs_queue_nr & 0x0000ffff)
+
 static u32 cs_etm__get_v7_protocol_version(u32 etmidr)
 {
 	etmidr &= ETMIDR_PTM_VERSION;
@@ -147,6 +161,29 @@ void cs_etm__etmq_set_traceid_queue_timestamp(struct cs_etm_queue *etmq,
 	etmq->pending_timestamp = trace_chan_id;
 }
 
+static u64 cs_etm__etmq_get_timestamp(struct cs_etm_queue *etmq,
+				      u8 *trace_chan_id)
+{
+	struct cs_etm_packet_queue *packet_queue;
+
+	if (!etmq->pending_timestamp)
+		return 0;
+
+	if (trace_chan_id)
+		*trace_chan_id = etmq->pending_timestamp;
+
+	packet_queue = cs_etm__etmq_get_packet_queue(etmq,
+						     etmq->pending_timestamp);
+	if (!packet_queue)
+		return 0;
+
+	/* Acknowledge pending status */
+	etmq->pending_timestamp = 0;
+
+	/* See function cs_etm_decoder__do_{hard|soft}_timestamp() */
+	return packet_queue->timestamp;
+}
+
 static void cs_etm__clear_packet_queue(struct cs_etm_packet_queue *queue)
 {
 	int i;
@@ -171,6 +208,20 @@ static void cs_etm__clear_packet_queue(struct cs_etm_packet_queue *queue)
 	}
 }
 
+static void cs_etm__clear_all_packet_queues(struct cs_etm_queue *etmq)
+{
+	int idx;
+	struct int_node *inode;
+	struct cs_etm_traceid_queue *tidq;
+	struct intlist *traceid_queues_list = etmq->traceid_queues_list;
+
+	intlist__for_each_entry(inode, traceid_queues_list) {
+		idx = (int)(intptr_t)inode->priv;
+		tidq = etmq->traceid_queues[idx];
+		cs_etm__clear_packet_queue(&tidq->packet_queue);
+	}
+}
+
 static int cs_etm__init_traceid_queue(struct cs_etm_queue *etmq,
 				      struct cs_etm_traceid_queue *tidq,
 				      u8 trace_chan_id)
@@ -458,15 +509,15 @@ static int cs_etm__flush_events(struct perf_session *session,
 	if (!tool->ordered_events)
 		return -EINVAL;
 
-	if (!etm->timeless_decoding)
-		return -EINVAL;
-
 	ret = cs_etm__update_queues(etm);
 
 	if (ret < 0)
 		return ret;
 
-	return cs_etm__process_timeless_queues(etm, -1);
+	if (etm->timeless_decoding)
+		return cs_etm__process_timeless_queues(etm, -1);
+
+	return cs_etm__process_queues(etm);
 }
 
 static void cs_etm__free_traceid_queues(struct cs_etm_queue *etmq)
@@ -685,6 +736,9 @@ static int cs_etm__setup_queue(struct cs_etm_auxtrace *etm,
 			       unsigned int queue_nr)
 {
 	int ret = 0;
+	unsigned int cs_queue_nr;
+	u8 trace_chan_id;
+	u64 timestamp;
 	struct cs_etm_queue *etmq = queue->priv;
 
 	if (list_empty(&queue->head) || etmq)
@@ -702,6 +756,67 @@ static int cs_etm__setup_queue(struct cs_etm_auxtrace *etm,
 	etmq->queue_nr = queue_nr;
 	etmq->offset = 0;
 
+	if (etm->timeless_decoding)
+		goto out;
+
+	/*
+	 * We are under a CPU-wide trace scenario.  As such we need to know
+	 * when the code that generated the traces started to execute so that
+	 * it can be correlated with execution on other CPUs.  So we get a
+	 * handle on the beginning of traces and decode until we find a
+	 * timestamp.  The timestamp is then added to the auxtrace min heap
+	 * in order to know what nibble (of all the etmqs) to decode first.
+	 */
+	while (1) {
+		/*
+		 * Fetch an aux_buffer from this etmq.  Bail if no more
+		 * blocks or an error has been encountered.
+		 */
+		ret = cs_etm__get_data_block(etmq);
+		if (ret <= 0)
+			goto out;
+
+		/*
+		 * Run decoder on the trace block.  The decoder will stop when
+		 * encountering a timestamp, a full packet queue or the end of
+		 * trace for that block.
+		 */
+		ret = cs_etm__decode_data_block(etmq);
+		if (ret)
+			goto out;
+
+		/*
+		 * 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);
+
+		/* We found a timestamp, no need to continue. */
+		if (timestamp)
+			break;
+
+		/*
+		 * We didn't find a timestamp so empty all the traceid packet
+		 * queues before looking for another timestamp packet, either
+		 * in the current data block or a new one.  Packets that were
+		 * just decoded are useless since no timestamp has been
+		 * associated with them.  As such simply discard them.
+		 */
+		cs_etm__clear_all_packet_queues(etmq);
+	}
+
+	/*
+	 * We have a timestamp.  Add it to the min heap to reflect when
+	 * instructions conveyed by the range packets of this traceID queue
+	 * started to execute.  Once the same has been done for all the traceID
+	 * queues of each etmq, redenring and decoding can start in
+	 * chronological order.
+	 *
+	 * Note that packets decoded above are still in the traceID's packet
+	 * queue and will be processed in cs_etm__process_queues().
+	 */
+	cs_queue_nr = TO_CS_QUEUE_NR(queue_nr, trace_id_chan);
+	ret = auxtrace_heap__add(&etm->heap, cs_queue_nr, timestamp);
 out:
 	return ret;
 }
@@ -1846,6 +1961,28 @@ static int cs_etm__process_traceid_queue(struct cs_etm_queue *etmq,
 	return ret;
 }
 
+static void cs_etm__clear_all_traceid_queues(struct cs_etm_queue *etmq)
+{
+	int idx;
+	struct int_node *inode;
+	struct cs_etm_traceid_queue *tidq;
+	struct intlist *traceid_queues_list = etmq->traceid_queues_list;
+
+	intlist__for_each_entry(inode, traceid_queues_list) {
+		idx = (int)(intptr_t)inode->priv;
+		tidq = etmq->traceid_queues[idx];
+
+		/* Ignore return value */
+		cs_etm__process_traceid_queue(etmq, tidq);
+
+		/*
+		 * Generate an instruction sample with the remaining
+		 * branchstack entries.
+		 */
+		cs_etm__flush(etmq, tidq);
+	}
+}
+
 static int cs_etm__run_decoder(struct cs_etm_queue *etmq)
 {
 	int err = 0;
@@ -1913,6 +2050,105 @@ static int cs_etm__process_timeless_queues(struct cs_etm_auxtrace *etm,
 	return 0;
 }
 
+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;
+	struct auxtrace_queue *queue;
+	struct cs_etm_queue *etmq;
+	struct cs_etm_traceid_queue *tidq;
+
+	while (1) {
+		if (!etm->heap.heap_cnt)
+			goto out;
+
+		/* Take the entry at the top of the min heap */
+		cs_queue_nr = etm->heap.heap_array[0].queue_nr;
+		queue_nr = TO_QUEUE_NR(cs_queue_nr);
+		trace_chan_id = TO_TRACE_CHAN_ID(cs_queue_nr);
+		queue = &etm->queues.queue_array[queue_nr];
+		etmq = queue->priv;
+
+		/*
+		 * Remove the top entry from the heap since we are about
+		 * to process it.
+		 */
+		auxtrace_heap__pop(&etm->heap);
+
+		tidq  = cs_etm__etmq_get_traceid_queue(etmq, trace_chan_id);
+		if (!tidq) {
+			/*
+			 * No traceID queue has been allocated for this traceID,
+			 * which means something somewhere went very wrong.  No
+			 * other choice than simply exit.
+			 */
+			ret = -EINVAL;
+			goto out;
+		}
+
+		/*
+		 * Packets associated with this timestamp are already in
+		 * the etmq's traceID queue, so process them.
+		 */
+		ret = cs_etm__process_traceid_queue(etmq, tidq);
+		if (ret < 0)
+			goto out;
+
+		/*
+		 * Packets for this timestamp have been processed, time to
+		 * move on to the next timestamp, fetching a new auxtrace_buffer
+		 * if need be.
+		 */
+refetch:
+		ret = cs_etm__get_data_block(etmq);
+		if (ret < 0)
+			goto out;
+
+		/*
+		 * No more auxtrace_buffers to process in this etmq, simply
+		 * move on to another entry in the auxtrace_heap.
+		 */
+		if (!ret)
+			continue;
+
+		ret = cs_etm__decode_data_block(etmq);
+		if (ret)
+			goto out;
+
+		timestamp = cs_etm__etmq_get_timestamp(etmq, &trace_chan_id);
+
+		if (!timestamp) {
+			/*
+			 * Function cs_etm__decode_data_block() returns when
+			 * there is no more traces to decode in the current
+			 * auxtrace_buffer OR when a timestamp has been
+			 * encountered on any of the traceID queues.  Since we
+			 * did not get a timestamp, there is no more traces to
+			 * process in this auxtrace_buffer.  As such empty and
+			 * flush all traceID queues.
+			 */
+			cs_etm__clear_all_traceid_queues(etmq);
+
+			/* Fetch another auxtrace_buffer for this etmq */
+			goto refetch;
+		}
+
+		/*
+		 * Add to the min heap the timestamp for packets that have
+		 * just been decoded.  They will be processed and synthesized
+		 * during the next call to cs_etm__process_traceid_queue() for
+		 * 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);
+	}
+
+out:
+	return ret;
+}
+
 static int cs_etm__process_itrace_start(struct cs_etm_auxtrace *etm,
 					union perf_event *event)
 {
@@ -1991,9 +2227,6 @@ static int cs_etm__process_event(struct perf_session *session,
 		return -EINVAL;
 	}
 
-	if (!etm->timeless_decoding)
-		return -EINVAL;
-
 	if (sample->time && (sample->time != (u64) -1))
 		timestamp = sample->time;
 	else
@@ -2005,7 +2238,8 @@ static int cs_etm__process_event(struct perf_session *session,
 			return err;
 	}
 
-	if (event->header.type == PERF_RECORD_EXIT)
+	if (etm->timeless_decoding &&
+	    event->header.type == PERF_RECORD_EXIT)
 		return cs_etm__process_timeless_queues(etm,
 						       event->fork.tid);
 
@@ -2014,6 +2248,10 @@ 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)
+		return cs_etm__process_queues(etm);
+
 	return 0;
 }
 

  reply	other threads:[~2019-06-17 19:31 UTC|newest]

Thread overview: 74+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-05-24 17:34 [PATCH v2 00/17] perf tools: Coresight: Add CPU-wide trace support Mathieu Poirier
2019-05-24 17:34 ` Mathieu Poirier
2019-05-24 17:34 ` [PATCH v2 01/17] perf tools: Configure contextID tracing in CPU-wide mode Mathieu Poirier
2019-05-24 17:34   ` Mathieu Poirier
2019-06-07  9:21   ` Suzuki K Poulose
2019-06-07  9:21     ` Suzuki K Poulose
2019-06-07 17:40     ` Mathieu Poirier
2019-06-07 17:40       ` Mathieu Poirier
2019-06-07 18:20     ` Arnaldo Carvalho de Melo
2019-06-07 18:20       ` Arnaldo Carvalho de Melo
2019-06-07 19:33       ` Mathieu Poirier
2019-06-07 19:33         ` Mathieu Poirier
2019-06-17 19:36     ` [tip:perf/core] perf cs-etm: Remove duplicate GENMASK() define, use linux/bits.h instead tip-bot for Arnaldo Carvalho de Melo
2019-06-17 19:20   ` [tip:perf/core] perf cs-etm: Configure contextID tracing in CPU-wide mode tip-bot for Mathieu Poirier
2019-05-24 17:34 ` [PATCH v2 02/17] perf tools: Configure timestsamp generation " Mathieu Poirier
2019-05-24 17:34   ` Mathieu Poirier
2019-06-07  9:41   ` Suzuki K Poulose
2019-06-07  9:41     ` Suzuki K Poulose
2019-06-07 17:46     ` Mathieu Poirier
2019-06-07 17:46       ` Mathieu Poirier
2019-06-07 18:34       ` Arnaldo Carvalho de Melo
2019-06-07 18:34         ` Arnaldo Carvalho de Melo
2019-06-17 19:20   ` [tip:perf/core] perf cs-etm: Configure timestamp " tip-bot for Mathieu Poirier
2019-05-24 17:34 ` [PATCH v2 03/17] perf tools: Configure SWITCH_EVENTS " Mathieu Poirier
2019-05-24 17:34   ` Mathieu Poirier
2019-06-17 19:21   ` [tip:perf/core] perf cs-etm: " tip-bot for Mathieu Poirier
2019-05-24 17:34 ` [PATCH v2 04/17] perf tools: Add handling of itrace start events Mathieu Poirier
2019-05-24 17:34   ` Mathieu Poirier
2019-06-17 19:22   ` [tip:perf/core] perf cs-etm: " tip-bot for Mathieu Poirier
2019-05-24 17:34 ` [PATCH v2 05/17] perf tools: Add handling of switch-CPU-wide events Mathieu Poirier
2019-05-24 17:34   ` Mathieu Poirier
2019-06-17 19:22   ` [tip:perf/core] perf cs-etm: " tip-bot for Mathieu Poirier
2019-05-24 17:34 ` [PATCH v2 06/17] perf tools: Refactor error path in cs_etm_decoder__new() Mathieu Poirier
2019-05-24 17:34   ` Mathieu Poirier
2019-06-17 19:23   ` [tip:perf/core] perf cs-etm: " tip-bot for Mathieu Poirier
2019-05-24 17:34 ` [PATCH v2 07/17] perf tools: Move packet queue out of decoder structure Mathieu Poirier
2019-05-24 17:34   ` Mathieu Poirier
2019-06-17 19:24   ` [tip:perf/core] perf cs-etm: " tip-bot for Mathieu Poirier
2019-05-24 17:34 ` [PATCH v2 08/17] perf tools: Fix indentation in function cs_etm__process_decoder_queue() Mathieu Poirier
2019-05-24 17:34   ` Mathieu Poirier
2019-06-17 19:25   ` [tip:perf/core] perf cs-etm: " tip-bot for Mathieu Poirier
2019-05-24 17:35 ` [PATCH v2 09/17] perf tools: Introduce the concept of trace ID queues Mathieu Poirier
2019-05-24 17:35   ` Mathieu Poirier
2019-06-17 19:25   ` [tip:perf/core] perf cs-etm: " tip-bot for Mathieu Poirier
2019-05-24 17:35 ` [PATCH v2 10/17] perf tools: Get rid of unused cpu in struct cs_etm_queue Mathieu Poirier
2019-05-24 17:35   ` Mathieu Poirier
2019-06-17 19:26   ` [tip:perf/core] perf cs-etm: " tip-bot for Mathieu Poirier
2019-05-24 17:35 ` [PATCH v2 11/17] perf tools: Move thread to traceid_queue Mathieu Poirier
2019-05-24 17:35   ` Mathieu Poirier
2019-06-17 19:27   ` [tip:perf/core] perf cs-etm: " tip-bot for Mathieu Poirier
2019-05-24 17:35 ` [PATCH v2 12/17] perf tools: Move tid/pid " Mathieu Poirier
2019-05-24 17:35   ` Mathieu Poirier
2019-06-17 19:27   ` [tip:perf/core] perf cs-etm: " tip-bot for Mathieu Poirier
2019-05-24 17:35 ` [PATCH v2 13/17] perf tools: Use traceID aware memory callback API Mathieu Poirier
2019-05-24 17:35   ` Mathieu Poirier
2019-06-17 19:28   ` [tip:perf/core] perf cs-etm: " tip-bot for Mathieu Poirier
2019-05-24 17:35 ` [PATCH v2 14/17] perf tools: Add support for multiple traceID queues Mathieu Poirier
2019-05-24 17:35   ` Mathieu Poirier
2019-06-17 19:29   ` [tip:perf/core] perf cs-etm: " tip-bot for Mathieu Poirier
2019-05-24 17:35 ` [PATCH v2 15/17] perf tools: Linking PE contextID with perf thread mechanic Mathieu Poirier
2019-05-24 17:35   ` Mathieu Poirier
2019-06-17 19:29   ` [tip:perf/core] perf cs-etm: " tip-bot for Mathieu Poirier
2019-05-24 17:35 ` [PATCH v2 16/17] perf tools: Add notion of time to decoding code Mathieu Poirier
2019-05-24 17:35   ` Mathieu Poirier
2019-06-06 18:50   ` Arnaldo Carvalho de Melo
2019-06-06 18:50     ` Arnaldo Carvalho de Melo
2019-06-07 14:38     ` Mathieu Poirier
2019-06-07 14:38       ` Mathieu Poirier
2019-06-17 19:30   ` [tip:perf/core] perf cs-etm: " tip-bot for Mathieu Poirier
2019-05-24 17:35 ` [PATCH v2 17/17] perf tools: Add support for CPU-wide trace scenarios Mathieu Poirier
2019-05-24 17:35   ` Mathieu Poirier
2019-06-17 19:31   ` tip-bot for Mathieu Poirier [this message]
2019-05-31  1:45 ` [PATCH v2 00/17] perf tools: Coresight: Add CPU-wide trace support Leo Yan
2019-05-31  1:45   ` Leo Yan

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=tip-21fe8dc1191a1528f6732e471f45d370a5c48045@git.kernel.org \
    --to=tipbot@zytor.com \
    --cc=acme@redhat.com \
    --cc=alexander.shishkin@linux.intel.com \
    --cc=hpa@zytor.com \
    --cc=jolsa@redhat.com \
    --cc=leo.yan@linaro.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-tip-commits@vger.kernel.org \
    --cc=mathieu.poirier@linaro.org \
    --cc=mingo@kernel.org \
    --cc=namhyung@kernel.org \
    --cc=peterz@infradead.org \
    --cc=suzuki.poulose@arm.com \
    --cc=tglx@linutronix.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.