Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/i915: Priority boost for waiting clients

Latency is in the eye of the beholder. In the case where a client stops
and waits for the gpu, give that request chain a small priority boost
(not so that it overtakes higher priority clients, to preserve the
external ordering) so that ideally the wait completes earlier.

v2: Tvrtko recommends to keep the boost-from-user-stall as small as
possible and to allow new client flows to be preferred for interactivity
over stalls.

Testcase: igt/gem_sync/switch-default
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: Dmitry Rogozhkin <dmitry.v.rogozhkin@intel.com>
Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20181001144755.7978-3-chris@chris-wilson.co.uk

+42 -11
+4 -1
drivers/gpu/drm/i915/i915_gem.c
··· 1748 1748 */ 1749 1749 err = i915_gem_object_wait(obj, 1750 1750 I915_WAIT_INTERRUPTIBLE | 1751 + I915_WAIT_PRIORITY | 1751 1752 (write_domain ? I915_WAIT_ALL : 0), 1752 1753 MAX_SCHEDULE_TIMEOUT, 1753 1754 to_rps_client(file)); ··· 3752 3751 start = ktime_get(); 3753 3752 3754 3753 ret = i915_gem_object_wait(obj, 3755 - I915_WAIT_INTERRUPTIBLE | I915_WAIT_ALL, 3754 + I915_WAIT_INTERRUPTIBLE | 3755 + I915_WAIT_PRIORITY | 3756 + I915_WAIT_ALL, 3756 3757 to_wait_timeout(args->timeout_ns), 3757 3758 to_rps_client(file)); 3758 3759
+2
drivers/gpu/drm/i915/i915_request.c
··· 1237 1237 add_wait_queue(errq, &reset); 1238 1238 1239 1239 intel_wait_init(&wait); 1240 + if (flags & I915_WAIT_PRIORITY) 1241 + i915_schedule_bump_priority(rq, I915_PRIORITY_WAIT); 1240 1242 1241 1243 restart: 1242 1244 do {
+3 -2
drivers/gpu/drm/i915/i915_request.h
··· 277 277 __attribute__((nonnull(1))); 278 278 #define I915_WAIT_INTERRUPTIBLE BIT(0) 279 279 #define I915_WAIT_LOCKED BIT(1) /* struct_mutex held, handle GPU reset */ 280 - #define I915_WAIT_ALL BIT(2) /* used by i915_gem_object_wait() */ 281 - #define I915_WAIT_FOR_IDLE_BOOST BIT(3) 280 + #define I915_WAIT_PRIORITY BIT(2) /* small priority bump for the request */ 281 + #define I915_WAIT_ALL BIT(3) /* used by i915_gem_object_wait() */ 282 + #define I915_WAIT_FOR_IDLE_BOOST BIT(4) 282 283 283 284 static inline bool intel_engine_has_started(struct intel_engine_cs *engine, 284 285 u32 seqno);
+28 -6
drivers/gpu/drm/i915/i915_scheduler.c
··· 239 239 return engine; 240 240 } 241 241 242 - void i915_schedule(struct i915_request *rq, const struct i915_sched_attr *attr) 242 + static void __i915_schedule(struct i915_request *rq, 243 + const struct i915_sched_attr *attr) 243 244 { 244 245 struct list_head *uninitialized_var(pl); 245 246 struct intel_engine_cs *engine, *last; ··· 249 248 const int prio = attr->priority; 250 249 LIST_HEAD(dfs); 251 250 251 + /* Needed in order to use the temporary link inside i915_dependency */ 252 + lockdep_assert_held(&schedule_lock); 252 253 GEM_BUG_ON(prio == I915_PRIORITY_INVALID); 253 254 254 255 if (i915_request_completed(rq)) ··· 258 255 259 256 if (prio <= READ_ONCE(rq->sched.attr.priority)) 260 257 return; 261 - 262 - /* Needed in order to use the temporary link inside i915_dependency */ 263 - spin_lock(&schedule_lock); 264 258 265 259 stack.signaler = &rq->sched; 266 260 list_add(&stack.dfs_link, &dfs); ··· 312 312 rq->sched.attr = *attr; 313 313 314 314 if (stack.dfs_link.next == stack.dfs_link.prev) 315 - goto out_unlock; 315 + return; 316 316 317 317 __list_del_entry(&stack.dfs_link); 318 318 } ··· 371 371 } 372 372 373 373 spin_unlock_irq(&engine->timeline.lock); 374 + } 374 375 375 - out_unlock: 376 + void i915_schedule(struct i915_request *rq, const struct i915_sched_attr *attr) 377 + { 378 + spin_lock(&schedule_lock); 379 + __i915_schedule(rq, attr); 376 380 spin_unlock(&schedule_lock); 381 + } 382 + 383 + void i915_schedule_bump_priority(struct i915_request *rq, unsigned int bump) 384 + { 385 + struct i915_sched_attr attr; 386 + 387 + GEM_BUG_ON(bump & ~I915_PRIORITY_MASK); 388 + 389 + if (READ_ONCE(rq->sched.attr.priority) == I915_PRIORITY_INVALID) 390 + return; 391 + 392 + spin_lock_bh(&schedule_lock); 393 + 394 + attr = rq->sched.attr; 395 + attr.priority |= bump; 396 + __i915_schedule(rq, &attr); 397 + 398 + spin_unlock_bh(&schedule_lock); 377 399 }
+5 -2
drivers/gpu/drm/i915/i915_scheduler.h
··· 24 24 I915_PRIORITY_INVALID = INT_MIN 25 25 }; 26 26 27 - #define I915_USER_PRIORITY_SHIFT 1 27 + #define I915_USER_PRIORITY_SHIFT 2 28 28 #define I915_USER_PRIORITY(x) ((x) << I915_USER_PRIORITY_SHIFT) 29 29 30 30 #define I915_PRIORITY_COUNT BIT(I915_USER_PRIORITY_SHIFT) 31 31 #define I915_PRIORITY_MASK (I915_PRIORITY_COUNT - 1) 32 32 33 - #define I915_PRIORITY_NEWCLIENT ((u8)BIT(0)) 33 + #define I915_PRIORITY_WAIT ((u8)BIT(0)) 34 + #define I915_PRIORITY_NEWCLIENT ((u8)BIT(1)) 34 35 35 36 struct i915_sched_attr { 36 37 /** ··· 99 98 100 99 void i915_schedule(struct i915_request *request, 101 100 const struct i915_sched_attr *attr); 101 + 102 + void i915_schedule_bump_priority(struct i915_request *rq, unsigned int bump); 102 103 103 104 struct list_head * 104 105 i915_sched_lookup_priolist(struct intel_engine_cs *engine, int prio);