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>
This commit is contained in:
Adrian Hunter
2015-08-13 12:40:57 +03:00
committed by Arnaldo Carvalho de Melo
parent 1b29ac59b1
commit 86c2786994
2 changed files with 151 additions and 33 deletions

View File

@@ -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);
}
}
/*