diff mbox

[RFC] perf: enable fsync to flush buffered samples

Message ID 1432230028-30987-1-git-send-email-robert@sixbynine.org (mailing list archive)
State New, archived
Headers show

Commit Message

Robert Bragg May 21, 2015, 5:40 p.m. UTC
Instead of having a PERF_EVENT_IOC_FLUSH ioctl this instead allows
userspace to use fsync for flushing pmu samples, as suggested by Ingo
Molnar - thanks.

For reference I've also pushed a patch to my Mesa branch to test
this: https://github.com/rib/mesa wip/rib/oa-hsw-4.0.0

- Robert

--- >8 ---

To allow for pmus that may have internal buffering (e.g. the hardware
writes out data to a circular buffer which is only periodically
forwarded to userspace via perf) this enables userspace to explicitly
ensure it has received all samples before a point in time.

Signed-off-by: Robert Bragg <robert@sixbynine.org>
---
 include/linux/perf_event.h |  7 +++++++
 kernel/events/core.c       | 23 +++++++++++++++++++++++
 2 files changed, 30 insertions(+)
diff mbox

Patch

diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index 04e98c8..d7fac05 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -305,6 +305,13 @@  struct pmu {
 	 * Free pmu-private AUX data structures
 	 */
 	void (*free_aux)		(void *aux); /* optional */
+
+	/*
+	 * Flush buffered samples (E.g. for pmu hardware that writes samples to
+	 * some intermediate buffer) userspace may need to explicitly ensure
+	 * such samples have been forwarded to perf.
+	 */
+	int (*flush)			(struct perf_event *event); /*optional */
 };
 
 /**
diff --git a/kernel/events/core.c b/kernel/events/core.c
index 2ba89a1..a604e0c 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -4728,6 +4728,28 @@  static int perf_fasync(int fd, struct file *filp, int on)
 	return 0;
 }
 
+static int perf_fsync(struct file *filp, loff_t start, loff_t end, int datasync)
+{
+	struct perf_event *event = filp->private_data;
+	struct perf_event_context *ctx;
+	int ret;
+
+	/* We don't have a use for synchonizing a specific range, or datasync
+	 * but lets not silently ignore them in case we think of uses later...
+	 */
+	if (start != 0 || end != LLONG_MAX || datasync != 0)
+		return -EINVAL;
+
+	if (!event->pmu->flush)
+		return 0;
+
+	ctx = perf_event_ctx_lock(event);
+	ret = event->pmu->flush(event);
+	perf_event_ctx_unlock(event, ctx);
+
+	return ret;
+}
+
 static const struct file_operations perf_fops = {
 	.llseek			= no_llseek,
 	.release		= perf_release,
@@ -4737,6 +4759,7 @@  static const struct file_operations perf_fops = {
 	.compat_ioctl		= perf_compat_ioctl,
 	.mmap			= perf_mmap,
 	.fasync			= perf_fasync,
+	.fsync			= perf_fsync,
 };
 
 /*