All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH V4 00/23] perf tools: Introduce an abstraction for Instruction Tracing
@ 2015-01-08 12:52 Adrian Hunter
  2015-01-08 12:52 ` [PATCH V4 01/23] perf header: Add Instruction Tracing feature Adrian Hunter
                   ` (23 more replies)
  0 siblings, 24 replies; 26+ messages in thread
From: Adrian Hunter @ 2015-01-08 12:52 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Peter Zijlstra, linux-kernel, David Ahern, Frederic Weisbecker,
	Jiri Olsa, Namhyung Kim, Paul Mackerras, Stephane Eranian

Hi

Here is V4 of some more preparatory patches for Intel PT
that introduce an abstraction for Instruction tracing.

The master branch of the tree:

	git://git.infradead.org/users/ahunter/linux-perf.git

contains these patches plus Intel PT and BTS and the kernel driver.

Changes in V4:

	perf tools: Add build option NO_ITRACE to exclude Instruction Tracing
		New patch

	Re-based on Arnaldo's perf/core branch:

		3dd417d4010c8e141b0f32121cdc8d82aa4a9c6a
		perf tools: Remove some unused functions from color.c

Changes in V3:

	perf tools: Add support for Instruction Trace recording
		Added evsel as a parameter to itrace_record__init

	perf record: Add basic Instruction Tracing support
		Moved the call to itrace_record__init after parse
		options so that evsel could be passed and the
		selected events used to determine what kind of
		Instruction Tracing to use e.g. Intel PT vs BTS

	Re-based on Arnaldo's perf/core branch:

		41e950c033b7df997d4b38653efe6554be9b96a7
		Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/urgent

Changes in V2:

	Dropped patches already applied.

	Re-based on Arnaldo's perf/core branch:

		a84808083688d82d7f1e5786ccf5df0ff7d448cb
		perf tools: Only override the default :tid comm entry


The abstraction has two separate aspects:
	1. recording Instruction Trace data
	2. processing Instruction Trace data

Recording consists of mmapping a separate buffer and copying
the data into the perf.data file.  The buffer is an AUX area
buffer although the details of the AUX area are not implemented
because the kernel support is pending.  The data is written
preceded by a new user event PERF_RECORD_ITRACE.  The data is
too big to fit in the event but follows immediately afterward.
Session processing has to skip to get to the next event header
in a similar fashion to the existing PERF_RECORD_HEADER_TRACING_DATA
event.  The main recording patches are:

      perf evlist: Add initial support for mmapping an Instruction Trace buffer
      perf tools: Add user events for Instruction Tracing
      perf tools: Add support for Instruction Trace recording
      perf record: Add basic Instruction Tracing support

Processing consists of providing hooks in session processing
to enable an Instruction Trace decoder to see all the events
and deliver synthesized events transparently into the event
stream.  The main processing patch is:

      perf session: Add hooks to allow transparent decoding of Instruction Tracing data


Adrian Hunter (23):
      perf header: Add Instruction Tracing feature
      perf evlist: Add initial support for mmapping an Instruction Trace buffer
      perf tools: Add user events for Instruction Tracing
      perf tools: Add support for Instruction Trace recording
      perf record: Add basic Instruction Tracing support
      perf record: Extend -m option for Instruction Tracing mmap pages
      perf tools: Add a user event for Instruction Tracing errors
      perf session: Add hooks to allow transparent decoding of Instruction Tracing data
      perf session: Add Instruction Tracing options
      perf itrace: Add helpers for Instruction Tracing errors
      perf itrace: Add helpers for queuing Instruction Tracing data
      perf itrace: Add a heap for sorting Instruction Tracing queues
      perf itrace: Add processing for Instruction Tracing events
      perf itrace: Add a hashtable for caching decoded instructions
      perf tools: Add member to struct dso for an instruction cache
      perf script: Add Instruction Tracing support
      perf script: Always allow fields 'addr' and 'cpu' for itrace
      perf report: Add Instruction Tracing support
      perf inject: Re-pipe Instruction Tracing events
      perf inject: Add Instruction Tracing support
      perf tools: Add Instruction Tracing index
      perf tools: Hit all build ids when Instruction Tracing
      perf tools: Add build option NO_ITRACE to exclude Instruction Tracing

 tools/perf/Documentation/perf-inject.txt |   27 +
 tools/perf/Documentation/perf-record.txt |    2 +
 tools/perf/Documentation/perf-report.txt |   28 +
 tools/perf/Documentation/perf-script.txt |   28 +
 tools/perf/Makefile.perf                 |    6 +
 tools/perf/builtin-buildid-list.c        |    9 +
 tools/perf/builtin-inject.c              |  172 +++-
 tools/perf/builtin-record.c              |  186 ++++-
 tools/perf/builtin-report.c              |   12 +
 tools/perf/builtin-script.c              |   39 +-
 tools/perf/config/Makefile               |    4 +
 tools/perf/perf.h                        |    2 +
 tools/perf/tests/make                    |    2 +
 tools/perf/util/dso.c                    |    2 +
 tools/perf/util/dso.h                    |    3 +
 tools/perf/util/event.c                  |    3 +
 tools/perf/util/event.h                  |   38 +
 tools/perf/util/evlist.c                 |   70 +-
 tools/perf/util/evlist.h                 |    6 +
 tools/perf/util/header.c                 |   36 +
 tools/perf/util/header.h                 |    1 +
 tools/perf/util/itrace.c                 | 1258 ++++++++++++++++++++++++++++++
 tools/perf/util/itrace.h                 |  561 +++++++++++++
 tools/perf/util/record.c                 |   11 +-
 tools/perf/util/session.c                |  148 +++-
 tools/perf/util/session.h                |    6 +
 tools/perf/util/tool.h                   |   10 +-
 27 files changed, 2624 insertions(+), 46 deletions(-)
 create mode 100644 tools/perf/util/itrace.c
 create mode 100644 tools/perf/util/itrace.h


Regards
Adrian

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH V4 01/23] perf header: Add Instruction Tracing feature
  2015-01-08 12:52 [PATCH V4 00/23] perf tools: Introduce an abstraction for Instruction Tracing Adrian Hunter
@ 2015-01-08 12:52 ` Adrian Hunter
  2015-01-08 12:52 ` [PATCH V4 02/23] perf evlist: Add initial support for mmapping an Instruction Trace buffer Adrian Hunter
                   ` (22 subsequent siblings)
  23 siblings, 0 replies; 26+ messages in thread
From: Adrian Hunter @ 2015-01-08 12:52 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Peter Zijlstra, linux-kernel, David Ahern, Frederic Weisbecker,
	Jiri Olsa, Namhyung Kim, Paul Mackerras, Stephane Eranian

Add a feature to indicate that a perf.data file
contains Instruction Tracing data.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 tools/perf/util/header.c | 14 ++++++++++++++
 tools/perf/util/header.h |  1 +
 2 files changed, 15 insertions(+)

diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index b20e40c..0fe5301 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -869,6 +869,13 @@ static int write_branch_stack(int fd __maybe_unused,
 	return 0;
 }
 
+static int write_itrace(int fd __maybe_unused,
+			struct perf_header *h __maybe_unused,
+			struct perf_evlist *evlist __maybe_unused)
+{
+	return 0;
+}
+
 static void print_hostname(struct perf_header *ph, int fd __maybe_unused,
 			   FILE *fp)
 {
@@ -1163,6 +1170,12 @@ static void print_branch_stack(struct perf_header *ph __maybe_unused,
 	fprintf(fp, "# contains samples with branch stack\n");
 }
 
+static void print_itrace(struct perf_header *ph __maybe_unused,
+			 int fd __maybe_unused, FILE *fp)
+{
+	fprintf(fp, "# contains Instruction Traces\n");
+}
+
 static void print_pmu_mappings(struct perf_header *ph, int fd __maybe_unused,
 			       FILE *fp)
 {
@@ -1873,6 +1886,7 @@ static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = {
 	FEAT_OPA(HEADER_BRANCH_STACK,	branch_stack),
 	FEAT_OPP(HEADER_PMU_MAPPINGS,	pmu_mappings),
 	FEAT_OPP(HEADER_GROUP_DESC,	group_desc),
+	FEAT_OPA(HEADER_ITRACE,		itrace),
 };
 
 struct header_print_data {
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index 3bb90ac..990edcf 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -30,6 +30,7 @@ enum {
 	HEADER_BRANCH_STACK,
 	HEADER_PMU_MAPPINGS,
 	HEADER_GROUP_DESC,
+	HEADER_ITRACE,
 	HEADER_LAST_FEATURE,
 	HEADER_FEAT_BITS	= 256,
 };
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH V4 02/23] perf evlist: Add initial support for mmapping an Instruction Trace buffer
  2015-01-08 12:52 [PATCH V4 00/23] perf tools: Introduce an abstraction for Instruction Tracing Adrian Hunter
  2015-01-08 12:52 ` [PATCH V4 01/23] perf header: Add Instruction Tracing feature Adrian Hunter
@ 2015-01-08 12:52 ` Adrian Hunter
  2015-01-08 12:52 ` [PATCH V4 03/23] perf tools: Add user events for Instruction Tracing Adrian Hunter
                   ` (21 subsequent siblings)
  23 siblings, 0 replies; 26+ messages in thread
From: Adrian Hunter @ 2015-01-08 12:52 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Peter Zijlstra, linux-kernel, David Ahern, Frederic Weisbecker,
	Jiri Olsa, Namhyung Kim, Paul Mackerras, Stephane Eranian

This patch anticipates the addition to the kernel
of an "aux" buffer that can be mmapped separately
from the perf-events buffer.

The expectation is that this buffer can be configured
to contain hardware-produced trace information for
Instruction Tracing, hence the name "itrace".
The first implementation will support Intel BTS and
Intel PT.

One itrace buffer is mmapped per perf-events buffer.
If the requested itrace buffer size is zero, which
it will be until further support is added, then
no itrace mmapping is attempted.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 tools/perf/Makefile.perf |   2 +
 tools/perf/util/evlist.c |  60 ++++++++++++++++++++++++++--
 tools/perf/util/evlist.h |   5 +++
 tools/perf/util/itrace.c | 101 +++++++++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/itrace.h |  96 ++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 261 insertions(+), 3 deletions(-)
 create mode 100644 tools/perf/util/itrace.c
 create mode 100644 tools/perf/util/itrace.h

diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf
index 67a03a82..a126e7a 100644
--- a/tools/perf/Makefile.perf
+++ b/tools/perf/Makefile.perf
@@ -322,6 +322,7 @@ LIB_H += util/perf_regs.h
 LIB_H += util/unwind.h
 LIB_H += util/vdso.h
 LIB_H += util/tsc.h
+LIB_H += util/itrace.h
 LIB_H += ui/helpline.h
 LIB_H += ui/progress.h
 LIB_H += ui/util.h
@@ -408,6 +409,7 @@ LIB_OBJS += $(OUTPUT)util/data.o
 LIB_OBJS += $(OUTPUT)util/tsc.o
 LIB_OBJS += $(OUTPUT)util/cloexec.o
 LIB_OBJS += $(OUTPUT)util/thread-stack.o
+LIB_OBJS += $(OUTPUT)util/itrace.o
 
 LIB_OBJS += $(OUTPUT)ui/setup.o
 LIB_OBJS += $(OUTPUT)ui/helpline.o
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index cbab1fb..6241948 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -726,6 +726,34 @@ void perf_evlist__mmap_consume(struct perf_evlist *evlist, int idx)
 		perf_evlist__mmap_put(evlist, idx);
 }
 
+int __weak itrace_mmap__mmap(struct itrace_mmap *mm __maybe_unused,
+			     struct itrace_mmap_params *mp __maybe_unused,
+			     void *userpg __maybe_unused,
+			     int fd __maybe_unused)
+{
+	return 0;
+}
+
+void __weak itrace_mmap__munmap(struct itrace_mmap *mm __maybe_unused)
+{
+}
+
+void __weak itrace_mmap_params__init(
+			struct itrace_mmap_params *mp __maybe_unused,
+			off_t itrace_offset __maybe_unused,
+			unsigned int itrace_pages __maybe_unused,
+			bool itrace_overwrite __maybe_unused)
+{
+}
+
+void __weak itrace_mmap_params__set_idx(
+			struct itrace_mmap_params *mp __maybe_unused,
+			struct perf_evlist *evlist __maybe_unused,
+			int idx __maybe_unused,
+			bool per_cpu __maybe_unused)
+{
+}
+
 static void __perf_evlist__munmap(struct perf_evlist *evlist, int idx)
 {
 	if (evlist->mmap[idx].base != NULL) {
@@ -733,6 +761,7 @@ static void __perf_evlist__munmap(struct perf_evlist *evlist, int idx)
 		evlist->mmap[idx].base = NULL;
 		evlist->mmap[idx].refcnt = 0;
 	}
+	itrace_mmap__munmap(&evlist->mmap[idx].itrace_mmap);
 }
 
 void perf_evlist__munmap(struct perf_evlist *evlist)
@@ -760,6 +789,7 @@ static int perf_evlist__alloc_mmap(struct perf_evlist *evlist)
 struct mmap_params {
 	int prot;
 	int mask;
+	struct itrace_mmap_params itrace_mp;
 };
 
 static int __perf_evlist__mmap(struct perf_evlist *evlist, int idx,
@@ -790,6 +820,10 @@ static int __perf_evlist__mmap(struct perf_evlist *evlist, int idx,
 		return -1;
 	}
 
+	if (itrace_mmap__mmap(&evlist->mmap[idx].itrace_mmap,
+			      &mp->itrace_mp, evlist->mmap[idx].base, fd))
+		return -1;
+
 	return 0;
 }
 
@@ -854,6 +888,8 @@ static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist,
 	for (cpu = 0; cpu < nr_cpus; cpu++) {
 		int output = -1;
 
+		itrace_mmap_params__set_idx(&mp->itrace_mp, evlist, cpu, true);
+
 		for (thread = 0; thread < nr_threads; thread++) {
 			if (perf_evlist__mmap_per_evsel(evlist, cpu, mp, cpu,
 							thread, &output))
@@ -879,6 +915,9 @@ static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist,
 	for (thread = 0; thread < nr_threads; thread++) {
 		int output = -1;
 
+		itrace_mmap_params__set_idx(&mp->itrace_mp, evlist, thread,
+					    false);
+
 		if (perf_evlist__mmap_per_evsel(evlist, thread, mp, 0, thread,
 						&output))
 			goto out_unmap;
@@ -982,19 +1021,25 @@ int perf_evlist__parse_mmap_pages(const struct option *opt, const char *str,
 }
 
 /**
- * perf_evlist__mmap - Create mmaps to receive events.
+ * perf_evlist__mmap_ex - Create mmaps to receive events.
  * @evlist: list of events
  * @pages: map length in pages
  * @overwrite: overwrite older events?
+ * @itrace_pages - itrace map length in pages
+ * @itrace_overwrite - overwrite older itrace data?
  *
  * If @overwrite is %false the user needs to signal event consumption using
  * perf_mmap__write_tail().  Using perf_evlist__mmap_read() does this
  * automatically.
  *
+ * Similarly, if @itrace_overwrite is %false the user needs to signal data
+ * consumption using itrace_mmap__write_tail().
+ *
  * Return: %0 on success, negative error code otherwise.
  */
-int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
-		      bool overwrite)
+int perf_evlist__mmap_ex(struct perf_evlist *evlist, unsigned int pages,
+			 bool overwrite, unsigned int itrace_pages,
+			 bool itrace_overwrite)
 {
 	struct perf_evsel *evsel;
 	const struct cpu_map *cpus = evlist->cpus;
@@ -1014,6 +1059,9 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
 	pr_debug("mmap size %zuB\n", evlist->mmap_len);
 	mp.mask = evlist->mmap_len - page_size - 1;
 
+	itrace_mmap_params__init(&mp.itrace_mp, evlist->mmap_len, itrace_pages,
+				 itrace_overwrite);
+
 	evlist__for_each(evlist, evsel) {
 		if ((evsel->attr.read_format & PERF_FORMAT_ID) &&
 		    evsel->sample_id == NULL &&
@@ -1027,6 +1075,12 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
 	return perf_evlist__mmap_per_cpu(evlist, &mp);
 }
 
+int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
+		      bool overwrite)
+{
+	return perf_evlist__mmap_ex(evlist, pages, overwrite, 0, false);
+}
+
 int perf_evlist__create_maps(struct perf_evlist *evlist, struct target *target)
 {
 	evlist->threads = thread_map__new_str(target->pid, target->tid,
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index 0ba93f6..0f1e716 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -8,6 +8,7 @@
 #include "event.h"
 #include "evsel.h"
 #include "util.h"
+#include "itrace.h"
 #include <unistd.h>
 
 struct pollfd;
@@ -28,6 +29,7 @@ struct perf_mmap {
 	int		 mask;
 	int		 refcnt;
 	unsigned int	 prev;
+	struct itrace_mmap itrace_mmap;
 	char		 event_copy[PERF_SAMPLE_MAX_SIZE];
 };
 
@@ -123,6 +125,9 @@ int perf_evlist__parse_mmap_pages(const struct option *opt,
 				  const char *str,
 				  int unset);
 
+int perf_evlist__mmap_ex(struct perf_evlist *evlist, unsigned int pages,
+			 bool overwrite, unsigned int itrace_pages,
+			 bool itrace_overwrite);
 int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
 		      bool overwrite);
 void perf_evlist__munmap(struct perf_evlist *evlist);
diff --git a/tools/perf/util/itrace.c b/tools/perf/util/itrace.c
new file mode 100644
index 0000000..021f49f
--- /dev/null
+++ b/tools/perf/util/itrace.c
@@ -0,0 +1,101 @@
+/*
+ * itrace.c: Instruction Tracing support
+ * Copyright (c) 2013-2014, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <stdbool.h>
+
+#include <linux/kernel.h>
+#include <linux/perf_event.h>
+#include <linux/types.h>
+#include <linux/bitops.h>
+#include <linux/log2.h>
+
+#include "../perf.h"
+#include "util.h"
+#include "evlist.h"
+#include "cpumap.h"
+#include "thread_map.h"
+#include "itrace.h"
+
+int itrace_mmap__mmap(struct itrace_mmap *mm, struct itrace_mmap_params *mp,
+		      void *userpg, int fd)
+{
+#if BITS_PER_LONG != 64 && !defined(HAVE_SYNC_COMPARE_AND_SWAP_SUPPORT)
+	pr_err("Cannot use Instruction Tracing mmaps\n");
+	return -1;
+#endif
+
+	mm->userpg = userpg;
+	mm->mask = mp->mask;
+	mm->len = mp->len;
+	mm->prev = 0;
+	mm->idx = mp->idx;
+	mm->tid = mp->tid;
+	mm->cpu = mp->cpu;
+
+	if (!mp->len) {
+		mm->base = NULL;
+		return 0;
+	}
+
+	mm->base = mmap(NULL, mp->len, mp->prot, MAP_SHARED, fd, mp->offset);
+	if (mm->base == MAP_FAILED) {
+		pr_debug2("failed to mmap itrace ring buffer\n");
+		mm->base = NULL;
+		return -1;
+	}
+
+	return 0;
+}
+
+void itrace_mmap__munmap(struct itrace_mmap *mm)
+{
+	if (mm->base)
+		munmap(mm->base, mm->len);
+}
+
+void itrace_mmap_params__init(struct itrace_mmap_params *mp,
+			      off_t itrace_offset,
+			      unsigned int itrace_pages, bool itrace_overwrite)
+{
+	if (itrace_pages) {
+		mp->offset = itrace_offset;
+		mp->len = itrace_pages * (size_t)page_size;
+		mp->mask = is_power_of_2(mp->len) ? mp->len - 1 : 0;
+		mp->prot = PROT_READ | (itrace_overwrite ? 0 : PROT_WRITE);
+		pr_debug2("itrace mmap length %zu\n", mp->len);
+	} else {
+		mp->len = 0;
+	}
+}
+
+void itrace_mmap_params__set_idx(struct itrace_mmap_params *mp,
+				 struct perf_evlist *evlist, int idx,
+				 bool per_cpu)
+{
+	mp->idx = idx;
+
+	if (per_cpu) {
+		mp->cpu = evlist->cpus->map[idx];
+		if (evlist->threads)
+			mp->tid = evlist->threads->map[0];
+		else
+			mp->tid = -1;
+	} else {
+		mp->cpu = -1;
+		mp->tid = evlist->threads->map[idx];
+	}
+}
diff --git a/tools/perf/util/itrace.h b/tools/perf/util/itrace.h
new file mode 100644
index 0000000..00ba409
--- /dev/null
+++ b/tools/perf/util/itrace.h
@@ -0,0 +1,96 @@
+/*
+ * itrace.h: Instruction Tracing support
+ * Copyright (c) 2013-2014, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#ifndef __PERF_ITRACE_H
+#define __PERF_ITRACE_H
+
+#include <sys/types.h>
+#include <stdbool.h>
+
+#include <linux/perf_event.h>
+#include <linux/types.h>
+
+#include "../perf.h"
+
+struct perf_evlist;
+
+/**
+ * struct itrace_mmap - records an mmap of the itrace buffer.
+ * @base: address of mapped area
+ * @userpg: pointer to buffer's perf_event_mmap_page
+ * @mask: %0 if @len is not a power of two, otherwise (@len - %1)
+ * @len: size of mapped area
+ * @prev: previous aux_head
+ * @idx: index of this mmap
+ * @tid: tid for a per-thread mmap (also set if there is only 1 tid on a per-cpu
+ *       mmap) otherwise %0
+ * @cpu: cpu number for a per-cpu mmap otherwise %-1
+ */
+struct itrace_mmap {
+	void		*base;
+	void		*userpg;
+	size_t		mask;
+	size_t		len;
+	u64		prev;
+	int		idx;
+	pid_t		tid;
+	int		cpu;
+};
+
+/**
+ * struct itrace_mmap_params - parameters to set up struct itrace_mmap.
+ * @mask: %0 if @len is not a power of two, otherwise (@len - %1)
+ * @offset: file offset of mapped area
+ * @len: size of mapped area
+ * @prot: mmap memory protection
+ * @idx: index of this mmap
+ * @tid: tid for a per-thread mmap (also set if there is only 1 tid on a per-cpu
+ *       mmap) otherwise %0
+ * @cpu: cpu number for a per-cpu mmap otherwise %-1
+ */
+struct itrace_mmap_params {
+	size_t		mask;
+	off_t		offset;
+	size_t		len;
+	int		prot;
+	int		idx;
+	pid_t		tid;
+	int		cpu;
+};
+
+static inline u64 itrace_mmap__read_head(struct itrace_mmap *mm __maybe_unused)
+{
+	/* Not yet implemented */
+	return 0;
+}
+
+static inline void itrace_mmap__write_tail(struct itrace_mmap *mm __maybe_unused,
+					   u64 tail __maybe_unused)
+{
+	/* Not yet implemented */
+}
+
+int itrace_mmap__mmap(struct itrace_mmap *mm,
+		      struct itrace_mmap_params *mp,
+		      void *userpg, int fd);
+void itrace_mmap__munmap(struct itrace_mmap *mm);
+void itrace_mmap_params__init(struct itrace_mmap_params *mp,
+			      off_t itrace_offset,
+			      unsigned int itrace_pages, bool itrace_overwrite);
+void itrace_mmap_params__set_idx(struct itrace_mmap_params *mp,
+				 struct perf_evlist *evlist, int idx,
+				 bool per_cpu);
+
+#endif
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH V4 03/23] perf tools: Add user events for Instruction Tracing
  2015-01-08 12:52 [PATCH V4 00/23] perf tools: Introduce an abstraction for Instruction Tracing Adrian Hunter
  2015-01-08 12:52 ` [PATCH V4 01/23] perf header: Add Instruction Tracing feature Adrian Hunter
  2015-01-08 12:52 ` [PATCH V4 02/23] perf evlist: Add initial support for mmapping an Instruction Trace buffer Adrian Hunter
@ 2015-01-08 12:52 ` Adrian Hunter
  2015-01-08 12:52 ` [PATCH V4 04/23] perf tools: Add support for Instruction Trace recording Adrian Hunter
                   ` (20 subsequent siblings)
  23 siblings, 0 replies; 26+ messages in thread
From: Adrian Hunter @ 2015-01-08 12:52 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Peter Zijlstra, linux-kernel, David Ahern, Frederic Weisbecker,
	Jiri Olsa, Namhyung Kim, Paul Mackerras, Stephane Eranian

Add two user events for Instruction Tracing.

PERF_RECORD_ITRACE_INFO contains metadata,
consisting primarily the type of the
Instruction Tracing data plus some amount
of architecture-specific information.
There should be only one
PERF_RECORD_ITRACE_INFO event.

PERF_RECORD_ITRACE identifies Instruction
Tracing data copied from the mmapped
Instruction Tracing region.  The actual
data is not part of the event but
immediately follows it.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 tools/perf/util/event.c   |  2 ++
 tools/perf/util/event.h   | 22 +++++++++++++++
 tools/perf/util/session.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/tool.h    |  9 ++++++-
 4 files changed, 101 insertions(+), 1 deletion(-)

diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 6c6d044..efe6475 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -29,6 +29,8 @@ static const char *perf_event__names[] = {
 	[PERF_RECORD_HEADER_BUILD_ID]		= "BUILD_ID",
 	[PERF_RECORD_FINISHED_ROUND]		= "FINISHED_ROUND",
 	[PERF_RECORD_ID_INDEX]			= "ID_INDEX",
+	[PERF_RECORD_ITRACE_INFO]		= "ITRACE_INFO",
+	[PERF_RECORD_ITRACE]			= "ITRACE",
 };
 
 const char *perf_event__name(unsigned int id)
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index c4ffe2b..660bae0 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -215,6 +215,8 @@ enum perf_user_event_type { /* above any possible kernel type */
 	PERF_RECORD_HEADER_BUILD_ID		= 67,
 	PERF_RECORD_FINISHED_ROUND		= 68,
 	PERF_RECORD_ID_INDEX			= 69,
+	PERF_RECORD_ITRACE_INFO			= 70,
+	PERF_RECORD_ITRACE			= 71,
 	PERF_RECORD_HEADER_MAX
 };
 
@@ -281,6 +283,24 @@ struct id_index_event {
 	struct id_index_entry entries[0];
 };
 
+struct itrace_info_event {
+	struct perf_event_header header;
+	u32 type;
+	u32 reserved__; /* For alignment */
+	u64 priv[];
+};
+
+struct itrace_event {
+	struct perf_event_header header;
+	u64 size;
+	u64 offset;
+	u64 reference;
+	u32 idx;
+	u32 tid;
+	u32 cpu;
+	u32 reserved__; /* For alignment */
+};
+
 union perf_event {
 	struct perf_event_header	header;
 	struct mmap_event		mmap;
@@ -296,6 +316,8 @@ union perf_event {
 	struct tracing_data_event	tracing_data;
 	struct build_id_event		build_id;
 	struct id_index_event		id_index;
+	struct itrace_info_event	itrace_info;
+	struct itrace_event		itrace;
 };
 
 void perf_event__print_totals(void);
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index b0ce3d6..cff6e35 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -237,6 +237,40 @@ static int process_id_index_stub(struct perf_tool *tool __maybe_unused,
 	return 0;
 }
 
+static int process_event_itrace_info_stub(struct perf_tool *tool __maybe_unused,
+				  union perf_event *event __maybe_unused,
+				  struct perf_session *session __maybe_unused)
+{
+	dump_printf(": unhandled!\n");
+	return 0;
+}
+
+static int skipn(int fd, off_t n)
+{
+	char buf[4096];
+	ssize_t ret;
+
+	while (n > 0) {
+		ret = read(fd, buf, MIN(n, sizeof(buf)));
+		if (ret <= 0)
+			return ret;
+		n -= ret;
+	}
+
+	return 0;
+}
+
+static s64 process_event_itrace_stub(struct perf_tool *tool __maybe_unused,
+				     union perf_event *event,
+				     struct perf_session *session
+				     __maybe_unused)
+{
+	dump_printf(": unhandled!\n");
+	if (perf_data_file__is_pipe(session->file))
+		skipn(perf_data_file__fd(session->file), event->itrace.size);
+	return event->itrace.size;
+}
+
 void perf_tool__fill_defaults(struct perf_tool *tool)
 {
 	if (tool->sample == NULL)
@@ -273,6 +307,10 @@ void perf_tool__fill_defaults(struct perf_tool *tool)
 	}
 	if (tool->id_index == NULL)
 		tool->id_index = process_id_index_stub;
+	if (tool->itrace_info == NULL)
+		tool->itrace_info = process_event_itrace_info_stub;
+	if (tool->itrace == NULL)
+		tool->itrace = process_event_itrace_stub;
 }
 
 static void swap_sample_id_all(union perf_event *event, void *data)
@@ -453,6 +491,29 @@ static void perf_event__tracing_data_swap(union perf_event *event,
 	event->tracing_data.size = bswap_32(event->tracing_data.size);
 }
 
+static void perf_event__itrace_info_swap(union perf_event *event,
+					 bool sample_id_all __maybe_unused)
+{
+	size_t size;
+
+	event->itrace_info.type = bswap_32(event->itrace_info.type);
+
+	size = event->header.size;
+	size -= (void *)&event->itrace_info.priv - (void *)event;
+	mem_bswap_64(event->itrace_info.priv, size);
+}
+
+static void perf_event__itrace_swap(union perf_event *event,
+				    bool sample_id_all __maybe_unused)
+{
+	event->itrace.size      = bswap_64(event->itrace.size);
+	event->itrace.offset    = bswap_64(event->itrace.offset);
+	event->itrace.reference = bswap_64(event->itrace.reference);
+	event->itrace.idx       = bswap_32(event->itrace.idx);
+	event->itrace.tid       = bswap_32(event->itrace.tid);
+	event->itrace.cpu       = bswap_32(event->itrace.cpu);
+}
+
 typedef void (*perf_event__swap_op)(union perf_event *event,
 				    bool sample_id_all);
 
@@ -472,6 +533,8 @@ static perf_event__swap_op perf_event__swap_ops[] = {
 	[PERF_RECORD_HEADER_TRACING_DATA] = perf_event__tracing_data_swap,
 	[PERF_RECORD_HEADER_BUILD_ID]	  = NULL,
 	[PERF_RECORD_ID_INDEX]		  = perf_event__all64_swap,
+	[PERF_RECORD_ITRACE_INFO]	  = perf_event__itrace_info_swap,
+	[PERF_RECORD_ITRACE]		  = perf_event__itrace_swap,
 	[PERF_RECORD_HEADER_MAX]	  = NULL,
 };
 
@@ -932,6 +995,12 @@ static s64 perf_session__process_user_event(struct perf_session *session,
 		return tool->finished_round(tool, event, session);
 	case PERF_RECORD_ID_INDEX:
 		return tool->id_index(tool, event, session);
+	case PERF_RECORD_ITRACE_INFO:
+		return tool->itrace_info(tool, event, session);
+	case PERF_RECORD_ITRACE:
+		/* setup for reading amidst mmap */
+		lseek(fd, file_offset + event->header.size, SEEK_SET);
+		return tool->itrace(tool, event, session);
 	default:
 		return -EINVAL;
 	}
diff --git a/tools/perf/util/tool.h b/tools/perf/util/tool.h
index bb2708b..b734c1a 100644
--- a/tools/perf/util/tool.h
+++ b/tools/perf/util/tool.h
@@ -3,6 +3,8 @@
 
 #include <stdbool.h>
 
+#include <linux/types.h>
+
 struct perf_session;
 union perf_event;
 struct perf_evlist;
@@ -25,6 +27,9 @@ typedef int (*event_attr_op)(struct perf_tool *tool,
 typedef int (*event_op2)(struct perf_tool *tool, union perf_event *event,
 			 struct perf_session *session);
 
+typedef s64 (*event_op3)(struct perf_tool *tool, union perf_event *event,
+			 struct perf_session *session);
+
 struct perf_tool {
 	event_sample	sample,
 			read;
@@ -40,7 +45,9 @@ struct perf_tool {
 	event_op2	tracing_data;
 	event_op2	finished_round,
 			build_id,
-			id_index;
+			id_index,
+			itrace_info;
+	event_op3	itrace;
 	bool		ordered_events;
 	bool		ordering_requires_timestamps;
 };
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH V4 04/23] perf tools: Add support for Instruction Trace recording
  2015-01-08 12:52 [PATCH V4 00/23] perf tools: Introduce an abstraction for Instruction Tracing Adrian Hunter
                   ` (2 preceding siblings ...)
  2015-01-08 12:52 ` [PATCH V4 03/23] perf tools: Add user events for Instruction Tracing Adrian Hunter
@ 2015-01-08 12:52 ` Adrian Hunter
  2015-01-08 12:52 ` [PATCH V4 05/23] perf record: Add basic Instruction Tracing support Adrian Hunter
                   ` (19 subsequent siblings)
  23 siblings, 0 replies; 26+ messages in thread
From: Adrian Hunter @ 2015-01-08 12:52 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Peter Zijlstra, linux-kernel, David Ahern, Frederic Weisbecker,
	Jiri Olsa, Namhyung Kim, Paul Mackerras, Stephane Eranian

Add support for reading from the Instruction
Tracing mmap and synthesizing Instruction
Tracing events.

This patch introduces an abstraction for recording
Instruction Trace data.  Recording is initialized
by itrace_record__init() which is a weak function
to be implemented by the architecture to provide
recording callbacks.  Recording is mainly handled
by itrace_mmap__read() and
perf_event__synthesize_itrace() but there are
callbacks for miscellaneous needs including
validating and processing user options, populating
private data in itrace_info_event, and freeing
the structure when finished.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 tools/perf/perf.h        |   2 +
 tools/perf/util/itrace.c | 196 +++++++++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/itrace.h |  59 +++++++++++++-
 tools/perf/util/record.c |  11 ++-
 4 files changed, 266 insertions(+), 2 deletions(-)

diff --git a/tools/perf/perf.h b/tools/perf/perf.h
index 1dabb85..ca4c09d 100644
--- a/tools/perf/perf.h
+++ b/tools/perf/perf.h
@@ -53,8 +53,10 @@ struct record_opts {
 	bool	     sample_time;
 	bool	     period;
 	bool	     sample_intr_regs;
+	bool	     full_itrace;
 	unsigned int freq;
 	unsigned int mmap_pages;
+	unsigned int itrace_mmap_pages;
 	unsigned int user_freq;
 	u64          branch_stack;
 	u64	     default_interval;
diff --git a/tools/perf/util/itrace.c b/tools/perf/util/itrace.c
index 021f49f..d8fc89d 100644
--- a/tools/perf/util/itrace.c
+++ b/tools/perf/util/itrace.c
@@ -23,6 +23,10 @@
 #include <linux/bitops.h>
 #include <linux/log2.h>
 
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
 #include "../perf.h"
 #include "util.h"
 #include "evlist.h"
@@ -30,6 +34,9 @@
 #include "thread_map.h"
 #include "itrace.h"
 
+#include "event.h"
+#include "debug.h"
+
 int itrace_mmap__mmap(struct itrace_mmap *mm, struct itrace_mmap_params *mp,
 		      void *userpg, int fd)
 {
@@ -99,3 +106,192 @@ void itrace_mmap_params__set_idx(struct itrace_mmap_params *mp,
 		mp->tid = evlist->threads->map[idx];
 	}
 }
+
+size_t itrace_record__info_priv_size(struct itrace_record *itr)
+{
+	if (itr)
+		return itr->info_priv_size(itr);
+	return 0;
+}
+
+static int itrace_not_supported(void)
+{
+	pr_err("Instruction tracing is not supported on this architecture\n");
+	return -EINVAL;
+}
+
+int itrace_record__info_fill(struct itrace_record *itr,
+			     struct perf_session *session,
+			     struct itrace_info_event *itrace_info,
+			     size_t priv_size)
+{
+	if (itr)
+		return itr->info_fill(itr, session, itrace_info, priv_size);
+	return itrace_not_supported();
+}
+
+void itrace_record__free(struct itrace_record *itr)
+{
+	if (itr)
+		itr->free(itr);
+}
+
+int itrace_record__options(struct itrace_record *itr,
+			   struct perf_evlist *evlist,
+			   struct record_opts *opts)
+{
+	if (itr)
+		return itr->recording_options(itr, evlist, opts);
+	return 0;
+}
+
+u64 itrace_record__reference(struct itrace_record *itr)
+{
+	if (itr)
+		return itr->reference(itr);
+	return 0;
+}
+
+struct itrace_record *__weak
+itrace_record__init(struct perf_evlist *evlist __maybe_unused, int *err)
+{
+	*err = 0;
+	return NULL;
+}
+
+int perf_event__synthesize_itrace_info(struct itrace_record *itr,
+				       struct perf_tool *tool,
+				       struct perf_session *session,
+				       perf_event__handler_t process)
+{
+	union perf_event *ev;
+	size_t priv_size;
+	int err;
+
+	pr_debug2("Synthesizing itrace information\n");
+	priv_size = itrace_record__info_priv_size(itr);
+	ev = zalloc(sizeof(struct itrace_info_event) + priv_size);
+	if (!ev)
+		return -ENOMEM;
+
+	ev->itrace_info.header.type = PERF_RECORD_ITRACE_INFO;
+	ev->itrace_info.header.size = sizeof(struct itrace_info_event) +
+				      priv_size;
+	err = itrace_record__info_fill(itr, session, &ev->itrace_info,
+				       priv_size);
+	if (err)
+		goto out_free;
+
+	err = process(tool, ev, NULL, NULL);
+out_free:
+	free(ev);
+	return err;
+}
+
+int perf_event__synthesize_itrace(struct perf_tool *tool,
+				  perf_event__handler_t process,
+				  size_t size, u64 offset, u64 ref, int idx,
+				  u32 tid, u32 cpu)
+{
+	union perf_event ev;
+
+	memset(&ev, 0, sizeof(ev));
+	ev.itrace.header.type = PERF_RECORD_ITRACE;
+	ev.itrace.header.size = sizeof(ev.itrace);
+	ev.itrace.size = size;
+	ev.itrace.offset = offset;
+	ev.itrace.reference = ref;
+	ev.itrace.idx = idx;
+	ev.itrace.tid = tid;
+	ev.itrace.cpu = cpu;
+
+	return process(tool, &ev, NULL, NULL);
+}
+
+int itrace_mmap__read(struct itrace_mmap *mm, struct itrace_record *itr,
+		      struct perf_tool *tool, process_itrace_t fn)
+{
+	u64 head = itrace_mmap__read_head(mm);
+	u64 old = mm->prev, offset, ref;
+	unsigned char *data = mm->base;
+	size_t size, head_off, old_off, len1, len2, padding;
+	union perf_event ev;
+	void *data1, *data2;
+
+	if (old == head)
+		return 0;
+
+	pr_debug3("itrace idx %d old %#"PRIx64" head %#"PRIx64" diff %#"PRIx64"\n",
+		  mm->idx, old, head, head - old);
+
+	if (mm->mask) {
+		head_off = head & mm->mask;
+		old_off = old & mm->mask;
+	} else {
+		head_off = head % mm->len;
+		old_off = old % mm->len;
+	}
+
+	if (head_off > old_off)
+		size = head_off - old_off;
+	else
+		size = mm->len - (old_off - head_off);
+
+	ref = itrace_record__reference(itr);
+
+	if (head > old || size <= head || mm->mask) {
+		offset = head - size;
+	} else {
+		/*
+		 * When the buffer size is not a power of 2, 'head' wraps at the
+		 * highest multiple of the buffer size, so we have to subtract
+		 * the remainder here.
+		 */
+		u64 rem = (0ULL - mm->len) % mm->len;
+
+		offset = head - size - rem;
+	}
+
+	if (size > head_off) {
+		len1 = size - head_off;
+		data1 = &data[mm->len - len1];
+		len2 = head_off;
+		data2 = &data[0];
+	} else {
+		len1 = size;
+		data1 = &data[head_off - len1];
+		len2 = 0;
+		data2 = NULL;
+	}
+
+	/* padding must be written by fn() e.g. record__process_itrace() */
+	padding = size & 7;
+	if (padding)
+		padding = 8 - padding;
+
+	memset(&ev, 0, sizeof(ev));
+	ev.itrace.header.type = PERF_RECORD_ITRACE;
+	ev.itrace.header.size = sizeof(ev.itrace);
+	ev.itrace.size = size + padding;
+	ev.itrace.offset = offset;
+	ev.itrace.reference = ref;
+	ev.itrace.idx = mm->idx;
+	ev.itrace.tid = mm->tid;
+	ev.itrace.cpu = mm->cpu;
+
+	if (fn(tool, &ev, data1, len1, data2, len2))
+		return -1;
+
+	mm->prev = head;
+
+	itrace_mmap__write_tail(mm, head);
+	if (itr->read_finish) {
+		int err;
+
+		err = itr->read_finish(itr, mm->idx);
+		if (err < 0)
+			return err;
+	}
+
+	return 1;
+}
diff --git a/tools/perf/util/itrace.h b/tools/perf/util/itrace.h
index 00ba409..6eef25c 100644
--- a/tools/perf/util/itrace.h
+++ b/tools/perf/util/itrace.h
@@ -18,13 +18,18 @@
 
 #include <sys/types.h>
 #include <stdbool.h>
-
+#include <stddef.h>
 #include <linux/perf_event.h>
 #include <linux/types.h>
 
 #include "../perf.h"
 
+union perf_event;
+struct perf_session;
 struct perf_evlist;
+struct perf_tool;
+struct record_opts;
+struct itrace_info_event;
 
 /**
  * struct itrace_mmap - records an mmap of the itrace buffer.
@@ -70,6 +75,29 @@ struct itrace_mmap_params {
 	int		cpu;
 };
 
+/**
+ * struct itrace_record - callbacks for recording Instruction Trace data.
+ * @recording_options: validate and process recording options
+ * @info_priv_size: return the size of the private data in itrace_info_event
+ * @info_fill: fill-in the private data in itrace_info_event
+ * @free: free this itrace record structure
+ * @reference: provide a 64-bit reference number for itrace_event
+ * @read_finish: called after reading from an itrace mmap
+ */
+struct itrace_record {
+	int (*recording_options)(struct itrace_record *itr,
+				 struct perf_evlist *evlist,
+				 struct record_opts *opts);
+	size_t (*info_priv_size)(struct itrace_record *itr);
+	int (*info_fill)(struct itrace_record *itr,
+			 struct perf_session *session,
+			 struct itrace_info_event *itrace_info,
+			 size_t priv_size);
+	void (*free)(struct itrace_record *itr);
+	u64 (*reference)(struct itrace_record *itr);
+	int (*read_finish)(struct itrace_record *itr, int idx);
+};
+
 static inline u64 itrace_mmap__read_head(struct itrace_mmap *mm __maybe_unused)
 {
 	/* Not yet implemented */
@@ -93,4 +121,33 @@ void itrace_mmap_params__set_idx(struct itrace_mmap_params *mp,
 				 struct perf_evlist *evlist, int idx,
 				 bool per_cpu);
 
+typedef int (*process_itrace_t)(struct perf_tool *tool, union perf_event *event,
+				void *data1, size_t len1, void *data2,
+				size_t len2);
+
+int itrace_mmap__read(struct itrace_mmap *mm, struct itrace_record *itr,
+		      struct perf_tool *tool, process_itrace_t fn);
+
+struct itrace_record *itrace_record__init(struct perf_evlist *evlist, int *err);
+
+int itrace_record__options(struct itrace_record *itr,
+			   struct perf_evlist *evlist,
+			   struct record_opts *opts);
+size_t itrace_record__info_priv_size(struct itrace_record *itr);
+int itrace_record__info_fill(struct itrace_record *itr,
+			     struct perf_session *session,
+			     struct itrace_info_event *itrace_info,
+			     size_t priv_size);
+void itrace_record__free(struct itrace_record *itr);
+u64 itrace_record__reference(struct itrace_record *itr);
+
+int perf_event__synthesize_itrace_info(struct itrace_record *itr,
+				       struct perf_tool *tool,
+				       struct perf_session *session,
+				       perf_event__handler_t process);
+int perf_event__synthesize_itrace(struct perf_tool *tool,
+				  perf_event__handler_t process,
+				  size_t size, u64 offset, u64 ref, int idx,
+				  u32 tid, u32 cpu);
+
 #endif
diff --git a/tools/perf/util/record.c b/tools/perf/util/record.c
index 8acd0df..1887484 100644
--- a/tools/perf/util/record.c
+++ b/tools/perf/util/record.c
@@ -119,7 +119,16 @@ void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts)
 			evsel->attr.comm_exec = 1;
 	}
 
-	if (evlist->nr_entries > 1) {
+	if (opts->full_itrace) {
+		/*
+		 * Need to be able to synthesize and parse selected events with
+		 * arbitrary sample types, which requires always being able to
+		 * match the id.
+		 */
+		use_sample_identifier = true;
+		evlist__for_each(evlist, evsel)
+			perf_evsel__set_sample_id(evsel, use_sample_identifier);
+	} else if (evlist->nr_entries > 1) {
 		struct perf_evsel *first = perf_evlist__first(evlist);
 
 		evlist__for_each(evlist, evsel) {
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH V4 05/23] perf record: Add basic Instruction Tracing support
  2015-01-08 12:52 [PATCH V4 00/23] perf tools: Introduce an abstraction for Instruction Tracing Adrian Hunter
                   ` (3 preceding siblings ...)
  2015-01-08 12:52 ` [PATCH V4 04/23] perf tools: Add support for Instruction Trace recording Adrian Hunter
@ 2015-01-08 12:52 ` Adrian Hunter
  2015-01-08 12:52 ` [PATCH V4 06/23] perf record: Extend -m option for Instruction Tracing mmap pages Adrian Hunter
                   ` (18 subsequent siblings)
  23 siblings, 0 replies; 26+ messages in thread
From: Adrian Hunter @ 2015-01-08 12:52 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Peter Zijlstra, linux-kernel, David Ahern, Frederic Weisbecker,
	Jiri Olsa, Namhyung Kim, Paul Mackerras, Stephane Eranian

Amend the perf record tool to read the
Instruction Tracing mmap and synthesize
Instruction Tracing events.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 tools/perf/builtin-record.c | 99 +++++++++++++++++++++++++++++++++++++++------
 1 file changed, 86 insertions(+), 13 deletions(-)

diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 8648c6d..ab8cd02 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -27,6 +27,7 @@
 #include "util/cpumap.h"
 #include "util/thread_map.h"
 #include "util/data.h"
+#include "util/itrace.h"
 
 #include <unistd.h>
 #include <sched.h>
@@ -38,6 +39,7 @@ struct record {
 	struct record_opts	opts;
 	u64			bytes_written;
 	struct perf_data_file	file;
+	struct itrace_record	*itr;
 	struct perf_evlist	*evlist;
 	struct perf_session	*session;
 	const char		*progname;
@@ -110,6 +112,43 @@ out:
 	return rc;
 }
 
+static int record__process_itrace(struct perf_tool *tool,
+				  union perf_event *event, void *data1,
+				  size_t len1, void *data2, size_t len2)
+{
+	struct record *rec = container_of(tool, struct record, tool);
+	size_t padding;
+	u8 pad[8] = {0};
+
+	/* event.itrace.size includes padding, see __itrace_mmap__read() */
+	padding = (len1 + len2) & 7;
+	if (padding)
+		padding = 8 - padding;
+
+	record__write(rec, event, event->header.size);
+	record__write(rec, data1, len1);
+	record__write(rec, data2, len2);
+	record__write(rec, &pad, padding);
+
+	return 0;
+}
+
+static int record__itrace_mmap_read(struct record *rec,
+				    struct itrace_mmap *mm)
+{
+	int ret;
+
+	ret = itrace_mmap__read(mm, rec->itr, &rec->tool,
+				record__process_itrace);
+	if (ret < 0)
+		return ret;
+
+	if (ret)
+		rec->samples++;
+
+	return 0;
+}
+
 static volatile int done = 0;
 static volatile int signr = -1;
 static volatile int child_finished = 0;
@@ -168,13 +207,15 @@ try_again:
 		goto out;
 	}
 
-	if (perf_evlist__mmap(evlist, opts->mmap_pages, false) < 0) {
+	if (perf_evlist__mmap_ex(evlist, opts->mmap_pages, false,
+				 opts->itrace_mmap_pages, false) < 0) {
 		if (errno == EPERM) {
 			pr_err("Permission error mapping pages.\n"
 			       "Consider increasing "
 			       "/proc/sys/kernel/perf_event_mlock_kb,\n"
 			       "or try again with a smaller value of -m/--mmap_pages.\n"
-			       "(current value: %u)\n", opts->mmap_pages);
+			       "(current value: %u,%u)\n",
+			       opts->mmap_pages, opts->itrace_mmap_pages);
 			rc = -errno;
 		} else {
 			pr_err("failed to mmap with %d (%s)\n", errno,
@@ -257,12 +298,20 @@ static int record__mmap_read_all(struct record *rec)
 	int rc = 0;
 
 	for (i = 0; i < rec->evlist->nr_mmaps; i++) {
+		struct itrace_mmap *mm = &rec->evlist->mmap[i].itrace_mmap;
+
 		if (rec->evlist->mmap[i].base) {
 			if (record__mmap_read(rec, i) != 0) {
 				rc = -1;
 				goto out;
 			}
 		}
+
+		if (mm->base &&
+		    record__itrace_mmap_read(rec, mm) != 0) {
+			rc = -1;
+			goto out;
+		}
 	}
 
 	/*
@@ -292,6 +341,9 @@ static void record__init_features(struct record *rec)
 
 	if (!rec->opts.branch_stack)
 		perf_header__clear_feat(&session->header, HEADER_BRANCH_STACK);
+
+	if (!rec->opts.full_itrace)
+		perf_header__clear_feat(&session->header, HEADER_ITRACE);
 }
 
 static volatile int workload_exec_errno;
@@ -407,6 +459,13 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
 		}
 	}
 
+	if (rec->opts.full_itrace) {
+		err = perf_event__synthesize_itrace_info(rec->itr, tool,
+					session, process_synthesized_event);
+		if (err)
+			goto out_delete_session;
+	}
+
 	err = perf_event__synthesize_kernel_mmap(tool, process_synthesized_event,
 						 machine);
 	if (err < 0)
@@ -505,16 +564,17 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
 	}
 
 	if (!quiet) {
-		fprintf(stderr, "[ perf record: Woken up %ld times to write data ]\n", waking);
-
-		/*
-		 * Approximate RIP event size: 24 bytes.
-		 */
-		fprintf(stderr,
-			"[ perf record: Captured and wrote %.3f MB %s (~%" PRIu64 " samples) ]\n",
-			(double)rec->bytes_written / 1024.0 / 1024.0,
-			file->path,
-			rec->bytes_written / 24);
+		fprintf(stderr, "[ perf record: Woken up %ld times to write data ]\n",
+			waking);
+		fprintf(stderr, "[ perf record: Captured and wrote %.3f MB %s",
+			(double)rec->bytes_written / 1024.0 / 1024.0, file->path);
+		if (rec->opts.full_itrace) {
+			fprintf(stderr, " ]\n");
+		} else {
+			/* Approximate RIP event size: 24 bytes */
+			fprintf(stderr, " (~%" PRIu64 " samples) ]\n",
+				rec->bytes_written / 24);
+		}
 	}
 
 out_child:
@@ -820,7 +880,7 @@ struct option *record_options = __record_options;
 
 int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
 {
-	int err = -ENOMEM;
+	int err;
 	struct record *rec = &record;
 	char errbuf[BUFSIZ];
 
@@ -841,6 +901,14 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
 		usage_with_options(record_usage, record_options);
 	}
 
+	if (!rec->itr) {
+		rec->itr = itrace_record__init(rec->evlist, &err);
+		if (err)
+			return err;
+	}
+
+	err = -ENOMEM;
+
 	symbol__init(NULL);
 
 	if (symbol_conf.kptr_restrict)
@@ -886,6 +954,10 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
 	if (perf_evlist__create_maps(rec->evlist, &rec->opts.target) < 0)
 		usage_with_options(record_usage, record_options);
 
+	err = itrace_record__options(rec->itr, rec->evlist, &rec->opts);
+	if (err)
+		goto out_symbol_exit;
+
 	if (record_opts__config(&rec->opts)) {
 		err = -EINVAL;
 		goto out_symbol_exit;
@@ -895,5 +967,6 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
 out_symbol_exit:
 	perf_evlist__delete(rec->evlist);
 	symbol__exit();
+	itrace_record__free(rec->itr);
 	return err;
 }
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH V4 06/23] perf record: Extend -m option for Instruction Tracing mmap pages
  2015-01-08 12:52 [PATCH V4 00/23] perf tools: Introduce an abstraction for Instruction Tracing Adrian Hunter
                   ` (4 preceding siblings ...)
  2015-01-08 12:52 ` [PATCH V4 05/23] perf record: Add basic Instruction Tracing support Adrian Hunter
@ 2015-01-08 12:52 ` Adrian Hunter
  2015-01-08 12:52 ` [PATCH V4 07/23] perf tools: Add a user event for Instruction Tracing errors Adrian Hunter
                   ` (17 subsequent siblings)
  23 siblings, 0 replies; 26+ messages in thread
From: Adrian Hunter @ 2015-01-08 12:52 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Peter Zijlstra, linux-kernel, David Ahern, Frederic Weisbecker,
	Jiri Olsa, Namhyung Kim, Paul Mackerras, Stephane Eranian

Extend the -m option so that the number
of mmap pages for Instruction Tracing
can be specified.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 tools/perf/Documentation/perf-record.txt |  2 ++
 tools/perf/builtin-record.c              | 49 ++++++++++++++++++++++++++++++--
 tools/perf/util/evlist.c                 | 10 +++++--
 tools/perf/util/evlist.h                 |  1 +
 4 files changed, 56 insertions(+), 6 deletions(-)

diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt
index af9a54e..a5f2096 100644
--- a/tools/perf/Documentation/perf-record.txt
+++ b/tools/perf/Documentation/perf-record.txt
@@ -91,6 +91,8 @@ OPTIONS
 	Number of mmap data pages (must be a power of two) or size
 	specification with appended unit character - B/K/M/G. The
 	size is rounded up to have nearest pages power of two value.
+	Also, by adding a comma, the number of mmap pages for Instruction
+	Tracing can be specified.
 
 -g::
 	Enables call-graph (stack chain/backtrace) recording.
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index ab8cd02..95519e3 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -751,6 +751,49 @@ static int perf_record_config(const char *var, const char *value, void *cb)
 	return perf_default_config(var, value, cb);
 }
 
+static int record__parse_mmap_pages(const struct option *opt,
+				    const char *str,
+				    int unset __maybe_unused)
+{
+	struct record_opts *opts = opt->value;
+	char *s, *p;
+	unsigned int mmap_pages;
+	int ret;
+
+	if (!str)
+		return -EINVAL;
+
+	s = strdup(str);
+	if (!s)
+		return -ENOMEM;
+
+	p = strchr(s, ',');
+	if (p)
+		*p = '\0';
+
+	if (*s) {
+		ret = __perf_evlist__parse_mmap_pages(&mmap_pages, s);
+		if (ret)
+			goto out_free;
+		opts->mmap_pages = mmap_pages;
+	}
+
+	if (!p) {
+		ret = 0;
+		goto out_free;
+	}
+
+	ret = __perf_evlist__parse_mmap_pages(&mmap_pages, p + 1);
+	if (ret)
+		goto out_free;
+
+	opts->itrace_mmap_pages = mmap_pages;
+
+out_free:
+	free(s);
+	return ret;
+}
+
 static const char * const __record_usage[] = {
 	"perf record [<options>] [<command>]",
 	"perf record [<options>] -- <command> [<options>]",
@@ -824,9 +867,9 @@ struct option __record_options[] = {
 			&record.opts.no_inherit_set,
 			"child tasks do not inherit counters"),
 	OPT_UINTEGER('F', "freq", &record.opts.user_freq, "profile at this frequency"),
-	OPT_CALLBACK('m', "mmap-pages", &record.opts.mmap_pages, "pages",
-		     "number of mmap data pages",
-		     perf_evlist__parse_mmap_pages),
+	OPT_CALLBACK('m', "mmap-pages", &record.opts, "pages[,pages]",
+		     "number of mmap data pages and instruction tracing mmap pages",
+		     record__parse_mmap_pages),
 	OPT_BOOLEAN(0, "group", &record.opts.group,
 		    "put the counters into a counter group"),
 	OPT_CALLBACK_NOOPT('g', NULL, &record.opts,
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index 6241948..ebf7899 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -1000,10 +1000,8 @@ static long parse_pages_arg(const char *str, unsigned long min,
 	return pages;
 }
 
-int perf_evlist__parse_mmap_pages(const struct option *opt, const char *str,
-				  int unset __maybe_unused)
+int __perf_evlist__parse_mmap_pages(unsigned int *mmap_pages, const char *str)
 {
-	unsigned int *mmap_pages = opt->value;
 	unsigned long max = UINT_MAX;
 	long pages;
 
@@ -1020,6 +1018,12 @@ int perf_evlist__parse_mmap_pages(const struct option *opt, const char *str,
 	return 0;
 }
 
+int perf_evlist__parse_mmap_pages(const struct option *opt, const char *str,
+				  int unset __maybe_unused)
+{
+	return __perf_evlist__parse_mmap_pages(opt->value, str);
+}
+
 /**
  * perf_evlist__mmap_ex - Create mmaps to receive events.
  * @evlist: list of events
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index 0f1e716..5bdb8a5 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -121,6 +121,7 @@ int perf_evlist__start_workload(struct perf_evlist *evlist);
 
 struct option;
 
+int __perf_evlist__parse_mmap_pages(unsigned int *mmap_pages, const char *str);
 int perf_evlist__parse_mmap_pages(const struct option *opt,
 				  const char *str,
 				  int unset);
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH V4 07/23] perf tools: Add a user event for Instruction Tracing errors
  2015-01-08 12:52 [PATCH V4 00/23] perf tools: Introduce an abstraction for Instruction Tracing Adrian Hunter
                   ` (5 preceding siblings ...)
  2015-01-08 12:52 ` [PATCH V4 06/23] perf record: Extend -m option for Instruction Tracing mmap pages Adrian Hunter
@ 2015-01-08 12:52 ` Adrian Hunter
  2015-01-08 12:52 ` [PATCH V4 08/23] perf session: Add hooks to allow transparent decoding of Instruction Tracing data Adrian Hunter
                   ` (16 subsequent siblings)
  23 siblings, 0 replies; 26+ messages in thread
From: Adrian Hunter @ 2015-01-08 12:52 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Peter Zijlstra, linux-kernel, David Ahern, Frederic Weisbecker,
	Jiri Olsa, Namhyung Kim, Paul Mackerras, Stephane Eranian

Errors encountered when decoding an Instruction
Trace need to be reported to the user. However
the "user" might be a script or another tool,
so provide a new user event to capture those
errors.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 tools/perf/util/event.c   |  1 +
 tools/perf/util/event.h   | 16 ++++++++++++++++
 tools/perf/util/session.c | 25 +++++++++++++++++++++++++
 tools/perf/util/tool.h    |  3 ++-
 4 files changed, 44 insertions(+), 1 deletion(-)

diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index efe6475..573fed2 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -31,6 +31,7 @@ static const char *perf_event__names[] = {
 	[PERF_RECORD_ID_INDEX]			= "ID_INDEX",
 	[PERF_RECORD_ITRACE_INFO]		= "ITRACE_INFO",
 	[PERF_RECORD_ITRACE]			= "ITRACE",
+	[PERF_RECORD_ITRACE_ERROR]		= "ITRACE_ERROR",
 };
 
 const char *perf_event__name(unsigned int id)
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 660bae0..7582d01 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -217,6 +217,7 @@ enum perf_user_event_type { /* above any possible kernel type */
 	PERF_RECORD_ID_INDEX			= 69,
 	PERF_RECORD_ITRACE_INFO			= 70,
 	PERF_RECORD_ITRACE			= 71,
+	PERF_RECORD_ITRACE_ERROR		= 72,
 	PERF_RECORD_HEADER_MAX
 };
 
@@ -301,6 +302,20 @@ struct itrace_event {
 	u32 reserved__; /* For alignment */
 };
 
+#define MAX_ITRACE_ERROR_MSG 64
+
+struct itrace_error_event {
+	struct perf_event_header header;
+	u32 type;
+	u32 code;
+	u32 cpu;
+	u32 pid;
+	u32 tid;
+	u32 reserved__; /* For alignment */
+	u64 ip;
+	char msg[MAX_ITRACE_ERROR_MSG];
+};
+
 union perf_event {
 	struct perf_event_header	header;
 	struct mmap_event		mmap;
@@ -318,6 +333,7 @@ union perf_event {
 	struct id_index_event		id_index;
 	struct itrace_info_event	itrace_info;
 	struct itrace_event		itrace;
+	struct itrace_error_event	itrace_error;
 };
 
 void perf_event__print_totals(void);
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index cff6e35..ea5d4ae 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -271,6 +271,15 @@ static s64 process_event_itrace_stub(struct perf_tool *tool __maybe_unused,
 	return event->itrace.size;
 }
 
+static
+int process_event_itrace_error_stub(struct perf_tool *tool __maybe_unused,
+				    union perf_event *event __maybe_unused,
+				    struct perf_session *session __maybe_unused)
+{
+	dump_printf(": unhandled!\n");
+	return 0;
+}
+
 void perf_tool__fill_defaults(struct perf_tool *tool)
 {
 	if (tool->sample == NULL)
@@ -311,6 +320,8 @@ void perf_tool__fill_defaults(struct perf_tool *tool)
 		tool->itrace_info = process_event_itrace_info_stub;
 	if (tool->itrace == NULL)
 		tool->itrace = process_event_itrace_stub;
+	if (tool->itrace_error == NULL)
+		tool->itrace_error = process_event_itrace_error_stub;
 }
 
 static void swap_sample_id_all(union perf_event *event, void *data)
@@ -514,6 +525,17 @@ static void perf_event__itrace_swap(union perf_event *event,
 	event->itrace.cpu       = bswap_32(event->itrace.cpu);
 }
 
+static void perf_event__itrace_error_swap(union perf_event *event,
+					  bool sample_id_all __maybe_unused)
+{
+	event->itrace_error.type = bswap_32(event->itrace_error.type);
+	event->itrace_error.code = bswap_32(event->itrace_error.code);
+	event->itrace_error.cpu  = bswap_32(event->itrace_error.cpu);
+	event->itrace_error.pid  = bswap_32(event->itrace_error.pid);
+	event->itrace_error.tid  = bswap_32(event->itrace_error.tid);
+	event->itrace_error.ip   = bswap_64(event->itrace_error.ip);
+}
+
 typedef void (*perf_event__swap_op)(union perf_event *event,
 				    bool sample_id_all);
 
@@ -535,6 +557,7 @@ static perf_event__swap_op perf_event__swap_ops[] = {
 	[PERF_RECORD_ID_INDEX]		  = perf_event__all64_swap,
 	[PERF_RECORD_ITRACE_INFO]	  = perf_event__itrace_info_swap,
 	[PERF_RECORD_ITRACE]		  = perf_event__itrace_swap,
+	[PERF_RECORD_ITRACE_ERROR]	  = perf_event__itrace_error_swap,
 	[PERF_RECORD_HEADER_MAX]	  = NULL,
 };
 
@@ -1001,6 +1024,8 @@ static s64 perf_session__process_user_event(struct perf_session *session,
 		/* setup for reading amidst mmap */
 		lseek(fd, file_offset + event->header.size, SEEK_SET);
 		return tool->itrace(tool, event, session);
+	case PERF_RECORD_ITRACE_ERROR:
+		return tool->itrace_error(tool, event, session);
 	default:
 		return -EINVAL;
 	}
diff --git a/tools/perf/util/tool.h b/tools/perf/util/tool.h
index b734c1a..b5c55de 100644
--- a/tools/perf/util/tool.h
+++ b/tools/perf/util/tool.h
@@ -46,7 +46,8 @@ struct perf_tool {
 	event_op2	finished_round,
 			build_id,
 			id_index,
-			itrace_info;
+			itrace_info,
+			itrace_error;
 	event_op3	itrace;
 	bool		ordered_events;
 	bool		ordering_requires_timestamps;
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH V4 08/23] perf session: Add hooks to allow transparent decoding of Instruction Tracing data
  2015-01-08 12:52 [PATCH V4 00/23] perf tools: Introduce an abstraction for Instruction Tracing Adrian Hunter
                   ` (6 preceding siblings ...)
  2015-01-08 12:52 ` [PATCH V4 07/23] perf tools: Add a user event for Instruction Tracing errors Adrian Hunter
@ 2015-01-08 12:52 ` Adrian Hunter
  2015-01-08 12:52 ` [PATCH V4 09/23] perf session: Add Instruction Tracing options Adrian Hunter
                   ` (15 subsequent siblings)
  23 siblings, 0 replies; 26+ messages in thread
From: Adrian Hunter @ 2015-01-08 12:52 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Peter Zijlstra, linux-kernel, David Ahern, Frederic Weisbecker,
	Jiri Olsa, Namhyung Kim, Paul Mackerras, Stephane Eranian

Hook into session processing so that Instruction Trace decoding can
synthesize events transparently to the tools.

The advantages of transparent decoding are that tools can be used
directly with perf.data files containing Instruction Tracing data,
which is easier for the user and more efficient than having a
separate decoding tool.

This will work as follows:
1. Tools will feed itrace events to the decoder using
perf_tool->itrace() (support for that still to come).
2. The decoder can process side-band events as needed due
to the itrace->process_event() hook.
3. The decoder can deliver synthesized events into the
event stream using perf_session__deliver_synth_event().

Note the expectation is that decoding will work on data that is
time-ordered with respect to the per-cpu or per-thread contexts
that were recorded.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 tools/perf/util/itrace.h  | 57 +++++++++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/session.c | 52 +++++++++++++++++++++++++++++++++++++-----
 tools/perf/util/session.h |  3 +++
 3 files changed, 106 insertions(+), 6 deletions(-)

diff --git a/tools/perf/util/itrace.h b/tools/perf/util/itrace.h
index 6eef25c..beea1d7 100644
--- a/tools/perf/util/itrace.h
+++ b/tools/perf/util/itrace.h
@@ -23,6 +23,7 @@
 #include <linux/types.h>
 
 #include "../perf.h"
+#include "session.h"
 
 union perf_event;
 struct perf_session;
@@ -32,6 +33,26 @@ struct record_opts;
 struct itrace_info_event;
 
 /**
+ * struct itrace - session callbacks to allow Instruction Trace data decoding.
+ * @process_event: lets the decoder see all session events
+ * @flush_events: process any remaining data
+ * @free_events: free resources associated with event processing
+ * @free: free resources associated with the session
+ * @error_count: number of errors
+ */
+struct itrace {
+	int (*process_event)(struct perf_session *session,
+			     union perf_event *event,
+			     struct perf_sample *sample,
+			     struct perf_tool *tool);
+	int (*flush_events)(struct perf_session *session,
+			    struct perf_tool *tool);
+	void (*free_events)(struct perf_session *session);
+	void (*free)(struct perf_session *session);
+	unsigned long long error_count;
+};
+
+/**
  * struct itrace_mmap - records an mmap of the itrace buffer.
  * @base: address of mapped area
  * @userpg: pointer to buffer's perf_event_mmap_page
@@ -150,4 +171,40 @@ int perf_event__synthesize_itrace(struct perf_tool *tool,
 				  size_t size, u64 offset, u64 ref, int idx,
 				  u32 tid, u32 cpu);
 
+static inline int itrace__process_event(struct perf_session *session,
+					union perf_event *event,
+					struct perf_sample *sample,
+					struct perf_tool *tool)
+{
+	if (!session->itrace)
+		return 0;
+
+	return session->itrace->process_event(session, event, sample, tool);
+}
+
+static inline int itrace__flush_events(struct perf_session *session,
+				       struct perf_tool *tool)
+{
+	if (!session->itrace)
+		return 0;
+
+	return session->itrace->flush_events(session, tool);
+}
+
+static inline void itrace__free_events(struct perf_session *session)
+{
+	if (!session->itrace)
+		return;
+
+	return session->itrace->free_events(session);
+}
+
+static inline void itrace__free(struct perf_session *session)
+{
+	if (!session->itrace)
+		return;
+
+	return session->itrace->free(session);
+}
+
 #endif
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index ea5d4ae..bb653ef 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -15,6 +15,7 @@
 #include "cpumap.h"
 #include "perf_regs.h"
 #include "asm/bug.h"
+#include "itrace.h"
 
 static int perf_session__open(struct perf_session *session)
 {
@@ -166,6 +167,7 @@ static void perf_session_env__delete(struct perf_session_env *env)
 
 void perf_session__delete(struct perf_session *session)
 {
+	itrace__free(session);
 	perf_session__destroy_kernel_maps(session);
 	perf_session__delete_dead_threads(session);
 	perf_session__delete_threads(session);
@@ -929,10 +931,11 @@ perf_session__deliver_sample(struct perf_session *session,
 					    &sample->read.one, machine);
 }
 
-int perf_session__deliver_event(struct perf_session *session,
-				union perf_event *event,
-				struct perf_sample *sample,
-				struct perf_tool *tool, u64 file_offset)
+static int __perf_session__deliver_event(struct perf_session *session,
+					 union perf_event *event,
+					 struct perf_sample *sample,
+					 struct perf_tool *tool,
+					 u64 file_offset)
 {
 	struct perf_evsel *evsel;
 	struct machine *machine;
@@ -983,6 +986,24 @@ int perf_session__deliver_event(struct perf_session *session,
 	}
 }
 
+int perf_session__deliver_event(struct perf_session *session,
+				union perf_event *event,
+				struct perf_sample *sample,
+				struct perf_tool *tool,
+				u64 file_offset)
+{
+	int ret;
+
+	ret = itrace__process_event(session, event, sample, tool);
+	if (ret < 0)
+		return ret;
+	if (ret > 0)
+		return 0;
+
+	return __perf_session__deliver_event(session, event, sample, tool,
+					     file_offset);
+}
+
 static s64 perf_session__process_user_event(struct perf_session *session,
 					    union perf_event *event,
 					    struct perf_tool *tool,
@@ -1041,7 +1062,7 @@ int perf_session__deliver_synth_event(struct perf_session *session,
 	if (event->header.type >= PERF_RECORD_USER_TYPE_START)
 		return perf_session__process_user_event(session, event, tool, 0);
 
-	return perf_session__deliver_event(session, event, sample, tool, 0);
+	return __perf_session__deliver_event(session, event, sample, tool, 0);
 }
 
 static void event_swap(union perf_event *event, bool sample_id_all)
@@ -1211,6 +1232,11 @@ static void perf_session__warn_about_errors(const struct perf_session *session,
 
 	if (session->stats.nr_unordered_events != 0)
 		ui__warning("%u out of order events recorded.\n", session->stats.nr_unordered_events);
+
+	if (session->itrace && session->itrace->error_count) {
+		ui__warning("%llu instruction trace errors\n",
+			    session->itrace->error_count);
+	}
 }
 
 volatile int session_done;
@@ -1298,10 +1324,14 @@ more:
 done:
 	/* do the final flush for ordered samples */
 	err = ordered_events__flush(session, tool, OE_FLUSH__FINAL);
+	if (err)
+		goto out_err;
+	err = itrace__flush_events(session, tool);
 out_err:
 	free(buf);
 	perf_session__warn_about_errors(session, tool);
 	ordered_events__free(&session->ordered_events);
+	itrace__free_events(session);
 	return err;
 }
 
@@ -1443,10 +1473,14 @@ more:
 out:
 	/* do the final flush for ordered samples */
 	err = ordered_events__flush(session, tool, OE_FLUSH__FINAL);
+	if (err)
+		goto out_err;
+	err = itrace__flush_events(session, tool);
 out_err:
 	ui_progress__finish();
 	perf_session__warn_about_errors(session, tool);
 	ordered_events__free(&session->ordered_events);
+	itrace__free_events(session);
 	session->one_mmap = false;
 	return err;
 }
@@ -1528,7 +1562,13 @@ size_t perf_session__fprintf_dsos_buildid(struct perf_session *session, FILE *fp
 
 size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp)
 {
-	size_t ret = fprintf(fp, "Aggregated stats:\n");
+	size_t ret;
+	const char *msg = "";
+
+	if (perf_header__has_feat(&session->header, HEADER_ITRACE))
+		msg = " (excludes Instruction Trace decoded/synthesized events)";
+
+	ret = fprintf(fp, "Aggregated stats:%s\n", msg);
 
 	ret += events_stats__fprintf(&session->stats, fp);
 	return ret;
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index dc26ebf..6f8ac2f 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -15,10 +15,13 @@
 struct ip_callchain;
 struct thread;
 
+struct itrace;
+
 struct perf_session {
 	struct perf_header	header;
 	struct machines		machines;
 	struct perf_evlist	*evlist;
+	struct itrace		*itrace;
 	struct trace_event	tevent;
 	struct events_stats	stats;
 	bool			repipe;
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH V4 09/23] perf session: Add Instruction Tracing options
  2015-01-08 12:52 [PATCH V4 00/23] perf tools: Introduce an abstraction for Instruction Tracing Adrian Hunter
                   ` (7 preceding siblings ...)
  2015-01-08 12:52 ` [PATCH V4 08/23] perf session: Add hooks to allow transparent decoding of Instruction Tracing data Adrian Hunter
@ 2015-01-08 12:52 ` Adrian Hunter
  2015-01-08 12:52 ` [PATCH V4 10/23] perf itrace: Add helpers for Instruction Tracing errors Adrian Hunter
                   ` (14 subsequent siblings)
  23 siblings, 0 replies; 26+ messages in thread
From: Adrian Hunter @ 2015-01-08 12:52 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Peter Zijlstra, linux-kernel, David Ahern, Frederic Weisbecker,
	Jiri Olsa, Namhyung Kim, Paul Mackerras, Stephane Eranian

It is assumed that Instruction Trace decoding will
synthesize events for consumption by other tools.
The nature of Instruction Tracing suggests the
initial inclusion of options for "instructions"
and "branches" events, but more could be added
as needed.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 tools/perf/util/itrace.c  | 131 ++++++++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/itrace.h  |  43 +++++++++++++++
 tools/perf/util/session.h |   2 +
 3 files changed, 176 insertions(+)

diff --git a/tools/perf/util/itrace.c b/tools/perf/util/itrace.c
index d8fc89d..817b7b7 100644
--- a/tools/perf/util/itrace.c
+++ b/tools/perf/util/itrace.c
@@ -36,6 +36,7 @@
 
 #include "event.h"
 #include "debug.h"
+#include "parse-options.h"
 
 int itrace_mmap__mmap(struct itrace_mmap *mm, struct itrace_mmap_params *mp,
 		      void *userpg, int fd)
@@ -208,6 +209,136 @@ int perf_event__synthesize_itrace(struct perf_tool *tool,
 	return process(tool, &ev, NULL, NULL);
 }
 
+#define PERF_ITRACE_DEFAULT_PERIOD_TYPE		PERF_ITRACE_PERIOD_NANOSECS
+#define PERF_ITRACE_DEFAULT_PERIOD		100000
+#define PERF_ITRACE_DEFAULT_CALLCHAIN_SZ	16
+#define PERF_ITRACE_MAX_CALLCHAIN_SZ		1024
+
+void itrace_synth_opts__set_default(struct itrace_synth_opts *synth_opts)
+{
+	synth_opts->instructions = true;
+	synth_opts->branches = true;
+	synth_opts->errors = true;
+	synth_opts->period_type = PERF_ITRACE_DEFAULT_PERIOD_TYPE;
+	synth_opts->period = PERF_ITRACE_DEFAULT_PERIOD;
+	synth_opts->callchain_sz = PERF_ITRACE_DEFAULT_CALLCHAIN_SZ;
+}
+
+int itrace_parse_synth_opts(const struct option *opt, const char *str,
+			    int unset)
+{
+	struct itrace_synth_opts *synth_opts = opt->value;
+	const char *p;
+	char *endptr;
+
+	synth_opts->set = true;
+
+	if (unset) {
+		synth_opts->dont_decode = true;
+		return 0;
+	}
+
+	if (!str) {
+		itrace_synth_opts__set_default(synth_opts);
+		return 0;
+	}
+
+	for (p = str; *p;) {
+		switch (*p++) {
+		case 'i':
+			synth_opts->instructions = true;
+			while (*p == ' ' || *p == ',')
+				p += 1;
+			if (isdigit(*p)) {
+				synth_opts->period = strtoull(p, &endptr, 10);
+				p = endptr;
+				while (*p == ' ' || *p == ',')
+					p += 1;
+				switch (*p++) {
+				case 'i':
+					synth_opts->period_type =
+						PERF_ITRACE_PERIOD_INSTRUCTIONS;
+					break;
+				case 't':
+					synth_opts->period_type =
+						PERF_ITRACE_PERIOD_TICKS;
+					break;
+				case 'm':
+					synth_opts->period *= 1000;
+					/* Fall through */
+				case 'u':
+					synth_opts->period *= 1000;
+					/* Fall through */
+				case 'n':
+					if (*p++ != 's')
+						goto out_err;
+					synth_opts->period_type =
+						PERF_ITRACE_PERIOD_NANOSECS;
+					break;
+				case '\0':
+					goto out;
+				default:
+					goto out_err;
+				}
+			}
+			break;
+		case 'b':
+			synth_opts->branches = true;
+			break;
+		case 'e':
+			synth_opts->errors = true;
+			break;
+		case 'd':
+			synth_opts->log = true;
+			break;
+		case 'c':
+			synth_opts->branches = true;
+			synth_opts->calls = true;
+			break;
+		case 'r':
+			synth_opts->branches = true;
+			synth_opts->returns = true;
+			break;
+		case 'g':
+			synth_opts->instructions = true;
+			synth_opts->callchain = true;
+			synth_opts->callchain_sz =
+					PERF_ITRACE_DEFAULT_CALLCHAIN_SZ;
+			while (*p == ' ' || *p == ',')
+				p += 1;
+			if (isdigit(*p)) {
+				unsigned int val;
+
+				val = strtoul(p, &endptr, 10);
+				p = endptr;
+				if (!val || val > PERF_ITRACE_MAX_CALLCHAIN_SZ)
+					goto out_err;
+				synth_opts->callchain_sz = val;
+			}
+			break;
+		case ' ':
+		case ',':
+			break;
+		default:
+			goto out_err;
+		}
+	}
+out:
+	if (synth_opts->instructions) {
+		if (!synth_opts->period_type)
+			synth_opts->period_type =
+					PERF_ITRACE_DEFAULT_PERIOD_TYPE;
+		if (!synth_opts->period)
+			synth_opts->period = PERF_ITRACE_DEFAULT_PERIOD;
+	}
+
+	return 0;
+
+out_err:
+	pr_err("Bad instruction trace options '%s'\n", str);
+	return -EINVAL;
+}
+
 int itrace_mmap__read(struct itrace_mmap *mm, struct itrace_record *itr,
 		      struct perf_tool *tool, process_itrace_t fn)
 {
diff --git a/tools/perf/util/itrace.h b/tools/perf/util/itrace.h
index beea1d7..5abb85a 100644
--- a/tools/perf/util/itrace.h
+++ b/tools/perf/util/itrace.h
@@ -29,9 +29,49 @@ union perf_event;
 struct perf_session;
 struct perf_evlist;
 struct perf_tool;
+struct option;
 struct record_opts;
 struct itrace_info_event;
 
+enum itrace_period_type {
+	PERF_ITRACE_PERIOD_INSTRUCTIONS,
+	PERF_ITRACE_PERIOD_TICKS,
+	PERF_ITRACE_PERIOD_NANOSECS,
+};
+
+/**
+ * struct itrace_synth_opts - Instruction Tracing synthesis options.
+ * @set: indicates whether or not options have been set
+ * @inject: indicates the event (not just the sample) must be fully synthesized
+ *          because 'perf inject' will write it out
+ * @instructions: whether to synthesize 'instructions' events
+ * @branches: whether to synthesize 'branches' events
+ * @errors: whether to synthesize decoder error events
+ * @dont_decode: whether to skip decoding entirely
+ * @log: write a decoding log
+ * @calls: limit branch samples to calls (can be combined with @returns)
+ * @returns: limit branch samples to returns (can be combined with @calls)
+ * @callchain: add callchain to 'instructions' events
+ * @callchain_sz: maximum callchain size
+ * @period: 'instructions' events period
+ * @period_type: 'instructions' events period type
+ */
+struct itrace_synth_opts {
+	bool			set;
+	bool			inject;
+	bool			instructions;
+	bool			branches;
+	bool			errors;
+	bool			dont_decode;
+	bool			log;
+	bool			calls;
+	bool			returns;
+	bool			callchain;
+	unsigned int		callchain_sz;
+	unsigned long long	period;
+	enum itrace_period_type	period_type;
+};
+
 /**
  * struct itrace - session callbacks to allow Instruction Trace data decoding.
  * @process_event: lets the decoder see all session events
@@ -170,6 +210,9 @@ int perf_event__synthesize_itrace(struct perf_tool *tool,
 				  perf_event__handler_t process,
 				  size_t size, u64 offset, u64 ref, int idx,
 				  u32 tid, u32 cpu);
+int itrace_parse_synth_opts(const struct option *opt, const char *str,
+			    int unset);
+void itrace_synth_opts__set_default(struct itrace_synth_opts *synth_opts);
 
 static inline int itrace__process_event(struct perf_session *session,
 					union perf_event *event,
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index 6f8ac2f..ccf6a75 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -16,12 +16,14 @@ struct ip_callchain;
 struct thread;
 
 struct itrace;
+struct itrace_synth_opts;
 
 struct perf_session {
 	struct perf_header	header;
 	struct machines		machines;
 	struct perf_evlist	*evlist;
 	struct itrace		*itrace;
+	struct itrace_synth_opts *itrace_synth_opts;
 	struct trace_event	tevent;
 	struct events_stats	stats;
 	bool			repipe;
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH V4 10/23] perf itrace: Add helpers for Instruction Tracing errors
  2015-01-08 12:52 [PATCH V4 00/23] perf tools: Introduce an abstraction for Instruction Tracing Adrian Hunter
                   ` (8 preceding siblings ...)
  2015-01-08 12:52 ` [PATCH V4 09/23] perf session: Add Instruction Tracing options Adrian Hunter
@ 2015-01-08 12:52 ` Adrian Hunter
  2015-01-08 12:52 ` [PATCH V4 11/23] perf itrace: Add helpers for queuing Instruction Tracing data Adrian Hunter
                   ` (13 subsequent siblings)
  23 siblings, 0 replies; 26+ messages in thread
From: Adrian Hunter @ 2015-01-08 12:52 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Peter Zijlstra, linux-kernel, David Ahern, Frederic Weisbecker,
	Jiri Olsa, Namhyung Kim, Paul Mackerras, Stephane Eranian

Add functions to synthesize, count and print
Instruction Tracing error events.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 tools/perf/util/itrace.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/itrace.h | 16 ++++++++++++++
 2 files changed, 71 insertions(+)

diff --git a/tools/perf/util/itrace.c b/tools/perf/util/itrace.c
index 817b7b7..e99166b 100644
--- a/tools/perf/util/itrace.c
+++ b/tools/perf/util/itrace.c
@@ -24,6 +24,7 @@
 #include <linux/log2.h>
 
 #include <stdlib.h>
+#include <stdio.h>
 #include <string.h>
 #include <errno.h>
 
@@ -35,6 +36,7 @@
 #include "itrace.h"
 
 #include "event.h"
+#include "session.h"
 #include "debug.h"
 #include "parse-options.h"
 
@@ -160,6 +162,28 @@ itrace_record__init(struct perf_evlist *evlist __maybe_unused, int *err)
 	return NULL;
 }
 
+void itrace_synth_error(struct itrace_error_event *itrace_error, int type,
+			int code, int cpu, pid_t pid, pid_t tid, u64 ip,
+			const char *msg)
+{
+	size_t size;
+
+	memset(itrace_error, 0, sizeof(struct itrace_error_event));
+
+	itrace_error->header.type = PERF_RECORD_ITRACE_ERROR;
+	itrace_error->type = type;
+	itrace_error->code = code;
+	itrace_error->cpu = cpu;
+	itrace_error->pid = pid;
+	itrace_error->tid = tid;
+	itrace_error->ip = ip;
+	strlcpy(itrace_error->msg, msg, MAX_ITRACE_ERROR_MSG);
+
+	size = (void *)itrace_error->msg - (void *)itrace_error +
+	       strlen(itrace_error->msg) + 1;
+	itrace_error->header.size = PERF_ALIGN(size, sizeof(u64));
+}
+
 int perf_event__synthesize_itrace_info(struct itrace_record *itr,
 				       struct perf_tool *tool,
 				       struct perf_session *session,
@@ -339,6 +363,37 @@ out_err:
 	return -EINVAL;
 }
 
+size_t perf_event__fprintf_itrace_error(union perf_event *event, FILE *fp)
+{
+	struct itrace_error_event *e = &event->itrace_error;
+	int ret;
+
+	ret = fprintf(fp, " Instruction trace error type %u", e->type);
+	ret += fprintf(fp, " cpu %d pid %d tid %d ip %#"PRIx64" code %u: %s\n",
+		       e->cpu, e->pid, e->tid, e->ip, e->code, e->msg);
+	return ret;
+}
+
+int perf_event__process_itrace_error(struct perf_tool *tool __maybe_unused,
+				     union perf_event *event,
+				     struct perf_session *session)
+{
+	if (session->itrace)
+		session->itrace->error_count += 1;
+
+	perf_event__fprintf_itrace_error(event, stdout);
+	return 0;
+}
+
+int perf_event__count_itrace_error(struct perf_tool *tool __maybe_unused,
+				   union perf_event *event __maybe_unused,
+				   struct perf_session *session)
+{
+	if (session->itrace)
+		session->itrace->error_count += 1;
+	return 0;
+}
+
 int itrace_mmap__read(struct itrace_mmap *mm, struct itrace_record *itr,
 		      struct perf_tool *tool, process_itrace_t fn)
 {
diff --git a/tools/perf/util/itrace.h b/tools/perf/util/itrace.h
index 5abb85a..54b8607 100644
--- a/tools/perf/util/itrace.h
+++ b/tools/perf/util/itrace.h
@@ -33,6 +33,10 @@ struct option;
 struct record_opts;
 struct itrace_info_event;
 
+enum itrace_error_type {
+	PERF_ITRACE_DECODER_ERROR = 1,
+};
+
 enum itrace_period_type {
 	PERF_ITRACE_PERIOD_INSTRUCTIONS,
 	PERF_ITRACE_PERIOD_TICKS,
@@ -202,6 +206,10 @@ int itrace_record__info_fill(struct itrace_record *itr,
 void itrace_record__free(struct itrace_record *itr);
 u64 itrace_record__reference(struct itrace_record *itr);
 
+void itrace_synth_error(struct itrace_error_event *itrace_error, int type,
+			int code, int cpu, pid_t pid, pid_t tid, u64 ip,
+			const char *msg);
+
 int perf_event__synthesize_itrace_info(struct itrace_record *itr,
 				       struct perf_tool *tool,
 				       struct perf_session *session,
@@ -210,10 +218,18 @@ int perf_event__synthesize_itrace(struct perf_tool *tool,
 				  perf_event__handler_t process,
 				  size_t size, u64 offset, u64 ref, int idx,
 				  u32 tid, u32 cpu);
+int perf_event__process_itrace_error(struct perf_tool *tool,
+				     union perf_event *event,
+				     struct perf_session *session);
+int perf_event__count_itrace_error(struct perf_tool *tool __maybe_unused,
+				   union perf_event *event __maybe_unused,
+				   struct perf_session *session);
 int itrace_parse_synth_opts(const struct option *opt, const char *str,
 			    int unset);
 void itrace_synth_opts__set_default(struct itrace_synth_opts *synth_opts);
 
+size_t perf_event__fprintf_itrace_error(union perf_event *event, FILE *fp);
+
 static inline int itrace__process_event(struct perf_session *session,
 					union perf_event *event,
 					struct perf_sample *sample,
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH V4 11/23] perf itrace: Add helpers for queuing Instruction Tracing data
  2015-01-08 12:52 [PATCH V4 00/23] perf tools: Introduce an abstraction for Instruction Tracing Adrian Hunter
                   ` (9 preceding siblings ...)
  2015-01-08 12:52 ` [PATCH V4 10/23] perf itrace: Add helpers for Instruction Tracing errors Adrian Hunter
@ 2015-01-08 12:52 ` Adrian Hunter
  2015-01-08 12:52 ` [PATCH V4 12/23] perf itrace: Add a heap for sorting Instruction Tracing queues Adrian Hunter
                   ` (12 subsequent siblings)
  23 siblings, 0 replies; 26+ messages in thread
From: Adrian Hunter @ 2015-01-08 12:52 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Peter Zijlstra, linux-kernel, David Ahern, Frederic Weisbecker,
	Jiri Olsa, Namhyung Kim, Paul Mackerras, Stephane Eranian

Provide functions to queue Instruction Tracing data
buffers for processing.  A Instruction Trace decoder
need not use the queues, however Intel BTS and Intel PT
will use them.

There is one queue for each of the mmap buffers that
were used for recording.  Because those mmaps were
associated with per-cpu or per-thread contexts, the
data is time-ordered with respect to those contexts.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 tools/perf/util/itrace.c | 304 +++++++++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/itrace.h |  87 ++++++++++++++
 2 files changed, 391 insertions(+)

diff --git a/tools/perf/util/itrace.c b/tools/perf/util/itrace.c
index e99166b..4b0439b 100644
--- a/tools/perf/util/itrace.c
+++ b/tools/perf/util/itrace.c
@@ -22,11 +22,15 @@
 #include <linux/types.h>
 #include <linux/bitops.h>
 #include <linux/log2.h>
+#include <linux/string.h>
 
+#include <sys/param.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
+#include <limits.h>
 #include <errno.h>
+#include <linux/list.h>
 
 #include "../perf.h"
 #include "util.h"
@@ -110,6 +114,241 @@ void itrace_mmap_params__set_idx(struct itrace_mmap_params *mp,
 	}
 }
 
+#define ITRACE_INIT_NR_QUEUES	32
+
+static struct itrace_queue *itrace_alloc_queue_array(unsigned int nr_queues)
+{
+	struct itrace_queue *queue_array;
+	unsigned int max_nr_queues, i;
+
+	max_nr_queues = MIN(UINT_MAX, SIZE_MAX) / sizeof(struct itrace_queue);
+	if (nr_queues > max_nr_queues)
+		return NULL;
+
+	queue_array = calloc(nr_queues, sizeof(struct itrace_queue));
+	if (!queue_array)
+		return NULL;
+
+	for (i = 0; i < nr_queues; i++) {
+		INIT_LIST_HEAD(&queue_array[i].head);
+		queue_array[i].priv = NULL;
+	}
+
+	return queue_array;
+}
+
+int itrace_queues__init(struct itrace_queues *queues)
+{
+	queues->nr_queues = ITRACE_INIT_NR_QUEUES;
+	queues->queue_array = itrace_alloc_queue_array(queues->nr_queues);
+	if (!queues->queue_array)
+		return -ENOMEM;
+	return 0;
+}
+
+static int itrace_queues__grow(struct itrace_queues *queues,
+			       unsigned int new_nr_queues)
+{
+	unsigned int nr_queues = queues->nr_queues;
+	struct itrace_queue *queue_array;
+	unsigned int i;
+
+	if (!nr_queues)
+		nr_queues = ITRACE_INIT_NR_QUEUES;
+
+	while (nr_queues && nr_queues < new_nr_queues)
+		nr_queues <<= 1;
+
+	if (nr_queues < queues->nr_queues || nr_queues < new_nr_queues)
+		return -EINVAL;
+
+	queue_array = itrace_alloc_queue_array(nr_queues);
+	if (!queue_array)
+		return -ENOMEM;
+
+	for (i = 0; i < queues->nr_queues; i++) {
+		list_splice_tail(&queues->queue_array[i].head,
+				 &queue_array[i].head);
+		queue_array[i].priv = queues->queue_array[i].priv;
+	}
+
+	queues->nr_queues = nr_queues;
+	queues->queue_array = queue_array;
+
+	return 0;
+}
+
+static void *itrace_copy_data(u64 size, struct perf_session *session)
+{
+	int fd = perf_data_file__fd(session->file);
+	void *p;
+	ssize_t ret;
+
+	if (size > SSIZE_MAX)
+		return NULL;
+
+	p = malloc(size);
+	if (!p)
+		return NULL;
+
+	ret = readn(fd, p, size);
+	if (ret != (ssize_t)size) {
+		free(p);
+		return NULL;
+	}
+
+	return p;
+}
+
+static int itrace_queues__add_buffer(struct itrace_queues *queues,
+				     unsigned int idx,
+				     struct itrace_buffer *buffer)
+{
+	struct itrace_queue *queue;
+	int err;
+
+	if (idx >= queues->nr_queues) {
+		err = itrace_queues__grow(queues, idx + 1);
+		if (err)
+			return err;
+	}
+
+	queue = &queues->queue_array[idx];
+
+	if (!queue->set) {
+		queue->set = true;
+		queue->tid = buffer->tid;
+		queue->cpu = buffer->cpu;
+	} else if (buffer->cpu != queue->cpu || buffer->tid != queue->tid) {
+		pr_err("itrace queue conflict: cpu %d, tid %d vs cpu %d, tid %d\n",
+		       queue->cpu, queue->tid, buffer->cpu, buffer->tid);
+		return -EINVAL;
+	}
+
+	buffer->buffer_nr = queues->next_buffer_nr++;
+
+	list_add_tail(&buffer->list, &queue->head);
+
+	queues->new_data = true;
+	queues->populated = true;
+
+	return 0;
+}
+
+/* Limit buffers to 32MiB on 32-bit */
+#define BUFFER_LIMIT_FOR_32_BIT (32 * 1024 * 1024)
+
+static int itrace_queues__split_buffer(struct itrace_queues *queues,
+				       unsigned int idx,
+				       struct itrace_buffer *buffer)
+{
+	u64 sz = buffer->size;
+	bool consecutive = false;
+	struct itrace_buffer *b;
+	int err;
+
+	while (sz > BUFFER_LIMIT_FOR_32_BIT) {
+		b = memdup(buffer, sizeof(struct itrace_buffer));
+		if (!b)
+			return -ENOMEM;
+		b->size = BUFFER_LIMIT_FOR_32_BIT;
+		b->consecutive = consecutive;
+		err = itrace_queues__add_buffer(queues, idx, b);
+		if (err) {
+			itrace_buffer__free(b);
+			return err;
+		}
+		buffer->data_offset += BUFFER_LIMIT_FOR_32_BIT;
+		sz -= BUFFER_LIMIT_FOR_32_BIT;
+		consecutive = true;
+	}
+
+	buffer->size = sz;
+	buffer->consecutive = consecutive;
+
+	return 0;
+}
+
+static int itrace_queues__add_event_buffer(struct itrace_queues *queues,
+					   struct perf_session *session,
+					   unsigned int idx,
+					   struct itrace_buffer *buffer)
+{
+	if (session->one_mmap) {
+		buffer->data = buffer->data_offset - session->one_mmap_offset +
+			       session->one_mmap_addr;
+	} else if (perf_data_file__is_pipe(session->file)) {
+		buffer->data = itrace_copy_data(buffer->size, session);
+		if (!buffer->data)
+			return -ENOMEM;
+		buffer->data_needs_freeing = true;
+	} else if (BITS_PER_LONG == 32 &&
+		   buffer->size > BUFFER_LIMIT_FOR_32_BIT) {
+		int err;
+
+		err = itrace_queues__split_buffer(queues, idx, buffer);
+		if (err)
+			return err;
+	}
+
+	return itrace_queues__add_buffer(queues, idx, buffer);
+}
+
+int itrace_queues__add_event(struct itrace_queues *queues,
+			     struct perf_session *session,
+			     union perf_event *event, off_t data_offset,
+			     struct itrace_buffer **buffer_ptr)
+{
+	struct itrace_buffer *buffer;
+	unsigned int idx;
+	int err;
+
+	buffer = zalloc(sizeof(struct itrace_buffer));
+	if (!buffer)
+		return -ENOMEM;
+
+	buffer->pid = -1;
+	buffer->tid = event->itrace.tid;
+	buffer->cpu = event->itrace.cpu;
+	buffer->data_offset = data_offset;
+	buffer->offset = event->itrace.offset;
+	buffer->reference = event->itrace.reference;
+	buffer->size = event->itrace.size;
+	idx = event->itrace.idx;
+
+	err = itrace_queues__add_event_buffer(queues, session, idx, buffer);
+	if (err)
+		goto out_err;
+
+	if (buffer_ptr)
+		*buffer_ptr = buffer;
+
+	return 0;
+
+out_err:
+	itrace_buffer__free(buffer);
+	return err;
+}
+
+void itrace_queues__free(struct itrace_queues *queues)
+{
+	unsigned int i;
+
+	for (i = 0; i < queues->nr_queues; i++) {
+		while (!list_empty(&queues->queue_array[i].head)) {
+			struct itrace_buffer *buffer;
+
+			buffer = list_entry(queues->queue_array[i].head.next,
+					    struct itrace_buffer, list);
+			list_del(&buffer->list);
+			itrace_buffer__free(buffer);
+		}
+	}
+
+	zfree(&queues->queue_array);
+	queues->nr_queues = 0;
+}
+
 size_t itrace_record__info_priv_size(struct itrace_record *itr)
 {
 	if (itr)
@@ -162,6 +401,71 @@ itrace_record__init(struct perf_evlist *evlist __maybe_unused, int *err)
 	return NULL;
 }
 
+struct itrace_buffer *itrace_buffer__next(struct itrace_queue *queue,
+					  struct itrace_buffer *buffer)
+{
+	if (buffer) {
+		if (list_is_last(&buffer->list, &queue->head))
+			return NULL;
+		return list_entry(buffer->list.next, struct itrace_buffer,
+				  list);
+	} else {
+		if (list_empty(&queue->head))
+			return NULL;
+		return list_entry(queue->head.next, struct itrace_buffer, list);
+	}
+}
+
+void *itrace_buffer__get_data(struct itrace_buffer *buffer, int fd)
+{
+	size_t adj = buffer->data_offset & (page_size - 1);
+	size_t size = buffer->size + adj;
+	off_t file_offset = buffer->data_offset - adj;
+	void *addr;
+
+	if (buffer->data)
+		return buffer->data;
+
+	addr = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, file_offset);
+	if (addr == MAP_FAILED)
+		return NULL;
+
+	buffer->mmap_addr = addr;
+	buffer->mmap_size = size;
+
+	buffer->data = addr + adj;
+
+	return buffer->data;
+}
+
+void itrace_buffer__put_data(struct itrace_buffer *buffer)
+{
+	if (!buffer->data || !buffer->mmap_addr)
+		return;
+	munmap(buffer->mmap_addr, buffer->mmap_size);
+	buffer->mmap_addr = NULL;
+	buffer->mmap_size = 0;
+	buffer->data = NULL;
+	buffer->use_data = NULL;
+}
+
+void itrace_buffer__drop_data(struct itrace_buffer *buffer)
+{
+	itrace_buffer__put_data(buffer);
+	if (buffer->data_needs_freeing) {
+		buffer->data_needs_freeing = false;
+		zfree(&buffer->data);
+		buffer->use_data = NULL;
+		buffer->size = 0;
+	}
+}
+
+void itrace_buffer__free(struct itrace_buffer *buffer)
+{
+	itrace_buffer__drop_data(buffer);
+	free(buffer);
+}
+
 void itrace_synth_error(struct itrace_error_event *itrace_error, int type,
 			int code, int cpu, pid_t pid, pid_t tid, u64 ip,
 			const char *msg)
diff --git a/tools/perf/util/itrace.h b/tools/perf/util/itrace.h
index 54b8607..fd97606 100644
--- a/tools/perf/util/itrace.h
+++ b/tools/perf/util/itrace.h
@@ -19,6 +19,7 @@
 #include <sys/types.h>
 #include <stdbool.h>
 #include <stddef.h>
+#include <linux/list.h>
 #include <linux/perf_event.h>
 #include <linux/types.h>
 
@@ -97,6 +98,80 @@ struct itrace {
 };
 
 /**
+ * struct itrace_buffer - a buffer containing Instruction Tracing data.
+ * @list: buffers are queued in a list held by struct itrace_queue
+ * @size: size of the buffer in bytes
+ * @pid: in per-thread mode, the pid this buffer is associated with
+ * @tid: in per-thread mode, the tid this buffer is associated with
+ * @cpu: in per-cpu mode, the cpu this buffer is associated with
+ * @data: actual buffer data (can be null if the data has not been loaded)
+ * @data_offset: file offset at which the buffer can be read
+ * @mmap_addr: mmap address at which the buffer can be read
+ * @mmap_size: size of the mmap at @mmap_addr
+ * @data_needs_freeing: @data was malloc'd so free it when it is no longer
+ *                      needed
+ * @consecutive: the original data was split up and this buffer is consecutive
+ *               to the previous buffer
+ * @offset: offset as determined by aux_head / aux_tail members of struct
+ *          perf_event_mmap_page
+ * @reference: an implementation-specific reference determined when the data is
+ *             recorded
+ * @buffer_nr: used to number each buffer
+ * @use_size: implementation actually only uses this number of bytes
+ * @use_data: implementation actually only uses data starting at this address
+ */
+struct itrace_buffer {
+	struct list_head	list;
+	size_t			size;
+	pid_t			pid;
+	pid_t			tid;
+	int			cpu;
+	void			*data;
+	off_t			data_offset;
+	void			*mmap_addr;
+	size_t			mmap_size;
+	bool			data_needs_freeing;
+	bool			consecutive;
+	u64			offset;
+	u64			reference;
+	u64			buffer_nr;
+	size_t			use_size;
+	void			*use_data;
+};
+
+/**
+ * struct itrace_queue - a queue of Instruction Tracing data buffers.
+ * @head: head of buffer list
+ * @tid: in per-thread mode, the tid this queue is associated with
+ * @cpu: in per-cpu mode, the cpu this queue is associated with
+ * @set: %true once this queue has been dedicated to a specific thread or cpu
+ * @priv: implementation-specific data
+ */
+struct itrace_queue {
+	struct list_head	head;
+	pid_t			tid;
+	int			cpu;
+	bool			set;
+	void			*priv;
+};
+
+/**
+ * struct itrace_queues - an array of Instruction Tracing queues.
+ * @queue_array: array of queues
+ * @nr_queues: number of queues
+ * @new_data: set whenever new data is queued
+ * @populated: queues have been fully populated using the itrace_index
+ * @next_buffer_nr: used to number each buffer
+ */
+struct itrace_queues {
+	struct itrace_queue	*queue_array;
+	unsigned int		nr_queues;
+	bool			new_data;
+	bool			populated;
+	u64			next_buffer_nr;
+};
+
+/**
  * struct itrace_mmap - records an mmap of the itrace buffer.
  * @base: address of mapped area
  * @userpg: pointer to buffer's perf_event_mmap_page
@@ -193,6 +268,18 @@ typedef int (*process_itrace_t)(struct perf_tool *tool, union perf_event *event,
 int itrace_mmap__read(struct itrace_mmap *mm, struct itrace_record *itr,
 		      struct perf_tool *tool, process_itrace_t fn);
 
+int itrace_queues__init(struct itrace_queues *queues);
+int itrace_queues__add_event(struct itrace_queues *queues,
+			     struct perf_session *session,
+			     union perf_event *event, off_t data_offset,
+			     struct itrace_buffer **buffer_ptr);
+void itrace_queues__free(struct itrace_queues *queues);
+struct itrace_buffer *itrace_buffer__next(struct itrace_queue *queue,
+					  struct itrace_buffer *buffer);
+void *itrace_buffer__get_data(struct itrace_buffer *buffer, int fd);
+void itrace_buffer__put_data(struct itrace_buffer *buffer);
+void itrace_buffer__drop_data(struct itrace_buffer *buffer);
+void itrace_buffer__free(struct itrace_buffer *buffer);
 struct itrace_record *itrace_record__init(struct perf_evlist *evlist, int *err);
 
 int itrace_record__options(struct itrace_record *itr,
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH V4 12/23] perf itrace: Add a heap for sorting Instruction Tracing queues
  2015-01-08 12:52 [PATCH V4 00/23] perf tools: Introduce an abstraction for Instruction Tracing Adrian Hunter
                   ` (10 preceding siblings ...)
  2015-01-08 12:52 ` [PATCH V4 11/23] perf itrace: Add helpers for queuing Instruction Tracing data Adrian Hunter
@ 2015-01-08 12:52 ` Adrian Hunter
  2015-01-08 12:52 ` [PATCH V4 13/23] perf itrace: Add processing for Instruction Tracing events Adrian Hunter
                   ` (11 subsequent siblings)
  23 siblings, 0 replies; 26+ messages in thread
From: Adrian Hunter @ 2015-01-08 12:52 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Peter Zijlstra, linux-kernel, David Ahern, Frederic Weisbecker,
	Jiri Olsa, Namhyung Kim, Paul Mackerras, Stephane Eranian

In order to process Instruction Tracing
data in time order, the queue with data
with the lowest timestamp must be
processed first.  Provide a heap to
keep track of which queue that is.

As with the queues, a decoder does not have
to use the heap, but Intel BTS and Intel PT
will use it.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 tools/perf/util/itrace.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/itrace.h | 29 +++++++++++++++++
 2 files changed, 114 insertions(+)

diff --git a/tools/perf/util/itrace.c b/tools/perf/util/itrace.c
index 4b0439b..e9c46fc 100644
--- a/tools/perf/util/itrace.c
+++ b/tools/perf/util/itrace.c
@@ -349,6 +349,91 @@ void itrace_queues__free(struct itrace_queues *queues)
 	queues->nr_queues = 0;
 }
 
+static void itrace_heapify(struct itrace_heap_item *heap_array,
+			   unsigned int pos, unsigned int queue_nr,
+			   u64 ordinal)
+{
+	unsigned int parent;
+
+	while (pos) {
+		parent = (pos - 1) >> 1;
+		if (heap_array[parent].ordinal <= ordinal)
+			break;
+		heap_array[pos] = heap_array[parent];
+		pos = parent;
+	}
+	heap_array[pos].queue_nr = queue_nr;
+	heap_array[pos].ordinal = ordinal;
+}
+
+int itrace_heap__add(struct itrace_heap *heap, unsigned int queue_nr,
+		     u64 ordinal)
+{
+	struct itrace_heap_item *heap_array;
+
+	if (queue_nr >= heap->heap_sz) {
+		unsigned int heap_sz = ITRACE_INIT_NR_QUEUES;
+
+		while (heap_sz <= queue_nr)
+			heap_sz <<= 1;
+		heap_array = realloc(heap->heap_array,
+				     heap_sz * sizeof(struct itrace_heap_item));
+		if (!heap_array)
+			return -ENOMEM;
+		heap->heap_array = heap_array;
+		heap->heap_sz = heap_sz;
+	}
+
+	itrace_heapify(heap->heap_array, heap->heap_cnt++, queue_nr, ordinal);
+
+	return 0;
+}
+
+void itrace_heap__free(struct itrace_heap *heap)
+{
+	zfree(&heap->heap_array);
+	heap->heap_cnt = 0;
+	heap->heap_sz = 0;
+}
+
+void itrace_heap__pop(struct itrace_heap *heap)
+{
+	unsigned int pos, last, heap_cnt = heap->heap_cnt;
+	struct itrace_heap_item *heap_array;
+
+	if (!heap_cnt)
+		return;
+
+	heap->heap_cnt -= 1;
+
+	heap_array = heap->heap_array;
+
+	pos = 0;
+	while (1) {
+		unsigned int left, right;
+
+		left = (pos << 1) + 1;
+		if (left >= heap_cnt)
+			break;
+		right = left + 1;
+		if (right >= heap_cnt) {
+			heap_array[pos] = heap_array[left];
+			return;
+		}
+		if (heap_array[left].ordinal < heap_array[right].ordinal) {
+			heap_array[pos] = heap_array[left];
+			pos = left;
+		} else {
+			heap_array[pos] = heap_array[right];
+			pos = right;
+		}
+	}
+
+	last = heap_cnt - 1;
+	itrace_heapify(heap_array, pos, heap_array[last].queue_nr,
+		       heap_array[last].ordinal);
+}
+
 size_t itrace_record__info_priv_size(struct itrace_record *itr)
 {
 	if (itr)
diff --git a/tools/perf/util/itrace.h b/tools/perf/util/itrace.h
index fd97606..0b00d50 100644
--- a/tools/perf/util/itrace.h
+++ b/tools/perf/util/itrace.h
@@ -172,6 +172,29 @@ struct itrace_queues {
 };
 
 /**
+ * struct itrace_heap_item - element of struct itrace_heap.
+ * @queue_nr: queue number
+ * @ordinal: value used for sorting (lowest ordinal is top of the heap) expected
+ *           to be a timestamp
+ */
+struct itrace_heap_item {
+	unsigned int		queue_nr;
+	u64			ordinal;
+};
+
+/**
+ * struct itrace_heap - a heap suitable for sorting Instruction Tracing queues.
+ * @heap_array: the heap
+ * @heap_cnt: the number of elements in the heap
+ * @heap_sz: maximum number of elements (grows as needed)
+ */
+struct itrace_heap {
+	struct itrace_heap_item	*heap_array;
+	unsigned int		heap_cnt;
+	unsigned int		heap_sz;
+};
+
+/**
  * struct itrace_mmap - records an mmap of the itrace buffer.
  * @base: address of mapped area
  * @userpg: pointer to buffer's perf_event_mmap_page
@@ -280,6 +303,12 @@ void *itrace_buffer__get_data(struct itrace_buffer *buffer, int fd);
 void itrace_buffer__put_data(struct itrace_buffer *buffer);
 void itrace_buffer__drop_data(struct itrace_buffer *buffer);
 void itrace_buffer__free(struct itrace_buffer *buffer);
+
+int itrace_heap__add(struct itrace_heap *heap, unsigned int queue_nr,
+		     u64 ordinal);
+void itrace_heap__pop(struct itrace_heap *heap);
+void itrace_heap__free(struct itrace_heap *heap);
+
 struct itrace_record *itrace_record__init(struct perf_evlist *evlist, int *err);
 
 int itrace_record__options(struct itrace_record *itr,
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH V4 13/23] perf itrace: Add processing for Instruction Tracing events
  2015-01-08 12:52 [PATCH V4 00/23] perf tools: Introduce an abstraction for Instruction Tracing Adrian Hunter
                   ` (11 preceding siblings ...)
  2015-01-08 12:52 ` [PATCH V4 12/23] perf itrace: Add a heap for sorting Instruction Tracing queues Adrian Hunter
@ 2015-01-08 12:52 ` Adrian Hunter
  2015-01-08 12:52 ` [PATCH V4 14/23] perf itrace: Add a hashtable for caching decoded instructions Adrian Hunter
                   ` (10 subsequent siblings)
  23 siblings, 0 replies; 26+ messages in thread
From: Adrian Hunter @ 2015-01-08 12:52 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Peter Zijlstra, linux-kernel, David Ahern, Frederic Weisbecker,
	Jiri Olsa, Namhyung Kim, Paul Mackerras, Stephane Eranian

Provide hooks so that an Instruction Trace
decoder can process Instruction Tracing
events.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 tools/perf/util/itrace.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/itrace.h | 13 +++++++++++++
 2 files changed, 62 insertions(+)

diff --git a/tools/perf/util/itrace.c b/tools/perf/util/itrace.c
index e9c46fc..c3b0993 100644
--- a/tools/perf/util/itrace.c
+++ b/tools/perf/util/itrace.c
@@ -602,6 +602,28 @@ out_free:
 	return err;
 }
 
+static bool itrace__dont_decode(struct perf_session *session)
+{
+	return !session->itrace_synth_opts ||
+	       session->itrace_synth_opts->dont_decode;
+}
+
+int perf_event__process_itrace_info(struct perf_tool *tool __maybe_unused,
+				    union perf_event *event,
+				    struct perf_session *session __maybe_unused)
+{
+	enum itrace_type type = event->itrace_info.type;
+
+	if (dump_trace)
+		fprintf(stdout, " type: %u\n", type);
+
+	switch (type) {
+	case PERF_ITRACE_UNKNOWN:
+	default:
+		return -EINVAL;
+	}
+}
+
 int perf_event__synthesize_itrace(struct perf_tool *tool,
 				  perf_event__handler_t process,
 				  size_t size, u64 offset, u64 ref, int idx,
@@ -622,6 +644,30 @@ int perf_event__synthesize_itrace(struct perf_tool *tool,
 	return process(tool, &ev, NULL, NULL);
 }
 
+s64 perf_event__process_itrace(struct perf_tool *tool, union perf_event *event,
+			       struct perf_session *session)
+{
+	s64 err;
+
+	if (dump_trace)
+		fprintf(stdout, " size: %#"PRIx64"  offset: %#"PRIx64"  ref: %#"PRIx64"  idx: %u  tid: %d  cpu: %d\n",
+			event->itrace.size, event->itrace.offset,
+			event->itrace.reference, event->itrace.idx,
+			event->itrace.tid, event->itrace.cpu);
+
+	if (itrace__dont_decode(session))
+		return event->itrace.size;
+
+	if (!session->itrace || event->header.type != PERF_RECORD_ITRACE)
+		return -EINVAL;
+
+	err = session->itrace->process_itrace_event(session, event, tool);
+	if (err < 0)
+		return err;
+
+	return event->itrace.size;
+}
+
 #define PERF_ITRACE_DEFAULT_PERIOD_TYPE		PERF_ITRACE_PERIOD_NANOSECS
 #define PERF_ITRACE_DEFAULT_PERIOD		100000
 #define PERF_ITRACE_DEFAULT_CALLCHAIN_SZ	16
@@ -767,6 +813,9 @@ int perf_event__process_itrace_error(struct perf_tool *tool __maybe_unused,
 				     union perf_event *event,
 				     struct perf_session *session)
 {
+	if (itrace__dont_decode(session))
+		return 0;
+
 	if (session->itrace)
 		session->itrace->error_count += 1;
 
diff --git a/tools/perf/util/itrace.h b/tools/perf/util/itrace.h
index 0b00d50..08247d5 100644
--- a/tools/perf/util/itrace.h
+++ b/tools/perf/util/itrace.h
@@ -34,6 +34,10 @@ struct option;
 struct record_opts;
 struct itrace_info_event;
 
+enum itrace_type {
+	PERF_ITRACE_UNKNOWN,
+};
+
 enum itrace_error_type {
 	PERF_ITRACE_DECODER_ERROR = 1,
 };
@@ -90,6 +94,9 @@ struct itrace {
 			     union perf_event *event,
 			     struct perf_sample *sample,
 			     struct perf_tool *tool);
+	int (*process_itrace_event)(struct perf_session *session,
+				    union perf_event *event,
+				    struct perf_tool *tool);
 	int (*flush_events)(struct perf_session *session,
 			    struct perf_tool *tool);
 	void (*free_events)(struct perf_session *session);
@@ -330,10 +337,16 @@ int perf_event__synthesize_itrace_info(struct itrace_record *itr,
 				       struct perf_tool *tool,
 				       struct perf_session *session,
 				       perf_event__handler_t process);
+int perf_event__process_itrace_info(struct perf_tool *tool,
+				    union perf_event *event,
+				    struct perf_session *session);
 int perf_event__synthesize_itrace(struct perf_tool *tool,
 				  perf_event__handler_t process,
 				  size_t size, u64 offset, u64 ref, int idx,
 				  u32 tid, u32 cpu);
+s64 perf_event__process_itrace(struct perf_tool *tool,
+			       union perf_event *event,
+			       struct perf_session *session);
 int perf_event__process_itrace_error(struct perf_tool *tool,
 				     union perf_event *event,
 				     struct perf_session *session);
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH V4 14/23] perf itrace: Add a hashtable for caching decoded instructions
  2015-01-08 12:52 [PATCH V4 00/23] perf tools: Introduce an abstraction for Instruction Tracing Adrian Hunter
                   ` (12 preceding siblings ...)
  2015-01-08 12:52 ` [PATCH V4 13/23] perf itrace: Add processing for Instruction Tracing events Adrian Hunter
@ 2015-01-08 12:52 ` Adrian Hunter
  2015-01-08 12:52 ` [PATCH V4 15/23] perf tools: Add member to struct dso for an instruction cache Adrian Hunter
                   ` (9 subsequent siblings)
  23 siblings, 0 replies; 26+ messages in thread
From: Adrian Hunter @ 2015-01-08 12:52 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Peter Zijlstra, linux-kernel, David Ahern, Frederic Weisbecker,
	Jiri Olsa, Namhyung Kim, Paul Mackerras, Stephane Eranian

Decoding Instruction Trace data may involve walking object
code.  Rather than repetitively decoding the same instructions,
a cache can be used to cache the results.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 tools/perf/util/itrace.c | 123 +++++++++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/itrace.h |  14 ++++++
 2 files changed, 137 insertions(+)

diff --git a/tools/perf/util/itrace.c b/tools/perf/util/itrace.c
index c3b0993..bdf19d2 100644
--- a/tools/perf/util/itrace.c
+++ b/tools/perf/util/itrace.c
@@ -39,6 +39,8 @@
 #include "thread_map.h"
 #include "itrace.h"
 
+#include <linux/hash.h>
+
 #include "event.h"
 #include "session.h"
 #include "debug.h"
@@ -919,3 +921,124 @@ int itrace_mmap__read(struct itrace_mmap *mm, struct itrace_record *itr,
 
 	return 1;
 }
+
+/**
+ * struct itrace_cache - hash table to cache decoded instruction blocks
+ * @hashtable: the hashtable
+ * @sz: hashtable size (number of hlists)
+ * @entry_size: size of an entry
+ * @limit: limit the number of entries to this maximum, when reached the cache
+ *         is dropped and caching begins again with an empty cache
+ * @cnt: current number of entries
+ * @bits: hashtable size (@sz = 2^@bits)
+ */
+struct itrace_cache {
+	struct hlist_head *hashtable;
+	size_t sz;
+	size_t entry_size;
+	size_t limit;
+	size_t cnt;
+	unsigned int bits;
+};
+
+struct itrace_cache *itrace_cache__new(unsigned int bits, size_t entry_size,
+				       unsigned int limit_percent)
+{
+	struct itrace_cache *c;
+	struct hlist_head *ht;
+	size_t sz, i;
+
+	c = zalloc(sizeof(struct itrace_cache));
+	if (!c)
+		return NULL;
+
+	sz = 1UL << bits;
+
+	ht = calloc(sz, sizeof(struct hlist_head));
+	if (!ht)
+		goto out_free;
+
+	for (i = 0; i < sz; i++)
+		INIT_HLIST_HEAD(&ht[i]);
+
+	c->hashtable = ht;
+	c->sz = sz;
+	c->entry_size = entry_size;
+	c->limit = (c->sz * limit_percent) / 100;
+	c->bits = bits;
+
+	return c;
+
+out_free:
+	free(c);
+	return NULL;
+}
+
+static void itrace_cache__drop(struct itrace_cache *c)
+{
+	struct itrace_cache_entry *entry;
+	struct hlist_node *tmp;
+	size_t i;
+
+	if (!c)
+		return;
+
+	for (i = 0; i < c->sz; i++) {
+		hlist_for_each_entry_safe(entry, tmp, &c->hashtable[i], hash) {
+			hlist_del(&entry->hash);
+			itrace_cache__free_entry(c, entry);
+		}
+	}
+
+	c->cnt = 0;
+}
+
+void itrace_cache__free(struct itrace_cache *c)
+{
+	if (!c)
+		return;
+
+	itrace_cache__drop(c);
+	free(c->hashtable);
+	free(c);
+}
+
+void *itrace_cache__alloc_entry(struct itrace_cache *c)
+{
+	return malloc(c->entry_size);
+}
+
+void itrace_cache__free_entry(struct itrace_cache *c __maybe_unused,
+			      void *entry)
+{
+	free(entry);
+}
+
+int itrace_cache__add(struct itrace_cache *c, u32 key,
+		      struct itrace_cache_entry *entry)
+{
+	if (c->limit && ++c->cnt > c->limit)
+		itrace_cache__drop(c);
+
+	entry->key = key;
+	hlist_add_head(&entry->hash, &c->hashtable[hash_32(key, c->bits)]);
+
+	return 0;
+}
+
+void *itrace_cache__lookup(struct itrace_cache *c, u32 key)
+{
+	struct itrace_cache_entry *entry;
+	struct hlist_head *hlist;
+
+	if (!c)
+		return NULL;
+
+	hlist = &c->hashtable[hash_32(key, c->bits)];
+	hlist_for_each_entry(entry, hlist, hash) {
+		if (entry->key == key)
+			return entry;
+	}
+
+	return NULL;
+}
diff --git a/tools/perf/util/itrace.h b/tools/perf/util/itrace.h
index 08247d5..3bd899e 100644
--- a/tools/perf/util/itrace.h
+++ b/tools/perf/util/itrace.h
@@ -316,6 +316,20 @@ int itrace_heap__add(struct itrace_heap *heap, unsigned int queue_nr,
 void itrace_heap__pop(struct itrace_heap *heap);
 void itrace_heap__free(struct itrace_heap *heap);
 
+struct itrace_cache_entry {
+	struct hlist_node hash;
+	u32 key;
+};
+
+struct itrace_cache *itrace_cache__new(unsigned int bits, size_t entry_size,
+				       unsigned int limit_percent);
+void itrace_cache__free(struct itrace_cache *itrace_cache);
+void *itrace_cache__alloc_entry(struct itrace_cache *c);
+void itrace_cache__free_entry(struct itrace_cache *c, void *entry);
+int itrace_cache__add(struct itrace_cache *c, u32 key,
+		      struct itrace_cache_entry *entry);
+void *itrace_cache__lookup(struct itrace_cache *c, u32 key);
+
 struct itrace_record *itrace_record__init(struct perf_evlist *evlist, int *err);
 
 int itrace_record__options(struct itrace_record *itr,
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH V4 15/23] perf tools: Add member to struct dso for an instruction cache
  2015-01-08 12:52 [PATCH V4 00/23] perf tools: Introduce an abstraction for Instruction Tracing Adrian Hunter
                   ` (13 preceding siblings ...)
  2015-01-08 12:52 ` [PATCH V4 14/23] perf itrace: Add a hashtable for caching decoded instructions Adrian Hunter
@ 2015-01-08 12:52 ` Adrian Hunter
  2015-01-08 12:52 ` [PATCH V4 16/23] perf script: Add Instruction Tracing support Adrian Hunter
                   ` (8 subsequent siblings)
  23 siblings, 0 replies; 26+ messages in thread
From: Adrian Hunter @ 2015-01-08 12:52 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Peter Zijlstra, linux-kernel, David Ahern, Frederic Weisbecker,
	Jiri Olsa, Namhyung Kim, Paul Mackerras, Stephane Eranian

Add a member to struct dso that can be used by Instruction
Trace implementations to hold a cache for decoded instructions.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 tools/perf/util/dso.c | 2 ++
 tools/perf/util/dso.h | 3 +++
 2 files changed, 5 insertions(+)

diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c
index 45be944..73e28ca 100644
--- a/tools/perf/util/dso.c
+++ b/tools/perf/util/dso.c
@@ -4,6 +4,7 @@
 #include "symbol.h"
 #include "dso.h"
 #include "machine.h"
+#include "itrace.h"
 #include "util.h"
 #include "debug.h"
 
@@ -914,6 +915,7 @@ void dso__delete(struct dso *dso)
 	}
 
 	dso__data_close(dso);
+	itrace_cache__free(dso->itrace_cache);
 	dso_cache__free(&dso->data.cache);
 	dso__free_a2l(dso);
 	zfree(&dso->symsrc_filename);
diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h
index 3782c82..c27c8fc 100644
--- a/tools/perf/util/dso.h
+++ b/tools/perf/util/dso.h
@@ -101,6 +101,8 @@ struct dsos {
 	struct rb_root	 root;	/* rbtree root sorted by long name */
 };
 
+struct itrace_cache;
+
 struct dso {
 	struct list_head node;
 	struct rb_node	 rb_node;	/* rbtree node sorted by long name */
@@ -130,6 +132,7 @@ struct dso {
 	u16		 long_name_len;
 	u16		 short_name_len;
 	void		*dwfl;			/* DWARF debug info */
+	struct itrace_cache *itrace_cache;
 
 	/* dso data file */
 	struct {
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH V4 16/23] perf script: Add Instruction Tracing support
  2015-01-08 12:52 [PATCH V4 00/23] perf tools: Introduce an abstraction for Instruction Tracing Adrian Hunter
                   ` (14 preceding siblings ...)
  2015-01-08 12:52 ` [PATCH V4 15/23] perf tools: Add member to struct dso for an instruction cache Adrian Hunter
@ 2015-01-08 12:52 ` Adrian Hunter
  2015-01-08 12:52 ` [PATCH V4 17/23] perf script: Always allow fields 'addr' and 'cpu' for itrace Adrian Hunter
                   ` (7 subsequent siblings)
  23 siblings, 0 replies; 26+ messages in thread
From: Adrian Hunter @ 2015-01-08 12:52 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Peter Zijlstra, linux-kernel, David Ahern, Frederic Weisbecker,
	Jiri Olsa, Namhyung Kim, Paul Mackerras, Stephane Eranian

Add support for decoding an Instruction Trace.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 tools/perf/Documentation/perf-script.txt | 28 ++++++++++++++++++++++++++++
 tools/perf/builtin-script.c              | 11 +++++++++++
 2 files changed, 39 insertions(+)

diff --git a/tools/perf/Documentation/perf-script.txt b/tools/perf/Documentation/perf-script.txt
index a21eec0..9a4aea1 100644
--- a/tools/perf/Documentation/perf-script.txt
+++ b/tools/perf/Documentation/perf-script.txt
@@ -215,6 +215,34 @@ OPTIONS
 --header-only
 	Show only perf.data header.
 
+-Z::
+--itrace::
+	Options for decoding Instruction Tracing data. The options are:
+
+		i	synthesize instructions events
+		b	synthesize branches events
+		c	synthesize branches events (calls only)
+		r	synthesize branches events (returns only)
+		e	synthesize error events
+		d	create a debug log
+		g	synthesize a call chain for instructions events
+
+	The default is all events i.e. the same as -Zibe
+
+	In addition, the period (default 1000) for instructions events can be
+	specified in units of:
+
+		i	instructions (default)
+		t	ticks
+		ms	milliseconds
+		us	microseconds
+		ns	nanoseconds
+
+	Also the call chain size (default 16, max. 1024) for instructions
+	events can be specified.
+
+	To disable decoding entirely, use --no-itrace.
+
 SEE ALSO
 --------
 linkperf:perf-record[1], linkperf:perf-script-perl[1],
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index ce304df..dbffd00 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -16,6 +16,7 @@
 #include "util/evsel.h"
 #include "util/sort.h"
 #include "util/data.h"
+#include "util/itrace.h"
 #include <linux/bitmap.h>
 
 static char const		*script_name;
@@ -1505,6 +1506,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
 	char *rec_script_path = NULL;
 	char *rep_script_path = NULL;
 	struct perf_session *session;
+	struct itrace_synth_opts itrace_synth_opts = {0};
 	char *script_path = NULL;
 	const char **__argv;
 	int i, j, err = 0;
@@ -1519,6 +1521,10 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
 			.attr		 = process_attr,
 			.tracing_data	 = perf_event__process_tracing_data,
 			.build_id	 = perf_event__process_build_id,
+			.id_index	 = perf_event__process_id_index,
+			.itrace_info	 = perf_event__process_itrace_info,
+			.itrace		 = perf_event__process_itrace,
+			.itrace_error	 = perf_event__process_itrace_error,
 			.ordered_events	 = true,
 			.ordering_requires_timestamps = true,
 		},
@@ -1570,6 +1576,9 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
 		    "Show the fork/comm/exit events"),
 	OPT_BOOLEAN('\0', "show-mmap-events", &script.show_mmap_events,
 		    "Show the mmap events"),
+	OPT_CALLBACK_OPTARG('Z', "itrace", &itrace_synth_opts, NULL, "opts",
+			    "Instruction Tracing options",
+			    itrace_parse_synth_opts),
 	OPT_END()
 	};
 	const char * const script_usage[] = {
@@ -1767,6 +1776,8 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
 
 	script.session = session;
 
+	session->itrace_synth_opts = &itrace_synth_opts;
+
 	if (cpu_list) {
 		err = perf_session__cpu_bitmap(session, cpu_list, cpu_bitmap);
 		if (err < 0)
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH V4 17/23] perf script: Always allow fields 'addr' and 'cpu' for itrace
  2015-01-08 12:52 [PATCH V4 00/23] perf tools: Introduce an abstraction for Instruction Tracing Adrian Hunter
                   ` (15 preceding siblings ...)
  2015-01-08 12:52 ` [PATCH V4 16/23] perf script: Add Instruction Tracing support Adrian Hunter
@ 2015-01-08 12:52 ` Adrian Hunter
  2015-01-08 12:52 ` [PATCH V4 18/23] perf report: Add Instruction Tracing support Adrian Hunter
                   ` (6 subsequent siblings)
  23 siblings, 0 replies; 26+ messages in thread
From: Adrian Hunter @ 2015-01-08 12:52 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Peter Zijlstra, linux-kernel, David Ahern, Frederic Weisbecker,
	Jiri Olsa, Namhyung Kim, Paul Mackerras, Stephane Eranian

If a file contains Instruction Tracing data then always allow
fields 'addr' and 'cpu' to be selected as options for perf
script.  This is necessary because Instruction Trace decoding
may synthesize events with that information.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 tools/perf/builtin-script.c | 28 +++++++++++++++++++++-------
 1 file changed, 21 insertions(+), 7 deletions(-)

diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index dbffd00..8976d9b 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -147,9 +147,10 @@ static const char *output_field2str(enum perf_output_field field)
 
 #define PRINT_FIELD(x)  (output[attr->type].fields & PERF_OUTPUT_##x)
 
-static int perf_evsel__check_stype(struct perf_evsel *evsel,
-				   u64 sample_type, const char *sample_msg,
-				   enum perf_output_field field)
+static int perf_evsel__do_check_stype(struct perf_evsel *evsel,
+				      u64 sample_type, const char *sample_msg,
+				      enum perf_output_field field,
+				      bool allow_user_set)
 {
 	struct perf_event_attr *attr = &evsel->attr;
 	int type = attr->type;
@@ -159,6 +160,8 @@ static int perf_evsel__check_stype(struct perf_evsel *evsel,
 		return 0;
 
 	if (output[type].user_set) {
+		if (allow_user_set)
+			return 0;
 		evname = perf_evsel__name(evsel);
 		pr_err("Samples for '%s' event do not have %s attribute set. "
 		       "Cannot print '%s' field.\n",
@@ -176,10 +179,21 @@ static int perf_evsel__check_stype(struct perf_evsel *evsel,
 	return 0;
 }
 
+static int perf_evsel__check_stype(struct perf_evsel *evsel,
+				   u64 sample_type, const char *sample_msg,
+				   enum perf_output_field field)
+{
+	return perf_evsel__do_check_stype(evsel, sample_type, sample_msg, field,
+					  false);
+}
+
 static int perf_evsel__check_attr(struct perf_evsel *evsel,
 				  struct perf_session *session)
 {
 	struct perf_event_attr *attr = &evsel->attr;
+	bool allow_user_set;
+
+	allow_user_set = perf_header__has_feat(&session->header, HEADER_ITRACE);
 
 	if (PRINT_FIELD(TRACE) &&
 		!perf_session__has_traces(session, "record -R"))
@@ -192,8 +206,8 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel,
 	}
 
 	if (PRINT_FIELD(ADDR) &&
-		perf_evsel__check_stype(evsel, PERF_SAMPLE_ADDR, "ADDR",
-					PERF_OUTPUT_ADDR))
+		perf_evsel__do_check_stype(evsel, PERF_SAMPLE_ADDR, "ADDR",
+					   PERF_OUTPUT_ADDR, allow_user_set))
 		return -EINVAL;
 
 	if (PRINT_FIELD(SYM) && !PRINT_FIELD(IP) && !PRINT_FIELD(ADDR)) {
@@ -230,8 +244,8 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel,
 		return -EINVAL;
 
 	if (PRINT_FIELD(CPU) &&
-		perf_evsel__check_stype(evsel, PERF_SAMPLE_CPU, "CPU",
-					PERF_OUTPUT_CPU))
+		perf_evsel__do_check_stype(evsel, PERF_SAMPLE_CPU, "CPU",
+					   PERF_OUTPUT_CPU, allow_user_set))
 		return -EINVAL;
 
 	if (PRINT_FIELD(PERIOD) &&
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH V4 18/23] perf report: Add Instruction Tracing support
  2015-01-08 12:52 [PATCH V4 00/23] perf tools: Introduce an abstraction for Instruction Tracing Adrian Hunter
                   ` (16 preceding siblings ...)
  2015-01-08 12:52 ` [PATCH V4 17/23] perf script: Always allow fields 'addr' and 'cpu' for itrace Adrian Hunter
@ 2015-01-08 12:52 ` Adrian Hunter
  2015-01-08 12:52 ` [PATCH V4 19/23] perf inject: Re-pipe Instruction Tracing events Adrian Hunter
                   ` (5 subsequent siblings)
  23 siblings, 0 replies; 26+ messages in thread
From: Adrian Hunter @ 2015-01-08 12:52 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Peter Zijlstra, linux-kernel, David Ahern, Frederic Weisbecker,
	Jiri Olsa, Namhyung Kim, Paul Mackerras, Stephane Eranian

Add support for decoding an Instruction Trace.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 tools/perf/Documentation/perf-report.txt | 28 ++++++++++++++++++++++++++++
 tools/perf/builtin-report.c              | 12 ++++++++++++
 2 files changed, 40 insertions(+)

diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt
index dd7cccd..835d1e0 100644
--- a/tools/perf/Documentation/perf-report.txt
+++ b/tools/perf/Documentation/perf-report.txt
@@ -318,6 +318,34 @@ OPTIONS
 --header-only::
 	Show only perf.data header (forces --stdio).
 
+-Z::
+--itrace::
+	Options for decoding Instruction Tracing data. The options are:
+
+		i	synthesize instructions events
+		b	synthesize branches events
+		c	synthesize branches events (calls only)
+		r	synthesize branches events (returns only)
+		e	synthesize error events
+		d	create a debug log
+		g	synthesize a call chain for instructions events
+
+	The default is all events i.e. the same as -Zibe
+
+	In addition, the period (default 1000) for instructions events can be
+	specified in units of:
+
+		i	instructions (default)
+		t	ticks
+		ms	milliseconds
+		us	microseconds
+		ns	nanoseconds
+
+	Also the call chain size (default 16, max. 1024) for instructions
+	events can be specified.
+
+	To disable decoding entirely, use --no-itrace.
+
 SEE ALSO
 --------
 linkperf:perf-stat[1], linkperf:perf-annotate[1]
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 2f91094..1533dbd 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -36,6 +36,8 @@
 #include "util/data.h"
 #include "arch/common.h"
 
+#include "util/itrace.h"
+
 #include <dlfcn.h>
 #include <linux/bitmap.h>
 
@@ -583,6 +585,7 @@ parse_percent_limit(const struct option *opt, const char *str,
 int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
 {
 	struct perf_session *session;
+	struct itrace_synth_opts itrace_synth_opts = {0};
 	struct stat st;
 	bool has_br_stack = false;
 	int branch_mode = -1;
@@ -605,6 +608,10 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
 			.attr		 = perf_event__process_attr,
 			.tracing_data	 = perf_event__process_tracing_data,
 			.build_id	 = perf_event__process_build_id,
+			.id_index	 = perf_event__process_id_index,
+			.itrace_info	 = perf_event__process_itrace_info,
+			.itrace		 = perf_event__process_itrace,
+			.itrace_error	 = perf_event__count_itrace_error,
 			.ordered_events	 = true,
 			.ordering_requires_timestamps = true,
 		},
@@ -711,6 +718,9 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
 		     "Don't show entries under that percent", parse_percent_limit),
 	OPT_CALLBACK(0, "percentage", NULL, "relative|absolute",
 		     "how to display percentage of filtered entries", parse_filter_percentage),
+	OPT_CALLBACK_OPTARG('Z', "itrace", &itrace_synth_opts, NULL, "opts",
+			    "Instruction Tracing options",
+			    itrace_parse_synth_opts),
 	OPT_END()
 	};
 	struct perf_data_file file = {
@@ -755,6 +765,8 @@ repeat:
 					       report.queue_size);
 	}
 
+	session->itrace_synth_opts = &itrace_synth_opts;
+
 	report.session = session;
 
 	has_br_stack = perf_header__has_feat(&session->header,
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH V4 19/23] perf inject: Re-pipe Instruction Tracing events
  2015-01-08 12:52 [PATCH V4 00/23] perf tools: Introduce an abstraction for Instruction Tracing Adrian Hunter
                   ` (17 preceding siblings ...)
  2015-01-08 12:52 ` [PATCH V4 18/23] perf report: Add Instruction Tracing support Adrian Hunter
@ 2015-01-08 12:52 ` Adrian Hunter
  2015-01-08 12:52 ` [PATCH V4 20/23] perf inject: Add Instruction Tracing support Adrian Hunter
                   ` (4 subsequent siblings)
  23 siblings, 0 replies; 26+ messages in thread
From: Adrian Hunter @ 2015-01-08 12:52 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Peter Zijlstra, linux-kernel, David Ahern, Frederic Weisbecker,
	Jiri Olsa, Namhyung Kim, Paul Mackerras, Stephane Eranian

New Instruction Tracing events must be re-piped by default.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 tools/perf/builtin-inject.c | 63 +++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 58 insertions(+), 5 deletions(-)

diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
index 84df2de..29e0840 100644
--- a/tools/perf/builtin-inject.c
+++ b/tools/perf/builtin-inject.c
@@ -38,14 +38,11 @@ struct event_entry {
 	union perf_event event[0];
 };
 
-static int perf_event__repipe_synth(struct perf_tool *tool,
-				    union perf_event *event)
+static int output_bytes(struct perf_inject *inject, void *buf, size_t sz)
 {
-	struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
 	ssize_t size;
 
-	size = perf_data_file__write(&inject->output, event,
-				     event->header.size);
+	size = perf_data_file__write(&inject->output, buf, sz);
 	if (size < 0)
 		return -errno;
 
@@ -53,6 +50,34 @@ static int perf_event__repipe_synth(struct perf_tool *tool,
 	return 0;
 }
 
+static int copy_bytes(struct perf_inject *inject, int fd, off_t size)
+{
+	char buf[4096];
+	ssize_t ssz;
+	int ret;
+
+	while (size > 0) {
+		ssz = read(fd, buf, MIN(size, sizeof(buf)));
+		if (ssz < 0)
+			return -errno;
+		ret = output_bytes(inject, buf, ssz);
+		if (ret)
+			return ret;
+		size -= ssz;
+	}
+
+	return 0;
+}
+
+static int perf_event__repipe_synth(struct perf_tool *tool,
+				    union perf_event *event)
+{
+	struct perf_inject *inject = container_of(tool, struct perf_inject,
+						  tool);
+
+	return output_bytes(inject, event, event->header.size);
+}
+
 static int perf_event__repipe_op2_synth(struct perf_tool *tool,
 					union perf_event *event,
 					struct perf_session *session
@@ -79,6 +104,31 @@ static int perf_event__repipe_attr(struct perf_tool *tool,
 	return perf_event__repipe_synth(tool, event);
 }
 
+static s64 perf_event__repipe_itrace(struct perf_tool *tool,
+				     union perf_event *event,
+				     struct perf_session *session
+				     __maybe_unused)
+{
+	struct perf_inject *inject = container_of(tool, struct perf_inject,
+						  tool);
+	int ret;
+
+	if (perf_data_file__is_pipe(session->file) || !session->one_mmap) {
+		ret = output_bytes(inject, event, event->header.size);
+		if (ret < 0)
+			return ret;
+		ret = copy_bytes(inject, perf_data_file__fd(session->file),
+				 event->itrace.size);
+	} else {
+		ret = output_bytes(inject, event,
+				   event->header.size + event->itrace.size);
+	}
+	if (ret < 0)
+		return ret;
+
+	return event->itrace.size;
+}
+
 static int perf_event__repipe(struct perf_tool *tool,
 			      union perf_event *event,
 			      struct perf_sample *sample __maybe_unused,
@@ -407,6 +457,9 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
 			.unthrottle	= perf_event__repipe,
 			.attr		= perf_event__repipe_attr,
 			.tracing_data	= perf_event__repipe_op2_synth,
+			.itrace_info	= perf_event__repipe_op2_synth,
+			.itrace		= perf_event__repipe_itrace,
+			.itrace_error	= perf_event__repipe_op2_synth,
 			.finished_round	= perf_event__repipe_op2_synth,
 			.build_id	= perf_event__repipe_op2_synth,
 			.id_index	= perf_event__repipe_op2_synth,
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH V4 20/23] perf inject: Add Instruction Tracing support
  2015-01-08 12:52 [PATCH V4 00/23] perf tools: Introduce an abstraction for Instruction Tracing Adrian Hunter
                   ` (18 preceding siblings ...)
  2015-01-08 12:52 ` [PATCH V4 19/23] perf inject: Re-pipe Instruction Tracing events Adrian Hunter
@ 2015-01-08 12:52 ` Adrian Hunter
  2015-01-08 12:52 ` [PATCH V4 21/23] perf tools: Add Instruction Tracing index Adrian Hunter
                   ` (3 subsequent siblings)
  23 siblings, 0 replies; 26+ messages in thread
From: Adrian Hunter @ 2015-01-08 12:52 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Peter Zijlstra, linux-kernel, David Ahern, Frederic Weisbecker,
	Jiri Olsa, Namhyung Kim, Paul Mackerras, Stephane Eranian

Add support for decoding an Instruction Trace.  The
Instruction Tracing events are stripped and replaced
by synthesized events.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 tools/perf/Documentation/perf-inject.txt | 27 ++++++++++++
 tools/perf/builtin-inject.c              | 71 +++++++++++++++++++++++++++++++-
 2 files changed, 96 insertions(+), 2 deletions(-)

diff --git a/tools/perf/Documentation/perf-inject.txt b/tools/perf/Documentation/perf-inject.txt
index dc7442c..9f49c43 100644
--- a/tools/perf/Documentation/perf-inject.txt
+++ b/tools/perf/Documentation/perf-inject.txt
@@ -44,6 +44,33 @@ OPTIONS
 --kallsyms=<file>::
 	kallsyms pathname
 
+-Z::
+--itrace::
+	Decode Instruction Tracing data, replacing it with synthesized events.
+	Options are:
+
+		i	synthesize instructions events
+		b	synthesize branches events
+		c	synthesize branches events (calls only)
+		r	synthesize branches events (returns only)
+		e	synthesize error events
+		d	create a debug log
+		g	synthesize a call chain for instructions events
+
+	The default is all events i.e. the same as -Zibe
+
+	In addition, the period (default 1000) for instructions events can be
+	specified in units of:
+
+		i	instructions (default)
+		t	ticks
+		ms	milliseconds
+		us	microseconds
+		ns	nanoseconds
+
+	Also the call chain size (default 16, max. 1024) for instructions
+	events can be specified.
+
 SEE ALSO
 --------
 linkperf:perf-record[1], linkperf:perf-report[1], linkperf:perf-archive[1]
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
index 29e0840..c3323ea 100644
--- a/tools/perf/builtin-inject.c
+++ b/tools/perf/builtin-inject.c
@@ -16,6 +16,7 @@
 #include "util/debug.h"
 #include "util/build-id.h"
 #include "util/data.h"
+#include "util/itrace.h"
 
 #include "util/parse-options.h"
 
@@ -30,6 +31,7 @@ struct perf_inject {
 	struct perf_data_file	output;
 	u64			bytes_written;
 	struct list_head	samples;
+	struct itrace_synth_opts itrace_synth_opts;
 };
 
 struct event_entry {
@@ -198,6 +200,32 @@ static int perf_event__repipe_fork(struct perf_tool *tool,
 	return err;
 }
 
+static int perf_event__repipe_comm(struct perf_tool *tool,
+				   union perf_event *event,
+				   struct perf_sample *sample,
+				   struct machine *machine)
+{
+	int err;
+
+	err = perf_event__process_comm(tool, event, sample, machine);
+	perf_event__repipe(tool, event, sample, machine);
+
+	return err;
+}
+
+static int perf_event__repipe_exit(struct perf_tool *tool,
+				   union perf_event *event,
+				   struct perf_sample *sample,
+				   struct machine *machine)
+{
+	int err;
+
+	err = perf_event__process_exit(tool, event, sample, machine);
+	perf_event__repipe(tool, event, sample, machine);
+
+	return err;
+}
+
 static int perf_event__repipe_tracing_data(struct perf_tool *tool,
 					   union perf_event *event,
 					   struct perf_session *session)
@@ -210,6 +238,18 @@ static int perf_event__repipe_tracing_data(struct perf_tool *tool,
 	return err;
 }
 
+static int perf_event__repipe_id_index(struct perf_tool *tool,
+				       union perf_event *event,
+				       struct perf_session *session)
+{
+	int err;
+
+	perf_event__repipe_synth(tool, event);
+	err = perf_event__process_id_index(tool, event, session);
+
+	return err;
+}
+
 static int dso__read_build_id(struct dso *dso)
 {
 	if (dso->has_build_id)
@@ -393,16 +433,20 @@ static int __cmd_inject(struct perf_inject *inject)
 	int ret = -EINVAL;
 	struct perf_session *session = inject->session;
 	struct perf_data_file *file_out = &inject->output;
+	u64 output_data_offset;
 
 	signal(SIGINT, sig_handler);
 
-	if (inject->build_ids || inject->sched_stat) {
+	if (inject->build_ids || inject->sched_stat ||
+	    inject->itrace_synth_opts.set) {
 		inject->tool.mmap	  = perf_event__repipe_mmap;
 		inject->tool.mmap2	  = perf_event__repipe_mmap2;
 		inject->tool.fork	  = perf_event__repipe_fork;
 		inject->tool.tracing_data = perf_event__repipe_tracing_data;
 	}
 
+	output_data_offset = session->header.data_offset;
+
 	if (inject->build_ids) {
 		inject->tool.sample = perf_event__inject_buildid;
 	} else if (inject->sched_stat) {
@@ -423,10 +467,22 @@ static int __cmd_inject(struct perf_inject *inject)
 			else if (!strncmp(name, "sched:sched_stat_", 17))
 				evsel->handler = perf_inject__sched_stat;
 		}
+	} else if (inject->itrace_synth_opts.set) {
+		session->itrace_synth_opts = &inject->itrace_synth_opts;
+		inject->itrace_synth_opts.inject = true;
+		inject->tool.comm	    = perf_event__repipe_comm;
+		inject->tool.exit	    = perf_event__repipe_exit;
+		inject->tool.id_index	    = perf_event__repipe_id_index;
+		inject->tool.itrace_info    = perf_event__process_itrace_info;
+		inject->tool.itrace	    = perf_event__process_itrace;
+		inject->tool.ordered_events = true;
+		inject->tool.ordering_requires_timestamps = true;
+		/* Allow space in the header for new attributes */
+		output_data_offset = 4096;
 	}
 
 	if (!file_out->is_pipe)
-		lseek(file_out->fd, session->header.data_offset, SEEK_SET);
+		lseek(file_out->fd, output_data_offset, SEEK_SET);
 
 	ret = perf_session__process_events(session, &inject->tool);
 
@@ -434,6 +490,14 @@ static int __cmd_inject(struct perf_inject *inject)
 		if (inject->build_ids)
 			perf_header__set_feat(&session->header,
 					      HEADER_BUILD_ID);
+		/*
+		 * The instruction traces have been removed and replaced with
+		 * synthesized hardware events, so clear the feature flag.
+		 */
+		if (inject->itrace_synth_opts.set)
+			perf_header__clear_feat(&session->header,
+						HEADER_ITRACE);
+		session->header.data_offset = output_data_offset;
 		session->header.data_size = inject->bytes_written;
 		perf_session__write_header(session, session->evlist, file_out->fd, true);
 	}
@@ -490,6 +554,9 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
 			 "be more verbose (show build ids, etc)"),
 		OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name, "file",
 			   "kallsyms pathname"),
+		OPT_CALLBACK_OPTARG('Z', "itrace", &inject.itrace_synth_opts,
+				    NULL, "opts", "Instruction Tracing options",
+				    itrace_parse_synth_opts),
 		OPT_END()
 	};
 	const char * const inject_usage[] = {
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH V4 21/23] perf tools: Add Instruction Tracing index
  2015-01-08 12:52 [PATCH V4 00/23] perf tools: Introduce an abstraction for Instruction Tracing Adrian Hunter
                   ` (19 preceding siblings ...)
  2015-01-08 12:52 ` [PATCH V4 20/23] perf inject: Add Instruction Tracing support Adrian Hunter
@ 2015-01-08 12:52 ` Adrian Hunter
  2015-01-08 12:52 ` [PATCH V4 22/23] perf tools: Hit all build ids when Instruction Tracing Adrian Hunter
                   ` (2 subsequent siblings)
  23 siblings, 0 replies; 26+ messages in thread
From: Adrian Hunter @ 2015-01-08 12:52 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Peter Zijlstra, linux-kernel, David Ahern, Frederic Weisbecker,
	Jiri Olsa, Namhyung Kim, Paul Mackerras, Stephane Eranian

Add an index of Instruction Tracing events within
a perf.data file.

perf record uses a special user event
PERF_RECORD_FINISHED_ROUND to enable sorting of
events in chunks instead of having to sort all
events altogether.

Instruction Tracing events contain data that can
span back to the very beginning of the recording
period. i.e. they do not obey the rules of
PERF_RECORD_FINISHED_ROUND.

By adding an index, Instruction Tracing events
can be found in advance and the
PERF_RECORD_FINISHED_ROUND approach works as
usual.

The index is recorded with the itrace feature
in the perf.data file.  A session reads the index
but does not process it.  An Instruction Trace
decoder can queue all the Instruction Trace data
in advance using itrace_queues__process_index()
or otherwise process the index in some custom
manner.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 tools/perf/builtin-inject.c |  15 ++++
 tools/perf/builtin-record.c |  15 ++++
 tools/perf/util/header.c    |  30 ++++++-
 tools/perf/util/itrace.c    | 214 ++++++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/itrace.h    |  35 ++++++++
 tools/perf/util/session.c   |   2 +
 tools/perf/util/session.h   |   1 +
 7 files changed, 308 insertions(+), 4 deletions(-)

diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
index c3323ea..4d0fe53 100644
--- a/tools/perf/builtin-inject.c
+++ b/tools/perf/builtin-inject.c
@@ -115,6 +115,18 @@ static s64 perf_event__repipe_itrace(struct perf_tool *tool,
 						  tool);
 	int ret;
 
+	if (!inject->output.is_pipe) {
+		off_t offset;
+
+		offset = lseek(inject->output.fd, 0, SEEK_CUR);
+		if (offset == -1)
+			return -errno;
+		ret = itrace_index__itrace_event(&session->itrace_index, event,
+						 offset);
+		if (ret < 0)
+			return ret;
+	}
+
 	if (perf_data_file__is_pipe(session->file) || !session->one_mmap) {
 		ret = output_bytes(inject, event, event->header.size);
 		if (ret < 0)
@@ -481,6 +493,9 @@ static int __cmd_inject(struct perf_inject *inject)
 		output_data_offset = 4096;
 	}
 
+	if (!inject->itrace_synth_opts.set)
+		itrace_index__free(&session->itrace_index);
+
 	if (!file_out->is_pipe)
 		lseek(file_out->fd, output_data_offset, SEEK_SET);
 
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 95519e3..962c973 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -117,9 +117,24 @@ static int record__process_itrace(struct perf_tool *tool,
 				  size_t len1, void *data2, size_t len2)
 {
 	struct record *rec = container_of(tool, struct record, tool);
+	struct perf_data_file *file = &rec->file;
 	size_t padding;
 	u8 pad[8] = {0};
 
+	if (!perf_data_file__is_pipe(file)) {
+		off_t file_offset;
+		int fd = perf_data_file__fd(file);
+		int err;
+
+		file_offset = lseek(fd, 0, SEEK_CUR);
+		if (file_offset == -1)
+			return -1;
+		err = itrace_index__itrace_event(&rec->session->itrace_index,
+						 event, file_offset);
+		if (err)
+			return err;
+	}
+
 	/* event.itrace.size includes padding, see __itrace_mmap__read() */
 	padding = (len1 + len2) & 7;
 	if (padding)
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 0fe5301..3f75cf6 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -869,11 +869,18 @@ static int write_branch_stack(int fd __maybe_unused,
 	return 0;
 }
 
-static int write_itrace(int fd __maybe_unused,
-			struct perf_header *h __maybe_unused,
+static int write_itrace(int fd, struct perf_header *h,
 			struct perf_evlist *evlist __maybe_unused)
 {
-	return 0;
+	struct perf_session *session;
+	int err;
+
+	session = container_of(h, struct perf_session, header);
+
+	err = itrace_index__write(fd, &session->itrace_index);
+	if (err < 0)
+		pr_err("Failed to write itrace index\n");
+	return err;
 }
 
 static void print_hostname(struct perf_header *ph, int fd __maybe_unused,
@@ -1846,6 +1853,21 @@ out_free:
 	return ret;
 }
 
+static int process_itrace(struct perf_file_section *section,
+			  struct perf_header *ph, int fd,
+			  void *data __maybe_unused)
+{
+	struct perf_session *session;
+	int err;
+
+	session = container_of(ph, struct perf_session, header);
+
+	err = itrace_index__process(fd, section->size, session, ph->needs_swap);
+	if (err < 0)
+		pr_err("Failed to process itrace index\n");
+	return err;
+}
+
 struct feature_ops {
 	int (*write)(int fd, struct perf_header *h, struct perf_evlist *evlist);
 	void (*print)(struct perf_header *h, int fd, FILE *fp);
@@ -1886,7 +1908,7 @@ static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = {
 	FEAT_OPA(HEADER_BRANCH_STACK,	branch_stack),
 	FEAT_OPP(HEADER_PMU_MAPPINGS,	pmu_mappings),
 	FEAT_OPP(HEADER_GROUP_DESC,	group_desc),
-	FEAT_OPA(HEADER_ITRACE,		itrace),
+	FEAT_OPP(HEADER_ITRACE,		itrace),
 };
 
 struct header_print_data {
diff --git a/tools/perf/util/itrace.c b/tools/perf/util/itrace.c
index bdf19d2..3819a31 100644
--- a/tools/perf/util/itrace.c
+++ b/tools/perf/util/itrace.c
@@ -332,6 +332,33 @@ out_err:
 	return err;
 }
 
+static int itrace_queues__add_indexed_event(struct itrace_queues *queues,
+					    struct perf_session *session,
+					    off_t file_offset, size_t sz)
+{
+	union perf_event *event;
+	int err;
+	char buf[PERF_SAMPLE_MAX_SIZE];
+
+	err = perf_session__peek_event(session, file_offset, buf,
+				       PERF_SAMPLE_MAX_SIZE, &event, NULL);
+	if (err)
+		return err;
+
+	if (event->header.type == PERF_RECORD_ITRACE) {
+		if (event->header.size != sizeof(struct itrace_event) ||
+		    event->header.size != sz) {
+			err = -EINVAL;
+			goto out;
+		}
+		file_offset += event->header.size;
+		err = itrace_queues__add_event(queues, session, event,
+					       file_offset, NULL);
+	}
+out:
+	return err;
+}
+
 void itrace_queues__free(struct itrace_queues *queues)
 {
 	unsigned int i;
@@ -488,6 +515,193 @@ itrace_record__init(struct perf_evlist *evlist __maybe_unused, int *err)
 	return NULL;
 }
 
+static int itrace_index__alloc(struct list_head *head)
+{
+	struct itrace_index *itrace_index;
+
+	itrace_index = malloc(sizeof(struct itrace_index));
+	if (!itrace_index)
+		return -ENOMEM;
+
+	itrace_index->nr = 0;
+	INIT_LIST_HEAD(&itrace_index->list);
+
+	list_add_tail(&itrace_index->list, head);
+
+	return 0;
+}
+
+void itrace_index__free(struct list_head *head)
+{
+	struct itrace_index *itrace_index, *n;
+
+	list_for_each_entry_safe(itrace_index, n, head, list) {
+		list_del(&itrace_index->list);
+		free(itrace_index);
+	}
+}
+
+static struct itrace_index *itrace_index__last(struct list_head *head)
+{
+	struct itrace_index *itrace_index;
+	int err;
+
+	if (list_empty(head)) {
+		err = itrace_index__alloc(head);
+		if (err)
+			return NULL;
+	}
+
+	itrace_index = list_entry(head->prev, struct itrace_index, list);
+
+	if (itrace_index->nr >= PERF_ITRACE_INDEX_ENTRY_COUNT) {
+		err = itrace_index__alloc(head);
+		if (err)
+			return NULL;
+		itrace_index = list_entry(head->prev, struct itrace_index,
+					  list);
+	}
+
+	return itrace_index;
+}
+
+int itrace_index__itrace_event(struct list_head *head, union perf_event *event,
+			       off_t file_offset)
+{
+	struct itrace_index *itrace_index;
+	size_t nr;
+
+	itrace_index = itrace_index__last(head);
+	if (!itrace_index)
+		return -ENOMEM;
+
+	nr = itrace_index->nr;
+	itrace_index->entries[nr].file_offset = file_offset;
+	itrace_index->entries[nr].sz = event->header.size;
+	itrace_index->nr += 1;
+
+	return 0;
+}
+
+static int itrace_index__do_write(int fd, struct itrace_index *itrace_index)
+{
+	struct itrace_index_entry index;
+	size_t i;
+
+	for (i = 0; i < itrace_index->nr; i++) {
+		index.file_offset = itrace_index->entries[i].file_offset;
+		index.sz = itrace_index->entries[i].sz;
+		if (writen(fd, &index, sizeof(index)) != sizeof(index))
+			return -errno;
+	}
+	return 0;
+}
+
+int itrace_index__write(int fd, struct list_head *head)
+{
+	struct itrace_index *itrace_index;
+	u64 total = 0;
+	int err;
+
+	list_for_each_entry(itrace_index, head, list)
+		total += itrace_index->nr;
+
+	if (writen(fd, &total, sizeof(total)) != sizeof(total))
+		return -errno;
+
+	list_for_each_entry(itrace_index, head, list) {
+		err = itrace_index__do_write(fd, itrace_index);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
+static int itrace_index__process_entry(int fd, struct list_head *head,
+				       bool needs_swap)
+{
+	struct itrace_index *itrace_index;
+	struct itrace_index_entry index;
+	size_t nr;
+
+	if (readn(fd, &index, sizeof(index)) != sizeof(index))
+		return -1;
+
+	itrace_index = itrace_index__last(head);
+	if (!itrace_index)
+		return -1;
+
+	nr = itrace_index->nr;
+	if (needs_swap) {
+		itrace_index->entries[nr].file_offset =
+						bswap_64(index.file_offset);
+		itrace_index->entries[nr].sz = bswap_64(index.sz);
+	} else {
+		itrace_index->entries[nr].file_offset = index.file_offset;
+		itrace_index->entries[nr].sz = index.sz;
+	}
+
+	itrace_index->nr = nr + 1;
+
+	return 0;
+}
+
+int itrace_index__process(int fd, u64 size, struct perf_session *session,
+			  bool needs_swap)
+{
+	struct list_head *head = &session->itrace_index;
+	u64 nr;
+
+	if (readn(fd, &nr, sizeof(u64)) != sizeof(u64))
+		return -1;
+
+	if (needs_swap)
+		nr = bswap_64(nr);
+
+	if (sizeof(u64) + nr * sizeof(struct itrace_index_entry) != size)
+		return -1;
+
+	while (nr--) {
+		int err;
+
+		err = itrace_index__process_entry(fd, head, needs_swap);
+		if (err)
+			return -1;
+	}
+
+	return 0;
+}
+
+static int itrace_queues__process_index_entry(struct itrace_queues *queues,
+					      struct perf_session *session,
+					      struct itrace_index_entry *index)
+{
+	return itrace_queues__add_indexed_event(queues, session,
+						index->file_offset, index->sz);
+}
+
+int itrace_queues__process_index(struct itrace_queues *queues,
+				 struct perf_session *session)
+{
+	struct itrace_index *itrace_index;
+	struct itrace_index_entry *index;
+	size_t i;
+	int err;
+
+	list_for_each_entry(itrace_index, &session->itrace_index, list) {
+		for (i = 0; i < itrace_index->nr; i++) {
+			index = &itrace_index->entries[i];
+			err = itrace_queues__process_index_entry(queues,
+								 session,
+								 index);
+			if (err)
+				return err;
+		}
+	}
+	return 0;
+}
+
 struct itrace_buffer *itrace_buffer__next(struct itrace_queue *queue,
 					  struct itrace_buffer *buffer)
 {
diff --git a/tools/perf/util/itrace.h b/tools/perf/util/itrace.h
index 3bd899e..25e3540 100644
--- a/tools/perf/util/itrace.h
+++ b/tools/perf/util/itrace.h
@@ -82,6 +82,32 @@ struct itrace_synth_opts {
 };
 
 /**
+ * struct itrace_index_entry - indexes a Instruction Tracing event within a
+ *                             perf.data file.
+ * @file_offset: offset within the perf.data file
+ * @sz: size of the event
+ */
+struct itrace_index_entry {
+	u64			file_offset;
+	u64			sz;
+};
+
+#define PERF_ITRACE_INDEX_ENTRY_COUNT 256
+
+/**
+ * struct itrace_index - index of Instruction Tracing events within a perf.data
+ *                       file.
+ * @list: linking a number of arrays of entries
+ * @nr: number of entries
+ * @entries: array of entries
+ */
+struct itrace_index {
+	struct list_head	list;
+	size_t			nr;
+	struct itrace_index_entry entries[PERF_ITRACE_INDEX_ENTRY_COUNT];
+};
+
+/**
  * struct itrace - session callbacks to allow Instruction Trace data decoding.
  * @process_event: lets the decoder see all session events
  * @flush_events: process any remaining data
@@ -304,6 +330,8 @@ int itrace_queues__add_event(struct itrace_queues *queues,
 			     union perf_event *event, off_t data_offset,
 			     struct itrace_buffer **buffer_ptr);
 void itrace_queues__free(struct itrace_queues *queues);
+int itrace_queues__process_index(struct itrace_queues *queues,
+				 struct perf_session *session);
 struct itrace_buffer *itrace_buffer__next(struct itrace_queue *queue,
 					  struct itrace_buffer *buffer);
 void *itrace_buffer__get_data(struct itrace_buffer *buffer, int fd);
@@ -343,6 +371,13 @@ int itrace_record__info_fill(struct itrace_record *itr,
 void itrace_record__free(struct itrace_record *itr);
 u64 itrace_record__reference(struct itrace_record *itr);
 
+int itrace_index__itrace_event(struct list_head *head, union perf_event *event,
+			       off_t file_offset);
+int itrace_index__write(int fd, struct list_head *head);
+int itrace_index__process(int fd, u64 size, struct perf_session *session,
+			  bool needs_swap);
+void itrace_index__free(struct list_head *head);
+
 void itrace_synth_error(struct itrace_error_event *itrace_error, int type,
 			int code, int cpu, pid_t pid, pid_t tid, u64 ip,
 			const char *msg);
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index bb653ef..5cefbb4 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -97,6 +97,7 @@ struct perf_session *perf_session__new(struct perf_data_file *file,
 
 	session->repipe = repipe;
 	ordered_events__init(&session->ordered_events);
+	INIT_LIST_HEAD(&session->itrace_index);
 	machines__init(&session->machines);
 
 	if (file) {
@@ -168,6 +169,7 @@ static void perf_session_env__delete(struct perf_session_env *env)
 void perf_session__delete(struct perf_session *session)
 {
 	itrace__free(session);
+	itrace_index__free(&session->itrace_index);
 	perf_session__destroy_kernel_maps(session);
 	perf_session__delete_dead_threads(session);
 	perf_session__delete_threads(session);
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index ccf6a75..01c4aa4 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -24,6 +24,7 @@ struct perf_session {
 	struct perf_evlist	*evlist;
 	struct itrace		*itrace;
 	struct itrace_synth_opts *itrace_synth_opts;
+	struct list_head	itrace_index;
 	struct trace_event	tevent;
 	struct events_stats	stats;
 	bool			repipe;
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH V4 22/23] perf tools: Hit all build ids when Instruction Tracing
  2015-01-08 12:52 [PATCH V4 00/23] perf tools: Introduce an abstraction for Instruction Tracing Adrian Hunter
                   ` (20 preceding siblings ...)
  2015-01-08 12:52 ` [PATCH V4 21/23] perf tools: Add Instruction Tracing index Adrian Hunter
@ 2015-01-08 12:52 ` Adrian Hunter
  2015-01-08 12:52 ` [PATCH V4 23/23] perf tools: Add build option NO_ITRACE to exclude " Adrian Hunter
  2015-02-10 12:31 ` [PATCH V4 00/23] perf tools: Introduce an abstraction for " Adrian Hunter
  23 siblings, 0 replies; 26+ messages in thread
From: Adrian Hunter @ 2015-01-08 12:52 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Peter Zijlstra, linux-kernel, David Ahern, Frederic Weisbecker,
	Jiri Olsa, Namhyung Kim, Paul Mackerras, Stephane Eranian

We need to include all buildids when a perf.data
file contains Instruction Tracing data because we
do not decode the trace for that purpose because
it would take too long.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 tools/perf/builtin-buildid-list.c |  9 +++++++++
 tools/perf/builtin-inject.c       |  8 +++++++-
 tools/perf/builtin-record.c       | 10 +++++++++-
 3 files changed, 25 insertions(+), 2 deletions(-)

diff --git a/tools/perf/builtin-buildid-list.c b/tools/perf/builtin-buildid-list.c
index ed3873b..d694309 100644
--- a/tools/perf/builtin-buildid-list.c
+++ b/tools/perf/builtin-buildid-list.c
@@ -69,6 +69,15 @@ static int perf_session__list_build_ids(bool force, bool with_hits)
 	session = perf_session__new(&file, false, &build_id__mark_dso_hit_ops);
 	if (session == NULL)
 		return -1;
+
+	/*
+	 * We take all buildids when the file contains Instruction Tracing data
+	 * because we do not decode the trace because it would take too long.
+	 */
+	if (!perf_data_file__is_pipe(&file) &&
+	    perf_header__has_feat(&session->header, HEADER_ITRACE))
+		with_hits = false;
+
 	/*
 	 * in pipe-mode, the only way to get the buildids is to parse
 	 * the record stream. Buildids are stored as RECORD_HEADER_BUILD_ID
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
index 4d0fe53..285f159 100644
--- a/tools/perf/builtin-inject.c
+++ b/tools/perf/builtin-inject.c
@@ -27,6 +27,7 @@ struct perf_inject {
 	struct perf_session	*session;
 	bool			build_ids;
 	bool			sched_stat;
+	bool			have_itrace;
 	const char		*input_name;
 	struct perf_data_file	output;
 	u64			bytes_written;
@@ -115,6 +116,8 @@ static s64 perf_event__repipe_itrace(struct perf_tool *tool,
 						  tool);
 	int ret;
 
+	inject->have_itrace = true;
+
 	if (!inject->output.is_pipe) {
 		off_t offset;
 
@@ -502,9 +505,12 @@ static int __cmd_inject(struct perf_inject *inject)
 	ret = perf_session__process_events(session, &inject->tool);
 
 	if (!file_out->is_pipe) {
-		if (inject->build_ids)
+		if (inject->build_ids) {
 			perf_header__set_feat(&session->header,
 					      HEADER_BUILD_ID);
+			if (inject->have_itrace)
+				dsos__hit_all(session);
+		}
 		/*
 		 * The instruction traces have been removed and replaced with
 		 * synthesized hardware events, so clear the feature flag.
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 962c973..182a42c 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -613,8 +613,16 @@ out_child:
 	if (!err && !file->is_pipe) {
 		rec->session->header.data_size += rec->bytes_written;
 
-		if (!rec->no_buildid)
+		if (!rec->no_buildid) {
 			process_buildids(rec);
+			/*
+			 * We take all buildids when the file contains
+			 * Instruction Tracing data because we do not decode the
+			 * trace because it would take too long.
+			 */
+			if (rec->opts.full_itrace)
+				dsos__hit_all(rec->session);
+		}
 		perf_session__write_header(rec->session, rec->evlist,
 					   file->fd, true);
 	}
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH V4 23/23] perf tools: Add build option NO_ITRACE to exclude Instruction Tracing
  2015-01-08 12:52 [PATCH V4 00/23] perf tools: Introduce an abstraction for Instruction Tracing Adrian Hunter
                   ` (21 preceding siblings ...)
  2015-01-08 12:52 ` [PATCH V4 22/23] perf tools: Hit all build ids when Instruction Tracing Adrian Hunter
@ 2015-01-08 12:52 ` Adrian Hunter
  2015-02-10 12:31 ` [PATCH V4 00/23] perf tools: Introduce an abstraction for " Adrian Hunter
  23 siblings, 0 replies; 26+ messages in thread
From: Adrian Hunter @ 2015-01-08 12:52 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Peter Zijlstra, linux-kernel, David Ahern, Frederic Weisbecker,
	Jiri Olsa, Namhyung Kim, Paul Mackerras, Stephane Eranian

Add build option NO_ITRACE to exclude compiling support
for Instruction Tracing. Support for both recording and
processing is excluded and by implication any future
additions such as Intel PT and Intel BTS will also not
be compiled in with this option.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 tools/perf/Makefile.perf    |   4 ++
 tools/perf/builtin-inject.c |  53 ++++++++++++--------
 tools/perf/builtin-record.c |  13 +++++
 tools/perf/config/Makefile  |   4 ++
 tools/perf/tests/make       |   2 +
 tools/perf/util/itrace.h    | 114 ++++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 171 insertions(+), 19 deletions(-)

diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf
index a126e7a..2c537aa 100644
--- a/tools/perf/Makefile.perf
+++ b/tools/perf/Makefile.perf
@@ -68,6 +68,8 @@ include config/utilities.mak
 # for reading the x32 mode 32-bit compatibility VDSO in 64-bit mode
 #
 # Define NO_ZLIB if you do not want to support compressed kernel modules
+#
+# Define NO_ITRACE if you do not want Instruction Tracing support
 
 
 ifeq ($(srctree),)
@@ -409,7 +411,9 @@ LIB_OBJS += $(OUTPUT)util/data.o
 LIB_OBJS += $(OUTPUT)util/tsc.o
 LIB_OBJS += $(OUTPUT)util/cloexec.o
 LIB_OBJS += $(OUTPUT)util/thread-stack.o
+ifndef NO_ITRACE
 LIB_OBJS += $(OUTPUT)util/itrace.o
+endif
 
 LIB_OBJS += $(OUTPUT)ui/setup.o
 LIB_OBJS += $(OUTPUT)ui/helpline.o
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
index 285f159..e6a2136 100644
--- a/tools/perf/builtin-inject.c
+++ b/tools/perf/builtin-inject.c
@@ -53,25 +53,6 @@ static int output_bytes(struct perf_inject *inject, void *buf, size_t sz)
 	return 0;
 }
 
-static int copy_bytes(struct perf_inject *inject, int fd, off_t size)
-{
-	char buf[4096];
-	ssize_t ssz;
-	int ret;
-
-	while (size > 0) {
-		ssz = read(fd, buf, MIN(size, sizeof(buf)));
-		if (ssz < 0)
-			return -errno;
-		ret = output_bytes(inject, buf, ssz);
-		if (ret)
-			return ret;
-		size -= ssz;
-	}
-
-	return 0;
-}
-
 static int perf_event__repipe_synth(struct perf_tool *tool,
 				    union perf_event *event)
 {
@@ -107,6 +88,27 @@ static int perf_event__repipe_attr(struct perf_tool *tool,
 	return perf_event__repipe_synth(tool, event);
 }
 
+#ifdef HAVE_ITRACE_SUPPORT
+
+static int copy_bytes(struct perf_inject *inject, int fd, off_t size)
+{
+	char buf[4096];
+	ssize_t ssz;
+	int ret;
+
+	while (size > 0) {
+		ssz = read(fd, buf, MIN(size, sizeof(buf)));
+		if (ssz < 0)
+			return -errno;
+		ret = output_bytes(inject, buf, ssz);
+		if (ret)
+			return ret;
+		size -= ssz;
+	}
+
+	return 0;
+}
+
 static s64 perf_event__repipe_itrace(struct perf_tool *tool,
 				     union perf_event *event,
 				     struct perf_session *session
@@ -146,6 +148,19 @@ static s64 perf_event__repipe_itrace(struct perf_tool *tool,
 	return event->itrace.size;
 }
 
+#else
+
+static s64
+perf_event__repipe_itrace(struct perf_tool *tool __maybe_unused,
+			  union perf_event *event __maybe_unused,
+			  struct perf_session *session __maybe_unused)
+{
+	pr_err("Instruction Tracing not supported\n");
+	return -EINVAL;
+}
+
+#endif
+
 static int perf_event__repipe(struct perf_tool *tool,
 			      union perf_event *event,
 			      struct perf_sample *sample __maybe_unused,
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 182a42c..3ed5312 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -112,6 +112,8 @@ out:
 	return rc;
 }
 
+#ifdef HAVE_ITRACE_SUPPORT
+
 static int record__process_itrace(struct perf_tool *tool,
 				  union perf_event *event, void *data1,
 				  size_t len1, void *data2, size_t len2)
@@ -164,6 +166,17 @@ static int record__itrace_mmap_read(struct record *rec,
 	return 0;
 }
 
+#else
+
+static inline
+int record__itrace_mmap_read(struct record *rec __maybe_unused,
+			     struct itrace_mmap *mm __maybe_unused)
+{
+	return 0;
+}
+
+#endif
+
 static volatile int done = 0;
 static volatile int signr = -1;
 static volatile int child_finished = 0;
diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile
index 5d4b039..ad33202 100644
--- a/tools/perf/config/Makefile
+++ b/tools/perf/config/Makefile
@@ -661,6 +661,10 @@ else
   NO_PERF_READ_VDSOX32 := 1
 endif
 
+ifndef NO_ITRACE
+  CFLAGS += -DHAVE_ITRACE_SUPPORT
+endif
+
 # Among the variables below, these:
 #   perfexecdir
 #   template_dir
diff --git a/tools/perf/tests/make b/tools/perf/tests/make
index 75709d2..2677337 100644
--- a/tools/perf/tests/make
+++ b/tools/perf/tests/make
@@ -32,6 +32,7 @@ make_no_backtrace   := NO_BACKTRACE=1
 make_no_libnuma     := NO_LIBNUMA=1
 make_no_libaudit    := NO_LIBAUDIT=1
 make_no_libbionic   := NO_LIBBIONIC=1
+make_no_itrace      := NO_ITRACE=1
 make_tags           := tags
 make_cscope         := cscope
 make_help           := help
@@ -74,6 +75,7 @@ run += make_no_backtrace
 run += make_no_libnuma
 run += make_no_libaudit
 run += make_no_libbionic
+run += make_no_itrace
 run += make_help
 run += make_doc
 run += make_perf_o
diff --git a/tools/perf/util/itrace.h b/tools/perf/util/itrace.h
index 25e3540..233b378 100644
--- a/tools/perf/util/itrace.h
+++ b/tools/perf/util/itrace.h
@@ -25,6 +25,7 @@
 
 #include "../perf.h"
 #include "session.h"
+#include "debug.h"
 
 union perf_event;
 struct perf_session;
@@ -294,6 +295,8 @@ struct itrace_record {
 	int (*read_finish)(struct itrace_record *itr, int idx);
 };
 
+#ifdef HAVE_ITRACE_SUPPORT
+
 static inline u64 itrace_mmap__read_head(struct itrace_mmap *mm __maybe_unused)
 {
 	/* Not yet implemented */
@@ -444,4 +447,115 @@ static inline void itrace__free(struct perf_session *session)
 	return session->itrace->free(session);
 }
 
+#else
+
+static inline struct itrace_record *
+itrace_record__init(struct perf_evlist *evlist __maybe_unused,
+		    int *err __maybe_unused)
+{
+	*err = 0;
+	return NULL;
+}
+
+static inline
+void itrace_record__free(struct itrace_record *itr __maybe_unused)
+{
+}
+
+static inline int
+perf_event__synthesize_itrace_info(struct itrace_record *itr __maybe_unused,
+				   struct perf_tool *tool __maybe_unused,
+				   struct perf_session *session __maybe_unused,
+				   perf_event__handler_t process __maybe_unused)
+{
+	return -EINVAL;
+}
+
+static inline
+int itrace_record__options(struct itrace_record *itr __maybe_unused,
+			   struct perf_evlist *evlist __maybe_unused,
+			   struct record_opts *opts __maybe_unused)
+{
+	return 0;
+}
+
+#define perf_event__process_itrace_info			0
+#define perf_event__process_itrace			0
+#define perf_event__count_itrace_error			0
+#define perf_event__process_itrace_error		0
+
+static inline
+int itrace_parse_synth_opts(const struct option *opt __maybe_unused,
+			    const char *str __maybe_unused,
+			    int unset __maybe_unused)
+{
+	pr_err("Instruction Tracing not supported\n");
+	return -EINVAL;
+}
+
+static inline
+int itrace__process_event(struct perf_session *session __maybe_unused,
+			  union perf_event *event __maybe_unused,
+			  struct perf_sample *sample __maybe_unused,
+			  struct perf_tool *tool __maybe_unused)
+{
+	return 0;
+}
+
+static inline
+int itrace__flush_events(struct perf_session *session __maybe_unused,
+			 struct perf_tool *tool __maybe_unused)
+{
+	return 0;
+}
+
+static inline
+void itrace__free_events(struct perf_session *session __maybe_unused)
+{
+}
+
+static inline
+void itrace_cache__free(struct itrace_cache *itrace_cache __maybe_unused)
+{
+}
+
+static inline
+void itrace__free(struct perf_session *session __maybe_unused)
+{
+}
+
+static inline
+int itrace_index__write(int fd __maybe_unused,
+			struct list_head *head __maybe_unused)
+{
+	return -EINVAL;
+}
+
+static inline
+int itrace_index__process(int fd __maybe_unused,
+			  u64 size __maybe_unused,
+			  struct perf_session *session __maybe_unused,
+			  bool needs_swap __maybe_unused)
+{
+	return -EINVAL;
+}
+
+static inline
+void itrace_index__free(struct list_head *head __maybe_unused)
+{
+}
+
+int itrace_mmap__mmap(struct itrace_mmap *mm,
+		      struct itrace_mmap_params *mp,
+		      void *userpg, int fd);
+void itrace_mmap__munmap(struct itrace_mmap *mm);
+void itrace_mmap_params__init(struct itrace_mmap_params *mp,
+			      off_t itrace_offset,
+			      unsigned int itrace_pages, bool itrace_overwrite);
+void itrace_mmap_params__set_idx(struct itrace_mmap_params *mp,
+				 struct perf_evlist *evlist, int idx,
+				 bool per_cpu);
+
+#endif
+
 #endif
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* Re: [PATCH V4 00/23] perf tools: Introduce an abstraction for Instruction Tracing
  2015-01-08 12:52 [PATCH V4 00/23] perf tools: Introduce an abstraction for Instruction Tracing Adrian Hunter
                   ` (22 preceding siblings ...)
  2015-01-08 12:52 ` [PATCH V4 23/23] perf tools: Add build option NO_ITRACE to exclude " Adrian Hunter
@ 2015-02-10 12:31 ` Adrian Hunter
  2015-02-11 20:40   ` Arnaldo Carvalho de Melo
  23 siblings, 1 reply; 26+ messages in thread
From: Adrian Hunter @ 2015-02-10 12:31 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Peter Zijlstra, linux-kernel, David Ahern, Frederic Weisbecker,
	Jiri Olsa, Namhyung Kim, Paul Mackerras, Stephane Eranian

On 08/01/15 14:52, Adrian Hunter wrote:
> Hi
> 
> Here is V4 of some more preparatory patches for Intel PT
> that introduce an abstraction for Instruction tracing.
> 
> The master branch of the tree:
> 
> 	git://git.infradead.org/users/ahunter/linux-perf.git
> 
> contains these patches plus Intel PT and BTS and the kernel driver.
> 

Arnaldo, I was thinking of sending V5 (re-based plus a couple of small
changes) but there seem to be a number of large patch sets pending and I
also have the main Intel PT patches (25 patches), so I was wondering if you
have preferred order for handling them all?

AFAICT Peter has accepted the Intel PT kernel driver but I don't know if it
will be in 3.20.


> Changes in V4:
> 
> 	perf tools: Add build option NO_ITRACE to exclude Instruction Tracing
> 		New patch
> 
> 	Re-based on Arnaldo's perf/core branch:
> 
> 		3dd417d4010c8e141b0f32121cdc8d82aa4a9c6a
> 		perf tools: Remove some unused functions from color.c
> 
> Changes in V3:
> 
> 	perf tools: Add support for Instruction Trace recording
> 		Added evsel as a parameter to itrace_record__init
> 
> 	perf record: Add basic Instruction Tracing support
> 		Moved the call to itrace_record__init after parse
> 		options so that evsel could be passed and the
> 		selected events used to determine what kind of
> 		Instruction Tracing to use e.g. Intel PT vs BTS
> 
> 	Re-based on Arnaldo's perf/core branch:
> 
> 		41e950c033b7df997d4b38653efe6554be9b96a7
> 		Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/urgent
> 
> Changes in V2:
> 
> 	Dropped patches already applied.
> 
> 	Re-based on Arnaldo's perf/core branch:
> 
> 		a84808083688d82d7f1e5786ccf5df0ff7d448cb
> 		perf tools: Only override the default :tid comm entry
> 
> 
> The abstraction has two separate aspects:
> 	1. recording Instruction Trace data
> 	2. processing Instruction Trace data
> 
> Recording consists of mmapping a separate buffer and copying
> the data into the perf.data file.  The buffer is an AUX area
> buffer although the details of the AUX area are not implemented
> because the kernel support is pending.  The data is written
> preceded by a new user event PERF_RECORD_ITRACE.  The data is
> too big to fit in the event but follows immediately afterward.
> Session processing has to skip to get to the next event header
> in a similar fashion to the existing PERF_RECORD_HEADER_TRACING_DATA
> event.  The main recording patches are:
> 
>       perf evlist: Add initial support for mmapping an Instruction Trace buffer
>       perf tools: Add user events for Instruction Tracing
>       perf tools: Add support for Instruction Trace recording
>       perf record: Add basic Instruction Tracing support
> 
> Processing consists of providing hooks in session processing
> to enable an Instruction Trace decoder to see all the events
> and deliver synthesized events transparently into the event
> stream.  The main processing patch is:
> 
>       perf session: Add hooks to allow transparent decoding of Instruction Tracing data
> 
> 
> Adrian Hunter (23):
>       perf header: Add Instruction Tracing feature
>       perf evlist: Add initial support for mmapping an Instruction Trace buffer
>       perf tools: Add user events for Instruction Tracing
>       perf tools: Add support for Instruction Trace recording
>       perf record: Add basic Instruction Tracing support
>       perf record: Extend -m option for Instruction Tracing mmap pages
>       perf tools: Add a user event for Instruction Tracing errors
>       perf session: Add hooks to allow transparent decoding of Instruction Tracing data
>       perf session: Add Instruction Tracing options
>       perf itrace: Add helpers for Instruction Tracing errors
>       perf itrace: Add helpers for queuing Instruction Tracing data
>       perf itrace: Add a heap for sorting Instruction Tracing queues
>       perf itrace: Add processing for Instruction Tracing events
>       perf itrace: Add a hashtable for caching decoded instructions
>       perf tools: Add member to struct dso for an instruction cache
>       perf script: Add Instruction Tracing support
>       perf script: Always allow fields 'addr' and 'cpu' for itrace
>       perf report: Add Instruction Tracing support
>       perf inject: Re-pipe Instruction Tracing events
>       perf inject: Add Instruction Tracing support
>       perf tools: Add Instruction Tracing index
>       perf tools: Hit all build ids when Instruction Tracing
>       perf tools: Add build option NO_ITRACE to exclude Instruction Tracing
> 
>  tools/perf/Documentation/perf-inject.txt |   27 +
>  tools/perf/Documentation/perf-record.txt |    2 +
>  tools/perf/Documentation/perf-report.txt |   28 +
>  tools/perf/Documentation/perf-script.txt |   28 +
>  tools/perf/Makefile.perf                 |    6 +
>  tools/perf/builtin-buildid-list.c        |    9 +
>  tools/perf/builtin-inject.c              |  172 +++-
>  tools/perf/builtin-record.c              |  186 ++++-
>  tools/perf/builtin-report.c              |   12 +
>  tools/perf/builtin-script.c              |   39 +-
>  tools/perf/config/Makefile               |    4 +
>  tools/perf/perf.h                        |    2 +
>  tools/perf/tests/make                    |    2 +
>  tools/perf/util/dso.c                    |    2 +
>  tools/perf/util/dso.h                    |    3 +
>  tools/perf/util/event.c                  |    3 +
>  tools/perf/util/event.h                  |   38 +
>  tools/perf/util/evlist.c                 |   70 +-
>  tools/perf/util/evlist.h                 |    6 +
>  tools/perf/util/header.c                 |   36 +
>  tools/perf/util/header.h                 |    1 +
>  tools/perf/util/itrace.c                 | 1258 ++++++++++++++++++++++++++++++
>  tools/perf/util/itrace.h                 |  561 +++++++++++++
>  tools/perf/util/record.c                 |   11 +-
>  tools/perf/util/session.c                |  148 +++-
>  tools/perf/util/session.h                |    6 +
>  tools/perf/util/tool.h                   |   10 +-
>  27 files changed, 2624 insertions(+), 46 deletions(-)
>  create mode 100644 tools/perf/util/itrace.c
>  create mode 100644 tools/perf/util/itrace.h
> 
> 
> Regards
> Adrian
> 
> 


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH V4 00/23] perf tools: Introduce an abstraction for Instruction Tracing
  2015-02-10 12:31 ` [PATCH V4 00/23] perf tools: Introduce an abstraction for " Adrian Hunter
@ 2015-02-11 20:40   ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 26+ messages in thread
From: Arnaldo Carvalho de Melo @ 2015-02-11 20:40 UTC (permalink / raw)
  To: Adrian Hunter
  Cc: Peter Zijlstra, linux-kernel, David Ahern, Frederic Weisbecker,
	Jiri Olsa, Namhyung Kim, Paul Mackerras, Stephane Eranian

Em Tue, Feb 10, 2015 at 02:31:56PM +0200, Adrian Hunter escreveu:
> On 08/01/15 14:52, Adrian Hunter wrote:
> > Hi
> > 
> > Here is V4 of some more preparatory patches for Intel PT
> > that introduce an abstraction for Instruction tracing.
> > 
> > The master branch of the tree:
> > 
> > 	git://git.infradead.org/users/ahunter/linux-perf.git
> > 
> > contains these patches plus Intel PT and BTS and the kernel driver.
> > 
> 
> Arnaldo, I was thinking of sending V5 (re-based plus a couple of small
> changes) but there seem to be a number of large patch sets pending and I
> also have the main Intel PT patches (25 patches), so I was wondering if you
> have preferred order for handling them all?
 
> AFAICT Peter has accepted the Intel PT kernel driver but I don't know if it
> will be in 3.20.

Wait a bit, I need to process a patchset from Jiri Olsa that touches the
Makefiles, to pave the way for Kconfig usage in tools/perf/ and a few
other bits, after that gets in, try again please.

- Arnaldo
 
> 
> > Changes in V4:
> > 
> > 	perf tools: Add build option NO_ITRACE to exclude Instruction Tracing
> > 		New patch
> > 
> > 	Re-based on Arnaldo's perf/core branch:
> > 
> > 		3dd417d4010c8e141b0f32121cdc8d82aa4a9c6a
> > 		perf tools: Remove some unused functions from color.c
> > 
> > Changes in V3:
> > 
> > 	perf tools: Add support for Instruction Trace recording
> > 		Added evsel as a parameter to itrace_record__init
> > 
> > 	perf record: Add basic Instruction Tracing support
> > 		Moved the call to itrace_record__init after parse
> > 		options so that evsel could be passed and the
> > 		selected events used to determine what kind of
> > 		Instruction Tracing to use e.g. Intel PT vs BTS
> > 
> > 	Re-based on Arnaldo's perf/core branch:
> > 
> > 		41e950c033b7df997d4b38653efe6554be9b96a7
> > 		Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/urgent
> > 
> > Changes in V2:
> > 
> > 	Dropped patches already applied.
> > 
> > 	Re-based on Arnaldo's perf/core branch:
> > 
> > 		a84808083688d82d7f1e5786ccf5df0ff7d448cb
> > 		perf tools: Only override the default :tid comm entry
> > 
> > 
> > The abstraction has two separate aspects:
> > 	1. recording Instruction Trace data
> > 	2. processing Instruction Trace data
> > 
> > Recording consists of mmapping a separate buffer and copying
> > the data into the perf.data file.  The buffer is an AUX area
> > buffer although the details of the AUX area are not implemented
> > because the kernel support is pending.  The data is written
> > preceded by a new user event PERF_RECORD_ITRACE.  The data is
> > too big to fit in the event but follows immediately afterward.
> > Session processing has to skip to get to the next event header
> > in a similar fashion to the existing PERF_RECORD_HEADER_TRACING_DATA
> > event.  The main recording patches are:
> > 
> >       perf evlist: Add initial support for mmapping an Instruction Trace buffer
> >       perf tools: Add user events for Instruction Tracing
> >       perf tools: Add support for Instruction Trace recording
> >       perf record: Add basic Instruction Tracing support
> > 
> > Processing consists of providing hooks in session processing
> > to enable an Instruction Trace decoder to see all the events
> > and deliver synthesized events transparently into the event
> > stream.  The main processing patch is:
> > 
> >       perf session: Add hooks to allow transparent decoding of Instruction Tracing data
> > 
> > 
> > Adrian Hunter (23):
> >       perf header: Add Instruction Tracing feature
> >       perf evlist: Add initial support for mmapping an Instruction Trace buffer
> >       perf tools: Add user events for Instruction Tracing
> >       perf tools: Add support for Instruction Trace recording
> >       perf record: Add basic Instruction Tracing support
> >       perf record: Extend -m option for Instruction Tracing mmap pages
> >       perf tools: Add a user event for Instruction Tracing errors
> >       perf session: Add hooks to allow transparent decoding of Instruction Tracing data
> >       perf session: Add Instruction Tracing options
> >       perf itrace: Add helpers for Instruction Tracing errors
> >       perf itrace: Add helpers for queuing Instruction Tracing data
> >       perf itrace: Add a heap for sorting Instruction Tracing queues
> >       perf itrace: Add processing for Instruction Tracing events
> >       perf itrace: Add a hashtable for caching decoded instructions
> >       perf tools: Add member to struct dso for an instruction cache
> >       perf script: Add Instruction Tracing support
> >       perf script: Always allow fields 'addr' and 'cpu' for itrace
> >       perf report: Add Instruction Tracing support
> >       perf inject: Re-pipe Instruction Tracing events
> >       perf inject: Add Instruction Tracing support
> >       perf tools: Add Instruction Tracing index
> >       perf tools: Hit all build ids when Instruction Tracing
> >       perf tools: Add build option NO_ITRACE to exclude Instruction Tracing
> > 
> >  tools/perf/Documentation/perf-inject.txt |   27 +
> >  tools/perf/Documentation/perf-record.txt |    2 +
> >  tools/perf/Documentation/perf-report.txt |   28 +
> >  tools/perf/Documentation/perf-script.txt |   28 +
> >  tools/perf/Makefile.perf                 |    6 +
> >  tools/perf/builtin-buildid-list.c        |    9 +
> >  tools/perf/builtin-inject.c              |  172 +++-
> >  tools/perf/builtin-record.c              |  186 ++++-
> >  tools/perf/builtin-report.c              |   12 +
> >  tools/perf/builtin-script.c              |   39 +-
> >  tools/perf/config/Makefile               |    4 +
> >  tools/perf/perf.h                        |    2 +
> >  tools/perf/tests/make                    |    2 +
> >  tools/perf/util/dso.c                    |    2 +
> >  tools/perf/util/dso.h                    |    3 +
> >  tools/perf/util/event.c                  |    3 +
> >  tools/perf/util/event.h                  |   38 +
> >  tools/perf/util/evlist.c                 |   70 +-
> >  tools/perf/util/evlist.h                 |    6 +
> >  tools/perf/util/header.c                 |   36 +
> >  tools/perf/util/header.h                 |    1 +
> >  tools/perf/util/itrace.c                 | 1258 ++++++++++++++++++++++++++++++
> >  tools/perf/util/itrace.h                 |  561 +++++++++++++
> >  tools/perf/util/record.c                 |   11 +-
> >  tools/perf/util/session.c                |  148 +++-
> >  tools/perf/util/session.h                |    6 +
> >  tools/perf/util/tool.h                   |   10 +-
> >  27 files changed, 2624 insertions(+), 46 deletions(-)
> >  create mode 100644 tools/perf/util/itrace.c
> >  create mode 100644 tools/perf/util/itrace.h
> > 
> > 
> > Regards
> > Adrian
> > 
> > 

^ permalink raw reply	[flat|nested] 26+ messages in thread

end of thread, other threads:[~2015-02-11 20:40 UTC | newest]

Thread overview: 26+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-01-08 12:52 [PATCH V4 00/23] perf tools: Introduce an abstraction for Instruction Tracing Adrian Hunter
2015-01-08 12:52 ` [PATCH V4 01/23] perf header: Add Instruction Tracing feature Adrian Hunter
2015-01-08 12:52 ` [PATCH V4 02/23] perf evlist: Add initial support for mmapping an Instruction Trace buffer Adrian Hunter
2015-01-08 12:52 ` [PATCH V4 03/23] perf tools: Add user events for Instruction Tracing Adrian Hunter
2015-01-08 12:52 ` [PATCH V4 04/23] perf tools: Add support for Instruction Trace recording Adrian Hunter
2015-01-08 12:52 ` [PATCH V4 05/23] perf record: Add basic Instruction Tracing support Adrian Hunter
2015-01-08 12:52 ` [PATCH V4 06/23] perf record: Extend -m option for Instruction Tracing mmap pages Adrian Hunter
2015-01-08 12:52 ` [PATCH V4 07/23] perf tools: Add a user event for Instruction Tracing errors Adrian Hunter
2015-01-08 12:52 ` [PATCH V4 08/23] perf session: Add hooks to allow transparent decoding of Instruction Tracing data Adrian Hunter
2015-01-08 12:52 ` [PATCH V4 09/23] perf session: Add Instruction Tracing options Adrian Hunter
2015-01-08 12:52 ` [PATCH V4 10/23] perf itrace: Add helpers for Instruction Tracing errors Adrian Hunter
2015-01-08 12:52 ` [PATCH V4 11/23] perf itrace: Add helpers for queuing Instruction Tracing data Adrian Hunter
2015-01-08 12:52 ` [PATCH V4 12/23] perf itrace: Add a heap for sorting Instruction Tracing queues Adrian Hunter
2015-01-08 12:52 ` [PATCH V4 13/23] perf itrace: Add processing for Instruction Tracing events Adrian Hunter
2015-01-08 12:52 ` [PATCH V4 14/23] perf itrace: Add a hashtable for caching decoded instructions Adrian Hunter
2015-01-08 12:52 ` [PATCH V4 15/23] perf tools: Add member to struct dso for an instruction cache Adrian Hunter
2015-01-08 12:52 ` [PATCH V4 16/23] perf script: Add Instruction Tracing support Adrian Hunter
2015-01-08 12:52 ` [PATCH V4 17/23] perf script: Always allow fields 'addr' and 'cpu' for itrace Adrian Hunter
2015-01-08 12:52 ` [PATCH V4 18/23] perf report: Add Instruction Tracing support Adrian Hunter
2015-01-08 12:52 ` [PATCH V4 19/23] perf inject: Re-pipe Instruction Tracing events Adrian Hunter
2015-01-08 12:52 ` [PATCH V4 20/23] perf inject: Add Instruction Tracing support Adrian Hunter
2015-01-08 12:52 ` [PATCH V4 21/23] perf tools: Add Instruction Tracing index Adrian Hunter
2015-01-08 12:52 ` [PATCH V4 22/23] perf tools: Hit all build ids when Instruction Tracing Adrian Hunter
2015-01-08 12:52 ` [PATCH V4 23/23] perf tools: Add build option NO_ITRACE to exclude " Adrian Hunter
2015-02-10 12:31 ` [PATCH V4 00/23] perf tools: Introduce an abstraction for " Adrian Hunter
2015-02-11 20:40   ` Arnaldo Carvalho de Melo

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.