Skip to content

Commit 17ca7fc

Browse files
committed
Merge tag 'perf-core-2024-05-13' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull perf events updates from Ingo Molnar: - Combine perf and BPF for fast evalution of HW breakpoint conditions - Add LBR capture support outside of hardware events - Trigger IO signals for watermark_wakeup - Add RAPL support for Intel Arrow Lake and Lunar Lake - Optimize frequency-throttling - Miscellaneous cleanups & fixes * tag 'perf-core-2024-05-13' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (21 commits) perf/bpf: Mark perf_event_set_bpf_handler() and perf_event_free_bpf_handler() as inline too selftests/perf_events: Test FASYNC with watermark wakeups perf/ring_buffer: Trigger IO signals for watermark_wakeup perf: Move perf_event_fasync() to perf_event.h perf/bpf: Change the !CONFIG_BPF_SYSCALL stubs to static inlines selftest/bpf: Test a perf BPF program that suppresses side effects perf/bpf: Allow a BPF program to suppress all sample side effects perf/bpf: Remove unneeded uses_default_overflow_handler() perf/bpf: Call BPF handler directly, not through overflow machinery perf/bpf: Remove #ifdef CONFIG_BPF_SYSCALL from struct perf_event members perf/bpf: Create bpf_overflow_handler() stub for !CONFIG_BPF_SYSCALL perf/bpf: Reorder bpf_overflow_handler() ahead of __perf_event_overflow() perf/x86/rapl: Add support for Intel Lunar Lake perf/x86/rapl: Add support for Intel Arrow Lake perf/core: Reduce PMU access to adjust sample freq perf/core: Optimize perf_adjust_freq_unthr_context() perf/x86/amd: Don't reject non-sampling events with configured LBR perf/x86/amd: Support capturing LBR from software events perf/x86/amd: Avoid taking branches before disabling LBR perf/x86/amd: Ensure amd_pmu_core_disable_all() is always inlined ...
2 parents 48fc82c + 854dd99 commit 17ca7fc

File tree

14 files changed

+525
-172
lines changed

14 files changed

+525
-172
lines changed

arch/arm/kernel/hw_breakpoint.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -626,7 +626,7 @@ int hw_breakpoint_arch_parse(struct perf_event *bp,
626626
hw->address &= ~alignment_mask;
627627
hw->ctrl.len <<= offset;
628628

629-
if (uses_default_overflow_handler(bp)) {
629+
if (is_default_overflow_handler(bp)) {
630630
/*
631631
* Mismatch breakpoints are required for single-stepping
632632
* breakpoints.
@@ -798,7 +798,7 @@ static void watchpoint_handler(unsigned long addr, unsigned int fsr,
798798
* Otherwise, insert a temporary mismatch breakpoint so that
799799
* we can single-step over the watchpoint trigger.
800800
*/
801-
if (!uses_default_overflow_handler(wp))
801+
if (!is_default_overflow_handler(wp))
802802
continue;
803803
step:
804804
enable_single_step(wp, instruction_pointer(regs));
@@ -811,7 +811,7 @@ static void watchpoint_handler(unsigned long addr, unsigned int fsr,
811811
info->trigger = addr;
812812
pr_debug("watchpoint fired: address = 0x%x\n", info->trigger);
813813
perf_bp_event(wp, regs);
814-
if (uses_default_overflow_handler(wp))
814+
if (is_default_overflow_handler(wp))
815815
enable_single_step(wp, instruction_pointer(regs));
816816
}
817817

@@ -886,7 +886,7 @@ static void breakpoint_handler(unsigned long unknown, struct pt_regs *regs)
886886
info->trigger = addr;
887887
pr_debug("breakpoint fired: address = 0x%x\n", addr);
888888
perf_bp_event(bp, regs);
889-
if (uses_default_overflow_handler(bp))
889+
if (is_default_overflow_handler(bp))
890890
enable_single_step(bp, addr);
891891
goto unlock;
892892
}

arch/arm64/kernel/hw_breakpoint.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -655,7 +655,7 @@ static int breakpoint_handler(unsigned long unused, unsigned long esr,
655655
perf_bp_event(bp, regs);
656656

657657
/* Do we need to handle the stepping? */
658-
if (uses_default_overflow_handler(bp))
658+
if (is_default_overflow_handler(bp))
659659
step = 1;
660660
unlock:
661661
rcu_read_unlock();
@@ -734,7 +734,7 @@ static u64 get_distance_from_watchpoint(unsigned long addr, u64 val,
734734
static int watchpoint_report(struct perf_event *wp, unsigned long addr,
735735
struct pt_regs *regs)
736736
{
737-
int step = uses_default_overflow_handler(wp);
737+
int step = is_default_overflow_handler(wp);
738738
struct arch_hw_breakpoint *info = counter_arch_bp(wp);
739739

740740
info->trigger = addr;

arch/x86/events/amd/core.c

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -647,7 +647,7 @@ static void amd_pmu_cpu_dead(int cpu)
647647
}
648648
}
649649

650-
static inline void amd_pmu_set_global_ctl(u64 ctl)
650+
static __always_inline void amd_pmu_set_global_ctl(u64 ctl)
651651
{
652652
wrmsrl(MSR_AMD64_PERF_CNTR_GLOBAL_CTL, ctl);
653653
}
@@ -907,6 +907,37 @@ static int amd_pmu_handle_irq(struct pt_regs *regs)
907907
return amd_pmu_adjust_nmi_window(handled);
908908
}
909909

910+
/*
911+
* AMD-specific callback invoked through perf_snapshot_branch_stack static
912+
* call, defined in include/linux/perf_event.h. See its definition for API
913+
* details. It's up to caller to provide enough space in *entries* to fit all
914+
* LBR records, otherwise returned result will be truncated to *cnt* entries.
915+
*/
916+
static int amd_pmu_v2_snapshot_branch_stack(struct perf_branch_entry *entries, unsigned int cnt)
917+
{
918+
struct cpu_hw_events *cpuc;
919+
unsigned long flags;
920+
921+
/*
922+
* The sequence of steps to freeze LBR should be completely inlined
923+
* and contain no branches to minimize contamination of LBR snapshot
924+
*/
925+
local_irq_save(flags);
926+
amd_pmu_core_disable_all();
927+
__amd_pmu_lbr_disable();
928+
929+
cpuc = this_cpu_ptr(&cpu_hw_events);
930+
931+
amd_pmu_lbr_read();
932+
cnt = min(cnt, x86_pmu.lbr_nr);
933+
memcpy(entries, cpuc->lbr_entries, sizeof(struct perf_branch_entry) * cnt);
934+
935+
amd_pmu_v2_enable_all(0);
936+
local_irq_restore(flags);
937+
938+
return cnt;
939+
}
940+
910941
static int amd_pmu_v2_handle_irq(struct pt_regs *regs)
911942
{
912943
struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
@@ -1443,6 +1474,10 @@ static int __init amd_core_pmu_init(void)
14431474
static_call_update(amd_pmu_branch_reset, amd_pmu_lbr_reset);
14441475
static_call_update(amd_pmu_branch_add, amd_pmu_lbr_add);
14451476
static_call_update(amd_pmu_branch_del, amd_pmu_lbr_del);
1477+
1478+
/* Only support branch_stack snapshot on perfmon v2 */
1479+
if (x86_pmu.handle_irq == amd_pmu_v2_handle_irq)
1480+
static_call_update(perf_snapshot_branch_stack, amd_pmu_v2_snapshot_branch_stack);
14461481
} else if (!amd_brs_init()) {
14471482
/*
14481483
* BRS requires special event constraints and flushing on ctxsw.

arch/x86/events/amd/lbr.c

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -310,10 +310,6 @@ int amd_pmu_lbr_hw_config(struct perf_event *event)
310310
{
311311
int ret = 0;
312312

313-
/* LBR is not recommended in counting mode */
314-
if (!is_sampling_event(event))
315-
return -EINVAL;
316-
317313
ret = amd_pmu_lbr_setup_filter(event);
318314
if (!ret)
319315
event->attach_state |= PERF_ATTACH_SCHED_CB;
@@ -414,18 +410,11 @@ void amd_pmu_lbr_enable_all(void)
414410
void amd_pmu_lbr_disable_all(void)
415411
{
416412
struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events);
417-
u64 dbg_ctl, dbg_extn_cfg;
418413

419414
if (!cpuc->lbr_users || !x86_pmu.lbr_nr)
420415
return;
421416

422-
rdmsrl(MSR_AMD_DBG_EXTN_CFG, dbg_extn_cfg);
423-
wrmsrl(MSR_AMD_DBG_EXTN_CFG, dbg_extn_cfg & ~DBG_EXTN_CFG_LBRV2EN);
424-
425-
if (cpu_feature_enabled(X86_FEATURE_AMD_LBR_PMC_FREEZE)) {
426-
rdmsrl(MSR_IA32_DEBUGCTLMSR, dbg_ctl);
427-
wrmsrl(MSR_IA32_DEBUGCTLMSR, dbg_ctl & ~DEBUGCTLMSR_FREEZE_LBRS_ON_PMI);
428-
}
417+
__amd_pmu_lbr_disable();
429418
}
430419

431420
__init int amd_pmu_lbr_init(void)

arch/x86/events/perf_event.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1329,6 +1329,19 @@ void amd_pmu_lbr_enable_all(void);
13291329
void amd_pmu_lbr_disable_all(void);
13301330
int amd_pmu_lbr_hw_config(struct perf_event *event);
13311331

1332+
static __always_inline void __amd_pmu_lbr_disable(void)
1333+
{
1334+
u64 dbg_ctl, dbg_extn_cfg;
1335+
1336+
rdmsrl(MSR_AMD_DBG_EXTN_CFG, dbg_extn_cfg);
1337+
wrmsrl(MSR_AMD_DBG_EXTN_CFG, dbg_extn_cfg & ~DBG_EXTN_CFG_LBRV2EN);
1338+
1339+
if (cpu_feature_enabled(X86_FEATURE_AMD_LBR_PMC_FREEZE)) {
1340+
rdmsrl(MSR_IA32_DEBUGCTLMSR, dbg_ctl);
1341+
wrmsrl(MSR_IA32_DEBUGCTLMSR, dbg_ctl & ~DEBUGCTLMSR_FREEZE_LBRS_ON_PMI);
1342+
}
1343+
}
1344+
13321345
#ifdef CONFIG_PERF_EVENTS_AMD_BRS
13331346

13341347
#define AMD_FAM19H_BRS_EVENT 0xc4 /* RETIRED_TAKEN_BRANCH_INSTRUCTIONS */

arch/x86/events/rapl.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -675,10 +675,8 @@ static const struct attribute_group *rapl_attr_update[] = {
675675
static int __init init_rapl_pmus(void)
676676
{
677677
int maxdie = topology_max_packages() * topology_max_dies_per_package();
678-
size_t size;
679678

680-
size = sizeof(*rapl_pmus) + maxdie * sizeof(struct rapl_pmu *);
681-
rapl_pmus = kzalloc(size, GFP_KERNEL);
679+
rapl_pmus = kzalloc(struct_size(rapl_pmus, pmus, maxdie), GFP_KERNEL);
682680
if (!rapl_pmus)
683681
return -ENOMEM;
684682

@@ -808,6 +806,9 @@ static const struct x86_cpu_id rapl_model_match[] __initconst = {
808806
X86_MATCH_INTEL_FAM6_MODEL(RAPTORLAKE_S, &model_skl),
809807
X86_MATCH_INTEL_FAM6_MODEL(METEORLAKE, &model_skl),
810808
X86_MATCH_INTEL_FAM6_MODEL(METEORLAKE_L, &model_skl),
809+
X86_MATCH_INTEL_FAM6_MODEL(ARROWLAKE_H, &model_skl),
810+
X86_MATCH_INTEL_FAM6_MODEL(ARROWLAKE, &model_skl),
811+
X86_MATCH_INTEL_FAM6_MODEL(LUNARLAKE_M, &model_skl),
811812
{},
812813
};
813814
MODULE_DEVICE_TABLE(x86cpu, rapl_model_match);

include/linux/perf_event.h

Lines changed: 17 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -809,11 +809,8 @@ struct perf_event {
809809
u64 (*clock)(void);
810810
perf_overflow_handler_t overflow_handler;
811811
void *overflow_handler_context;
812-
#ifdef CONFIG_BPF_SYSCALL
813-
perf_overflow_handler_t orig_overflow_handler;
814812
struct bpf_prog *prog;
815813
u64 bpf_cookie;
816-
#endif
817814

818815
#ifdef CONFIG_EVENT_TRACING
819816
struct trace_event_call *tp_event;
@@ -883,6 +880,7 @@ struct perf_event_pmu_context {
883880

884881
unsigned int nr_events;
885882
unsigned int nr_cgroups;
883+
unsigned int nr_freq;
886884

887885
atomic_t refcount; /* event <-> epc */
888886
struct rcu_head rcu_head;
@@ -897,6 +895,11 @@ struct perf_event_pmu_context {
897895
int rotate_necessary;
898896
};
899897

898+
static inline bool perf_pmu_ctx_is_active(struct perf_event_pmu_context *epc)
899+
{
900+
return !list_empty(&epc->flexible_active) || !list_empty(&epc->pinned_active);
901+
}
902+
900903
struct perf_event_groups {
901904
struct rb_root tree;
902905
u64 index;
@@ -1342,31 +1345,17 @@ extern int perf_event_output(struct perf_event *event,
13421345
struct pt_regs *regs);
13431346

13441347
static inline bool
1345-
__is_default_overflow_handler(perf_overflow_handler_t overflow_handler)
1348+
is_default_overflow_handler(struct perf_event *event)
13461349
{
1350+
perf_overflow_handler_t overflow_handler = event->overflow_handler;
1351+
13471352
if (likely(overflow_handler == perf_event_output_forward))
13481353
return true;
13491354
if (unlikely(overflow_handler == perf_event_output_backward))
13501355
return true;
13511356
return false;
13521357
}
13531358

1354-
#define is_default_overflow_handler(event) \
1355-
__is_default_overflow_handler((event)->overflow_handler)
1356-
1357-
#ifdef CONFIG_BPF_SYSCALL
1358-
static inline bool uses_default_overflow_handler(struct perf_event *event)
1359-
{
1360-
if (likely(is_default_overflow_handler(event)))
1361-
return true;
1362-
1363-
return __is_default_overflow_handler(event->orig_overflow_handler);
1364-
}
1365-
#else
1366-
#define uses_default_overflow_handler(event) \
1367-
is_default_overflow_handler(event)
1368-
#endif
1369-
13701359
extern void
13711360
perf_event_header__init_id(struct perf_event_header *header,
13721361
struct perf_sample_data *data,
@@ -1697,6 +1686,14 @@ perf_event_addr_filters(struct perf_event *event)
16971686
return ifh;
16981687
}
16991688

1689+
static inline struct fasync_struct **perf_event_fasync(struct perf_event *event)
1690+
{
1691+
/* Only the parent has fasync state */
1692+
if (event->parent)
1693+
event = event->parent;
1694+
return &event->fasync;
1695+
}
1696+
17001697
extern void perf_event_addr_filters_sync(struct perf_event *event);
17011698
extern void perf_report_aux_output_id(struct perf_event *event, u64 hw_id);
17021699

0 commit comments

Comments
 (0)