diff options
author | Wang Nan <wangnan0@huawei.com> | 2016-03-28 06:41:30 +0000 |
---|---|---|
committer | Michael Bestas <mkbestas@lineageos.org> | 2022-04-19 00:51:23 +0300 |
commit | 5434dca0dbda99ff62737ec849a96abb2ce73fdf (patch) | |
tree | e865a3c95ff0e1fd853d98b2d5ac276590764cac | |
parent | bf6c8c4cd830fe2822cc10fa35992e0270a1e3e5 (diff) |
perf/core: Set event's default ::overflow_handler()
Set a default event->overflow_handler in perf_event_alloc() so don't
need to check event->overflow_handler in __perf_event_overflow().
Following commits can give a different default overflow_handler.
Initial idea comes from Peter:
http://lkml.kernel.org/r/20130708121557.GA17211@twins.programming.kicks-ass.net
Since the default value of event->overflow_handler is not NULL, existing
'if (!overflow_handler)' checks need to be changed.
is_default_overflow_handler() is introduced for this.
No extra performance overhead is introduced into the hot path because in the
original code we still need to read this handler from memory. A conditional
branch is avoided so actually we remove some instructions.
Signed-off-by: Wang Nan <wangnan0@huawei.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: <pi3orama@163.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Brendan Gregg <brendan.d.gregg@gmail.com>
Cc: He Kuang <hekuang@huawei.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Vince Weaver <vincent.weaver@maine.edu>
Cc: Zefan Li <lizefan@huawei.com>
Link: http://lkml.kernel.org/r/1459147292-239310-3-git-send-email-wangnan0@huawei.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Signed-off-by: Chatur27 <jasonbright2709@gmail.com>
-rw-r--r-- | arch/arm/kernel/hw_breakpoint.c | 25 | ||||
-rw-r--r-- | arch/arm64/kernel/hw_breakpoint.c | 4 | ||||
-rw-r--r-- | include/linux/perf_event.h | 6 | ||||
-rw-r--r-- | kernel/events/core.c | 14 |
4 files changed, 24 insertions, 25 deletions
diff --git a/arch/arm/kernel/hw_breakpoint.c b/arch/arm/kernel/hw_breakpoint.c index 78c6be1b2714..89fd86301242 100644 --- a/arch/arm/kernel/hw_breakpoint.c +++ b/arch/arm/kernel/hw_breakpoint.c @@ -631,7 +631,7 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp) info->address &= ~alignment_mask; info->ctrl.len <<= offset; - if (!bp->overflow_handler) { + if (is_default_overflow_handler(bp)) { /* * Mismatch breakpoints are required for single-stepping * breakpoints. @@ -688,12 +688,6 @@ static void disable_single_step(struct perf_event *bp) arch_install_hw_breakpoint(bp); } -static int watchpoint_fault_on_uaccess(struct pt_regs *regs, - struct arch_hw_breakpoint *info) -{ - return !user_mode(regs) && info->ctrl.privilege == ARM_BREAKPOINT_USER; -} - static void watchpoint_handler(unsigned long addr, unsigned int fsr, struct pt_regs *regs) { @@ -760,20 +754,17 @@ static void watchpoint_handler(unsigned long addr, unsigned int fsr, * can't help us with this. */ if (watchpoint_fault_on_uaccess(regs, info)) - goto step; + enable_single_step(wp, instruction_pointer(regs)); perf_bp_event(wp, regs); /* - * Defer stepping to the overflow handler if one is installed. - * Otherwise, insert a temporary mismatch breakpoint so that - * we can single-step over the watchpoint trigger. + * If no overflow handler is present, insert a temporary + * mismatch breakpoint so we can single-step over the + * watchpoint trigger. */ - if (wp->overflow_handler) - goto unlock; - -step: - enable_single_step(wp, instruction_pointer(regs)); + if (is_default_overflow_handler(wp)) + enable_single_step(wp, instruction_pointer(regs)); unlock: rcu_read_unlock(); } @@ -1163,4 +1154,4 @@ int hw_breakpoint_exceptions_notify(struct notifier_block *unused, unsigned long val, void *data) { return NOTIFY_DONE; -} +}
\ No newline at end of file diff --git a/arch/arm64/kernel/hw_breakpoint.c b/arch/arm64/kernel/hw_breakpoint.c index bef4b659d816..3530541b3f5b 100644 --- a/arch/arm64/kernel/hw_breakpoint.c +++ b/arch/arm64/kernel/hw_breakpoint.c @@ -662,7 +662,7 @@ static int breakpoint_handler(unsigned long unused, unsigned int esr, perf_bp_event(bp, regs); /* Do we need to handle the stepping? */ - if (!bp->overflow_handler) + if (is_default_overflow_handler(bp)) step = 1; unlock: rcu_read_unlock(); @@ -788,7 +788,7 @@ static int watchpoint_handler(unsigned long addr, unsigned int esr, perf_bp_event(wp, regs); /* Do we need to handle the stepping? */ - if (!wp->overflow_handler) + if (is_default_overflow_handler(wp)) step = 1; } if (min_dist > 0 && min_dist != -1) { diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index 8e50962b984b..f29f84898698 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -863,6 +863,12 @@ extern void perf_event_output(struct perf_event *event, struct perf_sample_data *data, struct pt_regs *regs); +static inline bool +is_default_overflow_handler(struct perf_event *event) +{ + return (event->overflow_handler == perf_event_output); +} + extern void perf_event_header__init_id(struct perf_event_header *header, struct perf_sample_data *data, diff --git a/kernel/events/core.c b/kernel/events/core.c index befba6489d5e..658f21d9b180 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -6700,10 +6700,7 @@ static int __perf_event_overflow(struct perf_event *event, irq_work_queue(&event->pending); } - if (event->overflow_handler) - event->overflow_handler(event, data, regs); - else - perf_event_output(event, data, regs); + event->overflow_handler(event, data, regs); if (*perf_event_fasync(event) && event->pending_kill) { event->pending_wakeup = 1; @@ -8209,8 +8206,13 @@ perf_event_alloc(struct perf_event_attr *attr, int cpu, context = parent_event->overflow_handler_context; } - event->overflow_handler = overflow_handler; - event->overflow_handler_context = context; + if (overflow_handler) { + event->overflow_handler = overflow_handler; + event->overflow_handler_context = context; + } else { + event->overflow_handler = perf_event_output; + event->overflow_handler_context = NULL; + } perf_event__state_init(event); |