From patchwork Fri Dec 11 13:21:10 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Harrison X-Patchwork-Id: 7829701 Return-Path: X-Original-To: patchwork-intel-gfx@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 680E4BEEE1 for ; Fri, 11 Dec 2015 13:21:16 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 2810C20588 for ; Fri, 11 Dec 2015 13:21:15 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by mail.kernel.org (Postfix) with ESMTP id D3A3B2042A for ; Fri, 11 Dec 2015 13:21:13 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 6F9D36EFE7; Fri, 11 Dec 2015 05:21:13 -0800 (PST) X-Original-To: Intel-GFX@lists.freedesktop.org Delivered-To: Intel-GFX@lists.freedesktop.org Received: from mga01.intel.com (mga01.intel.com [192.55.52.88]) by gabe.freedesktop.org (Postfix) with ESMTP id 657CD6EFE7 for ; Fri, 11 Dec 2015 05:21:12 -0800 (PST) Received: from orsmga002.jf.intel.com ([10.7.209.21]) by fmsmga101.fm.intel.com with ESMTP; 11 Dec 2015 05:21:12 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.20,413,1444719600"; d="scan'208";a="869549746" Received: from johnharr-linux.isw.intel.com ([10.102.226.93]) by orsmga002.jf.intel.com with ESMTP; 11 Dec 2015 05:21:11 -0800 From: John.C.Harrison@Intel.com To: Intel-GFX@Lists.FreeDesktop.Org Date: Fri, 11 Dec 2015 13:21:10 +0000 Message-Id: <1449840070-22978-1-git-send-email-John.C.Harrison@Intel.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1448278774-31376-31-git-send-email-John.C.Harrison@Intel.com> References: <1448278774-31376-31-git-send-email-John.C.Harrison@Intel.com> Organization: Intel Corporation (UK) Ltd. - Co. Reg. #1134945 - Pipers Way, Swindon SN3 1RJ Subject: [Intel-gfx] [PATCH 31/40] drm/i915: Added debug state dump facilities to scheduler X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Intel graphics driver community testing & development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: intel-gfx-bounces@lists.freedesktop.org Sender: "Intel-gfx" X-Spam-Status: No, score=-4.2 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, T_RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: John Harrison When debugging batch buffer submission issues, it is useful to be able to see what the current state of the scheduler is. This change adds functions for decoding the internal scheduler state and reporting it. v3: Updated a debug message with the new state_str() function. Change-Id: I0634168e3f3465ff023f5a673165c90b07e535b6 For: VIZ-1587 Signed-off-by: John Harrison --- drivers/gpu/drm/i915/i915_scheduler.c | 280 +++++++++++++++++++++++++++++++++- drivers/gpu/drm/i915/i915_scheduler.h | 14 ++ 2 files changed, 292 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_scheduler.c b/drivers/gpu/drm/i915/i915_scheduler.c index e6e1bd967..be2430d 100644 --- a/drivers/gpu/drm/i915/i915_scheduler.c +++ b/drivers/gpu/drm/i915/i915_scheduler.c @@ -36,6 +36,9 @@ static int i915_scheduler_submit_max_priority(struct intel_engine_cs *ri bool is_locked); static uint32_t i915_scheduler_count_flying(struct i915_scheduler *scheduler, struct intel_engine_cs *ring); +static int i915_scheduler_dump_locked(struct intel_engine_cs *ring, + const char *msg); +static int i915_scheduler_dump_all_locked(struct drm_device *dev, const char *msg); static void i915_scheduler_priority_bump_clear(struct i915_scheduler *scheduler); static int i915_scheduler_priority_bump(struct i915_scheduler *scheduler, struct i915_scheduler_queue_entry *target, @@ -53,6 +56,116 @@ bool i915_scheduler_is_enabled(struct drm_device *dev) return dev_priv->scheduler != NULL; } +const char *i915_qe_state_str(struct i915_scheduler_queue_entry *node) +{ + static char str[50]; + char *ptr = str; + + *(ptr++) = node->bumped ? 'B' : '-', + *(ptr++) = i915_gem_request_completed(node->params.request) ? 'C' : '-'; + + *ptr = 0; + + return str; +} + +char i915_scheduler_queue_status_chr(enum i915_scheduler_queue_status status) +{ + switch (status) { + case i915_sqs_none: + return 'N'; + + case i915_sqs_queued: + return 'Q'; + + case i915_sqs_popped: + return 'X'; + + case i915_sqs_flying: + return 'F'; + + case i915_sqs_complete: + return 'C'; + + case i915_sqs_dead: + return 'D'; + + default: + break; + } + + return '?'; +} + +const char *i915_scheduler_queue_status_str( + enum i915_scheduler_queue_status status) +{ + static char str[50]; + + switch (status) { + case i915_sqs_none: + return "None"; + + case i915_sqs_queued: + return "Queued"; + + case i915_sqs_popped: + return "Popped"; + + case i915_sqs_flying: + return "Flying"; + + case i915_sqs_complete: + return "Complete"; + + case i915_sqs_dead: + return "Dead"; + + default: + break; + } + + sprintf(str, "[Unknown_%d!]", status); + return str; +} + +const char *i915_scheduler_flag_str(uint32_t flags) +{ + static char str[100]; + char *ptr = str; + + *ptr = 0; + +#define TEST_FLAG(flag, msg) \ + do { \ + if (flags & (flag)) { \ + strcpy(ptr, msg); \ + ptr += strlen(ptr); \ + flags &= ~(flag); \ + } \ + } while (0) + + TEST_FLAG(i915_sf_interrupts_enabled, "IntOn|"); + TEST_FLAG(i915_sf_submitting, "Submitting|"); + TEST_FLAG(i915_sf_dump_force, "DumpForce|"); + TEST_FLAG(i915_sf_dump_details, "DumpDetails|"); + TEST_FLAG(i915_sf_dump_dependencies, "DumpDeps|"); + +#undef TEST_FLAG + + if (flags) { + sprintf(ptr, "Unknown_0x%X!", flags); + ptr += strlen(ptr); + } + + if (ptr == str) + strcpy(str, "-"); + else + ptr[-1] = 0; + + return str; +}; + int i915_scheduler_init(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -631,6 +744,169 @@ void i915_gem_scheduler_work_handler(struct work_struct *work) } } +int i915_scheduler_dump_all(struct drm_device *dev, const char *msg) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct i915_scheduler *scheduler = dev_priv->scheduler; + unsigned long flags; + int ret; + + spin_lock_irqsave(&scheduler->lock, flags); + ret = i915_scheduler_dump_all_locked(dev, msg); + spin_unlock_irqrestore(&scheduler->lock, flags); + + return ret; +} + +static int i915_scheduler_dump_all_locked(struct drm_device *dev, const char *msg) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct i915_scheduler *scheduler = dev_priv->scheduler; + struct intel_engine_cs *ring; + int i, r, ret = 0; + + for_each_ring(ring, dev_priv, i) { + scheduler->flags[ring->id] |= i915_sf_dump_force | + i915_sf_dump_details | + i915_sf_dump_dependencies; + r = i915_scheduler_dump_locked(ring, msg); + if (ret == 0) + ret = r; + } + + return ret; +} + +int i915_scheduler_dump(struct intel_engine_cs *ring, const char *msg) +{ + struct drm_i915_private *dev_priv = ring->dev->dev_private; + struct i915_scheduler *scheduler = dev_priv->scheduler; + unsigned long flags; + int ret; + + spin_lock_irqsave(&scheduler->lock, flags); + ret = i915_scheduler_dump_locked(ring, msg); + spin_unlock_irqrestore(&scheduler->lock, flags); + + return ret; +} + +static int i915_scheduler_dump_locked(struct intel_engine_cs *ring, const char *msg) +{ + struct drm_i915_private *dev_priv = ring->dev->dev_private; + struct i915_scheduler *scheduler = dev_priv->scheduler; + struct i915_scheduler_queue_entry *node; + int flying = 0, queued = 0, complete = 0, other = 0; + static int old_flying = -1, old_queued = -1, old_complete = -1; + bool b_dump; + char brkt[2] = { '<', '>' }; + + if (!ring) + return -EINVAL; + + list_for_each_entry(node, &scheduler->node_queue[ring->id], link) { + if (I915_SQS_IS_QUEUED(node)) + queued++; + else if (I915_SQS_IS_FLYING(node)) + flying++; + else if (I915_SQS_IS_COMPLETE(node)) + complete++; + else + other++; + } + + b_dump = (flying != old_flying) || + (queued != old_queued) || + (complete != old_complete); + if (scheduler->flags[ring->id] & i915_sf_dump_force) { + if (!b_dump) { + b_dump = true; + brkt[0] = '{'; + brkt[1] = '}'; + } + + scheduler->flags[ring->id] &= ~i915_sf_dump_force; + } + + if (b_dump) { + old_flying = flying; + old_queued = queued; + old_complete = complete; + DRM_DEBUG_DRIVER("<%s> Q:%02d, F:%02d, C:%02d, O:%02d, " + "Flags = %s, Next = %d:%d %c%s%c\n", + ring->name, queued, flying, complete, other, + i915_scheduler_flag_str(scheduler->flags[ring->id]), + dev_priv->request_uniq, dev_priv->next_seqno, + brkt[0], msg, brkt[1]); + } else { + /*DRM_DEBUG_DRIVER("<%s> Q:%02d, F:%02d, C:%02d, O:%02d" + ", Flags = %s, Next = %d:%d [%s]\n", + ring->name, + queued, flying, complete, other, + i915_scheduler_flag_str(scheduler->flags[ring->id]), + dev_priv->request_uniq, dev_priv->next_seqno, msg); */ + + return 0; + } + + if (scheduler->flags[ring->id] & i915_sf_dump_details) { + int i, deps; + uint32_t count, counts[i915_sqs_MAX]; + + memset(counts, 0x00, sizeof(counts)); + + list_for_each_entry(node, &scheduler->node_queue[ring->id], link) { + if (node->status < i915_sqs_MAX) { + count = counts[node->status]++; + } else { + DRM_DEBUG_DRIVER("<%s> Unknown status: %d!\n", + ring->name, node->status); + count = -1; + } + + deps = 0; + for (i = 0; i < node->num_deps; i++) + if (i915_scheduler_is_dependency_valid(node, i)) + deps++; + + DRM_DEBUG_DRIVER("<%s> %c:%02d> uniq = %d, seqno" + " = %d/%s, deps = %d / %d, fence = %p/%d, %s [pri = " + "%4d]\n", ring->name, + i915_scheduler_queue_status_chr(node->status), + count, + node->params.request->uniq, + node->params.request->seqno, + node->params.ring->name, + deps, node->num_deps, + node->params.fence_wait, + node->params.fence_wait ? sync_fence_is_signaled(node->params.fence_wait) : 0, + i915_qe_state_str(node), + node->priority); + + if ((scheduler->flags[ring->id] & i915_sf_dump_dependencies) + == 0) + continue; + + for (i = 0; i < node->num_deps; i++) + if (node->dep_list[i]) + DRM_DEBUG_DRIVER("<%s> |-%c:" + "%02d%c uniq = %d, seqno = %d/%s, %s [pri = %4d]\n", + ring->name, + i915_scheduler_queue_status_chr(node->dep_list[i]->status), + i, + i915_scheduler_is_dependency_valid(node, i) + ? '>' : '#', + node->dep_list[i]->params.request->uniq, + node->dep_list[i]->params.request->seqno, + node->dep_list[i]->params.ring->name, + i915_qe_state_str(node->dep_list[i]), + node->dep_list[i]->priority); + } + } + + return 0; +} + int i915_scheduler_flush_stamp(struct intel_engine_cs *ring, unsigned long target, bool is_locked) @@ -1199,10 +1475,10 @@ int i915_scheduler_closefile(struct drm_device *dev, struct drm_file *file) continue; if(!I915_SQS_IS_COMPLETE(node)) - DRM_DEBUG_DRIVER("Closing file handle with outstanding work: %d:%d/%d on %s\n", + DRM_DEBUG_DRIVER("Closing file handle with outstanding work: %d:%d/%s on %s\n", node->params.request->uniq, node->params.request->seqno, - node->status, + i915_qe_state_str(node), ring->name); i915_scheduler_file_queue_dec(node->params.file); diff --git a/drivers/gpu/drm/i915/i915_scheduler.h b/drivers/gpu/drm/i915/i915_scheduler.h index 5de0506..1bf2fa6 100644 --- a/drivers/gpu/drm/i915/i915_scheduler.h +++ b/drivers/gpu/drm/i915/i915_scheduler.h @@ -41,6 +41,9 @@ enum i915_scheduler_queue_status { /* Limit value for use with arrays/loops */ i915_sqs_MAX }; +char i915_scheduler_queue_status_chr(enum i915_scheduler_queue_status status); +const char *i915_scheduler_queue_status_str( + enum i915_scheduler_queue_status status); #define I915_SQS_IS_QUEUED(node) (((node)->status == i915_sqs_queued)) #define I915_SQS_IS_FLYING(node) (((node)->status == i915_sqs_flying)) @@ -71,6 +74,7 @@ struct i915_scheduler_queue_entry { struct list_head link; uint32_t flags; }; +const char *i915_qe_state_str(struct i915_scheduler_queue_entry *node); struct i915_scheduler { struct list_head node_queue[I915_NUM_RINGS]; @@ -87,9 +91,16 @@ struct i915_scheduler { /* Flag bits for i915_scheduler::flags */ enum { + /* Internal state */ i915_sf_interrupts_enabled = (1 << 0), i915_sf_submitting = (1 << 1), + + /* Dump/debug flags */ + i915_sf_dump_force = (1 << 8), + i915_sf_dump_details = (1 << 9), + i915_sf_dump_dependencies = (1 << 10), }; +const char *i915_scheduler_flag_str(uint32_t flags); /* Options for 'scheduler_override' module parameter: */ enum { @@ -109,6 +120,9 @@ void i915_gem_scheduler_work_handler(struct work_struct *work); int i915_scheduler_flush(struct intel_engine_cs *ring, bool is_locked); int i915_scheduler_flush_stamp(struct intel_engine_cs *ring, unsigned long stamp, bool is_locked); +int i915_scheduler_dump(struct intel_engine_cs *ring, + const char *msg); +int i915_scheduler_dump_all(struct drm_device *dev, const char *msg); bool i915_scheduler_is_request_tracked(struct drm_i915_gem_request *req, bool *completed, bool *busy); bool i915_scheduler_file_queue_is_full(struct drm_file *file);