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 <b...@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

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

Reply via email to