[Intel-gfx] [RFC 28/37] drm/i915/preempt: scheduler logic for selecting preemptive requests
John.C.Harrison at Intel.com
John.C.Harrison at Intel.com
Mon Nov 23 03:42:03 PST 2015
From: Dave Gordon <david.s.gordon at intel.com>
This patch adds the scheduler logic for managing potentially preemptive
requests, including validating dependencies and working out when a
request can be downgraded to non-preemptive (e.g. when there's nothing
ahead for it to preempt).
Actually-preemptive requests are still disabled via a module parameter
at this early stage, as the rest of the logic to deal with the
consequences of preemption isn't in place yet.
For: VIZ-2021
Signed-off-by: Dave Gordon <david.s.gordon at intel.com>
---
drivers/gpu/drm/i915/i915_scheduler.c | 76 ++++++++++++++++++++++++++++-------
1 file changed, 61 insertions(+), 15 deletions(-)
diff --git a/drivers/gpu/drm/i915/i915_scheduler.c b/drivers/gpu/drm/i915/i915_scheduler.c
index 50ff8b7..61eabc6 100644
--- a/drivers/gpu/drm/i915/i915_scheduler.c
+++ b/drivers/gpu/drm/i915/i915_scheduler.c
@@ -498,6 +498,9 @@ static inline bool i915_scheduler_is_dependency_valid(
if (I915_SQS_IS_FLYING(dep)) {
if (node->params.ring != dep->params.ring)
return true;
+
+ if (node->params.request->scheduler_flags & i915_req_sf_preempt)
+ return true;
}
return false;
@@ -1317,10 +1320,11 @@ static int i915_scheduler_pop_from_queue_locked(struct intel_engine_cs *ring,
struct i915_scheduler_queue_entry *best_wait, *fence_wait = NULL;
struct i915_scheduler_queue_entry *best;
struct i915_scheduler_queue_entry *node;
+ struct drm_i915_gem_request *req;
int ret;
int i;
bool signalled, any_queued;
- bool has_local, has_remote, only_remote;
+ bool has_local, has_remote, only_remote, local_preempt_only;
*pop_node = NULL;
ret = -ENODATA;
@@ -1346,18 +1350,40 @@ static int i915_scheduler_pop_from_queue_locked(struct intel_engine_cs *ring,
scheduler->stats[node->params.ring->id].fence_ignore++;
}
+ /* Attempt to re-enable pre-emption if a node wants to pre-empt
+ * but previously got downgraded. */
+ req = node->params.request;
+ if (req->scheduler_flags & i915_req_sf_was_preempt)
+ req->scheduler_flags |= i915_req_sf_preempt;
+
has_local = false;
has_remote = false;
+ local_preempt_only = (req->scheduler_flags & i915_req_sf_preempt) != 0;
for (i = 0; i < node->num_deps; i++) {
if (!i915_scheduler_is_dependency_valid(node, i))
continue;
- if (node->dep_list[i]->params.ring == node->params.ring)
+ if (node->dep_list[i]->params.ring == node->params.ring) {
has_local = true;
- else
+
+ if (local_preempt_only) {
+ req->scheduler_flags &= ~i915_req_sf_preempt;
+ if (i915_scheduler_is_dependency_valid(node, i))
+ local_preempt_only = false;
+ req->scheduler_flags |= i915_req_sf_preempt;
+ }
+ } else
has_remote = true;
}
+ if (has_local && local_preempt_only) {
+ /* If a preemptive node's local dependencies are all
+ * flying, then they can be ignored by un-preempting
+ * the node. */
+ req->scheduler_flags &= ~i915_req_sf_preempt;
+ has_local = false;
+ }
+
if (has_remote && !has_local)
only_remote = true;
@@ -1447,6 +1473,7 @@ static int i915_scheduler_submit(struct intel_engine_cs *ring, bool was_locked)
struct drm_i915_private *dev_priv = dev->dev_private;
struct i915_scheduler *scheduler = dev_priv->scheduler;
struct i915_scheduler_queue_entry *node;
+ struct drm_i915_gem_request *req;
unsigned long flags;
int ret = 0, count = 0;
@@ -1462,14 +1489,8 @@ static int i915_scheduler_submit(struct intel_engine_cs *ring, bool was_locked)
/* First time around, complain if anything unexpected occurs: */
ret = i915_scheduler_pop_from_queue_locked(ring, &node, &flags);
- if (ret) {
- spin_unlock_irqrestore(&scheduler->lock, flags);
-
- if (!was_locked)
- mutex_unlock(&dev->struct_mutex);
-
- return ret;
- }
+ if (ret)
+ goto exit;
do {
BUG_ON(!node);
@@ -1477,6 +1498,30 @@ static int i915_scheduler_submit(struct intel_engine_cs *ring, bool was_locked)
BUG_ON(node->status != i915_sqs_popped);
count++;
+ req = node->params.request;
+ if (req->scheduler_flags & i915_req_sf_preempt) {
+ struct i915_scheduler_queue_entry *fly;
+ bool got_flying = false;
+
+ list_for_each_entry(fly, &scheduler->node_queue[ring->id], link) {
+ if (!I915_SQS_IS_FLYING(fly))
+ continue;
+
+ got_flying = true;
+ if (fly->priority >= node->priority) {
+ /* Already working on something at least
+ * as important, so don't interrupt it. */
+ req->scheduler_flags &= ~i915_req_sf_preempt;
+ break;
+ }
+ }
+
+ if (!got_flying) {
+ /* Nothing to preempt so don't bother. */
+ req->scheduler_flags &= ~i915_req_sf_preempt;
+ }
+ }
+
/* The call to pop above will have removed the node from the
* list. So add it back in and mark it as in flight. */
i915_scheduler_fly_node(node);
@@ -1545,6 +1590,10 @@ static int i915_scheduler_submit(struct intel_engine_cs *ring, bool was_locked)
ret = i915_scheduler_pop_from_queue_locked(ring, &node, &flags);
} while (ret == 0);
+ /* Don't complain about not being able to submit extra entries */
+ if (ret == -ENODATA)
+ ret = 0;
+
/*
* Bump the priority of everything that was not submitted to prevent
* starvation of low priority tasks by a spamming high priority task.
@@ -1558,15 +1607,12 @@ static int i915_scheduler_submit(struct intel_engine_cs *ring, bool was_locked)
scheduler->priority_level_bump);
}
+exit:
spin_unlock_irqrestore(&scheduler->lock, flags);
if (!was_locked)
mutex_unlock(&dev->struct_mutex);
- /* Don't complain about not being able to submit extra entries */
- if (ret == -ENODATA)
- ret = 0;
-
return (ret < 0) ? ret : count;
}
--
1.9.1
More information about the Intel-gfx
mailing list