From: John.C.Harrison@Intel.com
To: Intel-GFX@Lists.FreeDesktop.Org
Subject: [RFC 31/37] drm/i915/preempt: scheduler logic for landing preemptive requests
Date: Mon, 23 Nov 2015 11:42:06 +0000 [thread overview]
Message-ID: <1448278932-31551-32-git-send-email-John.C.Harrison@Intel.com> (raw)
In-Reply-To: <1448278932-31551-1-git-send-email-John.C.Harrison@Intel.com>
From: Dave Gordon <david.s.gordon@intel.com>
This patch adds the GEM & scheduler logic for detection and first-stage
processing of completed preemption requests. Similar to regular batches,
they deposit their sequence number in the hardware status page when
starting and again when finished, but using different locations so that
information pertaining to a preempted batch is not overwritten. Also,
the in-progress flag is not by the GPU cleared at the end of the batch;
instead driver software is responsible for clearing this once the
request completion has been noticed.
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@intel.com>
---
drivers/gpu/drm/i915/i915_gem.c | 68 ++++++++++++++++++++++++++++++++--
drivers/gpu/drm/i915/i915_scheduler.c | 70 ++++++++++++++++++++++++++---------
drivers/gpu/drm/i915/i915_scheduler.h | 3 +-
3 files changed, 120 insertions(+), 21 deletions(-)
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 55317b1ca..48a57c0 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -2493,6 +2493,14 @@ i915_gem_init_seqno(struct drm_device *dev, u32 seqno)
ring->last_irq_seqno = 0;
}
+ /* Also reset sw batch tracking state */
+ for_each_ring(ring, dev_priv, i) {
+ intel_write_status_page(ring, I915_BATCH_DONE_SEQNO, 0);
+ intel_write_status_page(ring, I915_BATCH_ACTIVE_SEQNO, 0);
+ intel_write_status_page(ring, I915_PREEMPTIVE_DONE_SEQNO, 0);
+ intel_write_status_page(ring, I915_PREEMPTIVE_ACTIVE_SEQNO, 0);
+ }
+
return 0;
}
@@ -2829,6 +2837,7 @@ void i915_gem_request_notify(struct intel_engine_cs *ring, bool fence_locked)
struct drm_i915_gem_request *req, *req_next;
unsigned long flags;
bool wake_sched = false;
+ u32 preempt;
u32 seqno;
if (list_empty(&ring->fence_signal_list)) {
@@ -2836,9 +2845,23 @@ void i915_gem_request_notify(struct intel_engine_cs *ring, bool fence_locked)
return;
}
- seqno = ring->get_seqno(ring, false);
+ seqno = ring->get_seqno(ring, false);
+ preempt = i915_scheduler_is_ring_preempting(ring) ?
+ intel_read_status_page(ring, I915_PREEMPTIVE_ACTIVE_SEQNO) : 0;
trace_i915_gem_request_notify(ring, seqno);
- if (seqno == ring->last_irq_seqno)
+
+ if (preempt) {
+ u32 preempt_done;
+
+ preempt_done = intel_read_status_page(ring, I915_PREEMPTIVE_DONE_SEQNO);
+
+ /* A mismatch indicates an in-progress operation so ignore it for now */
+ if (preempt_done != preempt)
+ preempt = 0;
+ }
+
+ /* Is there anything new to process? */
+ if ((seqno == ring->last_irq_seqno) && !preempt)
return;
ring->last_irq_seqno = seqno;
@@ -2866,7 +2889,7 @@ void i915_gem_request_notify(struct intel_engine_cs *ring, bool fence_locked)
* and call scheduler_clean() while the scheduler
* thinks it is still active.
*/
- wake_sched |= i915_scheduler_notify_request(req);
+ wake_sched |= i915_scheduler_notify_request(req, false);
if (!req->cancelled) {
fence_signal_locked(&req->fence);
@@ -2882,6 +2905,45 @@ void i915_gem_request_notify(struct intel_engine_cs *ring, bool fence_locked)
list_add_tail(&req->unsignal_link, &ring->fence_unsignal_list);
}
+ /*
+ * Note that doing the pre-emption seqno check before acquiring the
+ * spinlock means that there could be multiple request_notify() calls
+ * attempting to process preemption concurrently. The advantage is
+ * not needing to grab the spinlock when there is nothing to do.
+ * The disadvantage is needed to re-check to see if the preemption
+ * event has already been processed.
+ */
+ if (preempt) {
+ u32 preempt_done;
+
+ preempt = intel_read_status_page(ring, I915_PREEMPTIVE_ACTIVE_SEQNO);
+ preempt_done = intel_read_status_page(ring, I915_PREEMPTIVE_DONE_SEQNO);
+
+ /* A mismatch indicates an in-progress operation so ignore it for now */
+ if (preempt_done != preempt)
+ preempt = 0;
+ }
+
+ /* If a (completed) preemption has occurred then process it now. */
+ if (preempt) {
+ bool sched_ack = false;
+
+ list_for_each_entry_safe(req, req_next, &ring->fence_signal_list, signal_link) {
+ if (req->seqno == preempt) {
+ /* De-list and notify the scheduler, but don't signal yet */
+ list_del_init(&req->signal_link);
+ sched_ack = i915_scheduler_notify_request(req, true);
+ break;
+ }
+ }
+
+ WARN_ON(!sched_ack);
+ wake_sched = true;
+
+ /* Acknowledge/clear preemption-active flag */
+ intel_write_status_page(req->ring, I915_PREEMPTIVE_ACTIVE_SEQNO, 0);
+ }
+
if (!fence_locked)
spin_unlock_irqrestore(&ring->fence_lock, flags);
diff --git a/drivers/gpu/drm/i915/i915_scheduler.c b/drivers/gpu/drm/i915/i915_scheduler.c
index a037ba2..0c2344e 100644
--- a/drivers/gpu/drm/i915/i915_scheduler.c
+++ b/drivers/gpu/drm/i915/i915_scheduler.c
@@ -558,40 +558,71 @@ static void i915_scheduler_node_kill(struct i915_scheduler *scheduler,
* then i915_scheduler_wakeup() is called so the scheduler can do further
* processing (submit more work) at the end.
*/
-bool i915_scheduler_notify_request(struct drm_i915_gem_request *req)
+bool i915_scheduler_notify_request(struct drm_i915_gem_request *req,
+ bool preempt)
{
- struct drm_i915_private *dev_priv = to_i915(req->ring->dev);
- struct i915_scheduler *scheduler = dev_priv->scheduler;
+ struct drm_i915_private *dev_priv = req->i915;
+ struct i915_scheduler *scheduler = dev_priv->scheduler;
struct i915_scheduler_queue_entry *node = req->scheduler_qe;
- unsigned long flags;
+ uint32_t ring_id = req->ring->id;
+ unsigned long flags;
+ bool result;
trace_i915_scheduler_landing(req);
- if (!node)
- return false;
-
spin_lock_irqsave(&scheduler->lock, flags);
- WARN_ON(!I915_SQS_IS_FLYING(node));
-
- /* Node was in flight so mark it as complete. */
- if (req->cancelled) {
+ if (!node) {
+ /* Untracked request, presumably ring init */
+ WARN_ON(preempt);
+ WARN_ON(!(req->scheduler_flags & i915_req_sf_untracked));
+ scheduler->stats[ring_id].non_batch_done++;
+ result = false;
+ } else if (WARN(!I915_SQS_IS_FLYING(node), "Node not flying: %d:%d -> %s! [preempt = %d]\n",
+ req->uniq, req->seqno,
+ i915_scheduler_queue_status_str(node->status), preempt)) {
+ /* This shouldn't happen */
+ result = false;
+ } else if (req->cancelled) {
/* If a preemption was in progress, it won't complete now. */
+ // Need to clear I915_PREEMPTIVE_ACTIVE_SEQNO???
if (node->status == i915_sqs_overtaking)
scheduler->flags[req->ring->id] &= ~(i915_sf_preempting|i915_sf_preempted);
node->status = i915_sqs_dead;
scheduler->stats[req->ring->id].kill_flying++;
- } else {
+ result = true;
+ } else if (node->status == i915_sqs_flying) {
+ WARN(preempt, "Got flying node with preemption!\n");
+
+ /* Node was in flight so mark it as complete. */
node->status = i915_sqs_complete;
- scheduler->stats[req->ring->id].completed++;
+ scheduler->stats[ring_id].completed++;
+ result = true;
+ } else if (node->status == i915_sqs_overtaking) {
+ WARN(!preempt, "Got overtaking node without preemption!\n");
+
+ /* Preempting request has completed & becomes preempted */
+ node->status = i915_sqs_preempted;
+ trace_i915_scheduler_unfly(node->params.ring, node);
+
+ /* Scheduler is now in post-preemption state */
+ scheduler->flags[ring_id] |= i915_sf_preempted;
+ scheduler->stats[ring_id].preempts_completed++;
+ result = true;
+ } else {
+ WARN(true, "Unknown node state: %s [%s]!\n",
+ i915_scheduler_queue_status_str(node->status),
+ preempt ? "preempting" : "regular");
+ result = false;
}
- trace_i915_scheduler_node_state_change(req->ring, node);
+ if (result)
+ trace_i915_scheduler_node_state_change(req->ring, node);
spin_unlock_irqrestore(&scheduler->lock, flags);
- return true;
+ return result;
}
/*
@@ -894,11 +925,16 @@ static int i915_scheduler_dump_locked(struct intel_engine_cs *ring, const char *
}
if (scheduler->flags[ring->id] & i915_sf_dump_seqno) {
- uint32_t seqno;
+ uint32_t seqno, b_active, b_done, p_active, p_done;
seqno = ring->get_seqno(ring, true);
+ p_done = intel_read_status_page(ring, I915_PREEMPTIVE_DONE_SEQNO);
+ p_active = intel_read_status_page(ring, I915_PREEMPTIVE_ACTIVE_SEQNO);
+ b_done = intel_read_status_page(ring, I915_BATCH_DONE_SEQNO);
+ b_active = intel_read_status_page(ring, I915_BATCH_ACTIVE_SEQNO);
- DRM_DEBUG_DRIVER("<%s> Seqno = %d\n", ring->name, seqno);
+ DRM_DEBUG_DRIVER("<%s> Seqno = %08x, BD = %08x, BA = %08x, PD = %08x, PA = %08x\n",
+ ring->name, seqno, b_done, b_active, p_done, p_active);
}
if (scheduler->flags[ring->id] & i915_sf_dump_details) {
diff --git a/drivers/gpu/drm/i915/i915_scheduler.h b/drivers/gpu/drm/i915/i915_scheduler.h
index d5f4af3..2ca5433 100644
--- a/drivers/gpu/drm/i915/i915_scheduler.h
+++ b/drivers/gpu/drm/i915/i915_scheduler.h
@@ -191,7 +191,8 @@ int i915_scheduler_closefile(struct drm_device *dev,
struct drm_file *file);
void i915_gem_scheduler_clean_node(struct i915_scheduler_queue_entry *node);
int i915_scheduler_queue_execbuffer(struct i915_scheduler_queue_entry *qe);
-bool i915_scheduler_notify_request(struct drm_i915_gem_request *req);
+bool i915_scheduler_notify_request(struct drm_i915_gem_request *req,
+ bool preempt);
void i915_scheduler_wakeup(struct drm_device *dev);
bool i915_scheduler_is_ring_flying(struct intel_engine_cs *ring);
bool i915_scheduler_is_ring_preempting(struct intel_engine_cs *ring);
--
1.9.1
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx
next prev parent reply other threads:[~2015-11-23 11:42 UTC|newest]
Thread overview: 45+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-11-23 11:41 [RFC 00/37] Preemption support for GPU scheduler John.C.Harrison
2015-11-23 11:41 ` [RFC 01/37] drm/i915: update ring space correctly John.C.Harrison
2015-11-23 11:41 ` [RFC 02/37] drm/i915: recalculate ring space after reset John.C.Harrison
2015-11-23 11:41 ` [RFC 03/37] drm/i915: hangcheck=idle should wake_up_all every time, not just once John.C.Harrison
2015-11-23 11:41 ` [RFC 04/37] drm/i915/error: capture execlist state on error John.C.Harrison
2015-11-23 11:41 ` [RFC 05/37] drm/i915/error: capture ringbuffer pointed to by START John.C.Harrison
2015-11-23 11:41 ` [RFC 06/37] drm/i915/error: report ctx id & desc for each request in the queue John.C.Harrison
2015-11-23 11:41 ` [RFC 07/37] drm/i915/error: improve CSB reporting John.C.Harrison
2015-11-23 11:41 ` [RFC 08/37] drm/i915/error: report size in pages for each object dumped John.C.Harrison
2015-11-23 11:41 ` [RFC 09/37] drm/i915/error: track, capture & print ringbuffer submission activity John.C.Harrison
2015-11-23 11:41 ` [RFC 10/37] drm/i915/guc: Tidy up GuC proc/ctx descriptor setup John.C.Harrison
2015-11-23 11:41 ` [RFC 11/37] drm/i915/guc: Add a second client, to be used for preemption John.C.Harrison
2015-11-23 11:41 ` [RFC 12/37] drm/i915/guc: implement submission via REQUEST_PREEMPTION action John.C.Harrison
2015-11-23 11:41 ` [RFC 13/37] drm/i915/guc: Improve action error reporting, add preemption debug John.C.Harrison
2015-11-23 11:41 ` [RFC 14/37] drm/i915/guc: Expose GuC-maintained statistics John.C.Harrison
2015-11-23 11:41 ` [RFC 15/37] drm/i915: add i915_wait_request() call after i915_add_request_no_flush() John.C.Harrison
2015-11-23 11:41 ` [RFC 16/37] drm/i915/guc: Expose (intel)_lr_context_size() John.C.Harrison
2015-11-23 11:41 ` [RFC 17/37] drm/i915/guc: Add support for GuC ADS (Addition Data Structure) John.C.Harrison
2015-11-23 11:41 ` [RFC 18/37] drm/i915/guc: Fill in (part of?) the ADS whitelist John.C.Harrison
2015-11-23 11:41 ` [RFC 19/37] drm/i915/error: capture errored context based on request context-id John.C.Harrison
2015-11-23 11:41 ` [RFC 20/37] drm/i915/error: enhanced error capture of requests John.C.Harrison
2015-11-23 11:41 ` [RFC 21/37] drm/i915/error: add GuC state error capture & decode John.C.Harrison
2015-11-23 11:41 ` [RFC 22/37] drm/i915: track relative-constants-mode per-context not per-device John.C.Harrison
2015-11-23 11:41 ` [RFC 23/37] drm/i915: set request 'head' on allocation not in add_request() John.C.Harrison
2015-11-23 11:41 ` [RFC 24/37] drm/i915/sched: set request 'head' on at start of ring submission John.C.Harrison
2015-12-11 14:46 ` [RFC 24/38] " John.C.Harrison
2015-11-23 11:42 ` [RFC 25/37] drm/i915/sched: include scheduler state in error capture John.C.Harrison
2015-11-23 11:42 ` [RFC 26/37] drm/i915/preempt: preemption-related definitions and statistics John.C.Harrison
2015-11-23 11:42 ` [RFC 27/37] drm/i915/preempt: scheduler logic for queueing preemptive requests John.C.Harrison
2015-11-23 11:42 ` [RFC 28/37] drm/i915/preempt: scheduler logic for selecting " John.C.Harrison
2015-11-23 11:42 ` [RFC 29/37] drm/i915/preempt: scheduler logic for preventing recursive preemption John.C.Harrison
2015-11-23 11:42 ` [RFC 30/37] drm/i915/preempt: don't allow nonbatch ctx init when the scheduler is busy John.C.Harrison
2015-11-23 11:42 ` John.C.Harrison [this message]
2015-12-11 14:48 ` [RFC 31/38] drm/i915/preempt: scheduler logic for landing preemptive requests John.C.Harrison
2015-11-23 11:42 ` [RFC 32/37] drm/i915/preempt: add hook to catch 'unexpected' ring submissions John.C.Harrison
2015-12-11 14:49 ` [RFC 32/38] " John.C.Harrison
2015-11-23 11:42 ` [RFC 33/37] drm/i915/preempt: Refactor intel_lr_context_reset() John.C.Harrison
2015-11-23 11:42 ` [RFC 34/37] drm/i915/preempt: scheduler logic for postprocessing preemptive requests John.C.Harrison
2015-11-23 11:42 ` [RFC 35/37] drm/i915/preempt: update (LRC) ringbuffer-filling code to create " John.C.Harrison
2015-12-11 14:49 ` [RFC 36/38] " John.C.Harrison
2015-11-23 11:42 ` [RFC 36/37] drm/i915/preempt: update scheduler parameters to enable preemption John.C.Harrison
2015-11-23 11:42 ` [RFC 37/37] drm/i915: Added preemption info to various trace points John.C.Harrison
2015-12-11 14:50 ` [RFC 38/38] " John.C.Harrison
2015-12-11 14:50 ` [RFC 35/38] drm/i915/preempt: Implement mid-batch preemption support John.C.Harrison
2015-12-11 14:50 ` [RFC 00/38] Preemption support for GPU scheduler John.C.Harrison
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1448278932-31551-32-git-send-email-John.C.Harrison@Intel.com \
--to=john.c.harrison@intel.com \
--cc=Intel-GFX@Lists.FreeDesktop.Org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).