ring-buffer: Some minor updates
Subsystems (2)
Steven Rostedt
maintainercover ring-buffer: Some minor updates
git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace.git
for-next
Head SHA1: 985e871b28fc3e73ccd21cb999ce61266dc8c941
Steven Rostedt (Red Hat) (4):
ring-buffer: Add unlikelys to make fast path the default
ring-buffer: Move recursive check to per_cpu descriptor
ring-buffer: Allways do the trace_recursive checks
ring-buffer: Add trace_recursive checks to ring_buffer_write()
----
kernel/trace/ring_buffer.c | 59 +++++++++++++++++++++++----------------------- 1 file changed, 29 insertions(+), 30 deletions(-)
Steven Rostedt
maintainerPATCH 1/4 ring-buffer: Add unlikelys to make fast path the default
From: "Steven Rostedt (Red Hat)" <[email protected]>
I was running the trace_event benchmark and noticed that the times to record a trace_event was all over the place. I looked at the assembly of the ring_buffer_lock_reserver() and saw this:
<ring_buffer_lock_reserve>:
31 c0 xor %eax,%eax
48 83 3d 76 47 bd 00 cmpq $0x1,0xbd4776(%rip) # ffffffff81d10d60 <ring_buffer_flags>
01
55 push %rbp
48 89 e5 mov %rsp,%rbp
75 1d jne ffffffff8113c60d <ring_buffer_lock_reserve+0x2d>
65 ff 05 69 e3 ec 7e incl %gs:0x7eece369(%rip) # a960 <__preempt_count>
8b 47 08 mov 0x8(%rdi),%eax
85 c0 test %eax,%eax
+---- 74 12 je ffffffff8113c610 <ring_buffer_lock_reserve+0x30>
| 65 ff 0d 5b e3 ec 7e decl %gs:0x7eece35b(%rip) # a960 <__preempt_count>
| 0f 84 85 00 00 00 je ffffffff8113c690 <ring_buffer_lock_reserve+0xb0>
| 31 c0 xor %eax,%eax
| 5d pop %rbp
| c3 retq
| 90 nop
+---> 65 44 8b 05 48 e3 ec mov %gs:0x7eece348(%rip),%r8d # a960 <__preempt_count>
7e
41 81 e0 ff ff ff 7f and $0x7fffffff,%r8d
b0 08 mov $0x8,%al
65 8b 0d 58 36 ed 7e mov %gs:0x7eed3658(%rip),%ecx # fc80 <current_context>
41 f7 c0 00 ff 1f 00 test $0x1fff00,%r8d
74 1e je ffffffff8113c64f <ring_buffer_lock_reserve+0x6f>
41 f7 c0 00 00 10 00 test $0x100000,%r8d
b0 01 mov $0x1,%al
75 13 jne ffffffff8113c64f <ring_buffer_lock_reserve+0x6f>
41 81 e0 00 00 0f 00 and $0xf0000,%r8d
49 83 f8 01 cmp $0x1,%r8
19 c0 sbb %eax,%eax
83 e0 02 and $0x2,%eax
83 c0 02 add $0x2,%eax
85 c8 test %ecx,%eax
75 ab jne ffffffff8113c5fe <ring_buffer_lock_reserve+0x1e>
09 c8 or %ecx,%eax
65 89 05 24 36 ed 7e mov %eax,%gs:0x7eed3624(%rip) # fc80 <current_context>The arrow is the fast path.
After adding the unlikely's, the fast path looks a bit better:
<ring_buffer_lock_reserve>:
31 c0 xor %eax,%eax
48 83 3d 76 47 bd 00 cmpq $0x1,0xbd4776(%rip) # ffffffff81d10d60 <ring_buffer_flags>
01
55 push %rbp
48 89 e5 mov %rsp,%rbp
75 7b jne ffffffff8113c66b <ring_buffer_lock_reserve+0x8b>
65 ff 05 69 e3 ec 7e incl %gs:0x7eece369(%rip) # a960 <__preempt_count>
8b 47 08 mov 0x8(%rdi),%eax
85 c0 test %eax,%eax
0f 85 9f 00 00 00 jne ffffffff8113c6a1 <ring_buffer_lock_reserve+0xc1>
65 8b 0d 57 e3 ec 7e mov %gs:0x7eece357(%rip),%ecx # a960 <__preempt_count>
81 e1 ff ff ff 7f and $0x7fffffff,%ecx
b0 08 mov $0x8,%al
65 8b 15 68 36 ed 7e mov %gs:0x7eed3668(%rip),%edx # fc80 <current_context>
f7 c1 00 ff 1f 00 test $0x1fff00,%ecx
75 50 jne ffffffff8113c670 <ring_buffer_lock_reserve+0x90>
85 d0 test %edx,%eax
75 7d jne ffffffff8113c6a1 <ring_buffer_lock_reserve+0xc1>
09 d0 or %edx,%eax
65 89 05 53 36 ed 7e mov %eax,%gs:0x7eed3653(%rip) # fc80 <current_context>
65 8b 05 fc da ec 7e mov %gs:0x7eecdafc(%rip),%eax # a130 <cpu_number>
89 c2 mov %eax,%edx--- kernel/trace/ring_buffer.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
kernel/trace/ring_buffer.c +5 -5
@@ -2741,23 +2741,23 @@ ring_buffer_lock_reserve(struct ring_buffer *buffer, unsigned long length)/* If we are tracing schedule, we don't want to recurse */ preempt_disable_notrace (); -if (atomic_read (&buffer->record_disabled)) +if (unlikely (atomic_read (&buffer->record_disabled))) goto out_nocheck; -if (trace_recursive_lock ()) +if (unlikely (trace_recursive_lock ())) goto out_nocheck; cpu =raw_smp_processor_id (); -if (!cpumask_test_cpu (cpu, buffer->cpumask)) +if (unlikely (!cpumask_test_cpu (cpu, buffer->cpumask))) goto out; cpu_buffer = buffer->buffers[cpu]; -if (atomic_read (&cpu_buffer->record_disabled)) +if (unlikely (atomic_read (&cpu_buffer->record_disabled))) goto out; -if (length >BUF_MAX_DATA_SIZE ) +if (unlikely (length >BUF_MAX_DATA_SIZE )) goto out; event =rb_reserve_next_event (buffer, cpu_buffer, length);
Signature · 1 line
2.1.4
Steven Rostedt
maintainerPATCH 2/4 ring-buffer: Move recursive check to per_cpu descriptor
In reply to Steven RostedtFrom: "Steven Rostedt (Red Hat)" <[email protected]>
Instead of using a global per_cpu variable to perform the recursive checks into the ring buffer, use the already existing per_cpu descriptor that is part of the ring buffer itself.
Not only does this simplify the code, it also allows for one ring buffer to be used within the guts of the use of another ring buffer. For example trace_printk() can now be used within the ring buffer to record changes done by an instance into the main ring buffer. The recursion checks will prevent the trace_printk() itself from causing recursive issues with the main ring buffer (it is just ignored), but the recursive checks wont prevent the trace_printk() from recording other ring buffers.
--- kernel/trace/ring_buffer.c | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-)
kernel/trace/ring_buffer.c +19 -18
@@ -462,6 +462,7 @@ struct ring_buffer_per_cpu {arch_spinlock_t lock;struct lock_class_key lock_key;unsigned int nr_pages; +unsigned int current_context;struct list_head *pages;struct buffer_page *head_page;/* read from head */ struct buffer_page *tail_page;/* write to tail */
@@ -2675,11 +2676,11 @@ rb_reserve_next_event(struct ring_buffer *buffer,* just so happens that it is the same bit corresponding to * the current context. */ -static DEFINE_PER_CPU(unsigned int, current_context); -static __always_inline int trace_recursive_lock(void) +static __always_inline int +trace_recursive_lock (struct ring_buffer_per_cpu *cpu_buffer) { -unsigned int val =__this_cpu_read (current_context); +unsigned int val = cpu_buffer->current_context;int bit;if (in_interrupt ()) {
@@ -2696,20 +2697,21 @@ static __always_inline int trace_recursive_lock(void)return 1 ; val |= (1 << bit); -__this_cpu_write (current_context, val); + cpu_buffer->current_context = val;return 0 ; } -static __always_inline void trace_recursive_unlock(void) +static __always_inline void +trace_recursive_unlock (struct ring_buffer_per_cpu *cpu_buffer) { -__this_cpu_and (current_context,__this_cpu_read (current_context) -1 ); + cpu_buffer->current_context &= cpu_buffer->current_context -1 ; }#else -#define trace_recursive_lock () (0) -#define trace_recursive_unlock () do { } while (0) +#define trace_recursive_lock (cpu_buffer) (0) +#define trace_recursive_unlock (cpu_buffer) do { } while (0)#endif
@@ -2742,10 +2744,7 @@ ring_buffer_lock_reserve(struct ring_buffer *buffer, unsigned long length)preempt_disable_notrace ();if (unlikely (atomic_read (&buffer->record_disabled))) - goto out_nocheck; - -if (unlikely (trace_recursive_lock ())) - goto out_nocheck; + goto out; cpu =raw_smp_processor_id ();
@@ -2760,16 +2759,18 @@ ring_buffer_lock_reserve(struct ring_buffer *buffer, unsigned long length)if (unlikely (length >BUF_MAX_DATA_SIZE )) goto out; +if (unlikely (trace_recursive_lock (cpu_buffer))) + goto out; + event =rb_reserve_next_event (buffer, cpu_buffer, length);if (!event) - goto out; + goto out_unlock;return event; + out_unlock: +trace_recursive_unlock (cpu_buffer); out: -trace_recursive_unlock (); - - out_nocheck:preempt_enable_notrace ();return NULL ; }
@@ -2859,7 +2860,7 @@ int ring_buffer_unlock_commit(struct ring_buffer *buffer,rb_wakeups (buffer, cpu_buffer); -trace_recursive_unlock (); +trace_recursive_unlock (cpu_buffer);preempt_enable_notrace ();
@@ -2970,7 +2971,7 @@ void ring_buffer_discard_commit(struct ring_buffer *buffer, out:rb_end_commit (cpu_buffer); -trace_recursive_unlock (); +trace_recursive_unlock (cpu_buffer);preempt_enable_notrace ();
Signature · 1 line
2.1.4
Steven Rostedt
maintainerPATCH 3/4 ring-buffer: Allways do the trace_recursive checks
In reply to Steven RostedtFrom: "Steven Rostedt (Red Hat)" <[email protected]>
Currently the trace_recursive checks are only done if CONFIG_TRACING is enabled. That was because there use to be a dependency with tracing for the recursive checks (it used the task_struct trace recursive variable). But now it uses its own variable and there is no dependency.
--- kernel/trace/ring_buffer.c | 9 --------- 1 file changed, 9 deletions(-)
kernel/trace/ring_buffer.c +0 -9
@@ -2637,8 +2637,6 @@ rb_reserve_next_event(struct ring_buffer *buffer,return NULL ; } -#ifdef CONFIG_TRACING -/* * The lock and unlock are done within a preempt disable section. * The current_context per_cpu variable can only be modified
@@ -2708,13 +2706,6 @@ trace_recursive_unlock(struct ring_buffer_per_cpu *cpu_buffer) cpu_buffer->current_context &= cpu_buffer->current_context -1 ; } -#else - -#define trace_recursive_lock (cpu_buffer) (0) -#define trace_recursive_unlock (cpu_buffer) do { } while (0) - -#endif -/** * ring_buffer_lock_reserve - reserve a part of the buffer * @buffer: the ring buffer to reserve from
Signature · 1 line
2.1.4
Steven Rostedt
maintainerRe: [for-next][PATCH 3/4] ring-buffer: Allways do the trace_recursive checks
ring-buffer: Allways check for typos in subjects
-- Steve
Steven Rostedt
maintainerPATCH 4/4 ring-buffer: Add trace_recursive checks to ring_buffer_write()
In reply to Steven RostedtFrom: "Steven Rostedt (Red Hat)" <[email protected]>
The ring_buffer_write() function isn't protected by the trace recursive writes. Luckily, this function is not used as much and is unlikely to ever recurse. But it should still have the protection, because even a call to ring_buffer_lock_reserve() could cause ring buffer corruption if called when ring_buffer_write() is being used.
--- kernel/trace/ring_buffer.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)
kernel/trace/ring_buffer.c +8 -1
@@ -3013,9 +3013,12 @@ int ring_buffer_write(struct ring_buffer *buffer,if (length >BUF_MAX_DATA_SIZE ) goto out; +if (unlikely (trace_recursive_lock (cpu_buffer))) + goto out; + event =rb_reserve_next_event (buffer, cpu_buffer, length);if (!event) - goto out; + goto out_unlock; body =rb_event_data (event);
@@ -3026,6 +3029,10 @@ int ring_buffer_write(struct ring_buffer *buffer,rb_wakeups (buffer, cpu_buffer); ret =0 ; + + out_unlock: +trace_recursive_unlock (cpu_buffer); + out:preempt_enable_notrace ();
Signature · 1 line
2.1.4