linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/2] perf tools: Add support for PERF_RECORD_SWITCH to Intel PT
@ 2015-08-13  9:40 Adrian Hunter
  2015-08-13  9:40 ` [PATCH 1/2] perf tools: Add a helper function to probe whether cpu-wide tracing is possible Adrian Hunter
  2015-08-13  9:40 ` [PATCH 2/2] perf tools: Add support for PERF_RECORD_SWITCH to Intel PT Adrian Hunter
  0 siblings, 2 replies; 6+ messages in thread
From: Adrian Hunter @ 2015-08-13  9:40 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo; +Cc: linux-kernel, Jiri Olsa

Hi

Support to enable unprivileged users to see context switches
of their own processes has recently been added to the kernel.

These patches enhance Intel PT support to take advantage of that.

The patches apply on top of the other Intel PT perf tools patches.


Adrian Hunter (2):
      perf tools: Add a helper function to probe whether cpu-wide tracing is possible
      perf tools: Add support for PERF_RECORD_SWITCH to Intel PT

 tools/perf/arch/x86/util/intel-pt.c |  55 ++++++++++++---
 tools/perf/util/evlist.h            |   1 +
 tools/perf/util/intel-pt.c          | 129 +++++++++++++++++++++++++++++-------
 tools/perf/util/record.c            |  24 +++++++
 4 files changed, 176 insertions(+), 33 deletions(-)


Regards
Adrian

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

* [PATCH 1/2] perf tools: Add a helper function to probe whether cpu-wide tracing is possible
  2015-08-13  9:40 [PATCH 0/2] perf tools: Add support for PERF_RECORD_SWITCH to Intel PT Adrian Hunter
@ 2015-08-13  9:40 ` Adrian Hunter
  2015-08-20  9:56   ` [tip:perf/core] " tip-bot for Adrian Hunter
  2015-08-13  9:40 ` [PATCH 2/2] perf tools: Add support for PERF_RECORD_SWITCH to Intel PT Adrian Hunter
  1 sibling, 1 reply; 6+ messages in thread
From: Adrian Hunter @ 2015-08-13  9:40 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo; +Cc: linux-kernel, Jiri Olsa

Add a helper function to probe whether cpu-wide tracing is possible.

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

diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index 397757063da1..436e358300b1 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -115,6 +115,7 @@ void perf_evlist__close(struct perf_evlist *evlist);
 void perf_evlist__set_id_pos(struct perf_evlist *evlist);
 bool perf_can_sample_identifier(void);
 bool perf_can_record_switch_events(void);
+bool perf_can_record_cpu_wide(void);
 void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts);
 int record_opts__config(struct record_opts *opts);
 
diff --git a/tools/perf/util/record.c b/tools/perf/util/record.c
index 0d228a29526d..0467367dc315 100644
--- a/tools/perf/util/record.c
+++ b/tools/perf/util/record.c
@@ -105,6 +105,30 @@ bool perf_can_record_switch_events(void)
 	return perf_probe_api(perf_probe_context_switch);
 }
 
+bool perf_can_record_cpu_wide(void)
+{
+	struct perf_event_attr attr = {
+		.type = PERF_TYPE_SOFTWARE,
+		.config = PERF_COUNT_SW_CPU_CLOCK,
+		.exclude_kernel = 1,
+	};
+	struct cpu_map *cpus;
+	int cpu, fd;
+
+	cpus = cpu_map__new(NULL);
+	if (!cpus)
+		return false;
+	cpu = cpus->map[0];
+	cpu_map__put(cpus);
+
+	fd = sys_perf_event_open(&attr, -1, cpu, -1, 0);
+	if (fd < 0)
+		return false;
+	close(fd);
+
+	return true;
+}
+
 void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts)
 {
 	struct perf_evsel *evsel;
-- 
1.9.1


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

* [PATCH 2/2] perf tools: Add support for PERF_RECORD_SWITCH to Intel PT
  2015-08-13  9:40 [PATCH 0/2] perf tools: Add support for PERF_RECORD_SWITCH to Intel PT Adrian Hunter
  2015-08-13  9:40 ` [PATCH 1/2] perf tools: Add a helper function to probe whether cpu-wide tracing is possible Adrian Hunter
@ 2015-08-13  9:40 ` Adrian Hunter
  2015-09-02 13:09   ` Adrian Hunter
  2015-09-08 14:38   ` [tip:perf/core] perf intel-pt: Add support for PERF_RECORD_SWITCH tip-bot for Adrian Hunter
  1 sibling, 2 replies; 6+ messages in thread
From: Adrian Hunter @ 2015-08-13  9:40 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo; +Cc: linux-kernel, Jiri Olsa

Add support for selecting and processing PERF_RECORD_SWITCH
events for use by Intel PT.  If they are available, they will be
used in preference to sched_switch events.

This enables an unprivileged user to trace multi-threaded or
multi-process workloads with any level of perf_event_paranoid.
However it depends on kernel support for PERF_RECORD_SWITCH.

Without this patch, tracing a multi-threaded workload will
decode without error but all the data will be attributed to
the main thread.

Without this patch, tracing a multi-process workload will
result in decoder errors because the decoder will not know
which executable is executing.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 tools/perf/arch/x86/util/intel-pt.c |  55 ++++++++++++---
 tools/perf/util/intel-pt.c          | 129 +++++++++++++++++++++++++++++-------
 2 files changed, 151 insertions(+), 33 deletions(-)

diff --git a/tools/perf/arch/x86/util/intel-pt.c b/tools/perf/arch/x86/util/intel-pt.c
index 2ca10d796c0b..b02af064f0f9 100644
--- a/tools/perf/arch/x86/util/intel-pt.c
+++ b/tools/perf/arch/x86/util/intel-pt.c
@@ -624,13 +624,49 @@ static int intel_pt_recording_options(struct auxtrace_record *itr,
 	 * threads.
 	 */
 	if (have_timing_info && !cpu_map__empty(cpus)) {
-		err = intel_pt_track_switches(evlist);
-		if (err == -EPERM)
-			pr_debug2("Unable to select sched:sched_switch\n");
-		else if (err)
-			return err;
-		else
-			ptr->have_sched_switch = 1;
+		if (perf_can_record_switch_events()) {
+			bool cpu_wide = !target__none(&opts->target) &&
+					!target__has_task(&opts->target);
+
+			if (!cpu_wide && perf_can_record_cpu_wide()) {
+				struct perf_evsel *switch_evsel;
+
+				err = parse_events(evlist, "dummy:u", NULL);
+				if (err)
+					return err;
+
+				switch_evsel = perf_evlist__last(evlist);
+
+				switch_evsel->attr.freq = 0;
+				switch_evsel->attr.sample_period = 1;
+				switch_evsel->attr.context_switch = 1;
+
+				switch_evsel->system_wide = true;
+				switch_evsel->no_aux_samples = true;
+				switch_evsel->immediate = true;
+
+				perf_evsel__set_sample_bit(switch_evsel, TID);
+				perf_evsel__set_sample_bit(switch_evsel, TIME);
+				perf_evsel__set_sample_bit(switch_evsel, CPU);
+
+				opts->record_switch_events = false;
+				ptr->have_sched_switch = 3;
+			} else {
+				opts->record_switch_events = true;
+				if (cpu_wide)
+					ptr->have_sched_switch = 3;
+				else
+					ptr->have_sched_switch = 2;
+			}
+		} else {
+			err = intel_pt_track_switches(evlist);
+			if (err == -EPERM)
+				pr_debug2("Unable to select sched:sched_switch\n");
+			else if (err)
+				return err;
+			else
+				ptr->have_sched_switch = 1;
+		}
 	}
 
 	if (intel_pt_evsel) {
@@ -663,8 +699,11 @@ static int intel_pt_recording_options(struct auxtrace_record *itr,
 		tracking_evsel->attr.sample_period = 1;
 
 		/* In per-cpu case, always need the time of mmap events etc */
-		if (!cpu_map__empty(cpus))
+		if (!cpu_map__empty(cpus)) {
 			perf_evsel__set_sample_bit(tracking_evsel, TIME);
+			/* And the CPU for switch events */
+			perf_evsel__set_sample_bit(tracking_evsel, CPU);
+		}
 	}
 
 	/*
diff --git a/tools/perf/util/intel-pt.c b/tools/perf/util/intel-pt.c
index 4bae958096d4..1f6aab58e931 100644
--- a/tools/perf/util/intel-pt.c
+++ b/tools/perf/util/intel-pt.c
@@ -1145,11 +1145,13 @@ static int intel_pt_sample(struct intel_pt_queue *ptq)
 	return 0;
 }
 
-static u64 intel_pt_switch_ip(struct machine *machine, u64 *ptss_ip)
+static u64 intel_pt_switch_ip(struct intel_pt *pt, u64 *ptss_ip)
 {
+	struct machine *machine = pt->machine;
 	struct map *map;
 	struct symbol *sym, *start;
 	u64 ip, switch_ip = 0;
+	const char *ptss;
 
 	if (ptss_ip)
 		*ptss_ip = 0;
@@ -1177,8 +1179,13 @@ static u64 intel_pt_switch_ip(struct machine *machine, u64 *ptss_ip)
 	if (!switch_ip || !ptss_ip)
 		return 0;
 
+	if (pt->have_sched_switch == 1)
+		ptss = "perf_trace_sched_switch";
+	else
+		ptss = "__perf_event_task_sched_out";
+
 	for (sym = start; sym; sym = dso__next_symbol(sym)) {
-		if (!strcmp(sym->name, "perf_trace_sched_switch")) {
+		if (!strcmp(sym->name, ptss)) {
 			ip = map->unmap_ip(map, sym->start);
 			if (ip >= map->start && ip < map->end) {
 				*ptss_ip = ip;
@@ -1198,11 +1205,11 @@ static int intel_pt_run_decoder(struct intel_pt_queue *ptq, u64 *timestamp)
 
 	if (!pt->kernel_start) {
 		pt->kernel_start = machine__kernel_start(pt->machine);
-		if (pt->per_cpu_mmaps && pt->have_sched_switch &&
+		if (pt->per_cpu_mmaps &&
+		    (pt->have_sched_switch == 1 || pt->have_sched_switch == 3) &&
 		    !pt->timeless_decoding && intel_pt_tracing_kernel(pt) &&
 		    !pt->sampling_mode) {
-			pt->switch_ip = intel_pt_switch_ip(pt->machine,
-							   &pt->ptss_ip);
+			pt->switch_ip = intel_pt_switch_ip(pt, &pt->ptss_ip);
 			if (pt->switch_ip) {
 				intel_pt_log("switch_ip: %"PRIx64" ptss_ip: %"PRIx64"\n",
 					     pt->switch_ip, pt->ptss_ip);
@@ -1387,31 +1394,18 @@ static struct intel_pt_queue *intel_pt_cpu_to_ptq(struct intel_pt *pt, int cpu)
 	return NULL;
 }
 
-static int intel_pt_process_switch(struct intel_pt *pt,
-				   struct perf_sample *sample)
+static int intel_pt_sync_switch(struct intel_pt *pt, int cpu, pid_t tid,
+				u64 timestamp)
 {
 	struct intel_pt_queue *ptq;
-	struct perf_evsel *evsel;
-	pid_t tid;
-	int cpu, err;
-
-	evsel = perf_evlist__id2evsel(pt->session->evlist, sample->id);
-	if (evsel != pt->switch_evsel)
-		return 0;
-
-	tid = perf_evsel__intval(evsel, sample, "next_pid");
-	cpu = sample->cpu;
-
-	intel_pt_log("sched_switch: cpu %d tid %d time %"PRIu64" tsc %#"PRIx64"\n",
-		     cpu, tid, sample->time, perf_time_to_tsc(sample->time,
-		     &pt->tc));
+	int err;
 
 	if (!pt->sync_switch)
-		goto out;
+		return 1;
 
 	ptq = intel_pt_cpu_to_ptq(pt, cpu);
 	if (!ptq)
-		goto out;
+		return 1;
 
 	switch (ptq->switch_state) {
 	case INTEL_PT_SS_NOT_TRACING:
@@ -1424,7 +1418,7 @@ static int intel_pt_process_switch(struct intel_pt *pt,
 		return 0;
 	case INTEL_PT_SS_EXPECTING_SWITCH_EVENT:
 		if (!ptq->on_heap) {
-			ptq->timestamp = perf_time_to_tsc(sample->time,
+			ptq->timestamp = perf_time_to_tsc(timestamp,
 							  &pt->tc);
 			err = auxtrace_heap__add(&pt->heap, ptq->queue_nr,
 						 ptq->timestamp);
@@ -1441,10 +1435,76 @@ static int intel_pt_process_switch(struct intel_pt *pt,
 	default:
 		break;
 	}
-out:
+
+	return 1;
+}
+
+static int intel_pt_process_switch(struct intel_pt *pt,
+				   struct perf_sample *sample)
+{
+	struct perf_evsel *evsel;
+	pid_t tid;
+	int cpu, ret;
+
+	evsel = perf_evlist__id2evsel(pt->session->evlist, sample->id);
+	if (evsel != pt->switch_evsel)
+		return 0;
+
+	tid = perf_evsel__intval(evsel, sample, "next_pid");
+	cpu = sample->cpu;
+
+	intel_pt_log("sched_switch: cpu %d tid %d time %"PRIu64" tsc %#"PRIx64"\n",
+		     cpu, tid, sample->time, perf_time_to_tsc(sample->time,
+		     &pt->tc));
+
+	ret = intel_pt_sync_switch(pt, cpu, tid, sample->time);
+	if (ret <= 0)
+		return ret;
+
 	return machine__set_current_tid(pt->machine, cpu, -1, tid);
 }
 
+static int intel_pt_context_switch(struct intel_pt *pt, union perf_event *event,
+				   struct perf_sample *sample)
+{
+	bool out = event->header.misc & PERF_RECORD_MISC_SWITCH_OUT;
+	pid_t pid, tid;
+	int cpu, ret;
+
+	cpu = sample->cpu;
+
+	if (pt->have_sched_switch == 3) {
+		if (!out)
+			return 0;
+		if (event->header.type != PERF_RECORD_SWITCH_CPU_WIDE) {
+			pr_err("Expecting CPU-wide context switch event\n");
+			return -EINVAL;
+		}
+		pid = event->context_switch.next_prev_pid;
+		tid = event->context_switch.next_prev_tid;
+	} else {
+		if (out)
+			return 0;
+		pid = sample->pid;
+		tid = sample->tid;
+	}
+
+	if (tid == -1) {
+		pr_err("context_switch event has no tid\n");
+		return -EINVAL;
+	}
+
+	intel_pt_log("context_switch: cpu %d pid %d tid %d time %"PRIu64" tsc %#"PRIx64"\n",
+		     cpu, pid, tid, sample->time, perf_time_to_tsc(sample->time,
+		     &pt->tc));
+
+	ret = intel_pt_sync_switch(pt, cpu, tid, sample->time);
+	if (ret <= 0)
+		return ret;
+
+	return machine__set_current_tid(pt->machine, cpu, pid, tid);
+}
+
 static int intel_pt_process_itrace_start(struct intel_pt *pt,
 					 union perf_event *event,
 					 struct perf_sample *sample)
@@ -1515,6 +1575,9 @@ static int intel_pt_process_event(struct perf_session *session,
 		err = intel_pt_process_switch(pt, sample);
 	else if (event->header.type == PERF_RECORD_ITRACE_START)
 		err = intel_pt_process_itrace_start(pt, event, sample);
+	else if (event->header.type == PERF_RECORD_SWITCH ||
+		 event->header.type == PERF_RECORD_SWITCH_CPU_WIDE)
+		err = intel_pt_context_switch(pt, event, sample);
 
 	intel_pt_log("event %s (%u): cpu %d time %"PRIu64" tsc %#"PRIx64"\n",
 		     perf_event__name(event->header.type), event->header.type,
@@ -1777,6 +1840,18 @@ static struct perf_evsel *intel_pt_find_sched_switch(struct perf_evlist *evlist)
 	return NULL;
 }
 
+static bool intel_pt_find_switch(struct perf_evlist *evlist)
+{
+	struct perf_evsel *evsel;
+
+	evlist__for_each(evlist, evsel) {
+		if (evsel->attr.context_switch)
+			return true;
+	}
+
+	return false;
+}
+
 static const char * const intel_pt_info_fmts[] = {
 	[INTEL_PT_PMU_TYPE]		= "  PMU Type            %"PRId64"\n",
 	[INTEL_PT_TIME_SHIFT]		= "  Time Shift          %"PRIu64"\n",
@@ -1888,6 +1963,10 @@ int intel_pt_process_auxtrace_info(union perf_event *event,
 			pr_err("%s: missing sched_switch event\n", __func__);
 			goto err_delete_thread;
 		}
+	} else if (pt->have_sched_switch == 2 &&
+		   !intel_pt_find_switch(session->evlist)) {
+		pr_err("%s: missing context_switch attribute flag\n", __func__);
+		goto err_delete_thread;
 	}
 
 	if (session->itrace_synth_opts && session->itrace_synth_opts->set) {
-- 
1.9.1


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

* [tip:perf/core] perf tools: Add a helper function to probe whether cpu-wide tracing is possible
  2015-08-13  9:40 ` [PATCH 1/2] perf tools: Add a helper function to probe whether cpu-wide tracing is possible Adrian Hunter
@ 2015-08-20  9:56   ` tip-bot for Adrian Hunter
  0 siblings, 0 replies; 6+ messages in thread
From: tip-bot for Adrian Hunter @ 2015-08-20  9:56 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: hpa, jolsa, adrian.hunter, acme, linux-kernel, mingo, tglx

Commit-ID:  835095653ebfe4b16596a30db1c4e7c414014b5e
Gitweb:     http://git.kernel.org/tip/835095653ebfe4b16596a30db1c4e7c414014b5e
Author:     Adrian Hunter <adrian.hunter@intel.com>
AuthorDate: Thu, 13 Aug 2015 12:40:56 +0300
Committer:  Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Mon, 17 Aug 2015 11:08:37 -0300

perf tools: Add a helper function to probe whether cpu-wide tracing is possible

Add a helper function to probe whether cpu-wide tracing is possible.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Link: http://lkml.kernel.org/r/1439458857-30636-2-git-send-email-adrian.hunter@intel.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/util/evlist.h |  1 +
 tools/perf/util/record.c | 24 ++++++++++++++++++++++++
 2 files changed, 25 insertions(+)

diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index 3977570..436e358 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -115,6 +115,7 @@ void perf_evlist__close(struct perf_evlist *evlist);
 void perf_evlist__set_id_pos(struct perf_evlist *evlist);
 bool perf_can_sample_identifier(void);
 bool perf_can_record_switch_events(void);
+bool perf_can_record_cpu_wide(void);
 void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts);
 int record_opts__config(struct record_opts *opts);
 
diff --git a/tools/perf/util/record.c b/tools/perf/util/record.c
index 0d228a2..0467367 100644
--- a/tools/perf/util/record.c
+++ b/tools/perf/util/record.c
@@ -105,6 +105,30 @@ bool perf_can_record_switch_events(void)
 	return perf_probe_api(perf_probe_context_switch);
 }
 
+bool perf_can_record_cpu_wide(void)
+{
+	struct perf_event_attr attr = {
+		.type = PERF_TYPE_SOFTWARE,
+		.config = PERF_COUNT_SW_CPU_CLOCK,
+		.exclude_kernel = 1,
+	};
+	struct cpu_map *cpus;
+	int cpu, fd;
+
+	cpus = cpu_map__new(NULL);
+	if (!cpus)
+		return false;
+	cpu = cpus->map[0];
+	cpu_map__put(cpus);
+
+	fd = sys_perf_event_open(&attr, -1, cpu, -1, 0);
+	if (fd < 0)
+		return false;
+	close(fd);
+
+	return true;
+}
+
 void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts)
 {
 	struct perf_evsel *evsel;

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

* Re: [PATCH 2/2] perf tools: Add support for PERF_RECORD_SWITCH to Intel PT
  2015-08-13  9:40 ` [PATCH 2/2] perf tools: Add support for PERF_RECORD_SWITCH to Intel PT Adrian Hunter
@ 2015-09-02 13:09   ` Adrian Hunter
  2015-09-08 14:38   ` [tip:perf/core] perf intel-pt: Add support for PERF_RECORD_SWITCH tip-bot for Adrian Hunter
  1 sibling, 0 replies; 6+ messages in thread
From: Adrian Hunter @ 2015-09-02 13:09 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo; +Cc: linux-kernel, Jiri Olsa

On 13/08/15 12:40, Adrian Hunter wrote:
> Add support for selecting and processing PERF_RECORD_SWITCH
> events for use by Intel PT.  If they are available, they will be
> used in preference to sched_switch events.
> 
> This enables an unprivileged user to trace multi-threaded or
> multi-process workloads with any level of perf_event_paranoid.
> However it depends on kernel support for PERF_RECORD_SWITCH.
> 
> Without this patch, tracing a multi-threaded workload will
> decode without error but all the data will be attributed to
> the main thread.
> 
> Without this patch, tracing a multi-process workload will
> result in decoder errors because the decoder will not know
> which executable is executing.
> 
> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>

This one still applies.

> ---
>  tools/perf/arch/x86/util/intel-pt.c |  55 ++++++++++++---
>  tools/perf/util/intel-pt.c          | 129 +++++++++++++++++++++++++++++-------
>  2 files changed, 151 insertions(+), 33 deletions(-)
> 
> diff --git a/tools/perf/arch/x86/util/intel-pt.c b/tools/perf/arch/x86/util/intel-pt.c
> index 2ca10d796c0b..b02af064f0f9 100644
> --- a/tools/perf/arch/x86/util/intel-pt.c
> +++ b/tools/perf/arch/x86/util/intel-pt.c
> @@ -624,13 +624,49 @@ static int intel_pt_recording_options(struct auxtrace_record *itr,
>  	 * threads.
>  	 */
>  	if (have_timing_info && !cpu_map__empty(cpus)) {
> -		err = intel_pt_track_switches(evlist);
> -		if (err == -EPERM)
> -			pr_debug2("Unable to select sched:sched_switch\n");
> -		else if (err)
> -			return err;
> -		else
> -			ptr->have_sched_switch = 1;
> +		if (perf_can_record_switch_events()) {
> +			bool cpu_wide = !target__none(&opts->target) &&
> +					!target__has_task(&opts->target);
> +
> +			if (!cpu_wide && perf_can_record_cpu_wide()) {
> +				struct perf_evsel *switch_evsel;
> +
> +				err = parse_events(evlist, "dummy:u", NULL);
> +				if (err)
> +					return err;
> +
> +				switch_evsel = perf_evlist__last(evlist);
> +
> +				switch_evsel->attr.freq = 0;
> +				switch_evsel->attr.sample_period = 1;
> +				switch_evsel->attr.context_switch = 1;
> +
> +				switch_evsel->system_wide = true;
> +				switch_evsel->no_aux_samples = true;
> +				switch_evsel->immediate = true;
> +
> +				perf_evsel__set_sample_bit(switch_evsel, TID);
> +				perf_evsel__set_sample_bit(switch_evsel, TIME);
> +				perf_evsel__set_sample_bit(switch_evsel, CPU);
> +
> +				opts->record_switch_events = false;
> +				ptr->have_sched_switch = 3;
> +			} else {
> +				opts->record_switch_events = true;
> +				if (cpu_wide)
> +					ptr->have_sched_switch = 3;
> +				else
> +					ptr->have_sched_switch = 2;
> +			}
> +		} else {
> +			err = intel_pt_track_switches(evlist);
> +			if (err == -EPERM)
> +				pr_debug2("Unable to select sched:sched_switch\n");
> +			else if (err)
> +				return err;
> +			else
> +				ptr->have_sched_switch = 1;
> +		}
>  	}
>  
>  	if (intel_pt_evsel) {
> @@ -663,8 +699,11 @@ static int intel_pt_recording_options(struct auxtrace_record *itr,
>  		tracking_evsel->attr.sample_period = 1;
>  
>  		/* In per-cpu case, always need the time of mmap events etc */
> -		if (!cpu_map__empty(cpus))
> +		if (!cpu_map__empty(cpus)) {
>  			perf_evsel__set_sample_bit(tracking_evsel, TIME);
> +			/* And the CPU for switch events */
> +			perf_evsel__set_sample_bit(tracking_evsel, CPU);
> +		}
>  	}
>  
>  	/*
> diff --git a/tools/perf/util/intel-pt.c b/tools/perf/util/intel-pt.c
> index 4bae958096d4..1f6aab58e931 100644
> --- a/tools/perf/util/intel-pt.c
> +++ b/tools/perf/util/intel-pt.c
> @@ -1145,11 +1145,13 @@ static int intel_pt_sample(struct intel_pt_queue *ptq)
>  	return 0;
>  }
>  
> -static u64 intel_pt_switch_ip(struct machine *machine, u64 *ptss_ip)
> +static u64 intel_pt_switch_ip(struct intel_pt *pt, u64 *ptss_ip)
>  {
> +	struct machine *machine = pt->machine;
>  	struct map *map;
>  	struct symbol *sym, *start;
>  	u64 ip, switch_ip = 0;
> +	const char *ptss;
>  
>  	if (ptss_ip)
>  		*ptss_ip = 0;
> @@ -1177,8 +1179,13 @@ static u64 intel_pt_switch_ip(struct machine *machine, u64 *ptss_ip)
>  	if (!switch_ip || !ptss_ip)
>  		return 0;
>  
> +	if (pt->have_sched_switch == 1)
> +		ptss = "perf_trace_sched_switch";
> +	else
> +		ptss = "__perf_event_task_sched_out";
> +
>  	for (sym = start; sym; sym = dso__next_symbol(sym)) {
> -		if (!strcmp(sym->name, "perf_trace_sched_switch")) {
> +		if (!strcmp(sym->name, ptss)) {
>  			ip = map->unmap_ip(map, sym->start);
>  			if (ip >= map->start && ip < map->end) {
>  				*ptss_ip = ip;
> @@ -1198,11 +1205,11 @@ static int intel_pt_run_decoder(struct intel_pt_queue *ptq, u64 *timestamp)
>  
>  	if (!pt->kernel_start) {
>  		pt->kernel_start = machine__kernel_start(pt->machine);
> -		if (pt->per_cpu_mmaps && pt->have_sched_switch &&
> +		if (pt->per_cpu_mmaps &&
> +		    (pt->have_sched_switch == 1 || pt->have_sched_switch == 3) &&
>  		    !pt->timeless_decoding && intel_pt_tracing_kernel(pt) &&
>  		    !pt->sampling_mode) {
> -			pt->switch_ip = intel_pt_switch_ip(pt->machine,
> -							   &pt->ptss_ip);
> +			pt->switch_ip = intel_pt_switch_ip(pt, &pt->ptss_ip);
>  			if (pt->switch_ip) {
>  				intel_pt_log("switch_ip: %"PRIx64" ptss_ip: %"PRIx64"\n",
>  					     pt->switch_ip, pt->ptss_ip);
> @@ -1387,31 +1394,18 @@ static struct intel_pt_queue *intel_pt_cpu_to_ptq(struct intel_pt *pt, int cpu)
>  	return NULL;
>  }
>  
> -static int intel_pt_process_switch(struct intel_pt *pt,
> -				   struct perf_sample *sample)
> +static int intel_pt_sync_switch(struct intel_pt *pt, int cpu, pid_t tid,
> +				u64 timestamp)
>  {
>  	struct intel_pt_queue *ptq;
> -	struct perf_evsel *evsel;
> -	pid_t tid;
> -	int cpu, err;
> -
> -	evsel = perf_evlist__id2evsel(pt->session->evlist, sample->id);
> -	if (evsel != pt->switch_evsel)
> -		return 0;
> -
> -	tid = perf_evsel__intval(evsel, sample, "next_pid");
> -	cpu = sample->cpu;
> -
> -	intel_pt_log("sched_switch: cpu %d tid %d time %"PRIu64" tsc %#"PRIx64"\n",
> -		     cpu, tid, sample->time, perf_time_to_tsc(sample->time,
> -		     &pt->tc));
> +	int err;
>  
>  	if (!pt->sync_switch)
> -		goto out;
> +		return 1;
>  
>  	ptq = intel_pt_cpu_to_ptq(pt, cpu);
>  	if (!ptq)
> -		goto out;
> +		return 1;
>  
>  	switch (ptq->switch_state) {
>  	case INTEL_PT_SS_NOT_TRACING:
> @@ -1424,7 +1418,7 @@ static int intel_pt_process_switch(struct intel_pt *pt,
>  		return 0;
>  	case INTEL_PT_SS_EXPECTING_SWITCH_EVENT:
>  		if (!ptq->on_heap) {
> -			ptq->timestamp = perf_time_to_tsc(sample->time,
> +			ptq->timestamp = perf_time_to_tsc(timestamp,
>  							  &pt->tc);
>  			err = auxtrace_heap__add(&pt->heap, ptq->queue_nr,
>  						 ptq->timestamp);
> @@ -1441,10 +1435,76 @@ static int intel_pt_process_switch(struct intel_pt *pt,
>  	default:
>  		break;
>  	}
> -out:
> +
> +	return 1;
> +}
> +
> +static int intel_pt_process_switch(struct intel_pt *pt,
> +				   struct perf_sample *sample)
> +{
> +	struct perf_evsel *evsel;
> +	pid_t tid;
> +	int cpu, ret;
> +
> +	evsel = perf_evlist__id2evsel(pt->session->evlist, sample->id);
> +	if (evsel != pt->switch_evsel)
> +		return 0;
> +
> +	tid = perf_evsel__intval(evsel, sample, "next_pid");
> +	cpu = sample->cpu;
> +
> +	intel_pt_log("sched_switch: cpu %d tid %d time %"PRIu64" tsc %#"PRIx64"\n",
> +		     cpu, tid, sample->time, perf_time_to_tsc(sample->time,
> +		     &pt->tc));
> +
> +	ret = intel_pt_sync_switch(pt, cpu, tid, sample->time);
> +	if (ret <= 0)
> +		return ret;
> +
>  	return machine__set_current_tid(pt->machine, cpu, -1, tid);
>  }
>  
> +static int intel_pt_context_switch(struct intel_pt *pt, union perf_event *event,
> +				   struct perf_sample *sample)
> +{
> +	bool out = event->header.misc & PERF_RECORD_MISC_SWITCH_OUT;
> +	pid_t pid, tid;
> +	int cpu, ret;
> +
> +	cpu = sample->cpu;
> +
> +	if (pt->have_sched_switch == 3) {
> +		if (!out)
> +			return 0;
> +		if (event->header.type != PERF_RECORD_SWITCH_CPU_WIDE) {
> +			pr_err("Expecting CPU-wide context switch event\n");
> +			return -EINVAL;
> +		}
> +		pid = event->context_switch.next_prev_pid;
> +		tid = event->context_switch.next_prev_tid;
> +	} else {
> +		if (out)
> +			return 0;
> +		pid = sample->pid;
> +		tid = sample->tid;
> +	}
> +
> +	if (tid == -1) {
> +		pr_err("context_switch event has no tid\n");
> +		return -EINVAL;
> +	}
> +
> +	intel_pt_log("context_switch: cpu %d pid %d tid %d time %"PRIu64" tsc %#"PRIx64"\n",
> +		     cpu, pid, tid, sample->time, perf_time_to_tsc(sample->time,
> +		     &pt->tc));
> +
> +	ret = intel_pt_sync_switch(pt, cpu, tid, sample->time);
> +	if (ret <= 0)
> +		return ret;
> +
> +	return machine__set_current_tid(pt->machine, cpu, pid, tid);
> +}
> +
>  static int intel_pt_process_itrace_start(struct intel_pt *pt,
>  					 union perf_event *event,
>  					 struct perf_sample *sample)
> @@ -1515,6 +1575,9 @@ static int intel_pt_process_event(struct perf_session *session,
>  		err = intel_pt_process_switch(pt, sample);
>  	else if (event->header.type == PERF_RECORD_ITRACE_START)
>  		err = intel_pt_process_itrace_start(pt, event, sample);
> +	else if (event->header.type == PERF_RECORD_SWITCH ||
> +		 event->header.type == PERF_RECORD_SWITCH_CPU_WIDE)
> +		err = intel_pt_context_switch(pt, event, sample);
>  
>  	intel_pt_log("event %s (%u): cpu %d time %"PRIu64" tsc %#"PRIx64"\n",
>  		     perf_event__name(event->header.type), event->header.type,
> @@ -1777,6 +1840,18 @@ static struct perf_evsel *intel_pt_find_sched_switch(struct perf_evlist *evlist)
>  	return NULL;
>  }
>  
> +static bool intel_pt_find_switch(struct perf_evlist *evlist)
> +{
> +	struct perf_evsel *evsel;
> +
> +	evlist__for_each(evlist, evsel) {
> +		if (evsel->attr.context_switch)
> +			return true;
> +	}
> +
> +	return false;
> +}
> +
>  static const char * const intel_pt_info_fmts[] = {
>  	[INTEL_PT_PMU_TYPE]		= "  PMU Type            %"PRId64"\n",
>  	[INTEL_PT_TIME_SHIFT]		= "  Time Shift          %"PRIu64"\n",
> @@ -1888,6 +1963,10 @@ int intel_pt_process_auxtrace_info(union perf_event *event,
>  			pr_err("%s: missing sched_switch event\n", __func__);
>  			goto err_delete_thread;
>  		}
> +	} else if (pt->have_sched_switch == 2 &&
> +		   !intel_pt_find_switch(session->evlist)) {
> +		pr_err("%s: missing context_switch attribute flag\n", __func__);
> +		goto err_delete_thread;
>  	}
>  
>  	if (session->itrace_synth_opts && session->itrace_synth_opts->set) {
> 


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

* [tip:perf/core] perf intel-pt: Add support for PERF_RECORD_SWITCH
  2015-08-13  9:40 ` [PATCH 2/2] perf tools: Add support for PERF_RECORD_SWITCH to Intel PT Adrian Hunter
  2015-09-02 13:09   ` Adrian Hunter
@ 2015-09-08 14:38   ` tip-bot for Adrian Hunter
  1 sibling, 0 replies; 6+ messages in thread
From: tip-bot for Adrian Hunter @ 2015-09-08 14:38 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: linux-kernel, adrian.hunter, tglx, jolsa, hpa, mingo, acme

Commit-ID:  86c2786994bd7c0d4b525bbfbe42ac540d0b8166
Gitweb:     http://git.kernel.org/tip/86c2786994bd7c0d4b525bbfbe42ac540d0b8166
Author:     Adrian Hunter <adrian.hunter@intel.com>
AuthorDate: Thu, 13 Aug 2015 12:40:57 +0300
Committer:  Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Fri, 4 Sep 2015 12:01:05 -0300

perf intel-pt: Add support for PERF_RECORD_SWITCH

Add support for selecting and processing PERF_RECORD_SWITCH events for
use by Intel PT.  If they are available, they will be used in preference
to sched_switch events.

This enables an unprivileged user to trace multi-threaded or
multi-process workloads with any level of perf_event_paranoid.  However
it depends on kernel support for PERF_RECORD_SWITCH.

Without this patch, tracing a multi-threaded workload will decode
without error but all the data will be attributed to the main thread.

Without this patch, tracing a multi-process workload will result in
decoder errors because the decoder will not know which executable is
executing.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Link: http://lkml.kernel.org/r/1439458857-30636-3-git-send-email-adrian.hunter@intel.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/arch/x86/util/intel-pt.c |  55 ++++++++++++---
 tools/perf/util/intel-pt.c          | 129 +++++++++++++++++++++++++++++-------
 2 files changed, 151 insertions(+), 33 deletions(-)

diff --git a/tools/perf/arch/x86/util/intel-pt.c b/tools/perf/arch/x86/util/intel-pt.c
index 2ca10d7..b02af06 100644
--- a/tools/perf/arch/x86/util/intel-pt.c
+++ b/tools/perf/arch/x86/util/intel-pt.c
@@ -624,13 +624,49 @@ static int intel_pt_recording_options(struct auxtrace_record *itr,
 	 * threads.
 	 */
 	if (have_timing_info && !cpu_map__empty(cpus)) {
-		err = intel_pt_track_switches(evlist);
-		if (err == -EPERM)
-			pr_debug2("Unable to select sched:sched_switch\n");
-		else if (err)
-			return err;
-		else
-			ptr->have_sched_switch = 1;
+		if (perf_can_record_switch_events()) {
+			bool cpu_wide = !target__none(&opts->target) &&
+					!target__has_task(&opts->target);
+
+			if (!cpu_wide && perf_can_record_cpu_wide()) {
+				struct perf_evsel *switch_evsel;
+
+				err = parse_events(evlist, "dummy:u", NULL);
+				if (err)
+					return err;
+
+				switch_evsel = perf_evlist__last(evlist);
+
+				switch_evsel->attr.freq = 0;
+				switch_evsel->attr.sample_period = 1;
+				switch_evsel->attr.context_switch = 1;
+
+				switch_evsel->system_wide = true;
+				switch_evsel->no_aux_samples = true;
+				switch_evsel->immediate = true;
+
+				perf_evsel__set_sample_bit(switch_evsel, TID);
+				perf_evsel__set_sample_bit(switch_evsel, TIME);
+				perf_evsel__set_sample_bit(switch_evsel, CPU);
+
+				opts->record_switch_events = false;
+				ptr->have_sched_switch = 3;
+			} else {
+				opts->record_switch_events = true;
+				if (cpu_wide)
+					ptr->have_sched_switch = 3;
+				else
+					ptr->have_sched_switch = 2;
+			}
+		} else {
+			err = intel_pt_track_switches(evlist);
+			if (err == -EPERM)
+				pr_debug2("Unable to select sched:sched_switch\n");
+			else if (err)
+				return err;
+			else
+				ptr->have_sched_switch = 1;
+		}
 	}
 
 	if (intel_pt_evsel) {
@@ -663,8 +699,11 @@ static int intel_pt_recording_options(struct auxtrace_record *itr,
 		tracking_evsel->attr.sample_period = 1;
 
 		/* In per-cpu case, always need the time of mmap events etc */
-		if (!cpu_map__empty(cpus))
+		if (!cpu_map__empty(cpus)) {
 			perf_evsel__set_sample_bit(tracking_evsel, TIME);
+			/* And the CPU for switch events */
+			perf_evsel__set_sample_bit(tracking_evsel, CPU);
+		}
 	}
 
 	/*
diff --git a/tools/perf/util/intel-pt.c b/tools/perf/util/intel-pt.c
index bb41c20..2968b37 100644
--- a/tools/perf/util/intel-pt.c
+++ b/tools/perf/util/intel-pt.c
@@ -1145,11 +1145,13 @@ static int intel_pt_sample(struct intel_pt_queue *ptq)
 	return 0;
 }
 
-static u64 intel_pt_switch_ip(struct machine *machine, u64 *ptss_ip)
+static u64 intel_pt_switch_ip(struct intel_pt *pt, u64 *ptss_ip)
 {
+	struct machine *machine = pt->machine;
 	struct map *map;
 	struct symbol *sym, *start;
 	u64 ip, switch_ip = 0;
+	const char *ptss;
 
 	if (ptss_ip)
 		*ptss_ip = 0;
@@ -1177,8 +1179,13 @@ static u64 intel_pt_switch_ip(struct machine *machine, u64 *ptss_ip)
 	if (!switch_ip || !ptss_ip)
 		return 0;
 
+	if (pt->have_sched_switch == 1)
+		ptss = "perf_trace_sched_switch";
+	else
+		ptss = "__perf_event_task_sched_out";
+
 	for (sym = start; sym; sym = dso__next_symbol(sym)) {
-		if (!strcmp(sym->name, "perf_trace_sched_switch")) {
+		if (!strcmp(sym->name, ptss)) {
 			ip = map->unmap_ip(map, sym->start);
 			if (ip >= map->start && ip < map->end) {
 				*ptss_ip = ip;
@@ -1198,11 +1205,11 @@ static int intel_pt_run_decoder(struct intel_pt_queue *ptq, u64 *timestamp)
 
 	if (!pt->kernel_start) {
 		pt->kernel_start = machine__kernel_start(pt->machine);
-		if (pt->per_cpu_mmaps && pt->have_sched_switch &&
+		if (pt->per_cpu_mmaps &&
+		    (pt->have_sched_switch == 1 || pt->have_sched_switch == 3) &&
 		    !pt->timeless_decoding && intel_pt_tracing_kernel(pt) &&
 		    !pt->sampling_mode) {
-			pt->switch_ip = intel_pt_switch_ip(pt->machine,
-							   &pt->ptss_ip);
+			pt->switch_ip = intel_pt_switch_ip(pt, &pt->ptss_ip);
 			if (pt->switch_ip) {
 				intel_pt_log("switch_ip: %"PRIx64" ptss_ip: %"PRIx64"\n",
 					     pt->switch_ip, pt->ptss_ip);
@@ -1387,31 +1394,18 @@ static struct intel_pt_queue *intel_pt_cpu_to_ptq(struct intel_pt *pt, int cpu)
 	return NULL;
 }
 
-static int intel_pt_process_switch(struct intel_pt *pt,
-				   struct perf_sample *sample)
+static int intel_pt_sync_switch(struct intel_pt *pt, int cpu, pid_t tid,
+				u64 timestamp)
 {
 	struct intel_pt_queue *ptq;
-	struct perf_evsel *evsel;
-	pid_t tid;
-	int cpu, err;
-
-	evsel = perf_evlist__id2evsel(pt->session->evlist, sample->id);
-	if (evsel != pt->switch_evsel)
-		return 0;
-
-	tid = perf_evsel__intval(evsel, sample, "next_pid");
-	cpu = sample->cpu;
-
-	intel_pt_log("sched_switch: cpu %d tid %d time %"PRIu64" tsc %#"PRIx64"\n",
-		     cpu, tid, sample->time, perf_time_to_tsc(sample->time,
-		     &pt->tc));
+	int err;
 
 	if (!pt->sync_switch)
-		goto out;
+		return 1;
 
 	ptq = intel_pt_cpu_to_ptq(pt, cpu);
 	if (!ptq)
-		goto out;
+		return 1;
 
 	switch (ptq->switch_state) {
 	case INTEL_PT_SS_NOT_TRACING:
@@ -1424,7 +1418,7 @@ static int intel_pt_process_switch(struct intel_pt *pt,
 		return 0;
 	case INTEL_PT_SS_EXPECTING_SWITCH_EVENT:
 		if (!ptq->on_heap) {
-			ptq->timestamp = perf_time_to_tsc(sample->time,
+			ptq->timestamp = perf_time_to_tsc(timestamp,
 							  &pt->tc);
 			err = auxtrace_heap__add(&pt->heap, ptq->queue_nr,
 						 ptq->timestamp);
@@ -1441,10 +1435,76 @@ static int intel_pt_process_switch(struct intel_pt *pt,
 	default:
 		break;
 	}
-out:
+
+	return 1;
+}
+
+static int intel_pt_process_switch(struct intel_pt *pt,
+				   struct perf_sample *sample)
+{
+	struct perf_evsel *evsel;
+	pid_t tid;
+	int cpu, ret;
+
+	evsel = perf_evlist__id2evsel(pt->session->evlist, sample->id);
+	if (evsel != pt->switch_evsel)
+		return 0;
+
+	tid = perf_evsel__intval(evsel, sample, "next_pid");
+	cpu = sample->cpu;
+
+	intel_pt_log("sched_switch: cpu %d tid %d time %"PRIu64" tsc %#"PRIx64"\n",
+		     cpu, tid, sample->time, perf_time_to_tsc(sample->time,
+		     &pt->tc));
+
+	ret = intel_pt_sync_switch(pt, cpu, tid, sample->time);
+	if (ret <= 0)
+		return ret;
+
 	return machine__set_current_tid(pt->machine, cpu, -1, tid);
 }
 
+static int intel_pt_context_switch(struct intel_pt *pt, union perf_event *event,
+				   struct perf_sample *sample)
+{
+	bool out = event->header.misc & PERF_RECORD_MISC_SWITCH_OUT;
+	pid_t pid, tid;
+	int cpu, ret;
+
+	cpu = sample->cpu;
+
+	if (pt->have_sched_switch == 3) {
+		if (!out)
+			return 0;
+		if (event->header.type != PERF_RECORD_SWITCH_CPU_WIDE) {
+			pr_err("Expecting CPU-wide context switch event\n");
+			return -EINVAL;
+		}
+		pid = event->context_switch.next_prev_pid;
+		tid = event->context_switch.next_prev_tid;
+	} else {
+		if (out)
+			return 0;
+		pid = sample->pid;
+		tid = sample->tid;
+	}
+
+	if (tid == -1) {
+		pr_err("context_switch event has no tid\n");
+		return -EINVAL;
+	}
+
+	intel_pt_log("context_switch: cpu %d pid %d tid %d time %"PRIu64" tsc %#"PRIx64"\n",
+		     cpu, pid, tid, sample->time, perf_time_to_tsc(sample->time,
+		     &pt->tc));
+
+	ret = intel_pt_sync_switch(pt, cpu, tid, sample->time);
+	if (ret <= 0)
+		return ret;
+
+	return machine__set_current_tid(pt->machine, cpu, pid, tid);
+}
+
 static int intel_pt_process_itrace_start(struct intel_pt *pt,
 					 union perf_event *event,
 					 struct perf_sample *sample)
@@ -1515,6 +1575,9 @@ static int intel_pt_process_event(struct perf_session *session,
 		err = intel_pt_process_switch(pt, sample);
 	else if (event->header.type == PERF_RECORD_ITRACE_START)
 		err = intel_pt_process_itrace_start(pt, event, sample);
+	else if (event->header.type == PERF_RECORD_SWITCH ||
+		 event->header.type == PERF_RECORD_SWITCH_CPU_WIDE)
+		err = intel_pt_context_switch(pt, event, sample);
 
 	intel_pt_log("event %s (%u): cpu %d time %"PRIu64" tsc %#"PRIx64"\n",
 		     perf_event__name(event->header.type), event->header.type,
@@ -1777,6 +1840,18 @@ static struct perf_evsel *intel_pt_find_sched_switch(struct perf_evlist *evlist)
 	return NULL;
 }
 
+static bool intel_pt_find_switch(struct perf_evlist *evlist)
+{
+	struct perf_evsel *evsel;
+
+	evlist__for_each(evlist, evsel) {
+		if (evsel->attr.context_switch)
+			return true;
+	}
+
+	return false;
+}
+
 static const char * const intel_pt_info_fmts[] = {
 	[INTEL_PT_PMU_TYPE]		= "  PMU Type            %"PRId64"\n",
 	[INTEL_PT_TIME_SHIFT]		= "  Time Shift          %"PRIu64"\n",
@@ -1888,6 +1963,10 @@ int intel_pt_process_auxtrace_info(union perf_event *event,
 			pr_err("%s: missing sched_switch event\n", __func__);
 			goto err_delete_thread;
 		}
+	} else if (pt->have_sched_switch == 2 &&
+		   !intel_pt_find_switch(session->evlist)) {
+		pr_err("%s: missing context_switch attribute flag\n", __func__);
+		goto err_delete_thread;
 	}
 
 	if (session->itrace_synth_opts && session->itrace_synth_opts->set) {

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

end of thread, other threads:[~2015-09-08 14:39 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-08-13  9:40 [PATCH 0/2] perf tools: Add support for PERF_RECORD_SWITCH to Intel PT Adrian Hunter
2015-08-13  9:40 ` [PATCH 1/2] perf tools: Add a helper function to probe whether cpu-wide tracing is possible Adrian Hunter
2015-08-20  9:56   ` [tip:perf/core] " tip-bot for Adrian Hunter
2015-08-13  9:40 ` [PATCH 2/2] perf tools: Add support for PERF_RECORD_SWITCH to Intel PT Adrian Hunter
2015-09-02 13:09   ` Adrian Hunter
2015-09-08 14:38   ` [tip:perf/core] perf intel-pt: Add support for PERF_RECORD_SWITCH tip-bot for Adrian Hunter

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).