tracing: Updates for v4.11
Subsystems (2)
Steven Rostedt
maintainercover tracing: Updates for v4.11
git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace.git
for-next
Head SHA1: 068f530b3f274d313395663bf8d674798d4858c6
Kenny Yu (1):
uprobe: Find last occurrence of ':' when parsing uprobe PATH:OFFSET
Steven Rostedt (VMware) (3):
tracing: Process constants for (un)likely() profiler
tracing: Show number of constants profiled in likely profiler
tracing: Add the constant count for branch tracer
----
include/linux/compiler.h | 27 ++++++++------ kernel/trace/trace_branch.c | 83 ++++++++++++++++++++++++++++++++++---------- kernel/trace/trace_entries.h | 6 ++-- kernel/trace/trace_uprobe.c | 3 +- 4 files changed, 88 insertions(+), 31 deletions(-)
Steven Rostedt
maintainerPATCH 1/4 uprobe: Find last occurrence of : when parsing uprobe PATH:OFFSET
From: Kenny Yu <[email protected]>
Previously, create_trace_uprobe found the *first* occurence of the ':' character when parsing PATH:OFFSET for a uprobe. However, if the path contains a ':' character, then the function would parse the path incorrectly. Even worse, if the path does not exist, the subsequent call to kern_path() would set ret to ENOENT, leading to very cryptic errno values in user space.
The fix is to find the *last* occurence of ':'.
How to repro:: The write fails with "No such file or directory", suggesting incorrectly that the uprobe_events file does not exist.
$ mkdir testing && cd testing $ cp /bin/bash . $ cp /bin/bash ./bash:with:colon $ echo "p:uprobes/p__root_testing_bash_0x6 /root/testing/bash:0x6" > /sys/kernel/debug/tracing/uprobe_events # this works $ echo "p:uprobes/p__root_testing_bash_with_colon_0x6 /root/testing/bash:with:colon:0x6" >> /sys/kernel/debug/tracing/uprobe_events # this doesn't -bash: echo: write error: No such file or directory
With the patch:
$ echo "p:uprobes/p__root_testing_bash_0x6 /root/testing/bash:0x6" > /sys/kernel/debug/tracing/uprobe_events # this still works $ echo "p:uprobes/p__root_testing_bash_with_colon_0x6 /root/testing/bash:with:colon:0x6" >> /sys/kernel/debug/tracing/uprobe_events # this works now too! $ cat /sys/kernel/debug/tracing/uprobe_events p:uprobes/p__root_testing_bash_0x6 /root/testing/bash:0x0000000000000006 p:uprobes/p__root_testing_bash_with_colon_0x6 /root/testing/bash:with:colon:0x0000000000000006
--- kernel/trace/trace_uprobe.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
kernel/trace/trace_uprobe.c +2 -1
@@ -431,7 +431,8 @@ static int create_trace_uprobe(int argc, char **argv)pr_info ("Probe point is not specified.\n" );return -EINVAL ; } - arg =strchr (argv[1 ],':' ); +/* Find the last occurrence, in case the path contains ':' too. */ + arg =strrchr (argv[1 ],':' );if (!arg) { ret = -EINVAL ; goto fail_address_parse;
Signature · 1 line
2.10.2
Steven Rostedt
maintainerPATCH 2/4 tracing: Process constants for (un)likely() profiler
In reply to Steven RostedtFrom: "Steven Rostedt (VMware)" <[email protected]>
When running the likely/unlikely profiler, one of the results did not look accurate. It noted that the unlikely() in link_path_walk() was 100% incorrect. When I added a trace_printk() to see what was happening there, it became 80% correct! Looking deeper into what whas happening, I found that gcc split that if statement into two paths. One where the if statement became a constant, the other path a variable. The other path had the if statement always hit (making the unlikely there, always false), but since the #define unlikely() has:
#define unlikely() (__builtin_constant_p(x) ? !!(x) : __branch_check__(x, 0))
Where constants are ignored by the branch profiler, the "constant" path made by the compiler was ignored, even though it was hit 80% of the time.
By just passing the constant value to the __branch_check__() function and tracing it out of line (as always correct, as likely/unlikely isn't a factor for constants), then we get back the accurate readings of branches that were optimized by gcc causing part of the execution to become constant.
--- include/linux/compiler.h | 14 ++++++++------ kernel/trace/trace_branch.c | 6 +++++- 2 files changed, 13 insertions(+), 7 deletions(-)
include/linux/compiler.h +8 -6
@@ -107,12 +107,13 @@ struct ftrace_branch_data {*/ #if defined(CONFIG_TRACE_BRANCH_PROFILING ) \ && !defined(DISABLE_BRANCH_PROFILING ) && !defined(__CHECKER__) -void ftrace_likely_update (struct ftrace_branch_data *f,int val,int expect); +void ftrace_likely_update (struct ftrace_branch_data *f,int val, +int expect,int is_constant);#define likely_notrace (x) __builtin_expect(!!(x), 1)#define unlikely_notrace (x) __builtin_expect(!!(x), 0) -#define __branch_check__ (x, expect) ({ \ +#define __branch_check__ (x, expect, is_constant) ({ \ int ______r; \ static struct ftrace_branch_data \ __attribute__((__aligned__(4))) \
@@ -122,8 +123,9 @@ void ftrace_likely_update(struct ftrace_branch_data *f, int val, int expect); .file = __FILE__, \ .line = __LINE__, \ }; \ - ______r =likely_notrace (x); \ -ftrace_likely_update (&______f, ______r, expect); \ + ______r =__builtin_expect (!!(x), expect); \ +ftrace_likely_update (&______f, ______r, \ + expect, is_constant); \ ______r; \ })
@@ -133,10 +135,10 @@ void ftrace_likely_update(struct ftrace_branch_data *f, int val, int expect);* written by Daniel Walker. */ # ifndef likely -# define likely (x) (__builtin_constant_p(x) ? !!(x) : __branch_check__(x, 1)) +# define likely (x) (__branch_check__(x, 1, __builtin_constant_p(x)))# endif # ifndef unlikely -# define unlikely (x) (__builtin_constant_p(x) ? !!(x) : __branch_check__(x, 0)) +# define unlikely (x) (__branch_check__(x, 0, __builtin_constant_p(x)))# endif #ifdef CONFIG_PROFILE_ALL_BRANCHES
kernel/trace/trace_branch.c +5 -1
@@ -200,8 +200,12 @@ void trace_likely_condition(struct ftrace_branch_data *f, int val, int expect) }#endif /* CONFIG_BRANCH_TRACER */ -void ftrace_likely_update (struct ftrace_branch_data *f,int val,int expect) +void ftrace_likely_update (struct ftrace_branch_data *f,int val, +int expect,int is_constant) { +/* A constant is always correct */ +if (is_constant) + val = expect;/* * I would love to have a trace point here instead, but the * trace point code is so inundated with unlikely and likely
Signature · 1 line
2.10.2
Steven Rostedt
maintainerPATCH 3/4 tracing: Show number of constants profiled in likely profiler
In reply to Steven RostedtFrom: "Steven Rostedt (VMware)" <[email protected]>
Now that constants are traced, it is useful to see the number of constants that are traced in the likely/unlikely profiler in order to know if they should be ignored or not.
The likely/unlikely will display a number after the "correct" number if a "constant" count exists.
--- include/linux/compiler.h | 15 ++++++---- kernel/trace/trace_branch.c | 68 ++++++++++++++++++++++++++++++++++++--------- 2 files changed, 65 insertions(+), 18 deletions(-)
include/linux/compiler.h +10 -5
@@ -101,13 +101,18 @@ struct ftrace_branch_data { }; }; +struct ftrace_likely_data { +struct ftrace_branch_data data; +unsigned long constant; +}; +/* * Note: DISABLE_BRANCH_PROFILING can be used by special lowlevel code * to disable branch tracing on a per file basis. */ #if defined(CONFIG_TRACE_BRANCH_PROFILING ) \ && !defined(DISABLE_BRANCH_PROFILING ) && !defined(__CHECKER__) -void ftrace_likely_update (struct ftrace_branch_data *f,int val, +void ftrace_likely_update (struct ftrace_likely_data *f,int val,int expect,int is_constant);#define likely_notrace (x) __builtin_expect(!!(x), 1)
@@ -115,13 +120,13 @@ void ftrace_likely_update(struct ftrace_branch_data *f, int val,#define __branch_check__ (x, expect, is_constant) ({ \ int ______r; \ - static struct ftrace_branch_data \ + static struct ftrace_likely_data \ __attribute__((__aligned__(4))) \ __attribute__((section("_ftrace_annotated_branch"))) \ ______f = { \ - .func = __func__, \ - .file = __FILE__, \ - .line = __LINE__, \ + .data.func = __func__, \ + .data.file = __FILE__, \ + .data.line = __LINE__, \ }; \ ______r = __builtin_expect(!!(x), expect); \ ftrace_likely_update(&______f, ______r, \
kernel/trace/trace_branch.c +55 -13
135 lines not on this page · raw message
Signature · 1 line
2.10.2
Steven Rostedt
maintainerPATCH 4/4 tracing: Add the constant count for branch tracer
In reply to Steven RostedtFrom: "Steven Rostedt (VMware)" <[email protected]>
The unlikely/likely branch profiler now gets called even if the if statement is a constant (always goes in one direction without a compare). Add a value to denote this in the likely/unlikely tracer as well.
--- kernel/trace/trace_branch.c | 17 +++++++++-------- kernel/trace/trace_entries.h | 6 ++++-- 2 files changed, 13 insertions(+), 10 deletions(-)
kernel/trace/trace_branch.c +9 -8
@@ -27,7 +27,7 @@ static DEFINE_MUTEX(branch_tracing_mutex);static struct trace_array *branch_tracer;static void -probe_likely_condition (struct ftrace_branch_data *f,int val,int expect) +probe_likely_condition (struct ftrace_likely_data *f,int val,int expect) {struct trace_event_call *call = &event_branch;struct trace_array *tr = branch_tracer;
@@ -68,16 +68,17 @@ probe_likely_condition(struct ftrace_branch_data *f, int val, int expect) entry =ring_buffer_event_data (event);/* Strip off the path, only save the file */ - p = f->file +strlen (f->file); -while (p >= f->file && *p !='/' ) + p = f->data.file +strlen (f->data.file); +while (p >= f->data.file && *p !='/' ) p--; p++; -strncpy (entry->func, f->func,TRACE_FUNC_SIZE ); +strncpy (entry->func, f->data.func,TRACE_FUNC_SIZE );strncpy (entry->file, p,TRACE_FILE_SIZE ); entry->func[TRACE_FUNC_SIZE ] =0 ; entry->file[TRACE_FILE_SIZE ] =0 ; - entry->line = f->line; + entry->constant = f->constant; + entry->line = f->data.line; entry->correct = val == expect;if (!call_filter_check_discard (call, entry, buffer, event))
@@ -89,7 +90,7 @@ probe_likely_condition(struct ftrace_branch_data *f, int val, int expect) }static inline -void trace_likely_condition (struct ftrace_branch_data *f,int val,int expect) +void trace_likely_condition (struct ftrace_likely_data *f,int val,int expect) {if (!branch_tracing_enabled)return ;
@@ -195,7 +196,7 @@ core_initcall(init_branch_tracer);#else static inline -void trace_likely_condition (struct ftrace_branch_data *f,int val,int expect) +void trace_likely_condition (struct ftrace_likely_data *f,int val,int expect) { }#endif /* CONFIG_BRANCH_TRACER */
@@ -214,7 +215,7 @@ void ftrace_likely_update(struct ftrace_likely_data *f, int val,* conditions that the recursive nightmare that exists is too * much to try to get working. At least for now. */ -trace_likely_condition (&f->data, val, expect); +trace_likely_condition (f, val, expect);/* FIXME: Make this atomic! */ if (val == expect)
kernel/trace/trace_entries.h +4 -2
@@ -328,11 +328,13 @@ FTRACE_ENTRY(branch, trace_branch, __array( char, func, TRACE_FUNC_SIZE+1 ) __array( char, file, TRACE_FILE_SIZE+1 ) __field( char, correct ) +__field ( char, constant ) ), -F_printk ("%u:%s:%s (%u)" , +F_printk ("%u:%s:%s (%u)%s" , __entry->line, - __entry->func, __entry->file, __entry->correct), + __entry->func, __entry->file, __entry->correct, + __entry->constant ?" CONSTANT" :"" ),FILTER_OTHER );
Signature · 1 line
2.10.2