[Intel-gfx] [PATCH 15/15] drm/i915: Add handling for batch parameters in debugfs
Ben Widawsky
ben at bwidawsk.net
Sat Nov 19 03:24:32 CET 2011
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
More information about the Intel-gfx
mailing list