aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2019-02-07 02:18:22 -0500
committerChris Wilson <chris@chris-wilson.co.uk>2019-02-07 11:13:21 -0500
commitd6f328bfeb0b0a9304166c52ec15c08076ca5246 (patch)
tree7dc84afee99300ede3c6b30f1f279345dd638ae0
parentebfb6977801da521d8d5d752d373a187e2a2b9b3 (diff)
drm/i915: Hack and slash, throttle execbuffer hogs
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, preferably in an asynchronous, nonblocking fashion (pipelined operations for the win), for their own resources and never blocks another client within the driver at least. (Realtime priority goals would extend to ensuring that resource contention favours high priority clients as well.) This patch only limits excessive request production and does not attempt to throttle clients that block waiting for eviction (either global GTT or system memory) or any other global resources, see above for the long term goal. No microbenchmarks are harmed (to the best of my knowledge). Testcase: igt/gem_exec_schedule/pi-ringfull-* Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Cc: John Harrison <John.C.Harrison@Intel.com> Reviewed-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20190207071829.5574-1-chris@chris-wilson.co.uk
-rw-r--r--drivers/gpu/drm/i915/i915_gem_execbuffer.c67
-rw-r--r--drivers/gpu/drm/i915/intel_ringbuffer.c13
-rw-r--r--drivers/gpu/drm/i915/intel_ringbuffer.h12
3 files changed, 79 insertions, 13 deletions
diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
index 8eedf7cac493..02adcaf6ebea 100644
--- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c
+++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
@@ -753,6 +753,68 @@ static int eb_select_context(struct i915_execbuffer *eb)
753 return 0; 753 return 0;
754} 754}
755 755
756static struct i915_request *__eb_wait_for_ring(struct intel_ring *ring)
757{
758 struct i915_request *rq;
759
760 /*
761 * Completely unscientific finger-in-the-air estimates for suitable
762 * maximum user request size (to avoid blocking) and then backoff.
763 */
764 if (intel_ring_update_space(ring) >= PAGE_SIZE)
765 return NULL;
766
767 /*
768 * Find a request that after waiting upon, there will be at least half
769 * the ring available. The hysteresis allows us to compete for the
770 * shared ring and should mean that we sleep less often prior to
771 * claiming our resources, but not so long that the ring completely
772 * drains before we can submit our next request.
773 */
774 list_for_each_entry(rq, &ring->request_list, ring_link) {
775 if (__intel_ring_space(rq->postfix,
776 ring->emit, ring->size) > ring->size / 2)
777 break;
778 }
779 if (&rq->ring_link == &ring->request_list)
780 return NULL; /* weird, we will check again later for real */
781
782 return i915_request_get(rq);
783}
784
785static int eb_wait_for_ring(const struct i915_execbuffer *eb)
786{
787 const struct intel_context *ce;
788 struct i915_request *rq;
789 int ret = 0;
790
791 /*
792 * Apply a light amount of backpressure to prevent excessive hogs
793 * from blocking waiting for space whilst holding struct_mutex and
794 * keeping all of their resources pinned.
795 */
796
797 ce = to_intel_context(eb->ctx, eb->engine);
798 if (!ce->ring) /* first use, assume empty! */
799 return 0;
800
801 rq = __eb_wait_for_ring(ce->ring);
802 if (rq) {
803 mutex_unlock(&eb->i915->drm.struct_mutex);
804
805 if (i915_request_wait(rq,
806 I915_WAIT_INTERRUPTIBLE,
807 MAX_SCHEDULE_TIMEOUT) < 0)
808 ret = -EINTR;
809
810 i915_request_put(rq);
811
812 mutex_lock(&eb->i915->drm.struct_mutex);
813 }
814
815 return ret;
816}
817
756static int eb_lookup_vmas(struct i915_execbuffer *eb) 818static int eb_lookup_vmas(struct i915_execbuffer *eb)
757{ 819{
758 struct radix_tree_root *handles_vma = &eb->ctx->handles_vma; 820 struct radix_tree_root *handles_vma = &eb->ctx->handles_vma;
@@ -2291,6 +2353,10 @@ i915_gem_do_execbuffer(struct drm_device *dev,
2291 if (err) 2353 if (err)
2292 goto err_rpm; 2354 goto err_rpm;
2293 2355
2356 err = eb_wait_for_ring(&eb); /* may temporarily drop struct_mutex */
2357 if (unlikely(err))
2358 goto err_unlock;
2359
2294 err = eb_relocate(&eb); 2360 err = eb_relocate(&eb);
2295 if (err) { 2361 if (err) {
2296 /* 2362 /*
@@ -2435,6 +2501,7 @@ err_batch_unpin:
2435err_vma: 2501err_vma:
2436 if (eb.exec) 2502 if (eb.exec)
2437 eb_release_vmas(&eb); 2503 eb_release_vmas(&eb);
2504err_unlock:
2438 mutex_unlock(&dev->struct_mutex); 2505 mutex_unlock(&dev->struct_mutex);
2439err_rpm: 2506err_rpm:
2440 intel_runtime_pm_put(eb.i915, wakeref); 2507 intel_runtime_pm_put(eb.i915, wakeref);
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c
index b889b27f8aeb..7f841dba87b3 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.c
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
@@ -49,19 +49,6 @@ static inline u32 intel_hws_seqno_address(struct intel_engine_cs *engine)
49 I915_GEM_HWS_INDEX_ADDR); 49 I915_GEM_HWS_INDEX_ADDR);
50} 50}
51 51
52static unsigned int __intel_ring_space(unsigned int head,
53 unsigned int tail,
54 unsigned int size)
55{
56 /*
57 * "If the Ring Buffer Head Pointer and the Tail Pointer are on the
58 * same cacheline, the Head Pointer must not be greater than the Tail
59 * Pointer."
60 */
61 GEM_BUG_ON(!is_power_of_2(size));
62 return (head - tail - CACHELINE_BYTES) & (size - 1);
63}
64
65unsigned int intel_ring_update_space(struct intel_ring *ring) 52unsigned int intel_ring_update_space(struct intel_ring *ring)
66{ 53{
67 unsigned int space; 54 unsigned int space;
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h
index 4d4ea6963a72..710ffb221775 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.h
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.h
@@ -832,6 +832,18 @@ intel_ring_set_tail(struct intel_ring *ring, unsigned int tail)
832 return tail; 832 return tail;
833} 833}
834 834
835static inline unsigned int
836__intel_ring_space(unsigned int head, unsigned int tail, unsigned int size)
837{
838 /*
839 * "If the Ring Buffer Head Pointer and the Tail Pointer are on the
840 * same cacheline, the Head Pointer must not be greater than the Tail
841 * Pointer."
842 */
843 GEM_BUG_ON(!is_power_of_2(size));
844 return (head - tail - CACHELINE_BYTES) & (size - 1);
845}
846
835void intel_engine_write_global_seqno(struct intel_engine_cs *engine, u32 seqno); 847void intel_engine_write_global_seqno(struct intel_engine_cs *engine, u32 seqno);
836 848
837int intel_engine_setup_common(struct intel_engine_cs *engine); 849int intel_engine_setup_common(struct intel_engine_cs *engine);