From: Lai Jiangshan <laijs@cn.fujitsu.com>
To: Ingo Molnar <mingo@elte.hu>, Steven Rostedt <rostedt@goodmis.org>,
Frederic Weisbecker <fweisbec@gmail.com>,
LKML <linux-kernel@vger.kernel.org>
Subject: [PATCH 2/3] tracing: block-able ring_buffer consumer
Date: Thu, 27 Aug 2009 11:03:04 +0800 [thread overview]
Message-ID: <4A95F768.7070701@cn.fujitsu.com> (raw)
makes consumer side(per_cpu/cpu#/trace_pipe_raw) block-able,
which is a TODO in trace.c
Signed-off-by: Lai Jiangshan <laijs@cn.fujitsu.com>
---
diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
index dc3b132..b5dcf34 100644
--- a/include/linux/ftrace.h
+++ b/include/linux/ftrace.h
@@ -512,4 +512,10 @@ static inline void trace_hw_branch_oops(void) {}
#endif /* CONFIG_HW_BRANCH_TRACER */
+#ifdef CONFIG_TRACING
+void tracing_notify(void);
+#else
+static inline void tracing_notify(void) {}
+#endif
+
#endif /* _LINUX_FTRACE_H */
diff --git a/include/linux/ring_buffer.h b/include/linux/ring_buffer.h
index 7fca716..b81ceed 100644
--- a/include/linux/ring_buffer.h
+++ b/include/linux/ring_buffer.h
@@ -185,6 +185,10 @@ void ring_buffer_free_read_page(struct ring_buffer *buffer, void *data);
int ring_buffer_read_page(struct ring_buffer *buffer, void **data_page,
size_t len, int cpu, int full);
+void ring_buffer_notify(struct ring_buffer *buffer);
+signed long ring_buffer_wait_page(struct ring_buffer *buffer, int cpu,
+ signed long timeout);
+
struct trace_seq;
int ring_buffer_print_entry_header(struct trace_seq *s);
diff --git a/kernel/timer.c b/kernel/timer.c
index 6e712df..79f5596 100644
--- a/kernel/timer.c
+++ b/kernel/timer.c
@@ -39,6 +39,7 @@
#include <linux/kallsyms.h>
#include <linux/perf_counter.h>
#include <linux/sched.h>
+#include <linux/ftrace.h>
#include <asm/uaccess.h>
#include <asm/unistd.h>
@@ -1178,6 +1179,7 @@ void update_process_times(int user_tick)
printk_tick();
scheduler_tick();
run_posix_cpu_timers(p);
+ tracing_notify();
}
/*
diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c
index f1e1533..db82b38 100644
--- a/kernel/trace/ring_buffer.c
+++ b/kernel/trace/ring_buffer.c
@@ -443,6 +443,7 @@ struct ring_buffer_per_cpu {
u64 write_stamp;
u64 read_stamp;
atomic_t record_disabled;
+ wait_queue_head_t sleepers;
};
struct ring_buffer {
@@ -999,6 +999,7 @@ rb_allocate_cpu_buffer(struct ring_buffer *buffer, int cpu)
spin_lock_init(&cpu_buffer->reader_lock);
lockdep_set_class(&cpu_buffer->reader_lock, buffer->reader_lock_key);
cpu_buffer->lock = (raw_spinlock_t)__RAW_SPIN_LOCK_UNLOCKED;
+ init_waitqueue_head(&cpu_buffer->sleepers);
bpage = kzalloc_node(ALIGN(sizeof(*bpage), cache_line_size()),
GFP_KERNEL, cpu_to_node(cpu));
@@ -3318,6 +3319,77 @@ ring_buffer_read(struct ring_buffer_iter *iter, u64 *ts)
EXPORT_SYMBOL_GPL(ring_buffer_read);
/**
+ * ring_buffer_notify - notify the sleepers when there is any available page
+ * @buffer: The ring buffer.
+ */
+void ring_buffer_notify(struct ring_buffer *buffer)
+{
+ unsigned long flags;
+ struct ring_buffer_per_cpu *cpu_buffer;
+
+ cpu_buffer = buffer->buffers[smp_processor_id()];
+
+ if (!spin_trylock_irqsave(&cpu_buffer->reader_lock, flags))
+ return;
+
+ if (waitqueue_active(&cpu_buffer->sleepers)) {
+ struct buffer_page *reader_page;
+ struct buffer_page *commit_page;
+
+ reader_page = cpu_buffer->reader_page;
+ commit_page = ACCESS_ONCE(cpu_buffer->commit_page);
+
+ /*
+ * ring_buffer_notify() is fast path, so we don't use the slow
+ * rb_get_reader_page(cpu_buffer, 1) to detect available pages.
+ */
+ if (reader_page == commit_page)
+ goto out;
+
+ if (reader_page->read < rb_page_commit(reader_page)
+ || rb_set_head_page(cpu_buffer) != commit_page)
+ wake_up(&cpu_buffer->sleepers);
+ }
+
+out:
+ spin_unlock_irqrestore(&cpu_buffer->reader_lock, flags);
+}
+
+static
+int rb_page_available(struct ring_buffer_per_cpu *cpu_buffer)
+{
+ struct buffer_page *reader_page;
+
+ spin_lock_irq(&cpu_buffer->reader_lock);
+ reader_page = rb_get_reader_page(cpu_buffer, 1);
+ spin_unlock_irq(&cpu_buffer->reader_lock);
+
+ return !!reader_page;
+}
+
+/**
+ * ring_buffer_wait_page - wait until there are available pages to read
+ * @buffer: The ring buffer.
+ * @cpu: The CPU buffer to be wait
+ * @timeout: timeout value in jiffies
+ *
+ * Make the current task sleep until there are available pages to read or
+ * until @timeout jiffies have elapsed or until it is interrupted by signals.
+ *
+ * The function returns 0 if the @timeout elapsed, -ERESTARTSYS if it
+ * was interrupted by a signal, and the remaining jiffies otherwise
+ * if there are available pages to read before the timeout elapsed.
+ */
+signed long
+ring_buffer_wait_page(struct ring_buffer *buffer, int cpu, signed long timeout)
+{
+ struct ring_buffer_per_cpu *cpu_buffer = buffer->buffers[cpu];
+
+ return wait_event_interruptible_timeout(cpu_buffer->sleepers,
+ rb_page_available(cpu_buffer), timeout);
+}
+
+/**
* ring_buffer_size - return the size of the ring buffer (in bytes)
* @buffer: The ring buffer.
*/
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index b7d873b..ee435ed 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -2457,6 +2457,12 @@ int tracing_update_buffers(void)
return ret;
}
+void tracing_notify(void)
+{
+ if (global_trace.buffer)
+ ring_buffer_notify(global_trace.buffer);
+}
+
struct trace_option_dentry;
static struct trace_option_dentry *
@@ -3232,12 +3237,30 @@ tracing_buffers_read(struct file *filp, char __user *ubuf,
info->read = 0;
+ /*
+ * We try our best to read from full page,
+ * but we wait 2 seconds at most.
+ */
+ if (count >= PAGE_SIZE && !(filp->f_flags & O_NONBLOCK))
+ ring_buffer_wait_page(info->tr->buffer, info->cpu, HZ * 2);
+
+again:
ret = ring_buffer_read_page(info->tr->buffer,
&info->spare,
count,
info->cpu, 0);
- if (ret < 0)
- return 0;
+
+ if (ret < 0) {
+ ret = 0;
+ if (!(filp->f_flags & O_NONBLOCK)) {
+ ret = ring_buffer_wait_page(info->tr->buffer,
+ info->cpu, MAX_SCHEDULE_TIMEOUT);
+ if (ret > 0)
+ goto again;
+ }
+
+ return ret;
+ }
pos = ring_buffer_page_len(info->spare);
@@ -3363,6 +3386,7 @@ tracing_buffers_splice_read(struct file *file, loff_t *ppos,
len &= PAGE_MASK;
}
+again:
entries = ring_buffer_entries_cpu(info->tr->buffer, info->cpu);
for (i = 0; i < PIPE_BUFFERS && len && entries; i++, len -= PAGE_SIZE) {
@@ -3416,9 +3440,13 @@ tracing_buffers_splice_read(struct file *file, loff_t *ppos,
if (!spd.nr_pages) {
if (flags & SPLICE_F_NONBLOCK)
ret = -EAGAIN;
- else
- ret = 0;
- /* TODO: block */
+ else {
+ ret = ring_buffer_wait_page(info->tr->buffer,
+ info->cpu, MAX_SCHEDULE_TIMEOUT);
+ if ((ssize_t)ret > 0)
+ goto again;
+ }
+
return ret;
}
next reply other threads:[~2009-08-27 3:04 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-08-27 3:03 Lai Jiangshan [this message]
2009-08-29 10:21 ` Frederic Weisbecker
2009-09-01 12:53 ` Lai Jiangshan
2009-09-01 23:05 ` Frederic Weisbecker
2009-09-01 23:12 ` Frederic Weisbecker
2009-09-09 21:10 ` Steven Rostedt
2009-09-10 2:06 ` Frederic Weisbecker
2009-09-09 21:06 ` Steven Rostedt
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4A95F768.7070701@cn.fujitsu.com \
--to=laijs@cn.fujitsu.com \
--cc=fweisbec@gmail.com \
--cc=linux-kernel@vger.kernel.org \
--cc=mingo@elte.hu \
--cc=rostedt@goodmis.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Powered by JetHome