Couple up the context in/out accounting to record how long each engine
is busy handling requests. This is exposed to userspace for more accurate
measurements, and also enables our soft-rps timer.

Signed-off-by: Chris Wilson <ch...@chris-wilson.co.uk>
---
 drivers/gpu/drm/i915/gt/intel_engine_stats.h  | 49 ++++++++++
 drivers/gpu/drm/i915/gt/intel_lrc.c           | 34 +------
 .../gpu/drm/i915/gt/intel_ring_scheduler.c    |  4 +
 drivers/gpu/drm/i915/gt/selftest_engine_pm.c  | 90 +++++++++++++++++++
 drivers/gpu/drm/i915/gt/selftest_rps.c        |  5 ++
 5 files changed, 149 insertions(+), 33 deletions(-)
 create mode 100644 drivers/gpu/drm/i915/gt/intel_engine_stats.h

diff --git a/drivers/gpu/drm/i915/gt/intel_engine_stats.h 
b/drivers/gpu/drm/i915/gt/intel_engine_stats.h
new file mode 100644
index 000000000000..58491eae3482
--- /dev/null
+++ b/drivers/gpu/drm/i915/gt/intel_engine_stats.h
@@ -0,0 +1,49 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2020 Intel Corporation
+ */
+
+#ifndef __INTEL_ENGINE_STATS_H__
+#define __INTEL_ENGINE_STATS_H__
+
+#include <linux/atomic.h>
+#include <linux/ktime.h>
+#include <linux/seqlock.h>
+
+#include "i915_gem.h" /* GEM_BUG_ON */
+#include "intel_engine.h"
+
+static inline void intel_engine_context_in(struct intel_engine_cs *engine)
+{
+       unsigned long flags;
+
+       if (atomic_add_unless(&engine->stats.active, 1, 0))
+               return;
+
+       write_seqlock_irqsave(&engine->stats.lock, flags);
+       if (!atomic_add_unless(&engine->stats.active, 1, 0)) {
+               engine->stats.start = ktime_get();
+               atomic_inc(&engine->stats.active);
+       }
+       write_sequnlock_irqrestore(&engine->stats.lock, flags);
+}
+
+static inline void intel_engine_context_out(struct intel_engine_cs *engine)
+{
+       unsigned long flags;
+
+       GEM_BUG_ON(!atomic_read(&engine->stats.active));
+
+       if (atomic_add_unless(&engine->stats.active, -1, 1))
+               return;
+
+       write_seqlock_irqsave(&engine->stats.lock, flags);
+       if (atomic_dec_and_test(&engine->stats.active)) {
+               engine->stats.total =
+                       ktime_add(engine->stats.total,
+                                 ktime_sub(ktime_get(), engine->stats.start));
+       }
+       write_sequnlock_irqrestore(&engine->stats.lock, flags);
+}
+
+#endif /* __INTEL_ENGINE_STATS_H__ */
diff --git a/drivers/gpu/drm/i915/gt/intel_lrc.c 
b/drivers/gpu/drm/i915/gt/intel_lrc.c
index 6fc0966b75ff..13ef4f58cb08 100644
--- a/drivers/gpu/drm/i915/gt/intel_lrc.c
+++ b/drivers/gpu/drm/i915/gt/intel_lrc.c
@@ -139,6 +139,7 @@
 #include "i915_vgpu.h"
 #include "intel_context.h"
 #include "intel_engine_pm.h"
+#include "intel_engine_stats.h"
 #include "intel_gt.h"
 #include "intel_gt_pm.h"
 #include "intel_gt_requests.h"
@@ -1187,39 +1188,6 @@ execlists_context_status_change(struct i915_request *rq, 
unsigned long status)
                                   status, rq);
 }
 
-static void intel_engine_context_in(struct intel_engine_cs *engine)
-{
-       unsigned long flags;
-
-       if (atomic_add_unless(&engine->stats.active, 1, 0))
-               return;
-
-       write_seqlock_irqsave(&engine->stats.lock, flags);
-       if (!atomic_add_unless(&engine->stats.active, 1, 0)) {
-               engine->stats.start = ktime_get();
-               atomic_inc(&engine->stats.active);
-       }
-       write_sequnlock_irqrestore(&engine->stats.lock, flags);
-}
-
-static void intel_engine_context_out(struct intel_engine_cs *engine)
-{
-       unsigned long flags;
-
-       GEM_BUG_ON(!atomic_read(&engine->stats.active));
-
-       if (atomic_add_unless(&engine->stats.active, -1, 1))
-               return;
-
-       write_seqlock_irqsave(&engine->stats.lock, flags);
-       if (atomic_dec_and_test(&engine->stats.active)) {
-               engine->stats.total =
-                       ktime_add(engine->stats.total,
-                                 ktime_sub(ktime_get(), engine->stats.start));
-       }
-       write_sequnlock_irqrestore(&engine->stats.lock, flags);
-}
-
 static void
 execlists_check_context(const struct intel_context *ce,
                        const struct intel_engine_cs *engine)
diff --git a/drivers/gpu/drm/i915/gt/intel_ring_scheduler.c 
b/drivers/gpu/drm/i915/gt/intel_ring_scheduler.c
index c8cd435d1c51..aaff554865b1 100644
--- a/drivers/gpu/drm/i915/gt/intel_ring_scheduler.c
+++ b/drivers/gpu/drm/i915/gt/intel_ring_scheduler.c
@@ -9,6 +9,7 @@
 
 #include "i915_drv.h"
 #include "intel_context.h"
+#include "intel_engine_stats.h"
 #include "intel_gt.h"
 #include "intel_gt_pm.h"
 #include "intel_gt_requests.h"
@@ -59,6 +60,7 @@ static struct i915_request *
 schedule_in(struct intel_engine_cs *engine, struct i915_request *rq)
 {
        __intel_gt_pm_get(engine->gt);
+       intel_engine_context_in(engine);
        return i915_request_get(rq);
 }
 
@@ -71,6 +73,7 @@ schedule_out(struct intel_engine_cs *engine, struct 
i915_request *rq)
                intel_engine_add_retire(engine, ce->timeline);
 
        i915_request_put(rq);
+       intel_engine_context_out(engine);
        intel_gt_pm_put_async(engine->gt);
 }
 
@@ -747,6 +750,7 @@ int intel_ring_scheduler_setup(struct intel_engine_cs 
*engine)
        engine->legacy.ring = ring;
 
        engine->flags |= I915_ENGINE_NEEDS_BREADCRUMB_TASKLET;
+       engine->flags |= I915_ENGINE_SUPPORTS_STATS;
 
        /* Finally, take ownership and responsibility for cleanup! */
        engine->release = ring_release;
diff --git a/drivers/gpu/drm/i915/gt/selftest_engine_pm.c 
b/drivers/gpu/drm/i915/gt/selftest_engine_pm.c
index cbf6b0735272..64cfa2fdc9bf 100644
--- a/drivers/gpu/drm/i915/gt/selftest_engine_pm.c
+++ b/drivers/gpu/drm/i915/gt/selftest_engine_pm.c
@@ -7,6 +7,95 @@
 #include "i915_selftest.h"
 #include "selftest_engine.h"
 #include "selftests/igt_atomic.h"
+#include "selftests/igt_flush_test.h"
+#include "selftests/igt_spinner.h"
+
+static int live_engine_busy_stats(void *arg)
+{
+       struct intel_gt *gt = arg;
+       struct intel_engine_cs *engine;
+       enum intel_engine_id id;
+       struct igt_spinner spin;
+       int err;
+
+       /*
+        * Check that if an engine supports busy-stats, they tell the truth.
+        */
+
+       if (igt_spinner_init(&spin, gt))
+               return -ENOMEM;
+
+       GEM_BUG_ON(intel_gt_pm_is_awake(gt));
+       for_each_engine(engine, gt, id) {
+               struct i915_request *rq;
+               ktime_t dt, de;
+
+               if (!intel_engine_supports_stats(engine))
+                       continue;
+
+               if (!intel_engine_can_store_dword(engine))
+                       continue;
+
+               if (intel_gt_pm_wait_for_idle(gt)) {
+                       err = -EBUSY;
+                       break;
+               }
+
+               preempt_disable();
+               dt = ktime_get();
+               de = intel_engine_get_busy_time(engine);
+               udelay(100);
+               dt = ktime_sub(ktime_get(), dt);
+               de = ktime_sub(intel_engine_get_busy_time(engine), de);
+               preempt_enable();
+               if (de > 10) {
+                       pr_err("%s: reported %lldns [%d%%] busyness while 
sleeping [for %lldns]\n",
+                              engine->name,
+                              de, (int)div64_u64(100 * de, dt), dt);
+                       err = -EINVAL;
+                       break;
+               }
+
+               rq = igt_spinner_create_request(&spin,
+                                               engine->kernel_context,
+                                               MI_NOOP);
+               if (IS_ERR(rq)) {
+                       err = PTR_ERR(rq);
+                       break;
+               }
+               i915_request_add(rq);
+
+               if (!igt_wait_for_spinner(&spin, rq)) {
+                       intel_gt_set_wedged(engine->gt);
+                       err = -ETIME;
+                       break;
+               }
+
+               preempt_disable();
+               dt = ktime_get();
+               de = intel_engine_get_busy_time(engine);
+               udelay(100);
+               dt = ktime_sub(ktime_get(), dt);
+               de = ktime_sub(intel_engine_get_busy_time(engine), de);
+               preempt_enable();
+               if (100 * de < 95 * dt) {
+                       pr_err("%s: reported only %lldns [%d%%] busyness while 
spinning [for %lldns]\n",
+                              engine->name,
+                              de, (int)div64_u64(100 * de, dt), dt);
+                       err = -EINVAL;
+                       break;
+               }
+
+               igt_spinner_end(&spin);
+               if (igt_flush_test(gt->i915)) {
+                       err = -EIO;
+                       break;
+               }
+       }
+
+       igt_spinner_fini(&spin);
+       return err;
+}
 
 static int live_engine_pm(void *arg)
 {
@@ -77,6 +166,7 @@ static int live_engine_pm(void *arg)
 int live_engine_pm_selftests(struct intel_gt *gt)
 {
        static const struct i915_subtest tests[] = {
+               SUBTEST(live_engine_busy_stats),
                SUBTEST(live_engine_pm),
        };
 
diff --git a/drivers/gpu/drm/i915/gt/selftest_rps.c 
b/drivers/gpu/drm/i915/gt/selftest_rps.c
index 5049c3dd08a6..5e364fb31aea 100644
--- a/drivers/gpu/drm/i915/gt/selftest_rps.c
+++ b/drivers/gpu/drm/i915/gt/selftest_rps.c
@@ -1252,6 +1252,11 @@ int live_rps_dynamic(void *arg)
        if (igt_spinner_init(&spin, gt))
                return -ENOMEM;
 
+       if (intel_rps_has_interrupts(rps))
+               pr_info("RPS has interrupt support\n");
+       if (intel_rps_uses_timer(rps))
+               pr_info("RPS has timer support\n");
+
        for_each_engine(engine, gt, id) {
                struct i915_request *rq;
                struct {
-- 
2.20.1

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

Reply via email to