[PATCH 34/35] no-timeslice-supression
Chris Wilson
chris at chris-wilson.co.uk
Fri Jun 19 19:17:47 UTC 2020
---
drivers/gpu/drm/i915/gt/intel_engine_types.h | 10 --
drivers/gpu/drm/i915/gt/intel_lrc.c | 157 +++++++------------
2 files changed, 55 insertions(+), 112 deletions(-)
diff --git a/drivers/gpu/drm/i915/gt/intel_engine_types.h b/drivers/gpu/drm/i915/gt/intel_engine_types.h
index 0cc8a29e5572..8f27ac4e4251 100644
--- a/drivers/gpu/drm/i915/gt/intel_engine_types.h
+++ b/drivers/gpu/drm/i915/gt/intel_engine_types.h
@@ -231,16 +231,6 @@ struct intel_engine_execlists {
*/
unsigned int port_mask;
- /**
- * @switch_priority_hint: Second context priority.
- *
- * We submit multiple contexts to the HW simultaneously and would
- * like to occasionally switch between them to emulate timeslicing.
- * To know when timeslicing is suitable, we track the priority of
- * the context submitted second.
- */
- int switch_priority_hint;
-
/**
* @queue_priority_hint: Highest pending priority.
*
diff --git a/drivers/gpu/drm/i915/gt/intel_lrc.c b/drivers/gpu/drm/i915/gt/intel_lrc.c
index 4bfbfafa94c7..eb214f1beb7c 100644
--- a/drivers/gpu/drm/i915/gt/intel_lrc.c
+++ b/drivers/gpu/drm/i915/gt/intel_lrc.c
@@ -1890,40 +1890,6 @@ static void defer_active(struct intel_engine_cs *engine)
defer_request(rq, i915_sched_lookup_priolist(engine, rq_prio(rq)));
}
-static bool
-need_timeslice(const struct intel_engine_cs *engine,
- const struct i915_request *rq,
- const struct virtual_engine *ve)
-{
- int hint;
-
- if (!intel_engine_has_timeslices(engine))
- return false;
-
- hint = engine->execlists.queue_priority_hint;
-
- if (ve) {
- const struct intel_engine_cs *inflight =
- intel_context_inflight(&ve->context);
-
- if (!inflight || inflight == engine) {
- struct i915_request *next;
-
- rcu_read_lock();
- next = READ_ONCE(ve->request);
- if (next)
- hint = max(hint, rq_prio(next));
- rcu_read_unlock();
- }
- }
-
- if (!list_is_last(&rq->sched.link, &engine->active.requests))
- hint = max(hint, rq_prio(list_next_entry(rq, sched.link)));
-
- GEM_BUG_ON(hint >= I915_PRIORITY_UNPREEMPTABLE);
- return hint >= effective_prio(rq);
-}
-
static bool
timeslice_yield(const struct intel_engine_execlists *el,
const struct i915_request *rq)
@@ -1943,78 +1909,75 @@ timeslice_yield(const struct intel_engine_execlists *el,
return rq->context->lrc.ccid == READ_ONCE(el->yield);
}
-static bool
-timeslice_expired(const struct intel_engine_execlists *el,
- const struct i915_request *rq)
+static bool needs_timeslice(const struct intel_engine_cs *engine,
+ const struct i915_request *rq)
{
- return timer_expired(&el->timer) || timeslice_yield(el, rq);
+ /* If not currently active, or about to switch, wait for next event */
+ if (!rq || i915_request_completed(rq))
+ return false;
+
+ /* We do not need to start the timeslice until after the ACK */
+ if (READ_ONCE(engine->execlists.pending[0]))
+ return false;
+
+ /* If ELSP[1] is occupied, always check to see if worth slicing */
+ if (!list_is_last(&rq->sched.link, &engine->active.requests))
+ return true;
+
+ /* Otherwise, ELSP[0] is by itself, but may be waiting in the queue */
+ if (rb_first_cached(&engine->execlists.queue))
+ return true;
+
+ return rb_first_cached(&engine->execlists.virtual);
}
-static int
-switch_prio(struct intel_engine_cs *engine, const struct i915_request *rq)
+static bool
+timeslice_expired(struct intel_engine_cs *engine, const struct i915_request *rq)
{
- if (list_is_last(&rq->sched.link, &engine->active.requests))
- return engine->execlists.queue_priority_hint;
+ const struct intel_engine_execlists *el = &engine->execlists;
- return rq_prio(list_next_entry(rq, sched.link));
+ if (!intel_engine_has_timeslices(engine))
+ return false;
+
+ if (i915_request_has_nopreempt(rq) && i915_request_started(rq))
+ return false;
+
+ if (!needs_timeslice(engine, rq))
+ return false;
+
+ return timer_expired(&el->timer) || timeslice_yield(el, rq);
}
-static inline unsigned long
-timeslice(const struct intel_engine_cs *engine)
+static unsigned long timeslice(const struct intel_engine_cs *engine)
{
return READ_ONCE(engine->props.timeslice_duration_ms);
}
static unsigned long active_timeslice(const struct intel_engine_cs *engine)
{
- const struct intel_engine_execlists *execlists = &engine->execlists;
- const struct i915_request *rq = *execlists->active;
-
- if (!rq || i915_request_completed(rq))
- return 0;
-
- if (READ_ONCE(execlists->switch_priority_hint) < effective_prio(rq))
+ /* Disable the timer if there is nothing to switch to */
+ if (!needs_timeslice(engine, execlists_active(&engine->execlists)))
return 0;
return timeslice(engine);
}
-static void set_timeslice(struct intel_engine_cs *engine)
+static void start_timeslice(struct intel_engine_cs *engine)
{
unsigned long duration;
if (!intel_engine_has_timeslices(engine))
return;
+ if (timer_pending(&engine->execlists.timer))
+ return;
+
duration = active_timeslice(engine);
ENGINE_TRACE(engine, "bump timeslicing, interval:%lu", duration);
set_timer_ms(&engine->execlists.timer, duration);
}
-static void start_timeslice(struct intel_engine_cs *engine, int prio)
-{
- struct intel_engine_execlists *execlists = &engine->execlists;
- unsigned long duration;
-
- if (!intel_engine_has_timeslices(engine))
- return;
-
- WRITE_ONCE(execlists->switch_priority_hint, prio);
- if (prio == INT_MIN)
- return;
-
- if (timer_pending(&execlists->timer))
- return;
-
- duration = timeslice(engine);
- ENGINE_TRACE(engine,
- "start timeslicing, prio:%d, interval:%lu",
- prio, duration);
-
- set_timer_ms(&execlists->timer, duration);
-}
-
static void record_preemption(struct intel_engine_execlists *execlists)
{
(void)I915_SELFTEST_ONLY(execlists->preempt_hang.count++);
@@ -2131,13 +2094,12 @@ static void execlists_dequeue(struct intel_engine_cs *engine)
__unwind_incomplete_requests(engine);
last = NULL;
- } else if (need_timeslice(engine, last, ve) &&
- timeslice_expired(execlists, last)) {
+ } else if (timeslice_expired(engine, last)) {
ENGINE_TRACE(engine,
- "expired last=%llx:%lld, prio=%d, hint=%d, yield?=%s\n",
- last->fence.context,
- last->fence.seqno,
- last->sched.attr.priority,
+ "expired:%s last=%llx:%lld, prio=%d, hint=%d, yield?=%s\n",
+ yesno(timer_expired(&execlists->timer)),
+ last->fence.context, last->fence.seqno,
+ rq_prio(last),
execlists->queue_priority_hint,
yesno(timeslice_yield(execlists, last)));
@@ -2175,7 +2137,6 @@ static void execlists_dequeue(struct intel_engine_cs *engine)
* of timeslices, our queue might be.
*/
spin_unlock_irqrestore(&engine->active.lock, flags);
- start_timeslice(engine, queue_prio(execlists));
return;
}
}
@@ -2204,7 +2165,6 @@ static void execlists_dequeue(struct intel_engine_cs *engine)
if (last && !can_merge_rq(last, rq)) {
spin_unlock(&ve->base.active.lock);
spin_unlock_irqrestore(&engine->active.lock, flags);
- start_timeslice(engine, rq_prio(rq));
return; /* leave this for another sibling */
}
@@ -2378,28 +2338,22 @@ static void execlists_dequeue(struct intel_engine_cs *engine)
execlists->queue_priority_hint = queue_prio(execlists);
spin_unlock_irqrestore(&engine->active.lock, flags);
- if (submit) {
- /*
- * Skip if we ended up with exactly the same set of requests,
- * e.g. trying to timeslice a pair of ordered contexts
- */
- if (!memcmp(active, execlists->pending,
- (port - execlists->pending) * sizeof(*port)))
- goto skip_submit;
-
+ /*
+ * We can skip poking the HW if we ended up with exactly the same set
+ * of requests as currently running, e.g. trying to timeslice a pair
+ * of ordered contexts.
+ */
+ if (submit &&
+ memcmp(active, execlists->pending,
+ (port - execlists->pending) * sizeof(*port))) {
*port = NULL;
while (port-- != execlists->pending)
execlists_schedule_in(*port, port - execlists->pending);
- execlists->switch_priority_hint =
- switch_prio(engine, *execlists->pending);
-
WRITE_ONCE(execlists->yield, -1);
set_preempt_timeout(engine, *active);
execlists_submit_ports(engine);
} else {
- start_timeslice(engine, execlists->queue_priority_hint);
-skip_submit:
ring_set_paused(engine, 0);
while (port-- != execlists->pending)
i915_request_put(*port);
@@ -2653,7 +2607,6 @@ process_csb(struct intel_engine_cs *engine, struct i915_request **inactive)
} while (head != tail);
execlists->csb_head = head;
- set_timeslice(engine);
/*
* Gen11 has proven to fail wrt global observation point between
@@ -3073,6 +3026,7 @@ static void execlists_submission_tasklet(unsigned long data)
execlists_dequeue(engine);
post_process_csb(post, inactive);
+ start_timeslice(engine);
}
static void __execlists_kick(struct intel_engine_execlists *execlists)
@@ -3145,6 +3099,8 @@ static void execlists_submit_request(struct i915_request *request)
}
spin_unlock_irqrestore(&engine->active.lock, flags);
+
+ start_timeslice(engine);
}
static void __execlists_context_fini(struct intel_context *ce)
@@ -5819,9 +5775,6 @@ void intel_execlists_show_requests(struct intel_engine_cs *engine,
show_request(m, last, "\t\tE ");
}
- if (execlists->switch_priority_hint != INT_MIN)
- drm_printf(m, "\t\tSwitch priority hint: %d\n",
- READ_ONCE(execlists->switch_priority_hint));
if (execlists->queue_priority_hint != INT_MIN)
drm_printf(m, "\t\tQueue priority hint: %d\n",
READ_ONCE(execlists->queue_priority_hint));
--
2.20.1
More information about the Intel-gfx-trybot
mailing list