ftrace perf: Fixes and speedup
Subsystems (3)
Jiri Olsa
reviewerv2 cover ftrace perf: Fixes and speedup
hi,
sending some small perf related fixes plus one change to speedup ftrace:function perf registration.
v2 changes:
- added comment requested by Steven
- changed patch 1 according to Namhyung's suggestion
Also available in here:
git://git.kernel.org/pub/scm/linux/kernel/git/jolsa/perf.git
ftrace/fixes
thanks,
jirka
---
Jiri Olsa (5):
ftrace perf: Check sample types only for sampling events ftrace perf: Move exclude_kernel tracepoint check to init event ftrace perf: Use ftrace_ops::private to store event pointer
ftrace: Make ftrace_hash_rec_enable return update bool
ftrace: Update dynamic ftrace calls only if necessary
include/linux/perf_event.h | 3 +++ kernel/events/core.c | 27 ++++++++++++++++++++++----- kernel/trace/ftrace.c | 37 ++++++++++++++++++++++--------------- kernel/trace/trace_event_perf.c | 38 +++++++++++++++++++++++++++++++------- 4 files changed, 78 insertions(+), 27 deletions(-)
Jiri Olsa
reviewerPATCH v2 1/5 ftrace perf: Check sample types only for sampling events
Currently we check sample type for ftrace:function event even if it's not created as sampling event. That prevents creating ftrace_function event in counting mode.
Making sure we check sample types only for sampling events.
Before:
$ sudo perf stat -e ftrace:function ls ...
Performance counter stats for 'ls':
<not supported> ftrace:function
0.001983662 seconds time elapsed
After:
$ sudo perf stat -e ftrace:function ls ...
Performance counter stats for 'ls':
44,498 ftrace:function
0.037534722 seconds time elapsed--- kernel/trace/trace_event_perf.c | 3 +++ 1 file changed, 3 insertions(+)
kernel/trace/trace_event_perf.c +3 -0
@@ -47,6 +47,9 @@ static int perf_trace_event_perm(struct trace_event_call *tp_event,if (perf_paranoid_tracepoint_raw () && !capable (CAP_SYS_ADMIN ))return -EPERM ; +if (!is_sampling_event (p_event)) +return 0 ; +/* * We don't allow user space callchains for function trace * event, due to issues with page faults while tracing page
Signature · 1 line
2.4.3
Re: [PATCH 1/5] ftrace perf: Check sample types only for sampling events
Quoted 20 lines · On Wed, 16 Mar 2016 15:34:29 +0100 Jiri Olsa <[email protected]> wrote:
Currently we check sample type for ftrace:function event even if it's not created as sampling event. That prevents creating
ftrace_functionevent in counting mode.Making sure we check sample types only for sampling events.
Before:
$ sudo perf stat -e ftrace:function ls ...Performance counter stats for 'ls':
<not supported> ftrace:function
0.001983662 seconds time elapsed
After:
$ sudo perf stat -e ftrace:function ls ...
Quoted 8 lines
Performance counter stats for 'ls': 44,498 ftrace:function 0.037534722 seconds time elapsedSuggested-by Namhyung Kim <[email protected]>Signed-off-by Jiri Olsa <[email protected]>
-- Steve
tip-bot for Jiri Olsa
merge bot[tip:perf/core] ftrace/perf: Check sample types only for sampling events
In reply to Jiri Olsaftrace/perf: Check sample types only for sampling events
Commit-ID: 0a74c5b3d20d2a8693848b6ae4f1a97624f5b781 Gitweb: http://git.kernel.org/tip/0a74c5b3d20d2a8693848b6ae4f1a97624f5b781 Author: Jiri Olsa <[email protected]> AuthorDate: Wed, 16 Mar 2016 15:34:29 +0100 Committer: Ingo Molnar <[email protected]> CommitDate: Thu, 31 Mar 2016 10:30:45 +0200
ftrace/perf: Check sample types only for sampling events
Currently we check sample type for ftrace:function events even if it's not created as a sampling event. That prevents creating ftrace_function event in counting mode.
Make sure we check sample types only for sampling events.
Before:
$ sudo perf stat -e ftrace:function ls ...
Performance counter stats for 'ls':
<not supported> ftrace:function
0.001983662 seconds time elapsed
After:
$ sudo perf stat -e ftrace:function ls ...
Performance counter stats for 'ls':
44,498 ftrace:function
0.037534722 seconds time elapsed--- kernel/trace/trace_event_perf.c | 3 +++ 1 file changed, 3 insertions(+)
kernel/trace/trace_event_perf.c +3 -0
@@ -47,6 +47,9 @@ static int perf_trace_event_perm(struct trace_event_call *tp_event,if (perf_paranoid_tracepoint_raw () && !capable (CAP_SYS_ADMIN ))return -EPERM ; +if (!is_sampling_event (p_event)) +return 0 ; +/* * We don't allow user space callchains for function trace * event, due to issues with page faults while tracing page
Jiri Olsa
reviewerPATCH v2 2/5 ftrace perf: Move exclude_kernel tracepoint check to init event
In reply to Jiri OlsaWe suppress events with attr::exclude_kernel set when the event is generated, so following capture will give no warning but won't produce any data:
$ sudo perf record -e sched:sched_switch:u ls $ sudo /perf script | wc -l 0
Checking the attr::exclude_(kernel|user) at the event init time and failing right away for tracepoints from uprobes/kprobes and native ones:
$ sudo perf record -e sched:sched_switch:u ls Error: The sys_perf_event_open() syscall returned with 22 (Invalid argument) for event (sched:sched_switch). /bin/dmesg may provide additional information. No CONFIG_PERF_EVENTS=y kernel support configured?
$ sudo perf record -e probe:sys_read:u ls Error: The sys_perf_event_open() syscall returned with 22 (Invalid argument) for event (probe:sys_read). /bin/dmesg may provide additional information. No CONFIG_PERF_EVENTS=y kernel support configured?
$ ./perf record -e probe_ex:main:k ./ex Error: The sys_perf_event_open() syscall returned with 22 (Invalid argument) for event (probe_ex:main). /bin/dmesg may provide additional information. No CONFIG_PERF_EVENTS=y kernel support configured?
--- kernel/events/core.c | 5 ----- kernel/trace/trace_event_perf.c | 25 +++++++++++++++++++++++++ 2 files changed, 25 insertions(+), 5 deletions(-)
kernel/events/core.c +0 -5
@@ -6898,11 +6898,6 @@ static int perf_tp_event_match(struct perf_event *event, {if (event->hw.state &PERF_HES_STOPPED )return 0 ; -/* -* All tracepoints are from kernel-space. -*/ -if (event->attr.exclude_kernel) -return 0 ;if (!perf_tp_filter_match (event, data))return 0 ;
kernel/trace/trace_event_perf.c +25 -0
@@ -185,11 +185,36 @@ static void perf_trace_event_close(struct perf_event *p_event) tp_event->class->reg (tp_event,TRACE_REG_PERF_CLOSE , p_event); } +static int perf_trace_event_attr (struct trace_event_call *tp_event, +struct perf_event *event) +{ +/* +* All tracepoints and kprobes are from kernel-space. +*/ +if (((tp_event->flags &TRACE_EVENT_FL_TRACEPOINT ) || + (tp_event->flags &TRACE_EVENT_FL_KPROBE )) && + event->attr.exclude_kernel) +return -EINVAL ; + +/* +* All uprobes are from user-space. +*/ +if ((tp_event->flags &TRACE_EVENT_FL_UPROBE ) && + event->attr.exclude_user) +return -EINVAL ; + +return 0 ; +} +static int perf_trace_event_init (struct trace_event_call *tp_event,struct perf_event *p_event) {int ret; + ret =perf_trace_event_attr (tp_event, p_event); +if (ret) +return ret; + ret =perf_trace_event_perm (tp_event, p_event);if (ret)return ret;
Signature · 1 line
2.4.3
Re: [PATCH 2/5] ftrace perf: Move exclude_kernel tracepoint check to init event
Quoted 24 lines · On Wed, 16 Mar 2016 15:34:30 +0100 Jiri Olsa <[email protected]> wrote:
We suppress events with
attr::exclude_kernelset when the event is generated, so following capture will give no warning but won't produce any data:$ sudo perf record -e sched:sched_switch:u ls $ sudo /perf script | wc -l 0Checking the
attr::exclude_(kernel|user)at the event init time and failing right away for tracepoints from uprobes/kprobes and native ones:$ sudo perf record -e sched:sched_switch:u ls Error: The sys_perf_event_open() syscall returned with 22 (Invalid argument) for event (sched:sched_switch). /bin/dmesg may provide additional information. No CONFIG_PERF_EVENTS=y kernel support configured?$ sudo perf record -e probe:sys_read:u ls Error: The sys_perf_event_open() syscall returned with 22 (Invalid argument) for event (probe:sys_read). /bin/dmesg may provide additional information. No CONFIG_PERF_EVENTS=y kernel support configured?
Quoted 8 lines
$ ./perf record -e probe_ex:main:k ./ex Error: The sys_perf_event_open() syscall returned with 22 (Invalid argument) for event (probe_ex:main). /bin/dmesg may provide additional information. No CONFIG_PERF_EVENTS=y kernel support configured?Acked-by Namhyung Kim <[email protected]>Signed-off-by Jiri Olsa <[email protected]>
-- Steve
Peter Zijlstra
maintainerRe: [PATCH 2/5] ftrace perf: Move exclude_kernel tracepoint check to init event
In reply to Jiri OlsaQuoted 24 lines · Jiri Olsa
We suppress events with
attr::exclude_kernelset when the event is generated, so following capture will give no warning but won't produce any data:$ sudo perf record -e sched:sched_switch:u ls $ sudo /perf script | wc -l 0Checking the
attr::exclude_(kernel|user)at the event init time and failing right away for tracepoints from uprobes/kprobes and native ones:$ sudo perf record -e sched:sched_switch:u ls Error: The sys_perf_event_open() syscall returned with 22 (Invalid argument) for event (sched:sched_switch). /bin/dmesg may provide additional information. No CONFIG_PERF_EVENTS=y kernel support configured?$ sudo perf record -e probe:sys_read:u ls Error: The sys_perf_event_open() syscall returned with 22 (Invalid argument) for event (probe:sys_read). /bin/dmesg may provide additional information. No CONFIG_PERF_EVENTS=y kernel support configured?
Quoted 5 lines
$ ./perf record -e probe_ex:main:k ./ex Error: The sys_perf_event_open() syscall returned with 22 (Invalid argument) for event (probe_ex:main). /bin/dmesg may provide additional information. No CONFIG_PERF_EVENTS=y kernel support configured?
Not sure about this one. The previous behaviour suggests exclude_{user,kernel} is implemented, while the new behaviour says these flags are not implemented, which is a functional regression.
That is, if all events are from kernel space, and we exclude all kernel events, 0 is the right answer not an error.
Sure, with uprobes the situation is currently broken, but this isn't a fix.
Re: [PATCH 2/5] ftrace perf: Move exclude_kernel tracepoint check to init event
Quoted 31 lines · Peter Zijlstra
Quoted 24 lines · Jiri Olsa
We suppress events with
attr::exclude_kernelset when the event is generated, so following capture will give no warning but won't produce any data:$ sudo perf record -e sched:sched_switch:u ls $ sudo /perf script | wc -l 0Checking the
attr::exclude_(kernel|user)at the event init time and failing right away for tracepoints from uprobes/kprobes and native ones:$ sudo perf record -e sched:sched_switch:u ls Error: The sys_perf_event_open() syscall returned with 22 (Invalid argument) for event (sched:sched_switch). /bin/dmesg may provide additional information. No CONFIG_PERF_EVENTS=y kernel support configured?$ sudo perf record -e probe:sys_read:u ls Error: The sys_perf_event_open() syscall returned with 22 (Invalid argument) for event (probe:sys_read). /bin/dmesg may provide additional information. No CONFIG_PERF_EVENTS=y kernel support configured?Quoted 5 lines
$ ./perf record -e probe_ex:main:k ./ex Error: The sys_perf_event_open() syscall returned with 22 (Invalid argument) for event (probe_ex:main). /bin/dmesg may provide additional information. No CONFIG_PERF_EVENTS=y kernel support configured?
Quoted 3 lines
Not sure about this one. The previous behaviour suggests exclude_{user,kernel} is implemented, while the new behaviour says these flags are not implemented, which is a functional regression.
well I would not expect 'sched:sched_switch:u' to work (be implemented)
and I thought it's better to trigger an error than silently 'produce' no data
Quoted 6 lines
That is, if all events are from kernel space, and we exclude all kernel events, 0 is the right answer not an error.
Sure, with uprobes the situation is currently broken, but this isn't a fix.
Peter Zijlstra
maintainerRe: [PATCH 2/5] ftrace perf: Move exclude_kernel tracepoint check to init event
Quoted 20 lines · Jiri Olsa
Quoted 18 lines · Peter Zijlstra
Quoted 17 lines · Jiri Olsa
We suppress events with
attr::exclude_kernelset when the event is generated, so following capture will give no warning but won't produce any data:$ sudo perf record -e sched:sched_switch:u ls $ sudo /perf script | wc -l 0Checking the
attr::exclude_(kernel|user)at the event init time and failing right away for tracepoints from uprobes/kprobes and native ones:$ sudo perf record -e sched:sched_switch:u ls Error: The sys_perf_event_open() syscall returned with 22 (Invalid argument) for event (sched:sched_switch). /bin/dmesg may provide additional information. No CONFIG_PERF_EVENTS=y kernel support configured?
Quoted 7 lines
Quoted 3 lines
Not sure about this one. The previous behaviour suggests exclude_{user,kernel} is implemented, while the new behaviour says these flags are not implemented, which is a functional regression.
well I would not expect 'sched:sched_switch:u' to work (be implemented)
and I thought it's better to trigger an error than silently 'produce' no data
We're not in the business of protecting people from themselves are we? And if you want to help them, do so in userspace.
And its not like the [uk] flags are hard to implement here.
Re: [PATCH 2/5] ftrace perf: Move exclude_kernel tracepoint check to init event
Quoted 25 lines · Peter Zijlstra
Quoted 24 lines · Jiri Olsa
Quoted 22 lines · Peter Zijlstra
Quoted 12 lines · Jiri Olsa
We suppress events with
attr::exclude_kernelset when the event is generated, so following capture will give no warning but won't produce any data:$ sudo perf record -e sched:sched_switch:u ls $ sudo /perf script | wc -l 0Checking the
attr::exclude_(kernel|user)at the event init time and failing right away for tracepoints from uprobes/kprobes and native ones:Quoted 5 lines
$ sudo perf record -e sched:sched_switch:u ls Error: The sys_perf_event_open() syscall returned with 22 (Invalid argument) for event (sched:sched_switch). /bin/dmesg may provide additional information. No CONFIG_PERF_EVENTS=y kernel support configured?Not sure about this one. The previous behaviour suggests exclude_{user,kernel} is implemented, while the new behaviour says these flags are not implemented, which is a functional regression.
Quoted 6 lines
Quoted 3 lines
well I would not expect 'sched:sched_switch:u' to work (be implemented)
and I thought it's better to trigger an error than silently 'produce' no data
We're not in the business of protecting people from themselves are we? And if you want to help them, do so in userspace.
yep, I planned to make user space patch
to make that error more user friendly
Quoted 2 lines
And its not like the [uk] flags are hard to implement here.
sched:sched_switch:u ?
jirka
Peter Zijlstra
maintainerRe: [PATCH 2/5] ftrace perf: Move exclude_kernel tracepoint check to init event
Quoted 7 lines · Jiri Olsa
Quoted 5 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
$ sudo perf record -e sched:sched_switch:u ls $ sudo /perf script | wc -l 0And its not like the [uk] flags are hard to implement here.
sched:sched_switch:u ?
As per the above, its implemented and correct. The answer is 0.
The only problem is that currently it assumes all tracepoint events are from the kernel, and that is wrong for uprobes.
But returning an error is not right, its a valid configuration, a daft one, sure, but not invalid.
Similarly uprobe:foo:k is daft, but broken.
Re: [PATCH 2/5] ftrace perf: Move exclude_kernel tracepoint check to init event
Quoted 11 lines · Peter Zijlstra
Quoted 7 lines · Jiri Olsa
Quoted 5 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
$ sudo perf record -e sched:sched_switch:u ls $ sudo /perf script | wc -l 0And its not like the [uk] flags are hard to implement here.
sched:sched_switch:u ?
As per the above, its implemented and correct. The answer is 0.
Quoted 7 lines
The only problem is that currently it assumes all tracepoint events are from the kernel, and that is wrong for uprobes.
But returning an error is not right, its a valid configuration, a daft one, sure, but not invalid.
Similarly uprobe:foo:k is daft, but broken.
ok, will send fix for uprobes then
thanks,
jirka
Jiri Olsa
reviewerPATCH v2 3/5 ftrace perf: Use ftrace_ops::private to store event pointer
In reply to Jiri OlsaHaving following commands running concurrently:
# perf record -e ftrace:function -a -o krava.data sleep 10 # perf record -e ftrace:function --filter 'ip == SyS_read' ls
will end up in the latter one to fail on the filter rules and store all functions (in perf.data) as instructed by the first perf record instead of just SyS_read records.
The reason for this is, that tracepoint code by default triggers all events that registered for the tracepoint.
While ftrace:function is special because ftrace_ops itself carries a filter and only the event that owns ftrace_ops is eligible to be triggered.
Fixing this by using ftrace_ops::private value to keep the perf_event pointer. This way we don't need to search for triggered event (as tracepoint handler does) and directly store sample.
--- include/linux/perf_event.h | 3 +++ kernel/events/core.c | 22 ++++++++++++++++++++++ kernel/trace/trace_event_perf.c | 10 +++------- 3 files changed, 28 insertions(+), 7 deletions(-)
include/linux/perf_event.h +3 -0
@@ -1008,6 +1008,9 @@ extern void perf_tp_event(u64 addr, u64 count, void *record, int entry_size, struct pt_regs *regs, struct hlist_head *head, int rctx, struct task_struct *task); +void perf_function_event (struct perf_event *event, +void *record,int entry_size, +struct pt_regs *regs);extern void perf_bp_event (struct perf_event *event,void *data);#ifndef perf_misc_flags
kernel/events/core.c +22 -0
@@ -7063,6 +7063,28 @@ static void perf_event_free_bpf_prog(struct perf_event *event) } } +#ifdef CONFIG_FUNCTION_TRACER +void perf_function_event (struct perf_event *event, +void *record,int entry_size, +struct pt_regs *regs) + +{ +struct perf_sample_data data; +struct perf_raw_record raw = { + .size = entry_size, + .data = record, + }; + +if (event->hw.state &PERF_HES_STOPPED ) +return ; + +perf_sample_data_init (&data,0 ,0 ); + data.raw = &raw; + +perf_swevent_event (event,1 , &data, regs); +} +#endif /* CONFIG_FUNCTION_TRACER */ +#else static inline void perf_tp_register (void )
kernel/trace/trace_event_perf.c +3 -7
@@ -331,14 +331,9 @@ perf_ftrace_function_call(unsigned long ip, unsigned long parent_ip, struct ftrace_ops *ops, struct pt_regs *pt_regs) { struct ftrace_entry *entry; -struct hlist_head *head;struct pt_regs regs;int rctx; - head =this_cpu_ptr (event_function.perf_events); -if (hlist_empty (head)) -return ; -#define ENTRY_SIZE (ALIGN(sizeof(struct ftrace_entry) + sizeof(u32), \ sizeof(u64)) - sizeof(u32))
@@ -352,8 +347,8 @@ perf_ftrace_function_call(unsigned long ip, unsigned long parent_ip, entry->ip = ip; entry->parent_ip = parent_ip; -perf_trace_buf_submit (entry,ENTRY_SIZE , rctx,0 , -1 , ®s, head,NULL ); +perf_function_event (ops->private, entry,ENTRY_SIZE , ®s); +perf_swevent_put_recursion_context (rctx);#undef ENTRY_SIZE }
@@ -362,6 +357,7 @@ static int perf_ftrace_function_register(struct perf_event *event) {struct ftrace_ops *ops = &event->ftrace_ops; + ops->private = event; ops->flags |=FTRACE_OPS_FL_PER_CPU |FTRACE_OPS_FL_RCU ; ops->func = perf_ftrace_function_call;return register_ftrace_function (ops);
Signature · 1 line
2.4.3
Re: [PATCH 3/5] ftrace perf: Use ftrace_ops::private to store event pointer
Quoted 16 lines · On Wed, 16 Mar 2016 15:34:31 +0100 Jiri Olsa <[email protected]> wrote:
Having following commands running concurrently:
# perf record -e ftrace:function -a -o krava.data sleep 10 # perf record -e ftrace:function --filter 'ip == SyS_read' lswill end up in the latter one to fail on the filter rules and store all functions (in perf.data) as instructed by the first perf record instead of just
SyS_readrecords.The reason for this is, that tracepoint code by default triggers all events that registered for the tracepoint.
While ftrace:function is special because
ftrace_opsitself carries a filter and only the event that ownsftrace_opsis eligible to be triggered.
Quoted 8 lines
Fixing this by using
ftrace_ops::privatevalue to keep theperf_eventpointer. This way we don't need to search for triggered event (as tracepoint handler does) and directly store sample.Acked-by Namhyung Kim <[email protected]>Suggested-by Steven Rostedt <[email protected]>Signed-off-by Jiri Olsa <[email protected]>
-- Steve
Peter Zijlstra
maintainerRe: [PATCH 3/5] ftrace perf: Use ftrace_ops::private to store event pointer
In reply to Jiri OlsaQuoted 4 lines · Jiri Olsa
Fixing this by using
ftrace_ops::privatevalue to keep theperf_eventpointer. This way we don't need to search for triggered event (as tracepoint handler does) and directly store sample.
container_of(ops, struct perf_event, ftrace_ops) would also have worked, right?
Re: [PATCH 3/5] ftrace perf: Use ftrace_ops::private to store event pointer
Quoted 8 lines · Peter Zijlstra
Quoted 4 lines · Jiri Olsa
Fixing this by using
ftrace_ops::privatevalue to keep theperf_eventpointer. This way we don't need to search for triggered event (as tracepoint handler does) and directly store sample.
container_of(ops, struct perf_event, ftrace_ops)would also have worked, right?
yes, I think that would work too
jirka
Peter Zijlstra
maintainerRe: [PATCH 3/5] ftrace perf: Use ftrace_ops::private to store event pointer
Quoted 11 lines · Jiri Olsa
Quoted 8 lines · Peter Zijlstra
Quoted 4 lines · Jiri Olsa
Fixing this by using
ftrace_ops::privatevalue to keep theperf_eventpointer. This way we don't need to search for triggered event (as tracepoint handler does) and directly store sample.
container_of(ops, struct perf_event, ftrace_ops)would also have worked, right?yes, I think that would work too
OK, no need to change, I was just seeing if I actually understood the code.
Jiri Olsa
reviewerPATCH v2 4/5 ftrace: Make ftrace_hash_rec_enable return update bool
In reply to Jiri OlsaChange __ftrace_hash_rec_update to return true in case we need to update dynamic ftrace call records. It return false in case no update is needed.
--- kernel/trace/ftrace.c | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-)
kernel/trace/ftrace.c +17 -10
@@ -1610,7 +1610,7 @@ static bool test_rec_ops_needs_regs(struct dyn_ftrace *rec)return keep_regs; } -static void __ftrace_hash_rec_update (struct ftrace_ops *ops, +static bool __ftrace_hash_rec_update (struct ftrace_ops *ops,int filter_hash,bool inc) {
@@ -1618,12 +1618,13 @@ static void __ftrace_hash_rec_update(struct ftrace_ops *ops,struct ftrace_hash *other_hash;struct ftrace_page *pg;struct dyn_ftrace *rec; +bool update = false;int count =0 ;int all =0 ;/* Only update if the ops has been registered */ if (!(ops->flags &FTRACE_OPS_FL_ENABLED )) -return ; +return false;/* * In the filter_hash case:
@@ -1650,7 +1651,7 @@ static void __ftrace_hash_rec_update(struct ftrace_ops *ops,* then there's nothing to do. */ if (ftrace_hash_empty (hash)) -return ; +return false; }do_for_each_ftrace_rec (pg, rec) {
@@ -1694,7 +1695,7 @@ static void __ftrace_hash_rec_update(struct ftrace_ops *ops,if (inc) { rec->flags++;if (FTRACE_WARN_ON (ftrace_rec_count (rec) ==FTRACE_REF_MAX )) -return ; +return false;/* * If there's only a single callback registered to a
@@ -1720,7 +1721,7 @@ static void __ftrace_hash_rec_update(struct ftrace_ops *ops, rec->flags |=FTRACE_FL_REGS ; }else {if (FTRACE_WARN_ON (ftrace_rec_count (rec) ==0 )) -return ; +return false; rec->flags--;/*
@@ -1753,22 +1754,28 @@ static void __ftrace_hash_rec_update(struct ftrace_ops *ops,*/ } count++; + +/* Must match FTRACE_UPDATE_CALLS in ftrace_modify_all_code() */ + update |=ftrace_test_record (rec,1 ) !=FTRACE_UPDATE_IGNORE ; +/* Shortcut, if we handled all records, we are done. */ if (!all && count == hash->count) -return ; +return update; }while_for_each_ftrace_rec (); + +return update; } -static void ftrace_hash_rec_disable (struct ftrace_ops *ops, +static bool ftrace_hash_rec_disable (struct ftrace_ops *ops,int filter_hash) { -__ftrace_hash_rec_update (ops, filter_hash,0 ); +return __ftrace_hash_rec_update (ops, filter_hash,0 ); } -static void ftrace_hash_rec_enable (struct ftrace_ops *ops, +static bool ftrace_hash_rec_enable (struct ftrace_ops *ops,int filter_hash) { -__ftrace_hash_rec_update (ops, filter_hash,1 ); +return __ftrace_hash_rec_update (ops, filter_hash,1 ); } static void ftrace_hash_rec_update_modify(struct ftrace_ops *ops,
Signature · 1 line
2.4.3
Re: [PATCH 4/5] ftrace: Make ftrace_hash_rec_enable return update bool
Hi Jiri,
Quoted 5 lines · Jiri Olsa
Change
__ftrace_hash_rec_updateto return true in case we need to update dynamic ftrace call records. It return false in case no update is needed.Signed-off-by Jiri Olsa <[email protected]>
Thanks,
Namhyung
Quoted 96 lines
--- kernel/trace/ftrace.c | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-)kernel/trace/ftrace.c +17
-10@@ -1610,7 +1610,7 @@ static bool test_rec_ops_needs_regs(struct dyn_ftrace *rec)return keep_regs; } -static void __ftrace_hash_rec_update (struct ftrace_ops *ops, +static bool __ftrace_hash_rec_update (struct ftrace_ops *ops,int filter_hash,bool inc) {@@ -1618,12 +1618,13 @@ static void __ftrace_hash_rec_update(struct ftrace_ops *ops,struct ftrace_hash *other_hash;struct ftrace_page *pg;struct dyn_ftrace *rec; +bool update = false;int count =0 ;int all =0 ;/* Only update if the ops has been registered */ if (!(ops->flags &FTRACE_OPS_FL_ENABLED )) -return ; +return false;/* * In the filter_hash case: @@ -1650,7 +1651,7 @@ static void __ftrace_hash_rec_update(struct ftrace_ops *ops,* then there's nothing to do. */ if (ftrace_hash_empty (hash)) -return ; +return false; }do_for_each_ftrace_rec (pg, rec) {@@ -1694,7 +1695,7 @@ static void __ftrace_hash_rec_update(struct ftrace_ops *ops,if (inc) { rec->flags++;if (FTRACE_WARN_ON (ftrace_rec_count (rec) ==FTRACE_REF_MAX )) -return ; +return false;/* * If there's only a single callback registered to a @@ -1720,7 +1721,7 @@ static void __ftrace_hash_rec_update(struct ftrace_ops *ops, rec->flags |=FTRACE_FL_REGS ; }else {if (FTRACE_WARN_ON (ftrace_rec_count (rec) ==0 )) -return ; +return false; rec->flags--;/* @@ -1753,22 +1754,28 @@ static void __ftrace_hash_rec_update(struct ftrace_ops *ops,*/ } count++; + +/* Must match FTRACE_UPDATE_CALLS in ftrace_modify_all_code() */ + update |=ftrace_test_record (rec,1 ) !=FTRACE_UPDATE_IGNORE ; +/* Shortcut, if we handled all records, we are done. */ if (!all && count == hash->count) -return ; +return update; }while_for_each_ftrace_rec (); + +return update; } -static void ftrace_hash_rec_disable (struct ftrace_ops *ops, +static bool ftrace_hash_rec_disable (struct ftrace_ops *ops,int filter_hash) { -__ftrace_hash_rec_update (ops, filter_hash,0 ); +return __ftrace_hash_rec_update (ops, filter_hash,0 ); } -static void ftrace_hash_rec_enable (struct ftrace_ops *ops, +static bool ftrace_hash_rec_enable (struct ftrace_ops *ops,int filter_hash) { -__ftrace_hash_rec_update (ops, filter_hash,1 ); +return __ftrace_hash_rec_update (ops, filter_hash,1 ); } static void ftrace_hash_rec_update_modify(struct ftrace_ops *ops,Signature · 1 line
2.4.3
Jiri Olsa
reviewerPATCH v2 5/5 ftrace: Update dynamic ftrace calls only if necessary
In reply to Jiri OlsaCurrently dynamic ftrace calls are updated any time the ftrace_ops is un/registered. If we do this update only when it's needed, we save lot of time for perf system wide ftrace function sampling/counting.
The reason is that for system wide sampling/counting, perf creates event for each cpu in the system.
Each event then registers separate copy of ftrace_ops, which ends up in FTRACE_UPDATE_CALLS updates. On servers with many cpus that means serious stall (240 cpus server):
Counting:
# time ./perf stat -e ftrace:function -a sleep 1
Performance counter stats for 'system wide':
370,663 ftrace:function
1.401427505 seconds time elapsedreal 3m51.743s user 0m0.023s sys 3m48.569s
Sampling:
# time ./perf record -e ftrace:function -a sleep 1 [ perf record: Woken up 0 times to write data ] Warning: Processed 141200 events and lost 5 chunks!
[ perf record: Captured and wrote 10.703 MB perf.data (135950 samples) ]
real 2m31.429s user 0m0.213s sys 2m29.494s
There's no reason to do the FTRACE_UPDATE_CALLS update for each event in perf case, because all the ftrace_ops always share the same filter, so the updated calls are always the same.
It's required that only first ftrace_ops registration does the FTRACE_UPDATE_CALLS update (also sometimes the second if the first one used the trampoline), but the rest can be only cheaply linked into the ftrace_ops list.
Counting:
# time ./perf stat -e ftrace:function -a sleep 1
Performance counter stats for 'system wide':
398,571 ftrace:function
1.377503733 seconds time elapsedreal 0m2.787s user 0m0.005s sys 0m1.883s
Sampling:
# time ./perf record -e ftrace:function -a sleep 1 [ perf record: Woken up 0 times to write data ] Warning: Processed 261730 events and lost 9 chunks!
[ perf record: Captured and wrote 19.907 MB perf.data (256293 samples) ]
real 1m31.948s user 0m0.309s sys 1m32.051s
--- kernel/trace/ftrace.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
kernel/trace/ftrace.c +5 -5
@@ -2651,7 +2651,6 @@ static int ftrace_startup(struct ftrace_ops *ops, int command)return ret; ftrace_start_up++; - command |=FTRACE_UPDATE_CALLS ;/* * Note that ftrace probes uses this to start up
@@ -2672,7 +2671,8 @@ static int ftrace_startup(struct ftrace_ops *ops, int command)return ret; } -ftrace_hash_rec_enable (ops,1 ); +if (ftrace_hash_rec_enable (ops,1 )) + command |=FTRACE_UPDATE_CALLS ;ftrace_startup_enable (command);
@@ -2702,11 +2702,11 @@ static int ftrace_shutdown(struct ftrace_ops *ops, int command)/* Disabling ipmodify never fails */ ftrace_hash_ipmodify_disable (ops); -ftrace_hash_rec_disable (ops,1 ); - ops->flags &= ~FTRACE_OPS_FL_ENABLED ; +if (ftrace_hash_rec_disable (ops,1 )) + command |=FTRACE_UPDATE_CALLS ; - command |=FTRACE_UPDATE_CALLS ; + ops->flags &= ~FTRACE_OPS_FL_ENABLED ;if (saved_ftrace_func != ftrace_trace_function) { saved_ftrace_func = ftrace_trace_function;
Signature · 1 line
2.4.3
Re: [PATCH 5/5] ftrace: Update dynamic ftrace calls only if necessary
Quoted 67 lines · Jiri Olsa
Currently dynamic ftrace calls are updated any time the
ftrace_opsis un/registered. If we do this update only when it's needed, we save lot of time for perf system wide ftrace function sampling/counting.The reason is that for system wide sampling/counting, perf creates event for each cpu in the system.
Each event then registers separate copy of
ftrace_ops, which ends up inFTRACE_UPDATE_CALLSupdates. On servers with many cpus that means serious stall (240 cpus server):Counting:
# time ./perf stat -e ftrace:function -a sleep 1Performance counter stats for 'system wide': 370,663 ftrace:function 1.401427505 seconds time elapsedreal 3m51.743s user 0m0.023s sys 3m48.569sSampling:
# time ./perf record -e ftrace:function -a sleep 1 [ perf record: Woken up 0 times to write data ] Warning: Processed 141200 events and lost 5 chunks![ perf record: Captured and wrote 10.703 MB perf.data (135950 samples) ]
real 2m31.429s user 0m0.213s sys 2m29.494sThere's no reason to do the
FTRACE_UPDATE_CALLSupdate for each event in perf case, because all theftrace_opsalways share the same filter, so the updated calls are always the same.It's required that only first
ftrace_opsregistration does theFTRACE_UPDATE_CALLSupdate (also sometimes the second if the first one used the trampoline), but the rest can be only cheaply linked into theftrace_opslist.Counting:
# time ./perf stat -e ftrace:function -a sleep 1Performance counter stats for 'system wide': 398,571 ftrace:function 1.377503733 seconds time elapsedreal 0m2.787s user 0m0.005s sys 0m1.883sSampling:
# time ./perf record -e ftrace:function -a sleep 1 [ perf record: Woken up 0 times to write data ] Warning: Processed 261730 events and lost 9 chunks!
Quoted 7 lines
[ perf record: Captured and wrote 19.907 MB perf.data (256293 samples) ]
real 1m31.948s user 0m0.309s sys 1m32.051sSigned-off-by Jiri Olsa <[email protected]>
Thanks,
Namhyung
Quoted 44 lines
--- kernel/trace/ftrace.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)kernel/trace/ftrace.c +5
-5@@ -2651,7 +2651,6 @@ static int ftrace_startup(struct ftrace_ops *ops, int command)return ret; ftrace_start_up++; - command |=FTRACE_UPDATE_CALLS ;/* * Note that ftrace probes uses this to start up @@ -2672,7 +2671,8 @@ static int ftrace_startup(struct ftrace_ops *ops, int command)return ret; } -ftrace_hash_rec_enable (ops,1 ); +if (ftrace_hash_rec_enable (ops,1 )) + command |=FTRACE_UPDATE_CALLS ;ftrace_startup_enable (command);@@ -2702,11 +2702,11 @@ static int ftrace_shutdown(struct ftrace_ops *ops, int command)/* Disabling ipmodify never fails */ ftrace_hash_ipmodify_disable (ops); -ftrace_hash_rec_disable (ops,1 ); - ops->flags &= ~FTRACE_OPS_FL_ENABLED ; +if (ftrace_hash_rec_disable (ops,1 )) + command |=FTRACE_UPDATE_CALLS ; - command |=FTRACE_UPDATE_CALLS ; + ops->flags &= ~FTRACE_OPS_FL_ENABLED ;if (saved_ftrace_func != ftrace_trace_function) { saved_ftrace_func = ftrace_trace_function;Signature · 1 line
2.4.3
Steven Rostedt
maintainerRe: [PATCH 5/5] ftrace: Update dynamic ftrace calls only if necessary
In reply to Jiri OlsaPatches 4 and 5 seem agnostic to patches 1-3. I'll pull 4,5 into my tree and 1-3 can go though tip. I'd like to run theses through my tests.
OK?
-- Steve
Quoted 75 lines · On Wed, 16 Mar 2016 15:34:33 +0100 Jiri Olsa <[email protected]> wrote:
Currently dynamic ftrace calls are updated any time the
ftrace_opsis un/registered. If we do this update only when it's needed, we save lot of time for perf system wide ftrace function sampling/counting.The reason is that for system wide sampling/counting, perf creates event for each cpu in the system.
Each event then registers separate copy of
ftrace_ops, which ends up inFTRACE_UPDATE_CALLSupdates. On servers with many cpus that means serious stall (240 cpus server):Counting:
# time ./perf stat -e ftrace:function -a sleep 1Performance counter stats for 'system wide': 370,663 ftrace:function 1.401427505 seconds time elapsedreal 3m51.743s user 0m0.023s sys 3m48.569sSampling:
# time ./perf record -e ftrace:function -a sleep 1 [ perf record: Woken up 0 times to write data ] Warning: Processed 141200 events and lost 5 chunks![ perf record: Captured and wrote 10.703 MB perf.data (135950 samples) ]
real 2m31.429s user 0m0.213s sys 2m29.494sThere's no reason to do the
FTRACE_UPDATE_CALLSupdate for each event in perf case, because all theftrace_opsalways share the same filter, so the updated calls are always the same.It's required that only first
ftrace_opsregistration does theFTRACE_UPDATE_CALLSupdate (also sometimes the second if the first one used the trampoline), but the rest can be only cheaply linked into theftrace_opslist.Counting:
# time ./perf stat -e ftrace:function -a sleep 1Performance counter stats for 'system wide': 398,571 ftrace:function 1.377503733 seconds time elapsedreal 0m2.787s user 0m0.005s sys 0m1.883sSampling:
# time ./perf record -e ftrace:function -a sleep 1 [ perf record: Woken up 0 times to write data ] Warning: Processed 261730 events and lost 9 chunks![ perf record: Captured and wrote 19.907 MB perf.data (256293 samples) ]
real 1m31.948s user 0m0.309s sys 1m32.051sSigned-off-by Jiri Olsa <[email protected]>---