[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