[PATCH 10/18] drm/i915: Add stats for GuC log buffer flush interrupts

akash.goel
2016-08-15T14:36:36Z

From: Akash Goel <akash.goel@intel.com>

GuC firmware sends an interrupt to flush the log buffer when it
becomes half full. GuC firmware also tracks how many times the
buffer overflowed.
It would be useful to maintain a statistics of how many flush
interrupts were received and for which type of log buffer,
along with the overflow count of each buffer type.
Augmented i915_log_info debugfs to report back these statistics.

v2:
- Update the logic to detect multiple overflows between the 2
flush interrupts and also log a message for overflow (Tvrtko)
- Track the number of times there was no free sub buffer to capture
the GuC log buffer. (Tvrtko)

v3:
- Fix the printf field width for overflow counter, set it to 10 as per the
max value of u32, which takes 10 digits in decimal form. (Tvrtko)

Signed-off-by: Akash Goel <akash.goel@intel.com>
Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
---
drivers/gpu/drm/i915/i915_debugfs.c | 28 ++++++++++++++++++++++++++++
drivers/gpu/drm/i915/i915_guc_submission.c | 20 ++++++++++++++++++++
drivers/gpu/drm/i915/i915_irq.c | 2 ++
drivers/gpu/drm/i915/intel_guc.h | 7 +++++++
4 files changed, 57 insertions(+)

diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index b2cfcf4..aaa51bc 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -2491,6 +2491,32 @@ static int i915_guc_load_status_info(struct seq_file *m, void *data)
return 0;
}

+static void i915_guc_log_info(struct seq_file *m,
+ struct drm_i915_private *dev_priv)
+{
+ struct intel_guc *guc = &dev_priv->guc;
+
+ seq_puts(m, "\nGuC logging stats:\n");
+
+ seq_printf(m, "\tISR: flush count %10u, overflow count %10u\n",
+ guc->log.flush_count[GUC_ISR_LOG_BUFFER],
+ guc->log.total_overflow_count[GUC_ISR_LOG_BUFFER]);
+
+ seq_printf(m, "\tDPC: flush count %10u, overflow count %10u\n",
+ guc->log.flush_count[GUC_DPC_LOG_BUFFER],
+ guc->log.total_overflow_count[GUC_DPC_LOG_BUFFER]);
+
+ seq_printf(m, "\tCRASH: flush count %10u, overflow count %10u\n",
+ guc->log.flush_count[GUC_CRASH_DUMP_LOG_BUFFER],
+ guc->log.total_overflow_count[GUC_CRASH_DUMP_LOG_BUFFER]);
+
+ seq_printf(m, "\tTotal flush interrupt count: %u\n",
+ guc->log.flush_interrupt_count);
+
+ seq_printf(m, "\tCapture miss count: %u\n",
+ guc->log.capture_miss_count);
+}
+
static void i915_guc_client_info(struct seq_file *m,
struct drm_i915_private *dev_priv,
struct i915_guc_client *client)
@@ -2565,6 +2591,8 @@ static int i915_guc_info(struct seq_file *m, void *data)
seq_printf(m, "\nGuC execbuf client @ %p:\n", guc.execbuf_client);
i915_guc_client_info(m, dev_priv, &client);

+ i915_guc_log_info(m, dev_priv);
+
/* Add more as required ... */

return 0;
diff --git a/drivers/gpu/drm/i915/i915_guc_submission.c b/drivers/gpu/drm/i915/i915_guc_submission.c
index f4c5846..c7b4a57 100644
--- a/drivers/gpu/drm/i915/i915_guc_submission.c
+++ b/drivers/gpu/drm/i915/i915_guc_submission.c
@@ -1026,6 +1026,25 @@ static void guc_read_update_log_buffer(struct intel_guc *guc)
sizeof(struct guc_log_buffer_state));
buffer_size = log_buffer_state_local.size;

+ /* Bookkeeping stuff */
+ guc->log.flush_count[type] += log_buffer_state_local.flush_to_file;
+ if (log_buffer_state_local.buffer_full_cnt !=
+ guc->log.prev_overflow_count[type]) {
+ guc->log.total_overflow_count[type] +=
+ (log_buffer_state_local.buffer_full_cnt -
+ guc->log.prev_overflow_count[type]);
+
+ if (log_buffer_state_local.buffer_full_cnt <
+ guc->log.prev_overflow_count[type]) {
+ /* buffer_full_cnt is a 4 bit counter */
+ guc->log.total_overflow_count[type] += 16;
+ }
+
+ guc->log.prev_overflow_count[type] =
+ log_buffer_state_local.buffer_full_cnt;
+ DRM_ERROR_RATELIMITED("GuC log buffer overflow\n");
+ }
+
if (log_buffer_snapshot_state) {
/* First copy the state structure in snapshot buffer */
memcpy(log_buffer_snapshot_state, &log_buffer_state_local,
@@ -1084,6 +1103,7 @@ static void guc_read_update_log_buffer(struct intel_guc *guc)
* getting consumed by User at a slow rate.
*/
DRM_ERROR_RATELIMITED("no sub-buffer to capture log buffer\n");
+ guc->log.capture_miss_count++;
}
}

diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 7e43d7d..09c1260 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -1691,6 +1691,8 @@ static void gen9_guc_irq_handler(struct drm_i915_private *dev_priv, u32 gt_iir)
/* Handle flush interrupt in bottom half */
queue_work(dev_priv->guc.log.flush_wq,
&dev_priv->guc.log.flush_work);
+
+ dev_priv->guc.log.flush_interrupt_count++;
} else {
/* Not clearing of unhandled event bits won't
* result in re-triggering of the interrupt.
diff --git a/drivers/gpu/drm/i915/intel_guc.h b/drivers/gpu/drm/i915/intel_guc.h
index 1704495..8598f38 100644
--- a/drivers/gpu/drm/i915/intel_guc.h
+++ b/drivers/gpu/drm/i915/intel_guc.h
@@ -128,6 +128,13 @@ struct intel_guc_log {
struct workqueue_struct *flush_wq;
struct work_struct flush_work;
struct rchan *relay_chan;
+
+ /* logging related stats */
+ u32 capture_miss_count;
+ u32 flush_interrupt_count;
+ u32 prev_overflow_count[GUC_MAX_LOG_BUFFER];
+ u32 total_overflow_count[GUC_MAX_LOG_BUFFER];
+ u32 flush_count[GUC_MAX_LOG_BUFFER];
};

struct intel_guc {
--
1.9.2