@@ -248,6 +248,7 @@ intel_context_init(struct intel_context *ce,
INIT_LIST_HEAD(&ce->signals);
mutex_init(&ce->pin_mutex);
+ seqlock_init(&ce->stats.lock);
i915_active_init(&ce->active,
__intel_context_active, __intel_context_retire);
@@ -348,6 +349,25 @@ struct i915_request *intel_context_create_request(struct intel_context *ce)
return rq;
}
+ktime_t intel_context_get_busy_time(struct intel_context *ce)
+{
+ unsigned int seq;
+ ktime_t total;
+
+ do {
+ seq = read_seqbegin(&ce->stats.lock);
+
+ total = ce->stats.total;
+
+ if (ce->stats.active)
+ total = ktime_add(total,
+ ktime_sub(ktime_get(),
+ ce->stats.start));
+ } while (read_seqretry(&ce->stats.lock, seq));
+
+ return total;
+}
+
#if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
#include "selftest_context.c"
#endif
@@ -153,4 +153,13 @@ static inline struct intel_ring *__intel_context_ring_size(u64 sz)
return u64_to_ptr(struct intel_ring, sz);
}
+static inline void
+__intel_context_stats_start(struct intel_context_stats *stats, ktime_t now)
+{
+ stats->start = now;
+ stats->active = true;
+}
+
+ktime_t intel_context_get_busy_time(struct intel_context *ce);
+
#endif /* __INTEL_CONTEXT_H__ */
@@ -11,6 +11,7 @@
#include <linux/list.h>
#include <linux/mutex.h>
#include <linux/types.h>
+#include <linux/seqlock.h>
#include "i915_active_types.h"
#include "i915_utils.h"
@@ -75,6 +76,14 @@ struct intel_context {
/** sseu: Control eu/slice partitioning */
struct intel_sseu sseu;
+
+ /** stats: Context GPU engine busyness tracking. */
+ struct intel_context_stats {
+ seqlock_t lock;
+ bool active;
+ ktime_t start;
+ ktime_t total;
+ } stats;
};
#endif /* __INTEL_CONTEXT_TYPES__ */
@@ -1568,8 +1568,20 @@ int intel_enable_engine_stats(struct intel_engine_cs *engine)
engine->stats.enabled_at = ktime_get();
- /* XXX submission method oblivious? */
- for (port = execlists->active; (rq = *port); port++)
+ /*
+ * Mark currently running context as active.
+ * XXX submission method oblivious?
+ */
+
+ rq = NULL;
+ port = execlists->active;
+ if (port)
+ rq = *port;
+ if (rq)
+ __intel_context_stats_start(&rq->hw_context->stats,
+ engine->stats.enabled_at);
+
+ for (; (rq = *port); port++)
engine->stats.active++;
for (port = execlists->pending; (rq = *port); port++) {
@@ -944,26 +944,60 @@ execlists_context_status_change(struct i915_request *rq, unsigned long status)
status, rq);
}
-static void intel_engine_context_in(struct intel_engine_cs *engine)
+static void
+intel_context_stats_start(struct intel_context_stats *stats, ktime_t now)
+{
+ write_seqlock(&stats->lock);
+ __intel_context_stats_start(stats, now);
+ write_sequnlock(&stats->lock);
+}
+
+static void
+intel_context_stats_stop(struct intel_context_stats *stats, ktime_t now)
+{
+ write_seqlock(&stats->lock);
+ if (stats->active) {
+ stats->total = ktime_add(stats->total,
+ ktime_sub(now, stats->start));
+ stats->active = false;
+ }
+ write_sequnlock(&stats->lock);
+}
+
+static void intel_context_in(struct intel_context *ce, bool submit)
{
+ struct intel_engine_cs *engine = ce->engine;
unsigned long flags;
+ ktime_t now;
if (READ_ONCE(engine->stats.enabled) == 0)
return;
write_seqlock_irqsave(&engine->stats.lock, flags);
+ if (submit) {
+ now = ktime_get();
+ intel_context_stats_start(&ce->stats, now);
+ } else {
+ now = 0;
+ }
+
if (engine->stats.enabled > 0) {
- if (engine->stats.active++ == 0)
- engine->stats.start = ktime_get();
+ if (engine->stats.active++ == 0) {
+ if (!now)
+ now = ktime_get();
+ engine->stats.start = now;
+ }
+
GEM_BUG_ON(engine->stats.active == 0);
}
write_sequnlock_irqrestore(&engine->stats.lock, flags);
}
-static void intel_engine_context_out(struct intel_engine_cs *engine)
+static void intel_context_out(struct intel_context *ce)
{
+ struct intel_engine_cs *engine = ce->engine;
unsigned long flags;
if (READ_ONCE(engine->stats.enabled) == 0)
@@ -972,14 +1006,25 @@ static void intel_engine_context_out(struct intel_engine_cs *engine)
write_seqlock_irqsave(&engine->stats.lock, flags);
if (engine->stats.enabled > 0) {
+ ktime_t now = ktime_get();
+ struct i915_request *next;
ktime_t last;
+ intel_context_stats_stop(&ce->stats, now);
+
+ next = NULL;
+ if (engine->execlists.active)
+ next = *engine->execlists.active;
+ if (next)
+ intel_context_stats_start(&next->hw_context->stats,
+ now);
+
if (engine->stats.active && --engine->stats.active == 0) {
/*
* Decrement the active context count and in case GPU
* is now idle add up to the running total.
*/
- last = ktime_sub(ktime_get(), engine->stats.start);
+ last = ktime_sub(now, engine->stats.start);
engine->stats.total = ktime_add(engine->stats.total,
last);
@@ -989,7 +1034,7 @@ static void intel_engine_context_out(struct intel_engine_cs *engine)
* the first event in which case we account from the
* time stats gathering was turned on.
*/
- last = ktime_sub(ktime_get(), engine->stats.enabled_at);
+ last = ktime_sub(now, engine->stats.enabled_at);
engine->stats.total = ktime_add(engine->stats.total,
last);
@@ -1000,7 +1045,7 @@ static void intel_engine_context_out(struct intel_engine_cs *engine)
}
static inline struct intel_engine_cs *
-__execlists_schedule_in(struct i915_request *rq)
+__execlists_schedule_in(struct i915_request *rq, int idx)
{
struct intel_engine_cs * const engine = rq->engine;
struct intel_context * const ce = rq->hw_context;
@@ -1021,7 +1066,7 @@ __execlists_schedule_in(struct i915_request *rq)
intel_gt_pm_get(engine->gt);
execlists_context_status_change(rq, INTEL_CONTEXT_SCHEDULE_IN);
- intel_engine_context_in(engine);
+ intel_context_in(rq->hw_context, idx == 0);
return engine;
}
@@ -1038,7 +1083,8 @@ execlists_schedule_in(struct i915_request *rq, int idx)
old = READ_ONCE(ce->inflight);
do {
if (!old) {
- WRITE_ONCE(ce->inflight, __execlists_schedule_in(rq));
+ WRITE_ONCE(ce->inflight,
+ __execlists_schedule_in(rq, idx));
break;
}
} while (!try_cmpxchg(&ce->inflight, &old, ptr_inc(old)));
@@ -1114,7 +1160,7 @@ __execlists_schedule_out(struct i915_request *rq,
{
struct intel_context * const ce = rq->hw_context;
- intel_engine_context_out(engine);
+ intel_context_out(rq->hw_context);
execlists_context_status_change(rq, INTEL_CONTEXT_SCHEDULE_OUT);
intel_gt_pm_put(engine->gt);