[Intel-gfx] [PATCH] First stab at implementing batchbuffer queue latency tracking
Ben Gamari
bgamari.foss at gmail.com
Fri May 22 21:51:25 CEST 2009
---
drivers/gpu/drm/Kconfig | 7 ++++
drivers/gpu/drm/i915/i915_drv.h | 31 ++++++++++++++++
drivers/gpu/drm/i915/i915_gem.c | 3 ++
drivers/gpu/drm/i915/i915_gem_debugfs.c | 3 ++
drivers/gpu/drm/i915/i915_irq.c | 59 +++++++++++++++++++++++++++++++
5 files changed, 103 insertions(+), 0 deletions(-)
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index 4cd35d8..3e78973 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -97,6 +97,13 @@ config DRM_I915_KMS
the driver to bind to PCI devices, which precludes loading things
like intelfb.
+config DRM_I915_QUEUE_LATENCY_TRACKING
+ bool "Enable queue latency tracking"
+ depends on DRM_I915
+ help
+ Choose this option if you want to enable queue latency tracking. This
+ is used in identifying GPU stalls
+
endchoice
config DRM_MGA
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 9b149fe..06ddd40 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -126,6 +126,19 @@ struct drm_i915_fence_reg {
struct drm_gem_object *obj;
};
+/**
+ * Request completion structure.
+ *
+ * This structure is used in the request completion ringbuffer, used to track
+ * batchbuffer completion latency.
+ */
+#ifdef CONFIG_DRM_I915_QUEUE_LATENCY_TRACKING
+struct drm_i915_gem_request_completion {
+ uint32_t seqno;
+ struct timeval tv;
+};
+#endif
+
typedef struct drm_i915_private {
struct drm_device *dev;
@@ -380,6 +393,19 @@ typedef struct drm_i915_private {
/* storage for physical objects */
struct drm_i915_gem_phys_object *phys_objs[I915_MAX_PHYS_OBJECT];
+
+#ifdef CONFIG_DRM_I915_QUEUE_LATENCY_TRACKING
+ /**
+ * batchbuffer processing latency
+ * time from emission to beginning of processing
+ */
+ long int batch_latency;
+
+#define I915_COMPLETIONS_LEN 16
+ struct drm_i915_gem_request_completion completions[I915_COMPLETIONS_LEN];
+ int completions_head, completions_tail;
+ struct work_struct completions_work;
+#endif
} mm;
} drm_i915_private_t;
@@ -490,6 +516,11 @@ struct drm_i915_gem_request {
/** Time at which this request was emitted, in jiffies. */
unsigned long emitted_jiffies;
+ /** Time at which this request was emitted */
+#ifdef CONFIG_DRM_I915_QUEUE_LATENCY_TRACKING
+ struct timeval emitted_tv;
+#endif
+
struct list_head list;
};
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index b189b49..05da54e 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -1508,6 +1508,9 @@ i915_add_request(struct drm_device *dev, uint32_t flush_domains)
request->seqno = seqno;
request->emitted_jiffies = jiffies;
+#ifdef CONFIG_DRM_I915_QUEUE_LATENCY_TRACKING
+ do_gettimeofday(&request->emitted_tv);
+#endif
was_empty = list_empty(&dev_priv->mm.request_list);
list_add_tail(&request->list, &dev_priv->mm.request_list);
diff --git a/drivers/gpu/drm/i915/i915_gem_debugfs.c b/drivers/gpu/drm/i915/i915_gem_debugfs.c
index 986f108..84f54e8 100644
--- a/drivers/gpu/drm/i915/i915_gem_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_gem_debugfs.c
@@ -144,6 +144,9 @@ static int i915_gem_seqno_info(struct seq_file *m, void *data)
seq_printf(m, "Waiter sequence: %d\n",
dev_priv->mm.waiting_gem_seqno);
seq_printf(m, "IRQ sequence: %d\n", dev_priv->mm.irq_gem_seqno);
+#ifdef DRM_I915_QUEUE_LATENCY_TRACKING
+ seq_printf(m, "Queue latency: %ld\n", dev_priv->mm.batch_latency);
+#endif
return 0;
}
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 98bb4c8..6fd7c24 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -196,6 +196,52 @@ static void i915_hotplug_work_func(struct work_struct *work)
drm_sysfs_hotplug_event(dev);
}
+#ifdef CONFIG_DRM_I915_QUEUE_LATENCY_TRACKING
+static struct drm_i915_gem_request *i915_gem_find_request(struct drm_device *dev, uint32_t seqno) {
+ drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ struct drm_i915_gem_request *gem_request;
+
+ list_for_each_entry(gem_request, &dev_priv->mm.request_list, list) {
+ if (gem_request->seqno == seqno)
+ return gem_request;
+ }
+ return NULL;
+}
+
+static void i915_mark_request_completed(drm_i915_private_t *dev_priv, int32_t seqno, struct timeval tv) {
+ struct drm_i915_gem_request_completion *completion =
+ &dev_priv->mm.completions[dev_priv->mm.completions_tail];
+
+ if (dev_priv->mm.completions_tail ==
+ (dev_priv->mm.completions_head-1) % I915_COMPLETIONS_LEN)
+ return;
+
+ completion->seqno = seqno;
+ do_gettimeofday(&completion->tv);
+ dev_priv->mm.completions_tail = (dev_priv->mm.completions_tail+1)
+ % I915_COMPLETIONS_LEN;
+}
+
+static void i915_request_completed_work_func(struct work_struct *work)
+{
+ drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t, mm.completions_work);
+
+ while (dev_priv->mm.completions_head != dev_priv->mm.completions_tail) {
+ struct drm_i915_gem_request_completion *completion =
+ &dev_priv->mm.completions[dev_priv->mm.completions_head];
+ struct drm_i915_gem_request *request =
+ i915_gem_find_request(dev_priv->dev, completion->seqno);
+
+ if (request)
+ dev_priv->mm.batch_latency += completion->tv.tv_usec -
+ request->emitted_tv.tv_usec;
+
+ dev_priv->mm.completions_head = (dev_priv->mm.completions_head + 1)
+ % I915_COMPLETIONS_LEN;
+ }
+}
+#endif
+
irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
{
struct drm_device *dev = (struct drm_device *) arg;
@@ -278,8 +324,18 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
}
if (iir & I915_USER_INTERRUPT) {
+#ifdef CONFIG_DRM_I915_QUEUE_LATENCY_TRACKING
+ struct timeval tv;
+#endif
+
dev_priv->mm.irq_gem_seqno = i915_get_gem_seqno(dev);
DRM_WAKEUP(&dev_priv->irq_queue);
+
+#ifdef CONFIG_DRM_I915_QUEUE_LATENCY_TRACKING
+ do_gettimeofday(&tv);
+ i915_mark_request_completed(dev_priv, dev_priv->mm.irq_gem_seqno, tv);
+ schedule_work(&dev_priv->mm.completions_work);
+#endif
}
if (pipea_stats & vblank_status) {
@@ -563,6 +619,9 @@ void i915_driver_irq_preinstall(struct drm_device * dev)
I915_WRITE(IER, 0x0);
(void) I915_READ(IER);
INIT_WORK(&dev_priv->hotplug_work, i915_hotplug_work_func);
+#ifdef CONFIG_DRM_I915_QUEUE_LATENCY_TRACKING
+ INIT_WORK(&dev_priv->mm.completions_work, i915_request_completed_work_func);
+#endif
}
int i915_driver_irq_postinstall(struct drm_device *dev)
--
1.6.2.2
More information about the Intel-gfx
mailing list