Skip to contentSkip to conversation

perf tools: Add support for PERF_RECORD_SWITCH to Intel PT

PATCH In review Adrian Hunter 2 participants 6 messages Aug 13, 2015 – Sep 8, 2015 perf events

lore
Share & tools
lore

Adrian Hunter

author reviewer
#0 lore raw

cover perf tools: Add support for PERF_RECORD_SWITCH to Intel PT

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

author reviewer
#1 lore raw

PATCH 1/2 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.

---
 tools/perf/util/evlist.h |  1 +
 tools/perf/util/record.c | 24 ++++++++++++++++++++++++
 2 files changed, 25 insertions(+)
tools/perf/util/evlist.h +1 -0
index 397757063da1..436e358300b1 100644
@@ -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);
 
tools/perf/util/record.c +24 -0
index 0d228a29526d..0467367dc315 100644
@@ -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;
Signature · 1 line
1.9.1
#2 lore raw

[tip:perf/core] perf tools: Add a helper function to probe whether cpu-wide tracing is possible

perf tools: Add a helper function to probe whether cpu-wide tracing is possible
Commit-ID:  835095653ebfe4b16596a30db1c4e7c414014b5e
Gitweb:     http://git.kernel.org/tip/835095653ebfe4b16596a30db1c4e7c414014b5e
Author:     Adrian Hunter <[email protected]>
AuthorDate: Thu, 13 Aug 2015 12:40:56 +0300
Committer:  Arnaldo Carvalho de Melo <[email protected]>
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.

---
 tools/perf/util/evlist.h |  1 +
 tools/perf/util/record.c | 24 ++++++++++++++++++++++++
 2 files changed, 25 insertions(+)
tools/perf/util/evlist.h +1 -0
index 3977570..436e358 100644
@@ -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);
 
tools/perf/util/record.c +24 -0
index 0d228a2..0467367 100644
@@ -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;
author reviewer
#3 lore raw

PATCH 2/2 perf tools: Add support for PERF_RECORD_SWITCH to Intel PT

In reply to Adrian Hunter

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.

---
 tools/perf/arch/x86/util/intel-pt.c |  55 ++++++++++++---
 tools/perf/util/intel-pt.c          | 129 +++++++++++++++++++++++++++++-------
 2 files changed, 151 insertions(+), 33 deletions(-)
tools/perf/arch/x86/util/intel-pt.c +47 -8
index 2ca10d796c0b..b02af064f0f9 100644
@@ -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);
+		}
 	}
 
 	/*
tools/perf/util/intel-pt.c +104 -25

200 lines not on this page · raw message

Signature · 1 line
1.9.1
author reviewer
#4 lore raw
Quoted 12 lines · Adrian Hunter

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.

Quoted 5 lines

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

This one still applies.

Quoted 293 lines
---
 tools/perf/arch/x86/util/intel-pt.c |  55 ++++++++++++---
 tools/perf/util/intel-pt.c          | 129 +++++++++++++++++++++++++++++-------
 2 files changed, 151 insertions(+), 33 deletions(-)
tools/perf/arch/x86/util/intel-pt.c +47 -8
index 2ca10d796c0b..b02af064f0f9 100644
@@ -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);
+		}
 	}
 
 	/*
tools/perf/util/intel-pt.c +104 -25
index 4bae958096d4..1f6aab58e931 100644
@@ -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) {
#5 lore raw

[tip:perf/core] perf intel-pt: Add support for PERF_RECORD_SWITCH

In reply to Adrian Hunter
perf intel-pt: Add support for PERF_RECORD_SWITCH
Commit-ID:  86c2786994bd7c0d4b525bbfbe42ac540d0b8166
Gitweb:     http://git.kernel.org/tip/86c2786994bd7c0d4b525bbfbe42ac540d0b8166
Author:     Adrian Hunter <[email protected]>
AuthorDate: Thu, 13 Aug 2015 12:40:57 +0300
Committer:  Arnaldo Carvalho de Melo <[email protected]>
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.

---
 tools/perf/arch/x86/util/intel-pt.c |  55 ++++++++++++---
 tools/perf/util/intel-pt.c          | 129 +++++++++++++++++++++++++++++-------
 2 files changed, 151 insertions(+), 33 deletions(-)
tools/perf/arch/x86/util/intel-pt.c +47 -8
index 2ca10d7..b02af06 100644
@@ -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);
+		}
 	}
 
 	/*
tools/perf/util/intel-pt.c +104 -25

200 lines not on this page · raw message