[PATCH] drm/i915: Throttle execbuffer hogs

Chris Wilson chris at chris-wilson.co.uk
Tue Feb 5 21:01:24 UTC 2019


Apply backpressure to hogs that emit requests faster than the GPU can
process them by waiting for their ring to be less than half-full before
proceeding with taking the struct_mutex.

This is a gross hack to apply throttling backpressure, the long term
goal is to remove the struct_mutex contention so that each client
naturally waits for their own resources and never blocks another within
the driver at least. (Realtime priority goals would extend to ensuring
that resource contention favours high priority clients as well.)

Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
---
 drivers/gpu/drm/i915/i915_gem_execbuffer.c | 36 ++++++++++++++++++++++
 drivers/gpu/drm/i915/i915_request.c        |  4 +++
 drivers/gpu/drm/i915/intel_ringbuffer.c    |  2 ++
 drivers/gpu/drm/i915/intel_ringbuffer.h    |  2 ++
 4 files changed, 44 insertions(+)

diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
index 8eedf7cac493..98a3b79c5d5b 100644
--- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c
+++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
@@ -753,6 +753,37 @@ static int eb_select_context(struct i915_execbuffer *eb)
 	return 0;
 }
 
+static bool __eb_wait_for_space(struct intel_context *ce)
+{
+	return 2 * READ_ONCE(ce->ring->space) > ce->ring->size;
+}
+
+static int eb_wait_for_space(struct i915_execbuffer *eb)
+{
+	struct intel_context *ce;
+
+	ce = to_intel_context(eb->ctx, eb->engine);
+	if (!ce->ring)
+		return 0;
+
+	if (__eb_wait_for_space(ce))
+		return 0;
+
+	if (mutex_trylock(&eb->i915->drm.struct_mutex)) {
+		struct i915_request *rq;
+
+		list_for_each_entry(rq, &ce->ring->request_list, ring_link) {
+			if (!i915_request_completed(rq)) {
+				i915_request_retire_upto(rq);
+				break;
+			}
+		}
+	}
+
+	return wait_event_interruptible(ce->ring->waitqueue,
+					__eb_wait_for_space(ce));
+}
+
 static int eb_lookup_vmas(struct i915_execbuffer *eb)
 {
 	struct radix_tree_root *handles_vma = &eb->ctx->handles_vma;
@@ -2278,6 +2309,10 @@ i915_gem_do_execbuffer(struct drm_device *dev,
 	if (unlikely(err))
 		goto err_destroy;
 
+	err = eb_wait_for_space(&eb);
+	if (unlikely(err))
+		goto err_context;
+
 	/*
 	 * Take a local wakeref for preparing to dispatch the execbuf as
 	 * we expect to access the hardware fairly frequently in the
@@ -2438,6 +2473,7 @@ i915_gem_do_execbuffer(struct drm_device *dev,
 	mutex_unlock(&dev->struct_mutex);
 err_rpm:
 	intel_runtime_pm_put(eb.i915, wakeref);
+err_context:
 	i915_gem_context_put(eb.ctx);
 err_destroy:
 	eb_destroy(&eb);
diff --git a/drivers/gpu/drm/i915/i915_request.c b/drivers/gpu/drm/i915/i915_request.c
index c2a5c48c7541..efb42f79056b 100644
--- a/drivers/gpu/drm/i915/i915_request.c
+++ b/drivers/gpu/drm/i915/i915_request.c
@@ -129,6 +129,7 @@ static void unreserve_gt(struct drm_i915_private *i915)
 static void advance_ring(struct i915_request *request)
 {
 	struct intel_ring *ring = request->ring;
+	unsigned int old_space = ring->space;
 	unsigned int tail;
 
 	/*
@@ -159,6 +160,9 @@ static void advance_ring(struct i915_request *request)
 	list_del_init(&request->ring_link);
 
 	ring->head = tail;
+
+	if ((intel_ring_update_space(ring) ^ old_space) & PAGE_SIZE)
+		wake_up_all(&ring->waitqueue);
 }
 
 static void free_capture_list(struct i915_request *request)
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c
index b889b27f8aeb..a94edd50500c 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.c
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
@@ -1337,6 +1337,8 @@ intel_engine_create_ring(struct intel_engine_cs *engine,
 		return ERR_PTR(-ENOMEM);
 
 	INIT_LIST_HEAD(&ring->request_list);
+	init_waitqueue_head(&ring->waitqueue);
+
 	ring->timeline = i915_timeline_get(timeline);
 
 	ring->size = size;
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h
index 1398eb81dee6..406dc1ffc855 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.h
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.h
@@ -139,6 +139,8 @@ struct intel_ring {
 	u32 space;
 	u32 size;
 	u32 effective_size;
+
+	wait_queue_head_t waitqueue;
 };
 
 struct i915_gem_context;
-- 
2.20.1



More information about the Intel-gfx-trybot mailing list