[2/4] drm/i915: More proactive timeline retirement before new requests
diff mbox series

Message ID 20200117111546.3012803-2-chris@chris-wilson.co.uk
State New
Headers show
Series
  • [1/4] drm/i915: Only retire requests when eviction is allowed to blocked
Related show

Commit Message

Chris Wilson Jan. 17, 2020, 11:15 a.m. UTC
Currently, we only retire the oldest request on the timeline before
allocating the next, but only if there is a spare request. However,
since we rearranged the locking, e.g.  commit df9f85d8582e ("drm/i915:
Serialise i915_active_fence_set() with itself"), we no longer benefit
from keeping the active chain intact underneath the struct_mutex. As
such, retire all completed requests in the client's timeline before
creating the next, trying to keep our memory and resource usage tight
and ideally only penalising the heavy users.

v2: Keep a retire after submission to try and keep the amount of work
before the next submission to a minimum.

References: df9f85d8582e ("drm/i915: Serialise i915_active_fence_set() with itself")
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
---
 drivers/gpu/drm/i915/i915_request.c | 57 +++++++----------------------
 1 file changed, 13 insertions(+), 44 deletions(-)

Patch
diff mbox series

diff --git a/drivers/gpu/drm/i915/i915_request.c b/drivers/gpu/drm/i915/i915_request.c
index 9ed0d3bc7249..70f5010e89f5 100644
--- a/drivers/gpu/drm/i915/i915_request.c
+++ b/drivers/gpu/drm/i915/i915_request.c
@@ -556,31 +556,20 @@  static void retire_requests(struct intel_timeline *tl)
 static noinline struct i915_request *
 request_alloc_slow(struct intel_timeline *tl, gfp_t gfp)
 {
-	struct i915_request *rq;
-
-	if (list_empty(&tl->requests))
-		goto out;
-
 	if (!gfpflags_allow_blocking(gfp))
-		goto out;
+		return NULL;
 
-	/* Move our oldest request to the slab-cache (if not in use!) */
-	rq = list_first_entry(&tl->requests, typeof(*rq), link);
-	i915_request_retire(rq);
+	if (!list_empty(&tl->requests)) {
+		struct i915_request *rq;
 
-	rq = kmem_cache_alloc(global.slab_requests,
-			      gfp | __GFP_RETRY_MAYFAIL | __GFP_NOWARN);
-	if (rq)
-		return rq;
+		/* Ratelimit ourselves to prevent oom from malicious clients */
+		rq = list_last_entry(&tl->requests, typeof(*rq), link);
+		cond_synchronize_rcu(rq->rcustate);
 
-	/* Ratelimit ourselves to prevent oom from malicious clients */
-	rq = list_last_entry(&tl->requests, typeof(*rq), link);
-	cond_synchronize_rcu(rq->rcustate);
-
-	/* Retire our old requests in the hope that we free some */
-	retire_requests(tl);
+		/* Retire our old requests in the hope that we free some */
+		retire_requests(tl);
+	}
 
-out:
 	return kmem_cache_alloc(global.slab_requests, gfp);
 }
 
@@ -739,9 +728,7 @@  i915_request_create(struct intel_context *ce)
 		return ERR_CAST(tl);
 
 	/* Move our oldest request to the slab-cache (if not in use!) */
-	rq = list_first_entry(&tl->requests, typeof(*rq), link);
-	if (!list_is_last(&rq->link, &tl->requests))
-		i915_request_retire(rq);
+	retire_requests(tl);
 
 	intel_context_enter(ce);
 	rq = __i915_request_create(ce, GFP_KERNEL);
@@ -1344,27 +1331,9 @@  void i915_request_add(struct i915_request *rq)
 	__i915_request_queue(rq, &attr);
 	local_bh_enable(); /* Kick the execlists tasklet if just scheduled */
 
-	/*
-	 * In typical scenarios, we do not expect the previous request on
-	 * the timeline to be still tracked by timeline->last_request if it
-	 * has been completed. If the completed request is still here, that
-	 * implies that request retirement is a long way behind submission,
-	 * suggesting that we haven't been retiring frequently enough from
-	 * the combination of retire-before-alloc, waiters and the background
-	 * retirement worker. So if the last request on this timeline was
-	 * already completed, do a catch up pass, flushing the retirement queue
-	 * up to this client. Since we have now moved the heaviest operations
-	 * during retirement onto secondary workers, such as freeing objects
-	 * or contexts, retiring a bunch of requests is mostly list management
-	 * (and cache misses), and so we should not be overly penalizing this
-	 * client by performing excess work, though we may still performing
-	 * work on behalf of others -- but instead we should benefit from
-	 * improved resource management. (Well, that's the theory at least.)
-	 */
-	if (prev &&
-	    i915_request_completed(prev) &&
-	    rcu_access_pointer(prev->timeline) == tl)
-		i915_request_retire_upto(prev);
+	/* Try to clean up the client's timeline after submitting the request */
+	if (prev)
+		retire_requests(tl);
 
 	mutex_unlock(&tl->mutex);
 }