Skip to content

Commit b40d015

Browse files
sandip4nPeter Zijlstra
authored andcommitted
perf/x86/amd/brs: Move feature-specific functions
Move some of the Branch Sampling (BRS) specific functions out of the Core events sources and into the BRS sources in preparation for adding other mechanisms to record branches. Signed-off-by: Sandipan Das <sandipan.das@amd.com> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Link: https://lore.kernel.org/r/b60283b57179475d18ee242d117c335c16733693.1660211399.git.sandipan.das@amd.com
1 parent 1c23f9e commit b40d015

File tree

3 files changed

+76
-70
lines changed

3 files changed

+76
-70
lines changed

arch/x86/events/amd/brs.c

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ static bool __init amd_brs_detect(void)
8181
* a br_sel_map. Software filtering is not supported because it would not correlate well
8282
* with a sampling period.
8383
*/
84-
int amd_brs_setup_filter(struct perf_event *event)
84+
static int amd_brs_setup_filter(struct perf_event *event)
8585
{
8686
u64 type = event->attr.branch_sample_type;
8787

@@ -96,6 +96,73 @@ int amd_brs_setup_filter(struct perf_event *event)
9696
return 0;
9797
}
9898

99+
static inline int amd_is_brs_event(struct perf_event *e)
100+
{
101+
return (e->hw.config & AMD64_RAW_EVENT_MASK) == AMD_FAM19H_BRS_EVENT;
102+
}
103+
104+
int amd_brs_hw_config(struct perf_event *event)
105+
{
106+
int ret = 0;
107+
108+
/*
109+
* Due to interrupt holding, BRS is not recommended in
110+
* counting mode.
111+
*/
112+
if (!is_sampling_event(event))
113+
return -EINVAL;
114+
115+
/*
116+
* Due to the way BRS operates by holding the interrupt until
117+
* lbr_nr entries have been captured, it does not make sense
118+
* to allow sampling on BRS with an event that does not match
119+
* what BRS is capturing, i.e., retired taken branches.
120+
* Otherwise the correlation with the event's period is even
121+
* more loose:
122+
*
123+
* With retired taken branch:
124+
* Effective P = P + 16 + X
125+
* With any other event:
126+
* Effective P = P + Y + X
127+
*
128+
* Where X is the number of taken branches due to interrupt
129+
* skid. Skid is large.
130+
*
131+
* Where Y is the occurences of the event while BRS is
132+
* capturing the lbr_nr entries.
133+
*
134+
* By using retired taken branches, we limit the impact on the
135+
* Y variable. We know it cannot be more than the depth of
136+
* BRS.
137+
*/
138+
if (!amd_is_brs_event(event))
139+
return -EINVAL;
140+
141+
/*
142+
* BRS implementation does not work with frequency mode
143+
* reprogramming of the period.
144+
*/
145+
if (event->attr.freq)
146+
return -EINVAL;
147+
/*
148+
* The kernel subtracts BRS depth from period, so it must
149+
* be big enough.
150+
*/
151+
if (event->attr.sample_period <= x86_pmu.lbr_nr)
152+
return -EINVAL;
153+
154+
/*
155+
* Check if we can allow PERF_SAMPLE_BRANCH_STACK
156+
*/
157+
ret = amd_brs_setup_filter(event);
158+
159+
/* only set in case of success */
160+
if (!ret)
161+
event->hw.flags |= PERF_X86_EVENT_AMD_BRS;
162+
163+
return ret;
164+
}
165+
99166
/* tos = top of stack, i.e., last valid entry written */
100167
static inline int amd_brs_get_tos(union amd_debug_extn_cfg *cfg)
101168
{

arch/x86/events/amd/core.c

Lines changed: 3 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -330,16 +330,8 @@ static inline bool amd_is_pair_event_code(struct hw_perf_event *hwc)
330330
}
331331
}
332332

333-
#define AMD_FAM19H_BRS_EVENT 0xc4 /* RETIRED_TAKEN_BRANCH_INSTRUCTIONS */
334-
static inline int amd_is_brs_event(struct perf_event *e)
335-
{
336-
return (e->hw.config & AMD64_RAW_EVENT_MASK) == AMD_FAM19H_BRS_EVENT;
337-
}
338-
339333
static int amd_core_hw_config(struct perf_event *event)
340334
{
341-
int ret = 0;
342-
343335
if (event->attr.exclude_host && event->attr.exclude_guest)
344336
/*
345337
* When HO == GO == 1 the hardware treats that as GO == HO == 0
@@ -356,66 +348,10 @@ static int amd_core_hw_config(struct perf_event *event)
356348
if ((x86_pmu.flags & PMU_FL_PAIR) && amd_is_pair_event_code(&event->hw))
357349
event->hw.flags |= PERF_X86_EVENT_PAIR;
358350

359-
/*
360-
* if branch stack is requested
361-
*/
362-
if (has_branch_stack(event)) {
363-
/*
364-
* Due to interrupt holding, BRS is not recommended in
365-
* counting mode.
366-
*/
367-
if (!is_sampling_event(event))
368-
return -EINVAL;
369-
370-
/*
371-
* Due to the way BRS operates by holding the interrupt until
372-
* lbr_nr entries have been captured, it does not make sense
373-
* to allow sampling on BRS with an event that does not match
374-
* what BRS is capturing, i.e., retired taken branches.
375-
* Otherwise the correlation with the event's period is even
376-
* more loose:
377-
*
378-
* With retired taken branch:
379-
* Effective P = P + 16 + X
380-
* With any other event:
381-
* Effective P = P + Y + X
382-
*
383-
* Where X is the number of taken branches due to interrupt
384-
* skid. Skid is large.
385-
*
386-
* Where Y is the occurences of the event while BRS is
387-
* capturing the lbr_nr entries.
388-
*
389-
* By using retired taken branches, we limit the impact on the
390-
* Y variable. We know it cannot be more than the depth of
391-
* BRS.
392-
*/
393-
if (!amd_is_brs_event(event))
394-
return -EINVAL;
351+
if (has_branch_stack(event))
352+
return amd_brs_hw_config(event);
395353

396-
/*
397-
* BRS implementation does not work with frequency mode
398-
* reprogramming of the period.
399-
*/
400-
if (event->attr.freq)
401-
return -EINVAL;
402-
/*
403-
* The kernel subtracts BRS depth from period, so it must
404-
* be big enough.
405-
*/
406-
if (event->attr.sample_period <= x86_pmu.lbr_nr)
407-
return -EINVAL;
408-
409-
/*
410-
* Check if we can allow PERF_SAMPLE_BRANCH_STACK
411-
*/
412-
ret = amd_brs_setup_filter(event);
413-
414-
/* only set in case of success */
415-
if (!ret)
416-
event->hw.flags |= PERF_X86_EVENT_AMD_BRS;
417-
}
418-
return ret;
354+
return 0;
419355
}
420356

421357
static inline int amd_is_nb_event(struct hw_perf_event *hwc)

arch/x86/events/perf_event.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1233,6 +1233,9 @@ static inline bool fixed_counter_disabled(int i, struct pmu *pmu)
12331233
int amd_pmu_init(void);
12341234

12351235
#ifdef CONFIG_PERF_EVENTS_AMD_BRS
1236+
1237+
#define AMD_FAM19H_BRS_EVENT 0xc4 /* RETIRED_TAKEN_BRANCH_INSTRUCTIONS */
1238+
12361239
int amd_brs_init(void);
12371240
void amd_brs_disable(void);
12381241
void amd_brs_enable(void);
@@ -1241,7 +1244,7 @@ void amd_brs_disable_all(void);
12411244
void amd_brs_drain(void);
12421245
void amd_brs_lopwr_init(void);
12431246
void amd_brs_disable_all(void);
1244-
int amd_brs_setup_filter(struct perf_event *event);
1247+
int amd_brs_hw_config(struct perf_event *event);
12451248
void amd_brs_reset(void);
12461249

12471250
static inline void amd_pmu_brs_add(struct perf_event *event)
@@ -1277,7 +1280,7 @@ static inline void amd_brs_enable(void) {}
12771280
static inline void amd_brs_drain(void) {}
12781281
static inline void amd_brs_lopwr_init(void) {}
12791282
static inline void amd_brs_disable_all(void) {}
1280-
static inline int amd_brs_setup_filter(struct perf_event *event)
1283+
static inline int amd_brs_hw_config(struct perf_event *event)
12811284
{
12821285
return 0;
12831286
}

0 commit comments

Comments
 (0)