perf/ring_buffer: Introduce new ioctl options to pause and resume the ring-buffer
authorWang Nan <wangnan0@huawei.com>
Mon, 28 Mar 2016 06:41:29 +0000 (06:41 +0000)
committerIngo Molnar <mingo@kernel.org>
Thu, 31 Mar 2016 08:30:45 +0000 (10:30 +0200)
Add new ioctl() to pause/resume ring-buffer output.

In some situations we want to read from the ring-buffer only when we
ensure nothing can write to the ring-buffer during reading. Without
this patch we have to turn off all events attached to this ring-buffer
to achieve this.

This patch is a prerequisite to enable overwrite support for the
perf ring-buffer support. Following commits will introduce new methods
support reading from overwrite ring buffer. Before reading, caller
must ensure the ring buffer is frozen, or the reading is unreliable.

Signed-off-by: Wang Nan <wangnan0@huawei.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: <pi3orama@163.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Brendan Gregg <brendan.d.gregg@gmail.com>
Cc: He Kuang <hekuang@huawei.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Vince Weaver <vincent.weaver@maine.edu>
Cc: Zefan Li <lizefan@huawei.com>
Link: http://lkml.kernel.org/r/1459147292-239310-2-git-send-email-wangnan0@huawei.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
include/uapi/linux/perf_event.h
kernel/events/core.c
kernel/events/internal.h
kernel/events/ring_buffer.c

index 1afe962..a3c1903 100644 (file)
@@ -401,6 +401,7 @@ struct perf_event_attr {
 #define PERF_EVENT_IOC_SET_FILTER      _IOW('$', 6, char *)
 #define PERF_EVENT_IOC_ID              _IOR('$', 7, __u64 *)
 #define PERF_EVENT_IOC_SET_BPF         _IOW('$', 8, __u32)
+#define PERF_EVENT_IOC_PAUSE_OUTPUT    _IOW('$', 9, __u32)
 
 enum perf_event_ioc_flags {
        PERF_IOC_FLAG_GROUP             = 1U << 0,
index 243df4b..51386e8 100644 (file)
@@ -4379,6 +4379,19 @@ static long _perf_ioctl(struct perf_event *event, unsigned int cmd, unsigned lon
        case PERF_EVENT_IOC_SET_BPF:
                return perf_event_set_bpf_prog(event, arg);
 
+       case PERF_EVENT_IOC_PAUSE_OUTPUT: {
+               struct ring_buffer *rb;
+
+               rcu_read_lock();
+               rb = rcu_dereference(event->rb);
+               if (!rb || !rb->nr_pages) {
+                       rcu_read_unlock();
+                       return -EINVAL;
+               }
+               rb_toggle_paused(rb, !!arg);
+               rcu_read_unlock();
+               return 0;
+       }
        default:
                return -ENOTTY;
        }
index 2b229fd..2d67327 100644 (file)
@@ -17,6 +17,7 @@ struct ring_buffer {
 #endif
        int                             nr_pages;       /* nr of data pages  */
        int                             overwrite;      /* can overwrite itself */
+       int                             paused;         /* can write into ring buffer */
 
        atomic_t                        poll;           /* POLL_ for wakeups */
 
@@ -64,6 +65,14 @@ static inline void rb_free_rcu(struct rcu_head *rcu_head)
        rb_free(rb);
 }
 
+static inline void rb_toggle_paused(struct ring_buffer *rb, bool pause)
+{
+       if (!pause && rb->nr_pages)
+               rb->paused = 0;
+       else
+               rb->paused = 1;
+}
+
 extern struct ring_buffer *
 rb_alloc(int nr_pages, long watermark, int cpu, int flags);
 extern void perf_event_wakeup(struct perf_event *event);
index 0ed4555..72d8127 100644 (file)
@@ -125,8 +125,11 @@ int perf_output_begin(struct perf_output_handle *handle,
        if (unlikely(!rb))
                goto out;
 
-       if (unlikely(!rb->nr_pages))
+       if (unlikely(rb->paused)) {
+               if (rb->nr_pages)
+                       local_inc(&rb->lost);
                goto out;
+       }
 
        handle->rb    = rb;
        handle->event = event;
@@ -241,6 +244,13 @@ ring_buffer_init(struct ring_buffer *rb, long watermark, int flags)
 
        INIT_LIST_HEAD(&rb->event_list);
        spin_lock_init(&rb->event_lock);
+
+       /*
+        * perf_output_begin() only checks rb->paused, therefore
+        * rb->paused must be true if we have no pages for output.
+        */
+       if (!rb->nr_pages)
+               rb->paused = 1;
 }
 
 /*