Skip to content

Commit 8910075

Browse files
Stephane EranianPeter Zijlstra
authored andcommitted
perf/x86/amd: Enable branch sampling priv level filtering
The AMD Branch Sampling features does not provide hardware filtering by privilege level. The associated PMU counter does but not the branch sampling by itself. Given how BRS operates there is a possibility that BRS captures kernel level branches even though the event is programmed to count only at the user level. Implement a workaround in software by removing the branches which belong to the wrong privilege level. The privilege level is evaluated on the target of the branch and not the source so as to be compatible with other architectures. As a consequence of this patch, the number of entries in the PERF_RECORD_BRANCH_STACK buffer may be less than the maximum (16). It could even be zero. Another consequence is that consecutive entries in the branch stack may not reflect actual code path and may have discontinuities, in case kernel branches were suppressed. But this is no different than what happens on other architectures. Signed-off-by: Stephane Eranian <[email protected]> Signed-off-by: Peter Zijlstra (Intel) <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 4417599 commit 8910075

File tree

1 file changed

+20
-6
lines changed

1 file changed

+20
-6
lines changed

arch/x86/events/amd/brs.c

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -92,10 +92,6 @@ int amd_brs_setup_filter(struct perf_event *event)
9292
if ((type & ~PERF_SAMPLE_BRANCH_PLM_ALL) != PERF_SAMPLE_BRANCH_ANY)
9393
return -EINVAL;
9494

95-
/* can only capture at all priv levels due to the way BRS works */
96-
if ((type & PERF_SAMPLE_BRANCH_PLM_ALL) != PERF_SAMPLE_BRANCH_PLM_ALL)
97-
return -EINVAL;
98-
9995
return 0;
10096
}
10197

@@ -195,6 +191,21 @@ void amd_brs_disable_all(void)
195191
amd_brs_disable();
196192
}
197193

194+
static bool amd_brs_match_plm(struct perf_event *event, u64 to)
195+
{
196+
int type = event->attr.branch_sample_type;
197+
int plm_k = PERF_SAMPLE_BRANCH_KERNEL | PERF_SAMPLE_BRANCH_HV;
198+
int plm_u = PERF_SAMPLE_BRANCH_USER;
199+
200+
if (!(type & plm_k) && kernel_ip(to))
201+
return 0;
202+
203+
if (!(type & plm_u) && !kernel_ip(to))
204+
return 0;
205+
206+
return 1;
207+
}
208+
198209
/*
199210
* Caller must ensure amd_brs_inuse() is true before calling
200211
* return:
@@ -252,15 +263,18 @@ void amd_brs_drain(void)
252263
if (to == BRS_POISON)
253264
break;
254265

255-
rdmsrl(brs_from(brs_idx), from);
256-
257266
/*
258267
* Sign-extend SAMP_BR_TO to 64 bits, bits 61-63 are reserved.
259268
* Necessary to generate proper virtual addresses suitable for
260269
* symbolization
261270
*/
262271
to = (u64)(((s64)to << shift) >> shift);
263272

273+
if (!amd_brs_match_plm(event, to))
274+
continue;
275+
276+
rdmsrl(brs_from(brs_idx), from);
277+
264278
perf_clear_branch_entry_bitfields(br+nr);
265279

266280
br[nr].from = from;

0 commit comments

Comments
 (0)