[PATCH 15/15] drm/i915: Add handling for batch parameters in debugfs

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Module parameter only allows default high/low watermarks when batch scheduling.
Here we introduce some new debugfs parsing to allow settings per pid.

This patch is a bit more than just handling batch params as the code turned out
quite ugly as a result. So a bit of cleaning up happens here too, and ideally
it would be split out into another commit.

Here are some usage examples:
Set the globally fair scheduler
echo "type=fair,high=10,low=2" > /sys/kernel/debug/dri/0/i915_scheduler

Turn off scheduling
echo "type=none" > /sys/kernel/debug/dri/0/i915_scheduler

Set high watermark of 10, an low of 2 for pid 16603
echo "pidh=16603-10,pidl=16603,2"> /sys/kernel/debug/dri/0/i915_scheduler

Change scheduler to batch scheduler
echo "type=batch" > /sys/kernel/debug/dri/0/i915_scheduler

Set high watermark of 5, an low of 0 while already running batch sched
echo "pidh=16603-5,pidl=16603,0"> /sys/kernel/debug/dri/0/i915_scheduler

Signed-off-by: Ben Widawsky <ben at bwidawsk.net>
---
 drivers/gpu/drm/i915/i915_debugfs.c |  152 +++++++++++++++++++++++++++--------
 1 files changed, 117 insertions(+), 35 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index 903a004..f4c44fa 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -1544,7 +1544,7 @@ static const struct file_operations i915_cache_sharing_fops = {
 };
 
 static const char *sched_type[I915_SCHEDULER_INVALID] =
-	{"none", "fair"};
+	{"none", "fair", "batch"};
 
 static ssize_t
 i915_sched_read(struct file *filp,
@@ -1555,7 +1555,7 @@ i915_sched_read(struct file *filp,
 	struct drm_device *dev = filp->private_data;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct drm_i915_file_private *temp;
-	unsigned high, low, type;
+	unsigned type;
 	size_t len = 0;
 	char *buf, *buf2;
 	struct {
@@ -1572,14 +1572,19 @@ i915_sched_read(struct file *filp,
 		return ret;
 
 	type = dev_priv->scheduler.type;
-	high = dev_priv->scheduler.high_watermark;
-	low = dev_priv->scheduler.low_watermark;
 	list_for_each_entry(temp, &dev_priv->i915_client_list, client_link) {
 		struct drm_file *file = temp->drm_file;
 		requests[i].pid = file->pid;
 		spin_lock(&temp->lock);
 		requests[i].outstanding = temp->outstanding_requests;
 		requests[i].forced = temp->forced_throttles;
+		if (type == I915_SCHEDULER_BATCH) {
+			requests[i].high = temp->high_watermark;
+			requests[i].low = temp->low_watermark;
+		} else {
+			requests[i].high = dev_priv->scheduler.high_watermark;
+			requests[i].low = dev_priv->scheduler.low_watermark;
+		}
 		spin_unlock(&temp->lock);
 		i++;
 	}
@@ -1587,21 +1592,22 @@ i915_sched_read(struct file *filp,
 
 	entries = i;
 
-	entry_size = strlen("pid 123456 = XXXX outstanding (XXXXXX forced)\n") + 1;
+	entry_size = strlen("pid 123456 = XXXX outstanding (XXXXXX forced) "
+			    "h=XXXX l=YYYY\n") + 1;
 	buf2 = drm_malloc_ab(entries, entry_size);
 	memset(buf2, 0, entries * entry_size);
 	for(i = 0; i < entries; i++) {
 		len += sprintf(buf2 + len,
-			       "pid %06d = %06d outstanding (%06d forced)\n",
+			       "pid %06d = %06d outstanding (%06d forced) "
+			       "h=%04d l=%04d\n",
 				requests[i].pid, requests[i].outstanding,
-				requests[i].forced);
+				requests[i].forced, requests[i].high,
+				requests[i].low);
 	}
 
 	buf = kasprintf(GFP_KERNEL, "%s\n"
-				    "Scheduler = %s\n"
-				    "High watermark = %d buffers\n"
-				    "Low watermark = %d buffers\n",
-				     buf2, sched_type[type], high, low);
+				    "Scheduler = %s\n",
+				    buf2, sched_type[type]);
 
 	len = strlen(buf);
 
@@ -1612,6 +1618,49 @@ i915_sched_read(struct file *filp,
 	return ret;
 }
 
+static inline void
+test_and_do_idle(struct drm_device *dev, bool *change)
+{
+	if (*change == false && i915_gpu_idle(dev))
+		DRM_ERROR("Couldn't idle GPU before sched changes\n");
+
+	*change = true;
+}
+
+static void
+set_new_water(struct drm_device *dev, pid_t pid, uint32_t watermark, bool high,
+	      bool *change)
+{
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct drm_i915_file_private *temp;
+
+	list_for_each_entry(temp, &dev_priv->i915_client_list, client_link) {
+		struct drm_file *file = temp->drm_file;
+		if (file->pid == pid) {
+			uint32_t old = 0;
+			if (high) {
+				old = temp->high_watermark;
+				if (old != watermark) {
+					temp->high_watermark = watermark;
+					test_and_do_idle(dev, change);
+					DRM_INFO("New high watermark for pid "
+						 "%d = %d\n", pid, watermark);
+				}
+				break;
+			} else {
+				old = temp->low_watermark;
+				if (old != watermark) {
+					temp->low_watermark = watermark;
+					test_and_do_idle(dev, change);
+					DRM_INFO("New low watermark for pid "
+						 "%d = %d\n", pid, watermark);
+				}
+				break;
+			}
+		}
+	}
+}
+
 static ssize_t
 i915_sched_write(struct file *filp,
 		 const char __user *ubuf,
@@ -1622,59 +1671,92 @@ i915_sched_write(struct file *filp,
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	char *buf, *ptr;
 	uint32_t high, low, type;
-	int ret;
+	bool change = false;
 
 	buf = drm_malloc_ab(cnt + 1, 1);
 	if (!buf)
 		return -E2BIG;
 
-	ret = copy_from_user(buf, ubuf, cnt);
-	if (ret)
+	if (copy_from_user(buf, ubuf, cnt))
 		goto out;
 
-	ret = mutex_lock_interruptible(&dev->struct_mutex);
-	if (ret)
-		return ret;
+	if (mutex_lock_interruptible(&dev->struct_mutex))
+		goto out;
 
-	low = dev_priv->scheduler.low_watermark;
-	high = dev_priv->scheduler.high_watermark;
 	type = dev_priv->scheduler.type;
 
 	buf[cnt] = 0;
 	ptr = buf;
 
+	/* type=[none, fair, batch]
+	 * pidh=[pid]-[new high watermark]
+	 * pidl=[pid]-[new low watermark]
+	 * low=[new fair low watermark]
+	 * high=[new fair high watermark]
+	 */
 	while ((ptr != NULL) && *ptr != 0) {
 		if (!strncmp(ptr, "type=", 5)) {
 			char *tmp = strchr(ptr, '=');
 			if (tmp != NULL)
 				tmp += strspn(tmp, "= \t\n");
+			else
+				break;
+
 			if (!strncmp("fair", tmp, 4))
 				type = I915_SCHEDULER_FAIR;
+			if (!strncmp("batch", tmp, 5))
+				type = I915_SCHEDULER_BATCH;
 			if (!strncmp("none", tmp, 4))
 				type = I915_SCHEDULER_NONE;
-		}
-		if (!strncmp(ptr, "high=", 5))
+
+			if (dev_priv->scheduler.type != type) {
+				test_and_do_idle(dev, &change);
+				dev_priv->scheduler.type = type;
+				DRM_INFO("New scheduler type = %s\n",
+					 sched_type[type]);
+			}
+		} else if (!strncmp(ptr, "high=", 5)) {
 			high = simple_strtoul(ptr + 5, NULL, 0);
-		if (!strncmp(ptr, "low=", 4))
+			if (dev_priv->scheduler.high_watermark != high) {
+				test_and_do_idle(dev, &change);
+				dev_priv->scheduler.high_watermark = high;
+				DRM_INFO("New high watermark (fair) = %d\n",
+					 high);
+			}
+		} else if (!strncmp(ptr, "low=", 4)) {
 			low = simple_strtoul(ptr + 4, NULL, 0);
+			if (dev_priv->scheduler.low_watermark != low) {
+				test_and_do_idle(dev, &change);
+				dev_priv->scheduler.low_watermark = low;
+				DRM_INFO("New low watermark (fair) = %d\n",
+					 low);
+			}
+		} else if (!strncmp(ptr, "pidh=", 5)) {
+			pid_t pid = simple_strtoul(ptr + 5, NULL, 10);
+			ptr = strchr(ptr, '-');
+			if (ptr != NULL && ptr[1] != 0) {
+				high = simple_strtoul(ptr+1, NULL, 10);
+				set_new_water(dev, pid, high, true, &change);
+			} else if (ptr == NULL)
+				break;
+		} else if (!strncmp(ptr, "pidl=", 5)) {
+			pid_t pid = simple_strtoul(ptr + 5, NULL, 10);
+			ptr = strchr(ptr, '-');
+			if (ptr != NULL && ptr[1] != 0) {
+				low = simple_strtoul(ptr+1, NULL, 10);
+				set_new_water(dev, pid, low, false, &change);
+			} else if (ptr == NULL)
+				break;
+		} else {
+			/* Assume the whole string is busted, and gtfo */
+			DRM_ERROR("Unable to parse command %s\n", ptr);
+			break;
+		}
 		ptr = strchr(ptr, ',');
 		if (ptr != NULL)
 			ptr += strspn(ptr, ", \t\n");
 	}
 
-	if (high != dev_priv->scheduler.high_watermark ||
-	    (low != dev_priv->scheduler.low_watermark) ||
-	    (type != dev_priv->scheduler.type)) {
-		if (i915_gpu_idle(dev))
-			DRM_ERROR("Couldn't idle GPU before sched changes\n");
-		DRM_INFO("new type = %d\n", type);
-		DRM_INFO("new high = %d\n", high);
-		DRM_INFO("new low = %d\n", low);
-		dev_priv->scheduler.high_watermark = high;
-		dev_priv->scheduler.low_watermark = low;
-		dev_priv->scheduler.type = type;
-	}
-
 	mutex_unlock(&dev->struct_mutex);
 out:
 	drm_free_large(buf);
-- 
1.7.7.3



[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]
  Powered by Linux