Re: [Intel-gfx] [PATCH v4] drm/i915/selftests: Exercise context switching in parallel

2019-09-30 Thread Tvrtko Ursulin


On 30/09/2019 15:49, Chris Wilson wrote:

We currently test context switching on each engine as a basic stress
test (just verifying that nothing explodes if we execute 2 requests from
different contexts sequentially). What we have not tested is what
happens if we try and do so on all available engines simultaneously,
putting our SW and the HW under the maximal stress.

v2: Clone the set of engines from the first context into the secondary
contexts.

Signed-off-by: Chris Wilson 
Cc: Mika Kuoppala 
Cc: Tvrtko Ursulin 
---
  .../drm/i915/gem/selftests/i915_gem_context.c | 225 ++
  1 file changed, 225 insertions(+)

diff --git a/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c 
b/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c
index dc25bcc3e372..81a83c34404c 100644
--- a/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c
@@ -156,6 +156,230 @@ static int live_nop_switch(void *arg)
return err;
  }
  
+struct parallel_switch {

+   struct task_struct *tsk;
+   struct intel_context *ce[2];
+};
+
+static int __live_parallel_switch1(void *data)
+{
+   struct parallel_switch *arg = data;
+   struct drm_i915_private *i915 = arg->ce[0]->engine->i915;
+   IGT_TIMEOUT(end_time);
+   unsigned long count;
+
+   count = 0;
+   do {
+   struct i915_request *rq = NULL;
+   int err, n;
+
+   for (n = 0; n < ARRAY_SIZE(arg->ce); n++) {
+   i915_request_put(rq);
+
+   mutex_lock(>drm.struct_mutex);
+   rq = i915_request_create(arg->ce[n]);
+   if (IS_ERR(rq)) {
+   mutex_unlock(>drm.struct_mutex);
+   return PTR_ERR(rq);
+   }
+
+   i915_request_get(rq);
+   i915_request_add(rq);
+   mutex_unlock(>drm.struct_mutex);
+   }
+
+   err = 0;
+   if (i915_request_wait(rq, 0, HZ / 5) < 0)
+   err = -ETIME;
+   i915_request_put(rq);
+   if (err)
+   return err;
+
+   count++;
+   } while (!__igt_timeout(end_time, NULL));
+
+   pr_info("%s: %lu switches (sync)\n", arg->ce[0]->engine->name, count);
+   return 0;
+}
+
+static int __live_parallel_switchN(void *data)
+{
+   struct parallel_switch *arg = data;
+   struct drm_i915_private *i915 = arg->ce[0]->engine->i915;
+   IGT_TIMEOUT(end_time);
+   unsigned long count;
+   int n;
+
+   count = 0;
+   do {
+   for (n = 0; n < ARRAY_SIZE(arg->ce); n++) {
+   struct i915_request *rq;
+
+   mutex_lock(>drm.struct_mutex);
+   rq = i915_request_create(arg->ce[n]);
+   if (IS_ERR(rq)) {
+   mutex_unlock(>drm.struct_mutex);
+   return PTR_ERR(rq);
+   }
+
+   i915_request_add(rq);
+   mutex_unlock(>drm.struct_mutex);
+   }
+
+   count++;
+   } while (!__igt_timeout(end_time, NULL));
+
+   pr_info("%s: %lu switches (many)\n", arg->ce[0]->engine->name, count);
+   return 0;
+}
+
+static int live_parallel_switch(void *arg)
+{
+   struct drm_i915_private *i915 = arg;
+   static int (* const func[])(void *arg) = {
+   __live_parallel_switch1,
+   __live_parallel_switchN,
+   NULL,
+   };
+   struct parallel_switch *data = NULL;
+   struct i915_gem_engines *engines;
+   struct i915_gem_engines_iter it;
+   int (* const *fn)(void *arg);
+   struct i915_gem_context *ctx;
+   struct intel_context *ce;
+   struct drm_file *file;
+   int n, m, count;
+   int err = 0;
+
+   /*
+* Check we can process switches on all engines simultaneously.
+*/
+
+   if (!DRIVER_CAPS(i915)->has_logical_contexts)
+   return 0;
+
+   file = mock_file(i915);
+   if (IS_ERR(file))
+   return PTR_ERR(file);
+
+   mutex_lock(>drm.struct_mutex);
+
+   ctx = live_context(i915, file);
+   if (IS_ERR(ctx)) {
+   err = PTR_ERR(ctx);
+   goto out_locked;
+   }
+
+   engines = i915_gem_context_lock_engines(ctx);
+   count = engines->num_engines;
+
+   data = kcalloc(count, sizeof(*data), GFP_KERNEL);
+   if (!data) {
+   i915_gem_context_unlock_engines(ctx);
+   err = -ENOMEM;
+   goto out_locked;
+   }
+
+   m = 0; /* Use the first context as our template for the engines */
+   for_each_gem_engine(ce, engines, it) {
+   err = intel_context_pin(ce);
+   if (err) {
+   

[Intel-gfx] [PATCH v4] drm/i915/selftests: Exercise context switching in parallel

2019-09-30 Thread Chris Wilson
We currently test context switching on each engine as a basic stress
test (just verifying that nothing explodes if we execute 2 requests from
different contexts sequentially). What we have not tested is what
happens if we try and do so on all available engines simultaneously,
putting our SW and the HW under the maximal stress.

v2: Clone the set of engines from the first context into the secondary
contexts.

Signed-off-by: Chris Wilson 
Cc: Mika Kuoppala 
Cc: Tvrtko Ursulin 
---
 .../drm/i915/gem/selftests/i915_gem_context.c | 225 ++
 1 file changed, 225 insertions(+)

diff --git a/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c 
b/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c
index dc25bcc3e372..81a83c34404c 100644
--- a/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c
@@ -156,6 +156,230 @@ static int live_nop_switch(void *arg)
return err;
 }
 
+struct parallel_switch {
+   struct task_struct *tsk;
+   struct intel_context *ce[2];
+};
+
+static int __live_parallel_switch1(void *data)
+{
+   struct parallel_switch *arg = data;
+   struct drm_i915_private *i915 = arg->ce[0]->engine->i915;
+   IGT_TIMEOUT(end_time);
+   unsigned long count;
+
+   count = 0;
+   do {
+   struct i915_request *rq = NULL;
+   int err, n;
+
+   for (n = 0; n < ARRAY_SIZE(arg->ce); n++) {
+   i915_request_put(rq);
+
+   mutex_lock(>drm.struct_mutex);
+   rq = i915_request_create(arg->ce[n]);
+   if (IS_ERR(rq)) {
+   mutex_unlock(>drm.struct_mutex);
+   return PTR_ERR(rq);
+   }
+
+   i915_request_get(rq);
+   i915_request_add(rq);
+   mutex_unlock(>drm.struct_mutex);
+   }
+
+   err = 0;
+   if (i915_request_wait(rq, 0, HZ / 5) < 0)
+   err = -ETIME;
+   i915_request_put(rq);
+   if (err)
+   return err;
+
+   count++;
+   } while (!__igt_timeout(end_time, NULL));
+
+   pr_info("%s: %lu switches (sync)\n", arg->ce[0]->engine->name, count);
+   return 0;
+}
+
+static int __live_parallel_switchN(void *data)
+{
+   struct parallel_switch *arg = data;
+   struct drm_i915_private *i915 = arg->ce[0]->engine->i915;
+   IGT_TIMEOUT(end_time);
+   unsigned long count;
+   int n;
+
+   count = 0;
+   do {
+   for (n = 0; n < ARRAY_SIZE(arg->ce); n++) {
+   struct i915_request *rq;
+
+   mutex_lock(>drm.struct_mutex);
+   rq = i915_request_create(arg->ce[n]);
+   if (IS_ERR(rq)) {
+   mutex_unlock(>drm.struct_mutex);
+   return PTR_ERR(rq);
+   }
+
+   i915_request_add(rq);
+   mutex_unlock(>drm.struct_mutex);
+   }
+
+   count++;
+   } while (!__igt_timeout(end_time, NULL));
+
+   pr_info("%s: %lu switches (many)\n", arg->ce[0]->engine->name, count);
+   return 0;
+}
+
+static int live_parallel_switch(void *arg)
+{
+   struct drm_i915_private *i915 = arg;
+   static int (* const func[])(void *arg) = {
+   __live_parallel_switch1,
+   __live_parallel_switchN,
+   NULL,
+   };
+   struct parallel_switch *data = NULL;
+   struct i915_gem_engines *engines;
+   struct i915_gem_engines_iter it;
+   int (* const *fn)(void *arg);
+   struct i915_gem_context *ctx;
+   struct intel_context *ce;
+   struct drm_file *file;
+   int n, m, count;
+   int err = 0;
+
+   /*
+* Check we can process switches on all engines simultaneously.
+*/
+
+   if (!DRIVER_CAPS(i915)->has_logical_contexts)
+   return 0;
+
+   file = mock_file(i915);
+   if (IS_ERR(file))
+   return PTR_ERR(file);
+
+   mutex_lock(>drm.struct_mutex);
+
+   ctx = live_context(i915, file);
+   if (IS_ERR(ctx)) {
+   err = PTR_ERR(ctx);
+   goto out_locked;
+   }
+
+   engines = i915_gem_context_lock_engines(ctx);
+   count = engines->num_engines;
+
+   data = kcalloc(count, sizeof(*data), GFP_KERNEL);
+   if (!data) {
+   i915_gem_context_unlock_engines(ctx);
+   err = -ENOMEM;
+   goto out_locked;
+   }
+
+   m = 0; /* Use the first context as our template for the engines */
+   for_each_gem_engine(ce, engines, it) {
+   err = intel_context_pin(ce);
+   if (err) {
+   i915_gem_context_unlock_engines(ctx);
+   goto