Skip to content

Commit

Permalink
perf/x86: Sync branch stack sampling with precise_sampling
Browse files Browse the repository at this point in the history
If precise sampling is enabled on Intel x86 then perf_event uses PEBS.
To correct for the off-by-one error of PEBS, perf_event uses LBR when
precise_sample > 1.

On Intel x86 PERF_SAMPLE_BRANCH_STACK is implemented using LBR,
therefore both features must be coordinated as they may not
configure LBR the same way.

For PEBS, LBR needs to capture all branches at the priv level of
the associated event.

This patch checks that the branch type and priv level of BRANCH_STACK
is compatible with that of the PEBS LBR requirement, thereby allowing:

   $ perf record -b any,u -e instructions:upp ....

But:

   $ perf record -b any_call,u -e instructions:upp

Is not possible.

Signed-off-by: Stephane Eranian <eranian@google.com>
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Link: http://lkml.kernel.org/r/1328826068-11713-5-git-send-email-eranian@google.com
Signed-off-by: Ingo Molnar <mingo@elte.hu>
  • Loading branch information
Stephane Eranian authored and Ingo Molnar committed Mar 5, 2012
1 parent b36817e commit ff3fb51
Showing 1 changed file with 60 additions and 0 deletions.
60 changes: 60 additions & 0 deletions arch/x86/kernel/cpu/perf_event.c
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,36 @@ int x86_setup_perfctr(struct perf_event *event)
return 0;
}

/*
* check that branch_sample_type is compatible with
* settings needed for precise_ip > 1 which implies
* using the LBR to capture ALL taken branches at the
* priv levels of the measurement
*/
static inline int precise_br_compat(struct perf_event *event)
{
u64 m = event->attr.branch_sample_type;
u64 b = 0;

/* must capture all branches */
if (!(m & PERF_SAMPLE_BRANCH_ANY))
return 0;

m &= PERF_SAMPLE_BRANCH_KERNEL | PERF_SAMPLE_BRANCH_USER;

if (!event->attr.exclude_user)
b |= PERF_SAMPLE_BRANCH_USER;

if (!event->attr.exclude_kernel)
b |= PERF_SAMPLE_BRANCH_KERNEL;

/*
* ignore PERF_SAMPLE_BRANCH_HV, not supported on x86
*/

return m == b;
}

int x86_pmu_hw_config(struct perf_event *event)
{
if (event->attr.precise_ip) {
Expand All @@ -369,6 +399,36 @@ int x86_pmu_hw_config(struct perf_event *event)

if (event->attr.precise_ip > precise)
return -EOPNOTSUPP;
/*
* check that PEBS LBR correction does not conflict with
* whatever the user is asking with attr->branch_sample_type
*/
if (event->attr.precise_ip > 1) {
u64 *br_type = &event->attr.branch_sample_type;

if (has_branch_stack(event)) {
if (!precise_br_compat(event))
return -EOPNOTSUPP;

/* branch_sample_type is compatible */

} else {
/*
* user did not specify branch_sample_type
*
* For PEBS fixups, we capture all
* the branches at the priv level of the
* event.
*/
*br_type = PERF_SAMPLE_BRANCH_ANY;

if (!event->attr.exclude_user)
*br_type |= PERF_SAMPLE_BRANCH_USER;

if (!event->attr.exclude_kernel)
*br_type |= PERF_SAMPLE_BRANCH_KERNEL;
}
}
}

/*
Expand Down

0 comments on commit ff3fb51

Please sign in to comment.