@@ -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);
@@ -342,6 +343,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
@@ -224,4 +224,15 @@ intel_context_clear_nopreempt(struct intel_context *ce)
clear_bit(CONTEXT_NOPREEMPT, &ce->flags);
}
+static inline void
+__intel_context_stats_start(struct intel_context_stats *stats, ktime_t now)
+{
+ if (!stats->active) {
+ 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"
@@ -83,6 +84,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__ */
@@ -1543,8 +1543,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->context->stats,
+ engine->stats.enabled_at);
+
+ for (; (rq = *port); port++)
engine->stats.active++;
for (port = execlists->pending; (rq = *port); port++) {
@@ -1195,6 +1195,32 @@ static void reset_active(struct i915_request *rq,
ce->lrc_desc |= CTX_DESC_FORCE_RESTORE;
}
+static void
+intel_context_stats_start(struct intel_context_stats *stats)
+{
+ unsigned long flags;
+
+ write_seqlock_irqsave(&stats->lock, flags);
+ __intel_context_stats_start(stats, ktime_get());
+ write_sequnlock_irqrestore(&stats->lock, flags);
+}
+
+static void
+intel_context_stats_stop(struct intel_context_stats *stats)
+{
+ unsigned long flags;
+
+ if (!READ_ONCE(stats->active))
+ return;
+
+ write_seqlock_irqsave(&stats->lock, flags);
+ GEM_BUG_ON(!READ_ONCE(stats->active));
+ stats->total = ktime_add(stats->total,
+ ktime_sub(ktime_get(), stats->start));
+ stats->active = false;
+ write_sequnlock_irqrestore(&stats->lock, flags);
+}
+
static inline struct intel_engine_cs *
__execlists_schedule_in(struct i915_request *rq)
{
@@ -1262,7 +1288,7 @@ static inline void
__execlists_schedule_out(struct i915_request *rq,
struct intel_engine_cs * const engine)
{
- struct intel_context * const ce = rq->context;
+ struct intel_context *ce = rq->context;
/*
* NB process_csb() is not under the engine->active.lock and hence
@@ -1279,6 +1305,7 @@ __execlists_schedule_out(struct i915_request *rq,
intel_engine_add_retire(engine, ce->timeline);
intel_engine_context_out(engine);
+ intel_context_stats_stop(&ce->stats);
execlists_context_status_change(rq, INTEL_CONTEXT_SCHEDULE_OUT);
intel_gt_pm_put_async(engine->gt);
@@ -2250,6 +2277,7 @@ static void process_csb(struct intel_engine_cs *engine)
rmb();
do {
+ struct i915_request *rq;
bool promote;
if (++head == num_entries)
@@ -2305,7 +2333,11 @@ static void process_csb(struct intel_engine_cs *engine)
WRITE_ONCE(execlists->pending[0], NULL);
} else {
- GEM_BUG_ON(!*execlists->active);
+ rq = *execlists->active++;
+ GEM_BUG_ON(!rq);
+
+ GEM_BUG_ON(execlists->active - execlists->inflight >
+ execlists_num_ports(execlists));
/* port0 completed, advanced to port1 */
trace_ports(execlists, "completed", execlists->active);
@@ -2316,13 +2348,15 @@ static void process_csb(struct intel_engine_cs *engine)
* coherent (visible from the CPU) before the
* user interrupt and CSB is processed.
*/
- GEM_BUG_ON(!i915_request_completed(*execlists->active) &&
+ GEM_BUG_ON(!i915_request_completed(rq) &&
!reset_in_progress(execlists));
- execlists_schedule_out(*execlists->active++);
- GEM_BUG_ON(execlists->active - execlists->inflight >
- execlists_num_ports(execlists));
+ execlists_schedule_out(rq);
}
+
+ rq = *execlists->active;
+ if (rq)
+ intel_context_stats_start(&rq->context->stats);
} while (head != tail);
execlists->csb_head = head;