Skip to content

Commit 1e3f697

Browse files
committed
drm/i915/execlists: Suppress redundant preemption
On unwinding the active request we give it a small (limited to internal priority levels) boost to prevent it from being gazumped a second time. However, this means that it can be promoted to above the request that triggered the preemption request, causing a preempt-to-idle cycle for no change. We can avoid this if we take the boost into account when checking if the preemption request is valid. v2: After preemption the active request will be after the preemptee if they end up with equal priority. v3: Tvrtko pointed out that this, the existing logic, makes I915_PRIORITY_WAIT non-preemptible. Document this interesting quirk! v4: Prove Tvrtko was right about WAIT being non-preemptible and test it. v5: Except not all priorities were made equal, and the WAIT not preempting is only if we start off as !NEWCLIENT. v6: More commentary after coming to an understanding about what I had forgotten to say. Signed-off-by: Chris Wilson <[email protected]> Cc: Tvrtko Ursulin <[email protected]> Reviewed-by: Tvrtko Ursulin <[email protected]> Link: https://patchwork.freedesktop.org/patch/msgid/[email protected]
1 parent 34ae845 commit 1e3f697

File tree

1 file changed

+40
-4
lines changed

1 file changed

+40
-4
lines changed

drivers/gpu/drm/i915/intel_lrc.c

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,8 @@
164164
#define WA_TAIL_DWORDS 2
165165
#define WA_TAIL_BYTES (sizeof(u32) * WA_TAIL_DWORDS)
166166

167+
#define ACTIVE_PRIORITY (I915_PRIORITY_NEWCLIENT)
168+
167169
static int execlists_context_deferred_alloc(struct i915_gem_context *ctx,
168170
struct intel_engine_cs *engine,
169171
struct intel_context *ce);
@@ -190,8 +192,30 @@ static inline int rq_prio(const struct i915_request *rq)
190192

191193
static int effective_prio(const struct i915_request *rq)
192194
{
195+
int prio = rq_prio(rq);
196+
197+
/*
198+
* On unwinding the active request, we give it a priority bump
199+
* equivalent to a freshly submitted request. This protects it from
200+
* being gazumped again, but it would be preferable if we didn't
201+
* let it be gazumped in the first place!
202+
*
203+
* See __unwind_incomplete_requests()
204+
*/
205+
if (~prio & ACTIVE_PRIORITY && __i915_request_has_started(rq)) {
206+
/*
207+
* After preemption, we insert the active request at the
208+
* end of the new priority level. This means that we will be
209+
* _lower_ priority than the preemptee all things equal (and
210+
* so the preemption is valid), so adjust our comparison
211+
* accordingly.
212+
*/
213+
prio |= ACTIVE_PRIORITY;
214+
prio--;
215+
}
216+
193217
/* Restrict mere WAIT boosts from triggering preemption */
194-
return rq_prio(rq) | __NO_PREEMPTION;
218+
return prio | __NO_PREEMPTION;
195219
}
196220

197221
static int queue_prio(const struct intel_engine_execlists *execlists)
@@ -359,7 +383,7 @@ __unwind_incomplete_requests(struct intel_engine_cs *engine)
359383
{
360384
struct i915_request *rq, *rn, *active = NULL;
361385
struct list_head *uninitialized_var(pl);
362-
int prio = I915_PRIORITY_INVALID | I915_PRIORITY_NEWCLIENT;
386+
int prio = I915_PRIORITY_INVALID | ACTIVE_PRIORITY;
363387

364388
lockdep_assert_held(&engine->timeline.lock);
365389

@@ -390,9 +414,21 @@ __unwind_incomplete_requests(struct intel_engine_cs *engine)
390414
* The active request is now effectively the start of a new client
391415
* stream, so give it the equivalent small priority bump to prevent
392416
* it being gazumped a second time by another peer.
417+
*
418+
* Note we have to be careful not to apply a priority boost to a request
419+
* still spinning on its semaphores. If the request hasn't started, that
420+
* means it is still waiting for its dependencies to be signaled, and
421+
* if we apply a priority boost to this request, we will boost it past
422+
* its signalers and so break PI.
423+
*
424+
* One consequence of this preemption boost is that we may jump
425+
* over lesser priorities (such as I915_PRIORITY_WAIT), effectively
426+
* making those priorities non-preemptible. They will be moved forward
427+
* in the priority queue, but they will not gain immediate access to
428+
* the GPU.
393429
*/
394-
if (!(prio & I915_PRIORITY_NEWCLIENT)) {
395-
prio |= I915_PRIORITY_NEWCLIENT;
430+
if (~prio & ACTIVE_PRIORITY && __i915_request_has_started(active)) {
431+
prio |= ACTIVE_PRIORITY;
396432
active->sched.attr.priority = prio;
397433
list_move_tail(&active->sched.link,
398434
i915_sched_lookup_priolist(engine, prio));

0 commit comments

Comments
 (0)