Skip to content

Commit b23d7a5

Browse files
npigginrostedt
authored andcommitted
ring-buffer: speed up buffer resets by avoiding synchronize_rcu for each CPU
On a 144 thread system, `perf ftrace` takes about 20 seconds to start up, due to calling synchronize_rcu() for each CPU. cat /proc/108560/stack 0xc0003e7eb336f470 __switch_to+0x2e0/0x480 __wait_rcu_gp+0x20c/0x220 synchronize_rcu+0x9c/0xc0 ring_buffer_reset_cpu+0x88/0x2e0 tracing_reset_online_cpus+0x84/0xe0 tracing_open+0x1d4/0x1f0 On a system with 10x more threads, it starts to become an annoyance. Batch these up so we disable all the per-cpu buffers first, then synchronize_rcu() once, then reset each of the buffers. This brings the time down to about 0.5s. Link: https://lkml.kernel.org/r/20200625053403.2386972-1-npiggin@gmail.com Tested-by: Anton Blanchard <anton@ozlabs.org> Acked-by: Paul E. McKenney <paulmck@kernel.org> Signed-off-by: Nicholas Piggin <npiggin@gmail.com> Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
1 parent 10464b4 commit b23d7a5

File tree

3 files changed

+73
-17
lines changed

3 files changed

+73
-17
lines changed

include/linux/ring_buffer.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ bool ring_buffer_iter_dropped(struct ring_buffer_iter *iter);
143143
unsigned long ring_buffer_size(struct trace_buffer *buffer, int cpu);
144144

145145
void ring_buffer_reset_cpu(struct trace_buffer *buffer, int cpu);
146+
void ring_buffer_reset_online_cpus(struct trace_buffer *buffer);
146147
void ring_buffer_reset(struct trace_buffer *buffer);
147148

148149
#ifdef CONFIG_RING_BUFFER_ALLOW_SWAP

kernel/trace/ring_buffer.c

Lines changed: 71 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,9 @@ EXPORT_SYMBOL_GPL(ring_buffer_event_data);
270270
#define for_each_buffer_cpu(buffer, cpu) \
271271
for_each_cpu(cpu, buffer->cpumask)
272272

273+
#define for_each_online_buffer_cpu(buffer, cpu) \
274+
for_each_cpu_and(cpu, buffer->cpumask, cpu_online_mask)
275+
273276
#define TS_SHIFT 27
274277
#define TS_MASK ((1ULL << TS_SHIFT) - 1)
275278
#define TS_DELTA_TEST (~TS_MASK)
@@ -4790,6 +4793,26 @@ rb_reset_cpu(struct ring_buffer_per_cpu *cpu_buffer)
47904793
rb_head_page_activate(cpu_buffer);
47914794
}
47924795

4796+
/* Must have disabled the cpu buffer then done a synchronize_rcu */
4797+
static void reset_disabled_cpu_buffer(struct ring_buffer_per_cpu *cpu_buffer)
4798+
{
4799+
unsigned long flags;
4800+
4801+
raw_spin_lock_irqsave(&cpu_buffer->reader_lock, flags);
4802+
4803+
if (RB_WARN_ON(cpu_buffer, local_read(&cpu_buffer->committing)))
4804+
goto out;
4805+
4806+
arch_spin_lock(&cpu_buffer->lock);
4807+
4808+
rb_reset_cpu(cpu_buffer);
4809+
4810+
arch_spin_unlock(&cpu_buffer->lock);
4811+
4812+
out:
4813+
raw_spin_unlock_irqrestore(&cpu_buffer->reader_lock, flags);
4814+
}
4815+
47934816
/**
47944817
* ring_buffer_reset_cpu - reset a ring buffer per CPU buffer
47954818
* @buffer: The ring buffer to reset a per cpu buffer of
@@ -4798,7 +4821,6 @@ rb_reset_cpu(struct ring_buffer_per_cpu *cpu_buffer)
47984821
void ring_buffer_reset_cpu(struct trace_buffer *buffer, int cpu)
47994822
{
48004823
struct ring_buffer_per_cpu *cpu_buffer = buffer->buffers[cpu];
4801-
unsigned long flags;
48024824

48034825
if (!cpumask_test_cpu(cpu, buffer->cpumask))
48044826
return;
@@ -4809,35 +4831,70 @@ void ring_buffer_reset_cpu(struct trace_buffer *buffer, int cpu)
48094831
/* Make sure all commits have finished */
48104832
synchronize_rcu();
48114833

4812-
raw_spin_lock_irqsave(&cpu_buffer->reader_lock, flags);
4834+
reset_disabled_cpu_buffer(cpu_buffer);
48134835

4814-
if (RB_WARN_ON(cpu_buffer, local_read(&cpu_buffer->committing)))
4815-
goto out;
4836+
atomic_dec(&cpu_buffer->record_disabled);
4837+
atomic_dec(&cpu_buffer->resize_disabled);
4838+
}
4839+
EXPORT_SYMBOL_GPL(ring_buffer_reset_cpu);
48164840

4817-
arch_spin_lock(&cpu_buffer->lock);
4841+
/**
4842+
* ring_buffer_reset_cpu - reset a ring buffer per CPU buffer
4843+
* @buffer: The ring buffer to reset a per cpu buffer of
4844+
* @cpu: The CPU buffer to be reset
4845+
*/
4846+
void ring_buffer_reset_online_cpus(struct trace_buffer *buffer)
4847+
{
4848+
struct ring_buffer_per_cpu *cpu_buffer;
4849+
int cpu;
48184850

4819-
rb_reset_cpu(cpu_buffer);
4851+
for_each_online_buffer_cpu(buffer, cpu) {
4852+
cpu_buffer = buffer->buffers[cpu];
48204853

4821-
arch_spin_unlock(&cpu_buffer->lock);
4854+
atomic_inc(&cpu_buffer->resize_disabled);
4855+
atomic_inc(&cpu_buffer->record_disabled);
4856+
}
48224857

4823-
out:
4824-
raw_spin_unlock_irqrestore(&cpu_buffer->reader_lock, flags);
4858+
/* Make sure all commits have finished */
4859+
synchronize_rcu();
48254860

4826-
atomic_dec(&cpu_buffer->record_disabled);
4827-
atomic_dec(&cpu_buffer->resize_disabled);
4861+
for_each_online_buffer_cpu(buffer, cpu) {
4862+
cpu_buffer = buffer->buffers[cpu];
4863+
4864+
reset_disabled_cpu_buffer(cpu_buffer);
4865+
4866+
atomic_dec(&cpu_buffer->record_disabled);
4867+
atomic_dec(&cpu_buffer->resize_disabled);
4868+
}
48284869
}
4829-
EXPORT_SYMBOL_GPL(ring_buffer_reset_cpu);
48304870

48314871
/**
48324872
* ring_buffer_reset - reset a ring buffer
48334873
* @buffer: The ring buffer to reset all cpu buffers
48344874
*/
48354875
void ring_buffer_reset(struct trace_buffer *buffer)
48364876
{
4877+
struct ring_buffer_per_cpu *cpu_buffer;
48374878
int cpu;
48384879

4839-
for_each_buffer_cpu(buffer, cpu)
4840-
ring_buffer_reset_cpu(buffer, cpu);
4880+
for_each_buffer_cpu(buffer, cpu) {
4881+
cpu_buffer = buffer->buffers[cpu];
4882+
4883+
atomic_inc(&cpu_buffer->resize_disabled);
4884+
atomic_inc(&cpu_buffer->record_disabled);
4885+
}
4886+
4887+
/* Make sure all commits have finished */
4888+
synchronize_rcu();
4889+
4890+
for_each_buffer_cpu(buffer, cpu) {
4891+
cpu_buffer = buffer->buffers[cpu];
4892+
4893+
reset_disabled_cpu_buffer(cpu_buffer);
4894+
4895+
atomic_dec(&cpu_buffer->record_disabled);
4896+
atomic_dec(&cpu_buffer->resize_disabled);
4897+
}
48414898
}
48424899
EXPORT_SYMBOL_GPL(ring_buffer_reset);
48434900

kernel/trace/trace.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2003,7 +2003,6 @@ static void tracing_reset_cpu(struct array_buffer *buf, int cpu)
20032003
void tracing_reset_online_cpus(struct array_buffer *buf)
20042004
{
20052005
struct trace_buffer *buffer = buf->buffer;
2006-
int cpu;
20072006

20082007
if (!buffer)
20092008
return;
@@ -2015,8 +2014,7 @@ void tracing_reset_online_cpus(struct array_buffer *buf)
20152014

20162015
buf->time_start = buffer_ftrace_now(buf, buf->cpu);
20172016

2018-
for_each_online_cpu(cpu)
2019-
ring_buffer_reset_cpu(buffer, cpu);
2017+
ring_buffer_reset_online_cpus(buffer);
20202018

20212019
ring_buffer_record_enable(buffer);
20222020
}

0 commit comments

Comments
 (0)