2018-10-31 07:53:31 +07:00
|
|
|
/* SPDX-License-Identifier: MIT */
|
2010-05-21 08:08:55 +07:00
|
|
|
#ifndef _INTEL_RINGBUFFER_H_
|
|
|
|
#define _INTEL_RINGBUFFER_H_
|
|
|
|
|
2018-09-05 20:57:05 +07:00
|
|
|
#include <drm/drm_util.h>
|
|
|
|
|
2014-05-11 04:10:43 +07:00
|
|
|
#include <linux/hashtable.h>
|
drm/i915: Replace global breadcrumbs with per-context interrupt tracking
A few years ago, see commit 688e6c725816 ("drm/i915: Slaughter the
thundering i915_wait_request herd"), the issue of handling multiple
clients waiting in parallel was brought to our attention. The
requirement was that every client should be woken immediately upon its
request being signaled, without incurring any cpu overhead.
To handle certain fragility of our hw meant that we could not do a
simple check inside the irq handler (some generations required almost
unbounded delays before we could be sure of seqno coherency) and so
request completion checking required delegation.
Before commit 688e6c725816, the solution was simple. Every client
waiting on a request would be woken on every interrupt and each would do
a heavyweight check to see if their request was complete. Commit
688e6c725816 introduced an rbtree so that only the earliest waiter on
the global timeline would woken, and would wake the next and so on.
(Along with various complications to handle requests being reordered
along the global timeline, and also a requirement for kthread to provide
a delegate for fence signaling that had no process context.)
The global rbtree depends on knowing the execution timeline (and global
seqno). Without knowing that order, we must instead check all contexts
queued to the HW to see which may have advanced. We trim that list by
only checking queued contexts that are being waited on, but still we
keep a list of all active contexts and their active signalers that we
inspect from inside the irq handler. By moving the waiters onto the fence
signal list, we can combine the client wakeup with the dma_fence
signaling (a dramatic reduction in complexity, but does require the HW
being coherent, the seqno must be visible from the cpu before the
interrupt is raised - we keep a timer backup just in case).
Having previously fixed all the issues with irq-seqno serialisation (by
inserting delays onto the GPU after each request instead of random delays
on the CPU after each interrupt), we can rely on the seqno state to
perfom direct wakeups from the interrupt handler. This allows us to
preserve our single context switch behaviour of the current routine,
with the only downside that we lose the RT priority sorting of wakeups.
In general, direct wakeup latency of multiple clients is about the same
(about 10% better in most cases) with a reduction in total CPU time spent
in the waiter (about 20-50% depending on gen). Average herd behaviour is
improved, but at the cost of not delegating wakeups on task_prio.
v2: Capture fence signaling state for error state and add comments to
warm even the most cold of hearts.
v3: Check if the request is still active before busywaiting
v4: Reduce the amount of pointer misdirection with list_for_each_safe
and using a local i915_request variable inside the loops
v5: Add a missing pluralisation to a purely informative selftest message.
References: 688e6c725816 ("drm/i915: Slaughter the thundering i915_wait_request herd")
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20190129205230.19056-2-chris@chris-wilson.co.uk
2019-01-30 03:52:29 +07:00
|
|
|
#include <linux/irq_work.h>
|
2019-02-26 16:49:19 +07:00
|
|
|
#include <linux/random.h>
|
2018-04-26 14:47:16 +07:00
|
|
|
#include <linux/seqlock.h>
|
2018-02-21 16:56:36 +07:00
|
|
|
|
2015-04-07 22:20:36 +07:00
|
|
|
#include "i915_gem_batch_pool.h"
|
drm/i915/pmu: Expose a PMU interface for perf queries
From: Chris Wilson <chris@chris-wilson.co.uk>
From: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
From: Dmitry Rogozhkin <dmitry.v.rogozhkin@intel.com>
The first goal is to be able to measure GPU (and invidual ring) busyness
without having to poll registers from userspace. (Which not only incurs
holding the forcewake lock indefinitely, perturbing the system, but also
runs the risk of hanging the machine.) As an alternative we can use the
perf event counter interface to sample the ring registers periodically
and send those results to userspace.
Functionality we are exporting to userspace is via the existing perf PMU
API and can be exercised via the existing tools. For example:
perf stat -a -e i915/rcs0-busy/ -I 1000
Will print the render engine busynnes once per second. All the performance
counters can be enumerated (perf list) and have their unit of measure
correctly reported in sysfs.
v1-v2 (Chris Wilson):
v2: Use a common timer for the ring sampling.
v3: (Tvrtko Ursulin)
* Decouple uAPI from i915 engine ids.
* Complete uAPI defines.
* Refactor some code to helpers for clarity.
* Skip sampling disabled engines.
* Expose counters in sysfs.
* Pass in fake regs to avoid null ptr deref in perf core.
* Convert to class/instance uAPI.
* Use shared driver code for rc6 residency, power and frequency.
v4: (Dmitry Rogozhkin)
* Register PMU with .task_ctx_nr=perf_invalid_context
* Expose cpumask for the PMU with the single CPU in the mask
* Properly support pmu->stop(): it should call pmu->read()
* Properly support pmu->del(): it should call stop(event, PERF_EF_UPDATE)
* Introduce refcounting of event subscriptions.
* Make pmu.busy_stats a refcounter to avoid busy stats going away
with some deleted event.
* Expose cpumask for i915 PMU to avoid multiple events creation of
the same type followed by counter aggregation by perf-stat.
* Track CPUs getting online/offline to migrate perf context. If (likely)
cpumask will initially set CPU0, CONFIG_BOOTPARAM_HOTPLUG_CPU0 will be
needed to see effect of CPU status tracking.
* End result is that only global events are supported and perf stat
works correctly.
* Deny perf driver level sampling - it is prohibited for uncore PMU.
v5: (Tvrtko Ursulin)
* Don't hardcode number of engine samplers.
* Rewrite event ref-counting for correctness and simplicity.
* Store initial counter value when starting already enabled events
to correctly report values to all listeners.
* Fix RC6 residency readout.
* Comments, GPL header.
v6:
* Add missing entry to v4 changelog.
* Fix accounting in CPU hotplug case by copying the approach from
arch/x86/events/intel/cstate.c. (Dmitry Rogozhkin)
v7:
* Log failure message only on failure.
* Remove CPU hotplug notification state on unregister.
v8:
* Fix error unwind on failed registration.
* Checkpatch cleanup.
v9:
* Drop the energy metric, it is available via intel_rapl_perf.
(Ville Syrjälä)
* Use HAS_RC6(p). (Chris Wilson)
* Handle unsupported non-engine events. (Dmitry Rogozhkin)
* Rebase for intel_rc6_residency_ns needing caller managed
runtime pm.
* Drop HAS_RC6 checks from the read callback since creating those
events will be rejected at init time already.
* Add counter units to sysfs so perf stat output is nicer.
* Cleanup the attribute tables for brevity and readability.
v10:
* Fixed queued accounting.
v11:
* Move intel_engine_lookup_user to intel_engine_cs.c
* Commit update. (Joonas Lahtinen)
v12:
* More accurate sampling. (Chris Wilson)
* Store and report frequency in MHz for better usability from
perf stat.
* Removed metrics: queued, interrupts, rc6 counters.
* Sample engine busyness based on seqno difference only
for less MMIO (and forcewake) on all platforms. (Chris Wilson)
v13:
* Comment spelling, use mul_u32_u32 to work around potential GCC
issue and somne code alignment changes. (Chris Wilson)
v14:
* Rebase.
v15:
* Rebase for RPS refactoring.
v16:
* Use the dynamic slot in the CPU hotplug state machine so that we are
free to setup our state as multi-instance. Previously we were re-using
the CPUHP_AP_PERF_X86_UNCORE_ONLINE slot which is neither used as
multi-instance, nor owned by our driver to start with.
* Register the CPU hotplug handlers after the PMU, otherwise the callback
will get called before the PMU is initialized which can end up in
perf_pmu_migrate_context with an un-initialized base.
* Added workaround for a probable bug in cpuhp core.
v17:
* Remove workaround for the cpuhp bug.
v18:
* Rebase for drm_i915_gem_engine_class getting upstream before us.
v19:
* Rebase. (trivial)
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Signed-off-by: Dmitry Rogozhkin <dmitry.v.rogozhkin@intel.com>
Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Cc: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Dmitry Rogozhkin <dmitry.v.rogozhkin@intel.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20171121181852.16128-2-tvrtko.ursulin@linux.intel.com
2017-11-22 01:18:45 +07:00
|
|
|
#include "i915_pmu.h"
|
2019-03-06 01:03:30 +07:00
|
|
|
#include "i915_reg.h"
|
2018-02-21 16:56:36 +07:00
|
|
|
#include "i915_request.h"
|
2017-02-14 00:15:14 +07:00
|
|
|
#include "i915_selftest.h"
|
2018-05-02 23:38:39 +07:00
|
|
|
#include "i915_timeline.h"
|
2019-03-06 01:03:30 +07:00
|
|
|
#include "intel_device_info.h"
|
2018-03-14 06:19:20 +07:00
|
|
|
#include "intel_gpu_commands.h"
|
2018-12-03 20:33:41 +07:00
|
|
|
#include "intel_workarounds.h"
|
2014-05-11 04:10:43 +07:00
|
|
|
|
2017-10-09 18:02:57 +07:00
|
|
|
struct drm_printer;
|
2018-04-19 01:40:52 +07:00
|
|
|
struct i915_sched_attr;
|
2017-10-09 18:02:57 +07:00
|
|
|
|
2014-05-11 04:10:43 +07:00
|
|
|
#define I915_CMD_HASH_ORDER 9
|
|
|
|
|
2014-07-24 23:04:28 +07:00
|
|
|
/* Early gen2 devices have a cacheline of just 32 bytes, using 64 is overkill,
|
|
|
|
* but keeps the logic simple. Indeed, the whole purpose of this macro is just
|
|
|
|
* to give some inclination as to some of the magic values used in the various
|
|
|
|
* workarounds!
|
|
|
|
*/
|
|
|
|
#define CACHELINE_BYTES 64
|
2019-01-16 16:15:19 +07:00
|
|
|
#define CACHELINE_DWORDS (CACHELINE_BYTES / sizeof(u32))
|
2014-07-24 23:04:28 +07:00
|
|
|
|
2016-08-15 16:48:57 +07:00
|
|
|
struct intel_hw_status_page {
|
|
|
|
struct i915_vma *vma;
|
2019-01-28 17:23:55 +07:00
|
|
|
u32 *addr;
|
2010-05-21 08:08:55 +07:00
|
|
|
};
|
|
|
|
|
2016-07-21 00:16:05 +07:00
|
|
|
#define I915_READ_TAIL(engine) I915_READ(RING_TAIL((engine)->mmio_base))
|
|
|
|
#define I915_WRITE_TAIL(engine, val) I915_WRITE(RING_TAIL((engine)->mmio_base), val)
|
2010-11-09 16:17:32 +07:00
|
|
|
|
2016-07-21 00:16:05 +07:00
|
|
|
#define I915_READ_START(engine) I915_READ(RING_START((engine)->mmio_base))
|
|
|
|
#define I915_WRITE_START(engine, val) I915_WRITE(RING_START((engine)->mmio_base), val)
|
2010-11-09 16:17:32 +07:00
|
|
|
|
2016-07-21 00:16:05 +07:00
|
|
|
#define I915_READ_HEAD(engine) I915_READ(RING_HEAD((engine)->mmio_base))
|
|
|
|
#define I915_WRITE_HEAD(engine, val) I915_WRITE(RING_HEAD((engine)->mmio_base), val)
|
2010-11-09 16:17:32 +07:00
|
|
|
|
2016-07-21 00:16:05 +07:00
|
|
|
#define I915_READ_CTL(engine) I915_READ(RING_CTL((engine)->mmio_base))
|
|
|
|
#define I915_WRITE_CTL(engine, val) I915_WRITE(RING_CTL((engine)->mmio_base), val)
|
2010-11-09 16:17:32 +07:00
|
|
|
|
2016-07-21 00:16:05 +07:00
|
|
|
#define I915_READ_IMR(engine) I915_READ(RING_IMR((engine)->mmio_base))
|
|
|
|
#define I915_WRITE_IMR(engine, val) I915_WRITE(RING_IMR((engine)->mmio_base), val)
|
2010-08-02 21:29:44 +07:00
|
|
|
|
2016-07-21 00:16:05 +07:00
|
|
|
#define I915_READ_MODE(engine) I915_READ(RING_MI_MODE((engine)->mmio_base))
|
|
|
|
#define I915_WRITE_MODE(engine, val) I915_WRITE(RING_MI_MODE((engine)->mmio_base), val)
|
2014-03-12 18:09:41 +07:00
|
|
|
|
2014-06-30 23:53:37 +07:00
|
|
|
/* seqno size is actually only a uint32, but since we plan to use MI_FLUSH_DW to
|
|
|
|
* do the writes, and that must have qw aligned offsets, simply pretend it's 8b.
|
|
|
|
*/
|
2016-08-03 04:50:21 +07:00
|
|
|
enum intel_engine_hangcheck_action {
|
2016-11-18 20:09:04 +07:00
|
|
|
ENGINE_IDLE = 0,
|
|
|
|
ENGINE_WAIT,
|
|
|
|
ENGINE_ACTIVE_SEQNO,
|
|
|
|
ENGINE_ACTIVE_HEAD,
|
|
|
|
ENGINE_ACTIVE_SUBUNITS,
|
|
|
|
ENGINE_WAIT_KICK,
|
|
|
|
ENGINE_DEAD,
|
2013-08-11 16:44:01 +07:00
|
|
|
};
|
2013-06-12 16:35:32 +07:00
|
|
|
|
2016-11-18 20:09:04 +07:00
|
|
|
static inline const char *
|
|
|
|
hangcheck_action_to_str(const enum intel_engine_hangcheck_action a)
|
|
|
|
{
|
|
|
|
switch (a) {
|
|
|
|
case ENGINE_IDLE:
|
|
|
|
return "idle";
|
|
|
|
case ENGINE_WAIT:
|
|
|
|
return "wait";
|
|
|
|
case ENGINE_ACTIVE_SEQNO:
|
|
|
|
return "active seqno";
|
|
|
|
case ENGINE_ACTIVE_HEAD:
|
|
|
|
return "active head";
|
|
|
|
case ENGINE_ACTIVE_SUBUNITS:
|
|
|
|
return "active subunits";
|
|
|
|
case ENGINE_WAIT_KICK:
|
|
|
|
return "wait kick";
|
|
|
|
case ENGINE_DEAD:
|
|
|
|
return "dead";
|
|
|
|
}
|
|
|
|
|
|
|
|
return "unknown";
|
|
|
|
}
|
2014-01-31 00:04:43 +07:00
|
|
|
|
2016-09-20 20:54:33 +07:00
|
|
|
#define I915_MAX_SLICES 3
|
2018-03-16 19:14:51 +07:00
|
|
|
#define I915_MAX_SUBSLICES 8
|
2016-09-20 20:54:33 +07:00
|
|
|
|
|
|
|
#define instdone_slice_mask(dev_priv__) \
|
drm/i915: replace IS_GEN<N> with IS_GEN(..., N)
Define IS_GEN() similarly to our IS_GEN_RANGE(). but use gen instead of
gen_mask to do the comparison. Now callers can pass then gen as a parameter,
so we don't require one macro for each gen.
The following spatch was used to convert the users of these macros:
@@
expression e;
@@
(
- IS_GEN2(e)
+ IS_GEN(e, 2)
|
- IS_GEN3(e)
+ IS_GEN(e, 3)
|
- IS_GEN4(e)
+ IS_GEN(e, 4)
|
- IS_GEN5(e)
+ IS_GEN(e, 5)
|
- IS_GEN6(e)
+ IS_GEN(e, 6)
|
- IS_GEN7(e)
+ IS_GEN(e, 7)
|
- IS_GEN8(e)
+ IS_GEN(e, 8)
|
- IS_GEN9(e)
+ IS_GEN(e, 9)
|
- IS_GEN10(e)
+ IS_GEN(e, 10)
|
- IS_GEN11(e)
+ IS_GEN(e, 11)
)
v2: use IS_GEN rather than GT_GEN and compare to info.gen rather than
using the bitmask
Signed-off-by: Lucas De Marchi <lucas.demarchi@intel.com>
Reviewed-by: Jani Nikula <jani.nikula@intel.com>
Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20181212181044.15886-2-lucas.demarchi@intel.com
2018-12-13 01:10:43 +07:00
|
|
|
(IS_GEN(dev_priv__, 7) ? \
|
2018-12-31 21:56:41 +07:00
|
|
|
1 : RUNTIME_INFO(dev_priv__)->sseu.slice_mask)
|
2016-09-20 20:54:33 +07:00
|
|
|
|
|
|
|
#define instdone_subslice_mask(dev_priv__) \
|
drm/i915: replace IS_GEN<N> with IS_GEN(..., N)
Define IS_GEN() similarly to our IS_GEN_RANGE(). but use gen instead of
gen_mask to do the comparison. Now callers can pass then gen as a parameter,
so we don't require one macro for each gen.
The following spatch was used to convert the users of these macros:
@@
expression e;
@@
(
- IS_GEN2(e)
+ IS_GEN(e, 2)
|
- IS_GEN3(e)
+ IS_GEN(e, 3)
|
- IS_GEN4(e)
+ IS_GEN(e, 4)
|
- IS_GEN5(e)
+ IS_GEN(e, 5)
|
- IS_GEN6(e)
+ IS_GEN(e, 6)
|
- IS_GEN7(e)
+ IS_GEN(e, 7)
|
- IS_GEN8(e)
+ IS_GEN(e, 8)
|
- IS_GEN9(e)
+ IS_GEN(e, 9)
|
- IS_GEN10(e)
+ IS_GEN(e, 10)
|
- IS_GEN11(e)
+ IS_GEN(e, 11)
)
v2: use IS_GEN rather than GT_GEN and compare to info.gen rather than
using the bitmask
Signed-off-by: Lucas De Marchi <lucas.demarchi@intel.com>
Reviewed-by: Jani Nikula <jani.nikula@intel.com>
Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20181212181044.15886-2-lucas.demarchi@intel.com
2018-12-13 01:10:43 +07:00
|
|
|
(IS_GEN(dev_priv__, 7) ? \
|
2018-12-31 21:56:41 +07:00
|
|
|
1 : RUNTIME_INFO(dev_priv__)->sseu.subslice_mask[0])
|
2016-09-20 20:54:33 +07:00
|
|
|
|
|
|
|
#define for_each_instdone_slice_subslice(dev_priv__, slice__, subslice__) \
|
|
|
|
for ((slice__) = 0, (subslice__) = 0; \
|
|
|
|
(slice__) < I915_MAX_SLICES; \
|
|
|
|
(subslice__) = ((subslice__) + 1) < I915_MAX_SUBSLICES ? (subslice__) + 1 : 0, \
|
|
|
|
(slice__) += ((subslice__) == 0)) \
|
|
|
|
for_each_if((BIT(slice__) & instdone_slice_mask(dev_priv__)) && \
|
|
|
|
(BIT(subslice__) & instdone_subslice_mask(dev_priv__)))
|
|
|
|
|
2016-09-20 20:54:32 +07:00
|
|
|
struct intel_instdone {
|
|
|
|
u32 instdone;
|
|
|
|
/* The following exist only in the RCS engine */
|
|
|
|
u32 slice_common;
|
2016-09-20 20:54:33 +07:00
|
|
|
u32 sampler[I915_MAX_SLICES][I915_MAX_SUBSLICES];
|
|
|
|
u32 row[I915_MAX_SLICES][I915_MAX_SUBSLICES];
|
2016-09-20 20:54:32 +07:00
|
|
|
};
|
|
|
|
|
2016-08-03 04:50:21 +07:00
|
|
|
struct intel_engine_hangcheck {
|
2014-03-21 19:41:53 +07:00
|
|
|
u64 acthd;
|
2019-02-26 16:49:19 +07:00
|
|
|
u32 last_seqno;
|
|
|
|
u32 next_seqno;
|
2016-11-18 20:09:04 +07:00
|
|
|
unsigned long action_timestamp;
|
2016-09-20 20:54:32 +07:00
|
|
|
struct intel_instdone instdone;
|
2013-05-24 21:16:07 +07:00
|
|
|
};
|
|
|
|
|
2016-08-03 04:50:21 +07:00
|
|
|
struct intel_ring {
|
2016-01-15 22:10:28 +07:00
|
|
|
struct i915_vma *vma;
|
2016-08-15 16:48:57 +07:00
|
|
|
void *vaddr;
|
2014-05-22 20:13:34 +07:00
|
|
|
|
2018-05-02 23:38:39 +07:00
|
|
|
struct i915_timeline *timeline;
|
2016-08-04 13:52:36 +07:00
|
|
|
struct list_head request_list;
|
2018-04-30 20:15:03 +07:00
|
|
|
struct list_head active_link;
|
2016-08-04 13:52:36 +07:00
|
|
|
|
2014-05-22 20:13:34 +07:00
|
|
|
u32 head;
|
|
|
|
u32 tail;
|
2017-04-25 20:00:49 +07:00
|
|
|
u32 emit;
|
2017-02-07 00:05:01 +07:00
|
|
|
|
2017-05-04 20:08:44 +07:00
|
|
|
u32 space;
|
|
|
|
u32 size;
|
|
|
|
u32 effective_size;
|
2014-05-22 20:13:34 +07:00
|
|
|
};
|
|
|
|
|
2016-05-24 20:53:34 +07:00
|
|
|
struct i915_gem_context;
|
2016-03-07 14:30:27 +07:00
|
|
|
struct drm_i915_reg_table;
|
2015-01-15 20:10:38 +07:00
|
|
|
|
2015-06-20 01:07:01 +07:00
|
|
|
/*
|
|
|
|
* we use a single page to load ctx workarounds so all of these
|
|
|
|
* values are referred in terms of dwords
|
|
|
|
*
|
|
|
|
* struct i915_wa_ctx_bb:
|
|
|
|
* offset: specifies batch starting position, also helpful in case
|
|
|
|
* if we want to have multiple batches at different offsets based on
|
|
|
|
* some criteria. It is not a requirement at the moment but provides
|
|
|
|
* an option for future use.
|
|
|
|
* size: size of the batch in DWORDS
|
|
|
|
*/
|
2016-08-15 16:49:04 +07:00
|
|
|
struct i915_ctx_workarounds {
|
2015-06-20 01:07:01 +07:00
|
|
|
struct i915_wa_ctx_bb {
|
|
|
|
u32 offset;
|
|
|
|
u32 size;
|
|
|
|
} indirect_ctx, per_ctx;
|
2016-08-15 16:49:04 +07:00
|
|
|
struct i915_vma *vma;
|
2015-06-20 01:07:01 +07:00
|
|
|
};
|
|
|
|
|
2018-02-21 16:56:36 +07:00
|
|
|
struct i915_request;
|
2016-07-01 23:23:25 +07:00
|
|
|
|
2018-02-28 17:11:52 +07:00
|
|
|
#define I915_MAX_VCS 4
|
|
|
|
#define I915_MAX_VECS 2
|
|
|
|
|
2017-03-02 03:26:15 +07:00
|
|
|
/*
|
|
|
|
* Engine IDs definitions.
|
|
|
|
* Keep instances of the same type engine together.
|
|
|
|
*/
|
|
|
|
enum intel_engine_id {
|
2019-03-06 01:03:30 +07:00
|
|
|
RCS0 = 0,
|
|
|
|
BCS0,
|
|
|
|
VCS0,
|
|
|
|
VCS1,
|
2017-03-02 03:26:15 +07:00
|
|
|
VCS2,
|
2018-02-28 17:11:52 +07:00
|
|
|
VCS3,
|
2019-03-06 01:03:30 +07:00
|
|
|
#define _VCS(n) (VCS0 + (n))
|
|
|
|
VECS0,
|
|
|
|
VECS1
|
|
|
|
#define _VECS(n) (VECS0 + (n))
|
2017-03-02 03:26:15 +07:00
|
|
|
};
|
|
|
|
|
2018-07-16 20:21:54 +07:00
|
|
|
struct st_preempt_hang {
|
|
|
|
struct completion completion;
|
drm/i915/execlists: Suppress preempting self
In order to avoid preempting ourselves, we currently refuse to schedule
the tasklet if we reschedule an inflight context. However, this glosses
over a few issues such as what happens after a CS completion event and
we then preempt the newly executing context with itself, or if something
else causes a tasklet_schedule triggering the same evaluation to
preempt the active context with itself.
However, when we avoid preempting ELSP[0], we still retain the preemption
value as it may match a second preemption request within the same time period
that we need to resolve after the next CS event. However, since we only
store the maximum preemption priority seen, it may not match the
subsequent event and so we should double check whether or not we
actually do need to trigger a preempt-to-idle by comparing the top
priorities from each queue. Later, this gives us a hook for finer
control over deciding whether the preempt-to-idle is justified.
The sequence of events where we end up preempting for no avail is:
1. Queue requests/contexts A, B
2. Priority boost A; no preemption as it is executing, but keep hint
3. After CS switch, B is less than hint, force preempt-to-idle
4. Resubmit B after idling
v2: We can simplify a bunch of tests based on the knowledge that PI will
ensure that earlier requests along the same context will have the highest
priority.
v3: Demonstrate the stale preemption hint with a selftest
References: a2bf92e8cc16 ("drm/i915/execlists: Avoid kicking priority on the current context")
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20190129185452.20989-4-chris@chris-wilson.co.uk
2019-01-30 01:54:52 +07:00
|
|
|
unsigned int count;
|
2018-07-16 20:21:54 +07:00
|
|
|
bool inject_hang;
|
|
|
|
};
|
|
|
|
|
2017-09-22 19:43:03 +07:00
|
|
|
/**
|
|
|
|
* struct intel_engine_execlists - execlist submission queue and port state
|
|
|
|
*
|
|
|
|
* The struct intel_engine_execlists represents the combined logical state of
|
|
|
|
* driver and the hardware state for execlist mode of submission.
|
|
|
|
*/
|
|
|
|
struct intel_engine_execlists {
|
|
|
|
/**
|
2017-11-16 20:32:37 +07:00
|
|
|
* @tasklet: softirq tasklet for bottom handler
|
2017-09-22 19:43:03 +07:00
|
|
|
*/
|
2017-11-16 20:32:37 +07:00
|
|
|
struct tasklet_struct tasklet;
|
2017-09-22 19:43:03 +07:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @default_priolist: priority list for I915_PRIORITY_NORMAL
|
|
|
|
*/
|
|
|
|
struct i915_priolist default_priolist;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @no_priolist: priority lists disabled
|
|
|
|
*/
|
|
|
|
bool no_priolist;
|
|
|
|
|
2017-12-08 05:24:34 +07:00
|
|
|
/**
|
2018-03-02 23:14:59 +07:00
|
|
|
* @submit_reg: gen-specific execlist submission register
|
|
|
|
* set to the ExecList Submission Port (elsp) register pre-Gen11 and to
|
|
|
|
* the ExecList Submission Queue Contents register array for Gen11+
|
2017-12-08 05:24:34 +07:00
|
|
|
*/
|
2018-03-02 23:14:59 +07:00
|
|
|
u32 __iomem *submit_reg;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @ctrl_reg: the enhanced execlists control register, used to load the
|
|
|
|
* submit queue on the HW and to request preemptions to idle
|
|
|
|
*/
|
|
|
|
u32 __iomem *ctrl_reg;
|
2017-12-08 05:24:34 +07:00
|
|
|
|
2017-09-22 19:43:03 +07:00
|
|
|
/**
|
|
|
|
* @port: execlist port states
|
|
|
|
*
|
|
|
|
* For each hardware ELSP (ExecList Submission Port) we keep
|
|
|
|
* track of the last request and the number of times we submitted
|
|
|
|
* that port to hw. We then count the number of times the hw reports
|
|
|
|
* a context completion or preemption. As only one context can
|
|
|
|
* be active on hw, we limit resubmission of context to port[0]. This
|
|
|
|
* is called Lite Restore, of the context.
|
|
|
|
*/
|
|
|
|
struct execlist_port {
|
|
|
|
/**
|
|
|
|
* @request_count: combined request and submission count
|
|
|
|
*/
|
2018-02-21 16:56:36 +07:00
|
|
|
struct i915_request *request_count;
|
2017-09-22 19:43:03 +07:00
|
|
|
#define EXECLIST_COUNT_BITS 2
|
|
|
|
#define port_request(p) ptr_mask_bits((p)->request_count, EXECLIST_COUNT_BITS)
|
|
|
|
#define port_count(p) ptr_unmask_bits((p)->request_count, EXECLIST_COUNT_BITS)
|
|
|
|
#define port_pack(rq, count) ptr_pack_bits(rq, count, EXECLIST_COUNT_BITS)
|
|
|
|
#define port_unpack(p, count) ptr_unpack_bits((p)->request_count, count, EXECLIST_COUNT_BITS)
|
|
|
|
#define port_set(p, packed) ((p)->request_count = (packed))
|
|
|
|
#define port_isset(p) ((p)->request_count)
|
2017-09-22 19:43:06 +07:00
|
|
|
#define port_index(p, execlists) ((p) - (execlists)->port)
|
2017-09-22 19:43:03 +07:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @context_id: context ID for port
|
|
|
|
*/
|
|
|
|
GEM_DEBUG_DECL(u32 context_id);
|
2017-09-22 19:43:07 +07:00
|
|
|
|
|
|
|
#define EXECLIST_MAX_PORTS 2
|
|
|
|
} port[EXECLIST_MAX_PORTS];
|
|
|
|
|
drm/i915/execlists: Preemption!
When we write to ELSP, it triggers a context preemption at the earliest
arbitration point (3DPRIMITIVE, some PIPECONTROLs, a few other
operations and the explicit MI_ARB_CHECK). If this is to the same
context, it triggers a LITE_RESTORE where the RING_TAIL is merely
updated (used currently to chain requests from the same context
together, avoiding bubbles). However, if it is to a different context, a
full context-switch is performed and it will start to execute the new
context saving the image of the old for later execution.
Previously we avoided preemption by only submitting a new context when
the old was idle. But now we wish embrace it, and if the new request has
a higher priority than the currently executing request, we write to the
ELSP regardless, thus triggering preemption, but we tell the GPU to
switch to our special preemption context (not the target). In the
context-switch interrupt handler, we know that the previous contexts
have finished execution and so can unwind all the incomplete requests
and compute the new highest priority request to execute.
It would be feasible to avoid the switch-to-idle intermediate by
programming the ELSP with the target context. The difficulty is in
tracking which request that should be whilst maintaining the dependency
change, the error comes in with coalesced requests. As we only track the
most recent request and its priority, we may run into the issue of being
tricked in preempting a high priority request that was followed by a
low priority request from the same context (e.g. for PI); worse still
that earlier request may be our own dependency and the order then broken
by preemption. By injecting the switch-to-idle and then recomputing the
priority queue, we avoid the issue with tracking in-flight coalesced
requests. Having tried the preempt-to-busy approach, and failed to find
a way around the coalesced priority issue, Michal's original proposal to
inject an idle context (based on handling GuC preemption) succeeds.
The current heuristic for deciding when to preempt are only if the new
request is of higher priority, and has the privileged priority of
greater than 0. Note that the scheduler remains unfair!
v2: Disable for gen8 (bdw/bsw) as we need additional w/a for GPGPU.
Since, the feature is now conditional and not always available when we
have a scheduler, make it known via the HAS_SCHEDULER GETPARAM (now a
capability mask).
v3: Stylistic tweaks.
v4: Appease Joonas with a snippet of kerneldoc, only to fuel to fire of
the preempt vs preempting debate.
Suggested-by: Michal Winiarski <michal.winiarski@intel.com>
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Michal Winiarski <michal.winiarski@intel.com>
Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Cc: Arkadiusz Hiler <arkadiusz.hiler@intel.com>
Cc: Mika Kuoppala <mika.kuoppala@intel.com>
Cc: Ben Widawsky <benjamin.widawsky@intel.com>
Cc: Zhenyu Wang <zhenyuw@linux.intel.com>
Cc: Zhi Wang <zhi.a.wang@intel.com>
Reviewed-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20171003203453.15692-8-chris@chris-wilson.co.uk
2017-10-04 03:34:52 +07:00
|
|
|
/**
|
2017-10-24 04:32:36 +07:00
|
|
|
* @active: is the HW active? We consider the HW as active after
|
|
|
|
* submitting any context for execution and until we have seen the
|
|
|
|
* last context completion event. After that, we do not expect any
|
|
|
|
* more events until we submit, and so can park the HW.
|
|
|
|
*
|
|
|
|
* As we have a small number of different sources from which we feed
|
|
|
|
* the HW, we track the state of each inside a single bitfield.
|
drm/i915/execlists: Preemption!
When we write to ELSP, it triggers a context preemption at the earliest
arbitration point (3DPRIMITIVE, some PIPECONTROLs, a few other
operations and the explicit MI_ARB_CHECK). If this is to the same
context, it triggers a LITE_RESTORE where the RING_TAIL is merely
updated (used currently to chain requests from the same context
together, avoiding bubbles). However, if it is to a different context, a
full context-switch is performed and it will start to execute the new
context saving the image of the old for later execution.
Previously we avoided preemption by only submitting a new context when
the old was idle. But now we wish embrace it, and if the new request has
a higher priority than the currently executing request, we write to the
ELSP regardless, thus triggering preemption, but we tell the GPU to
switch to our special preemption context (not the target). In the
context-switch interrupt handler, we know that the previous contexts
have finished execution and so can unwind all the incomplete requests
and compute the new highest priority request to execute.
It would be feasible to avoid the switch-to-idle intermediate by
programming the ELSP with the target context. The difficulty is in
tracking which request that should be whilst maintaining the dependency
change, the error comes in with coalesced requests. As we only track the
most recent request and its priority, we may run into the issue of being
tricked in preempting a high priority request that was followed by a
low priority request from the same context (e.g. for PI); worse still
that earlier request may be our own dependency and the order then broken
by preemption. By injecting the switch-to-idle and then recomputing the
priority queue, we avoid the issue with tracking in-flight coalesced
requests. Having tried the preempt-to-busy approach, and failed to find
a way around the coalesced priority issue, Michal's original proposal to
inject an idle context (based on handling GuC preemption) succeeds.
The current heuristic for deciding when to preempt are only if the new
request is of higher priority, and has the privileged priority of
greater than 0. Note that the scheduler remains unfair!
v2: Disable for gen8 (bdw/bsw) as we need additional w/a for GPGPU.
Since, the feature is now conditional and not always available when we
have a scheduler, make it known via the HAS_SCHEDULER GETPARAM (now a
capability mask).
v3: Stylistic tweaks.
v4: Appease Joonas with a snippet of kerneldoc, only to fuel to fire of
the preempt vs preempting debate.
Suggested-by: Michal Winiarski <michal.winiarski@intel.com>
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Michal Winiarski <michal.winiarski@intel.com>
Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Cc: Arkadiusz Hiler <arkadiusz.hiler@intel.com>
Cc: Mika Kuoppala <mika.kuoppala@intel.com>
Cc: Ben Widawsky <benjamin.widawsky@intel.com>
Cc: Zhenyu Wang <zhenyuw@linux.intel.com>
Cc: Zhi Wang <zhi.a.wang@intel.com>
Reviewed-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20171003203453.15692-8-chris@chris-wilson.co.uk
2017-10-04 03:34:52 +07:00
|
|
|
*/
|
2017-10-24 04:32:36 +07:00
|
|
|
unsigned int active;
|
|
|
|
#define EXECLISTS_ACTIVE_USER 0
|
|
|
|
#define EXECLISTS_ACTIVE_PREEMPT 1
|
2017-11-20 19:34:58 +07:00
|
|
|
#define EXECLISTS_ACTIVE_HWACK 2
|
drm/i915/execlists: Preemption!
When we write to ELSP, it triggers a context preemption at the earliest
arbitration point (3DPRIMITIVE, some PIPECONTROLs, a few other
operations and the explicit MI_ARB_CHECK). If this is to the same
context, it triggers a LITE_RESTORE where the RING_TAIL is merely
updated (used currently to chain requests from the same context
together, avoiding bubbles). However, if it is to a different context, a
full context-switch is performed and it will start to execute the new
context saving the image of the old for later execution.
Previously we avoided preemption by only submitting a new context when
the old was idle. But now we wish embrace it, and if the new request has
a higher priority than the currently executing request, we write to the
ELSP regardless, thus triggering preemption, but we tell the GPU to
switch to our special preemption context (not the target). In the
context-switch interrupt handler, we know that the previous contexts
have finished execution and so can unwind all the incomplete requests
and compute the new highest priority request to execute.
It would be feasible to avoid the switch-to-idle intermediate by
programming the ELSP with the target context. The difficulty is in
tracking which request that should be whilst maintaining the dependency
change, the error comes in with coalesced requests. As we only track the
most recent request and its priority, we may run into the issue of being
tricked in preempting a high priority request that was followed by a
low priority request from the same context (e.g. for PI); worse still
that earlier request may be our own dependency and the order then broken
by preemption. By injecting the switch-to-idle and then recomputing the
priority queue, we avoid the issue with tracking in-flight coalesced
requests. Having tried the preempt-to-busy approach, and failed to find
a way around the coalesced priority issue, Michal's original proposal to
inject an idle context (based on handling GuC preemption) succeeds.
The current heuristic for deciding when to preempt are only if the new
request is of higher priority, and has the privileged priority of
greater than 0. Note that the scheduler remains unfair!
v2: Disable for gen8 (bdw/bsw) as we need additional w/a for GPGPU.
Since, the feature is now conditional and not always available when we
have a scheduler, make it known via the HAS_SCHEDULER GETPARAM (now a
capability mask).
v3: Stylistic tweaks.
v4: Appease Joonas with a snippet of kerneldoc, only to fuel to fire of
the preempt vs preempting debate.
Suggested-by: Michal Winiarski <michal.winiarski@intel.com>
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Michal Winiarski <michal.winiarski@intel.com>
Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Cc: Arkadiusz Hiler <arkadiusz.hiler@intel.com>
Cc: Mika Kuoppala <mika.kuoppala@intel.com>
Cc: Ben Widawsky <benjamin.widawsky@intel.com>
Cc: Zhenyu Wang <zhenyuw@linux.intel.com>
Cc: Zhi Wang <zhi.a.wang@intel.com>
Reviewed-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20171003203453.15692-8-chris@chris-wilson.co.uk
2017-10-04 03:34:52 +07:00
|
|
|
|
2017-09-22 19:43:07 +07:00
|
|
|
/**
|
|
|
|
* @port_mask: number of execlist ports - 1
|
|
|
|
*/
|
|
|
|
unsigned int port_mask;
|
2017-09-22 19:43:03 +07:00
|
|
|
|
2018-02-22 21:22:29 +07:00
|
|
|
/**
|
2019-01-30 01:54:51 +07:00
|
|
|
* @queue_priority_hint: Highest pending priority.
|
2018-02-22 21:22:29 +07:00
|
|
|
*
|
|
|
|
* When we add requests into the queue, or adjust the priority of
|
|
|
|
* executing requests, we compute the maximum priority of those
|
|
|
|
* pending requests. We can then use this value to determine if
|
|
|
|
* we need to preempt the executing requests to service the queue.
|
2019-01-30 01:54:51 +07:00
|
|
|
* However, since the we may have recorded the priority of an inflight
|
|
|
|
* request we wanted to preempt but since completed, at the time of
|
|
|
|
* dequeuing the priority hint may no longer may match the highest
|
|
|
|
* available request priority.
|
2018-02-22 21:22:29 +07:00
|
|
|
*/
|
2019-01-30 01:54:51 +07:00
|
|
|
int queue_priority_hint;
|
2018-02-22 21:22:29 +07:00
|
|
|
|
2017-09-22 19:43:03 +07:00
|
|
|
/**
|
|
|
|
* @queue: queue of requests, in priority lists
|
|
|
|
*/
|
2018-06-29 14:53:20 +07:00
|
|
|
struct rb_root_cached queue;
|
2017-09-22 19:43:03 +07:00
|
|
|
|
|
|
|
/**
|
2018-06-29 03:12:07 +07:00
|
|
|
* @csb_write: control register for Context Switch buffer
|
|
|
|
*
|
|
|
|
* Note this register may be either mmio or HWSP shadow.
|
2017-09-22 19:43:03 +07:00
|
|
|
*/
|
2018-06-29 03:12:07 +07:00
|
|
|
u32 *csb_write;
|
2017-09-22 19:43:03 +07:00
|
|
|
|
|
|
|
/**
|
2018-06-29 03:12:07 +07:00
|
|
|
* @csb_status: status array for Context Switch buffer
|
|
|
|
*
|
|
|
|
* Note these register may be either mmio or HWSP shadow.
|
2017-09-22 19:43:03 +07:00
|
|
|
*/
|
2018-06-29 03:12:07 +07:00
|
|
|
u32 *csb_status;
|
2018-02-08 04:05:44 +07:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @preempt_complete_status: expected CSB upon completing preemption
|
|
|
|
*/
|
|
|
|
u32 preempt_complete_status;
|
2018-06-29 03:12:07 +07:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @csb_head: context status buffer head
|
|
|
|
*/
|
|
|
|
u8 csb_head;
|
2018-07-16 20:21:54 +07:00
|
|
|
|
|
|
|
I915_SELFTEST_DECLARE(struct st_preempt_hang preempt_hang;)
|
2017-09-22 19:43:03 +07:00
|
|
|
};
|
|
|
|
|
2017-04-10 21:34:31 +07:00
|
|
|
#define INTEL_ENGINE_CS_MAX_NAME 8
|
|
|
|
|
2016-05-06 21:40:21 +07:00
|
|
|
struct intel_engine_cs {
|
|
|
|
struct drm_i915_private *i915;
|
2017-04-10 21:34:31 +07:00
|
|
|
char name[INTEL_ENGINE_CS_MAX_NAME];
|
2017-11-10 21:26:27 +07:00
|
|
|
|
2017-03-02 03:26:15 +07:00
|
|
|
enum intel_engine_id id;
|
|
|
|
unsigned int hw_id;
|
2017-04-28 14:53:36 +07:00
|
|
|
unsigned int guc_id;
|
2019-03-06 01:03:30 +07:00
|
|
|
intel_engine_mask_t mask;
|
2017-04-10 21:34:29 +07:00
|
|
|
|
2017-11-10 21:26:27 +07:00
|
|
|
u8 uabi_class;
|
|
|
|
|
2017-04-10 21:34:29 +07:00
|
|
|
u8 class;
|
|
|
|
u8 instance;
|
2017-04-28 14:53:36 +07:00
|
|
|
u32 context_size;
|
|
|
|
u32 mmio_base;
|
|
|
|
|
2016-08-03 04:50:21 +07:00
|
|
|
struct intel_ring *buffer;
|
2018-05-02 23:38:39 +07:00
|
|
|
|
|
|
|
struct i915_timeline timeline;
|
2010-05-21 08:08:55 +07:00
|
|
|
|
2017-11-10 21:26:33 +07:00
|
|
|
struct drm_i915_gem_object *default_state;
|
2018-05-18 16:02:11 +07:00
|
|
|
void *pinned_default_state;
|
2016-10-28 19:58:31 +07:00
|
|
|
|
drm/i915: Slaughter the thundering i915_wait_request herd
One particularly stressful scenario consists of many independent tasks
all competing for GPU time and waiting upon the results (e.g. realtime
transcoding of many, many streams). One bottleneck in particular is that
each client waits on its own results, but every client is woken up after
every batchbuffer - hence the thunder of hooves as then every client must
do its heavyweight dance to read a coherent seqno to see if it is the
lucky one.
Ideally, we only want one client to wake up after the interrupt and
check its request for completion. Since the requests must retire in
order, we can select the first client on the oldest request to be woken.
Once that client has completed his wait, we can then wake up the
next client and so on. However, all clients then incur latency as every
process in the chain may be delayed for scheduling - this may also then
cause some priority inversion. To reduce the latency, when a client
is added or removed from the list, we scan the tree for completed
seqno and wake up all the completed waiters in parallel.
Using igt/benchmarks/gem_latency, we can demonstrate this effect. The
benchmark measures the number of GPU cycles between completion of a
batch and the client waking up from a call to wait-ioctl. With many
concurrent waiters, with each on a different request, we observe that
the wakeup latency before the patch scales nearly linearly with the
number of waiters (before external factors kick in making the scaling much
worse). After applying the patch, we can see that only the single waiter
for the request is being woken up, providing a constant wakeup latency
for every operation. However, the situation is not quite as rosy for
many waiters on the same request, though to the best of my knowledge this
is much less likely in practice. Here, we can observe that the
concurrent waiters incur extra latency from being woken up by the
solitary bottom-half, rather than directly by the interrupt. This
appears to be scheduler induced (having discounted adverse effects from
having a rbtree walk/erase in the wakeup path), each additional
wake_up_process() costs approximately 1us on big core. Another effect of
performing the secondary wakeups from the first bottom-half is the
incurred delay this imposes on high priority threads - rather than
immediately returning to userspace and leaving the interrupt handler to
wake the others.
To offset the delay incurred with additional waiters on a request, we
could use a hybrid scheme that did a quick read in the interrupt handler
and dequeued all the completed waiters (incurring the overhead in the
interrupt handler, not the best plan either as we then incur GPU
submission latency) but we would still have to wake up the bottom-half
every time to do the heavyweight slow read. Or we could only kick the
waiters on the seqno with the same priority as the current task (i.e. in
the realtime waiter scenario, only it is woken up immediately by the
interrupt and simply queues the next waiter before returning to userspace,
minimising its delay at the expense of the chain, and also reducing
contention on its scheduler runqueue). This is effective at avoid long
pauses in the interrupt handler and at avoiding the extra latency in
realtime/high-priority waiters.
v2: Convert from a kworker per engine into a dedicated kthread for the
bottom-half.
v3: Rename request members and tweak comments.
v4: Use a per-engine spinlock in the breadcrumbs bottom-half.
v5: Fix race in locklessly checking waiter status and kicking the task on
adding a new waiter.
v6: Fix deciding when to force the timer to hide missing interrupts.
v7: Move the bottom-half from the kthread to the first client process.
v8: Reword a few comments
v9: Break the busy loop when the interrupt is unmasked or has fired.
v10: Comments, unnecessary churn, better debugging from Tvrtko
v11: Wake all completed waiters on removing the current bottom-half to
reduce the latency of waking up a herd of clients all waiting on the
same request.
v12: Rearrange missed-interrupt fault injection so that it works with
igt/drv_missed_irq_hang
v13: Rename intel_breadcrumb and friends to intel_wait in preparation
for signal handling.
v14: RCU commentary, assert_spin_locked
v15: Hide BUG_ON behind the compiler; report on gem_latency findings.
v16: Sort seqno-groups by priority so that first-waiter has the highest
task priority (and so avoid priority inversion).
v17: Add waiters to post-mortem GPU hang state.
v18: Return early for a completed wait after acquiring the spinlock.
Avoids adding ourselves to the tree if the is already complete, and
skips the awkward question of why we don't do completion wakeups for
waits earlier than or equal to ourselves.
v19: Prepare for init_breadcrumbs to fail. Later patches may want to
allocate during init, so be prepared to propagate back the error code.
Testcase: igt/gem_concurrent_blit
Testcase: igt/benchmarks/gem_latency
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: "Rogozhkin, Dmitry V" <dmitry.v.rogozhkin@intel.com>
Cc: "Gong, Zhipeng" <zhipeng.gong@intel.com>
Cc: Tvrtko Ursulin <tvrtko.ursulin@linux.intel.com>
Cc: Dave Gordon <david.s.gordon@intel.com>
Cc: "Goel, Akash" <akash.goel@intel.com>
Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@linux.intel.com> #v18
Link: http://patchwork.freedesktop.org/patch/msgid/1467390209-3576-6-git-send-email-chris@chris-wilson.co.uk
2016-07-01 23:23:15 +07:00
|
|
|
/* Rather than have every client wait upon all user interrupts,
|
|
|
|
* with the herd waking after every interrupt and each doing the
|
|
|
|
* heavyweight seqno dance, we delegate the task (of being the
|
|
|
|
* bottom-half of the user interrupt) to the first client. After
|
|
|
|
* every interrupt, we wake up one client, who does the heavyweight
|
|
|
|
* coherent seqno read and either goes back to sleep (if incomplete),
|
|
|
|
* or wakes up all the completed clients in parallel, before then
|
|
|
|
* transferring the bottom-half status to the next client in the queue.
|
|
|
|
*
|
|
|
|
* Compared to walking the entire list of waiters in a single dedicated
|
|
|
|
* bottom-half, we reduce the latency of the first waiter by avoiding
|
|
|
|
* a context switch, but incur additional coherent seqno reads when
|
|
|
|
* following the chain of request breadcrumbs. Since it is most likely
|
|
|
|
* that we have a single client waiting on each seqno, then reducing
|
|
|
|
* the overhead of waking that client is much preferred.
|
|
|
|
*/
|
|
|
|
struct intel_breadcrumbs {
|
drm/i915: Replace global breadcrumbs with per-context interrupt tracking
A few years ago, see commit 688e6c725816 ("drm/i915: Slaughter the
thundering i915_wait_request herd"), the issue of handling multiple
clients waiting in parallel was brought to our attention. The
requirement was that every client should be woken immediately upon its
request being signaled, without incurring any cpu overhead.
To handle certain fragility of our hw meant that we could not do a
simple check inside the irq handler (some generations required almost
unbounded delays before we could be sure of seqno coherency) and so
request completion checking required delegation.
Before commit 688e6c725816, the solution was simple. Every client
waiting on a request would be woken on every interrupt and each would do
a heavyweight check to see if their request was complete. Commit
688e6c725816 introduced an rbtree so that only the earliest waiter on
the global timeline would woken, and would wake the next and so on.
(Along with various complications to handle requests being reordered
along the global timeline, and also a requirement for kthread to provide
a delegate for fence signaling that had no process context.)
The global rbtree depends on knowing the execution timeline (and global
seqno). Without knowing that order, we must instead check all contexts
queued to the HW to see which may have advanced. We trim that list by
only checking queued contexts that are being waited on, but still we
keep a list of all active contexts and their active signalers that we
inspect from inside the irq handler. By moving the waiters onto the fence
signal list, we can combine the client wakeup with the dma_fence
signaling (a dramatic reduction in complexity, but does require the HW
being coherent, the seqno must be visible from the cpu before the
interrupt is raised - we keep a timer backup just in case).
Having previously fixed all the issues with irq-seqno serialisation (by
inserting delays onto the GPU after each request instead of random delays
on the CPU after each interrupt), we can rely on the seqno state to
perfom direct wakeups from the interrupt handler. This allows us to
preserve our single context switch behaviour of the current routine,
with the only downside that we lose the RT priority sorting of wakeups.
In general, direct wakeup latency of multiple clients is about the same
(about 10% better in most cases) with a reduction in total CPU time spent
in the waiter (about 20-50% depending on gen). Average herd behaviour is
improved, but at the cost of not delegating wakeups on task_prio.
v2: Capture fence signaling state for error state and add comments to
warm even the most cold of hearts.
v3: Check if the request is still active before busywaiting
v4: Reduce the amount of pointer misdirection with list_for_each_safe
and using a local i915_request variable inside the loops
v5: Add a missing pluralisation to a purely informative selftest message.
References: 688e6c725816 ("drm/i915: Slaughter the thundering i915_wait_request herd")
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20190129205230.19056-2-chris@chris-wilson.co.uk
2019-01-30 03:52:29 +07:00
|
|
|
spinlock_t irq_lock;
|
|
|
|
struct list_head signalers;
|
2017-03-04 02:08:24 +07:00
|
|
|
|
drm/i915: Replace global breadcrumbs with per-context interrupt tracking
A few years ago, see commit 688e6c725816 ("drm/i915: Slaughter the
thundering i915_wait_request herd"), the issue of handling multiple
clients waiting in parallel was brought to our attention. The
requirement was that every client should be woken immediately upon its
request being signaled, without incurring any cpu overhead.
To handle certain fragility of our hw meant that we could not do a
simple check inside the irq handler (some generations required almost
unbounded delays before we could be sure of seqno coherency) and so
request completion checking required delegation.
Before commit 688e6c725816, the solution was simple. Every client
waiting on a request would be woken on every interrupt and each would do
a heavyweight check to see if their request was complete. Commit
688e6c725816 introduced an rbtree so that only the earliest waiter on
the global timeline would woken, and would wake the next and so on.
(Along with various complications to handle requests being reordered
along the global timeline, and also a requirement for kthread to provide
a delegate for fence signaling that had no process context.)
The global rbtree depends on knowing the execution timeline (and global
seqno). Without knowing that order, we must instead check all contexts
queued to the HW to see which may have advanced. We trim that list by
only checking queued contexts that are being waited on, but still we
keep a list of all active contexts and their active signalers that we
inspect from inside the irq handler. By moving the waiters onto the fence
signal list, we can combine the client wakeup with the dma_fence
signaling (a dramatic reduction in complexity, but does require the HW
being coherent, the seqno must be visible from the cpu before the
interrupt is raised - we keep a timer backup just in case).
Having previously fixed all the issues with irq-seqno serialisation (by
inserting delays onto the GPU after each request instead of random delays
on the CPU after each interrupt), we can rely on the seqno state to
perfom direct wakeups from the interrupt handler. This allows us to
preserve our single context switch behaviour of the current routine,
with the only downside that we lose the RT priority sorting of wakeups.
In general, direct wakeup latency of multiple clients is about the same
(about 10% better in most cases) with a reduction in total CPU time spent
in the waiter (about 20-50% depending on gen). Average herd behaviour is
improved, but at the cost of not delegating wakeups on task_prio.
v2: Capture fence signaling state for error state and add comments to
warm even the most cold of hearts.
v3: Check if the request is still active before busywaiting
v4: Reduce the amount of pointer misdirection with list_for_each_safe
and using a local i915_request variable inside the loops
v5: Add a missing pluralisation to a purely informative selftest message.
References: 688e6c725816 ("drm/i915: Slaughter the thundering i915_wait_request herd")
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20190129205230.19056-2-chris@chris-wilson.co.uk
2019-01-30 03:52:29 +07:00
|
|
|
struct irq_work irq_work; /* for use from inside irq_lock */
|
2018-02-22 16:25:44 +07:00
|
|
|
|
2017-10-25 21:39:42 +07:00
|
|
|
unsigned int irq_enabled;
|
2016-07-06 18:39:02 +07:00
|
|
|
|
drm/i915: Replace global breadcrumbs with per-context interrupt tracking
A few years ago, see commit 688e6c725816 ("drm/i915: Slaughter the
thundering i915_wait_request herd"), the issue of handling multiple
clients waiting in parallel was brought to our attention. The
requirement was that every client should be woken immediately upon its
request being signaled, without incurring any cpu overhead.
To handle certain fragility of our hw meant that we could not do a
simple check inside the irq handler (some generations required almost
unbounded delays before we could be sure of seqno coherency) and so
request completion checking required delegation.
Before commit 688e6c725816, the solution was simple. Every client
waiting on a request would be woken on every interrupt and each would do
a heavyweight check to see if their request was complete. Commit
688e6c725816 introduced an rbtree so that only the earliest waiter on
the global timeline would woken, and would wake the next and so on.
(Along with various complications to handle requests being reordered
along the global timeline, and also a requirement for kthread to provide
a delegate for fence signaling that had no process context.)
The global rbtree depends on knowing the execution timeline (and global
seqno). Without knowing that order, we must instead check all contexts
queued to the HW to see which may have advanced. We trim that list by
only checking queued contexts that are being waited on, but still we
keep a list of all active contexts and their active signalers that we
inspect from inside the irq handler. By moving the waiters onto the fence
signal list, we can combine the client wakeup with the dma_fence
signaling (a dramatic reduction in complexity, but does require the HW
being coherent, the seqno must be visible from the cpu before the
interrupt is raised - we keep a timer backup just in case).
Having previously fixed all the issues with irq-seqno serialisation (by
inserting delays onto the GPU after each request instead of random delays
on the CPU after each interrupt), we can rely on the seqno state to
perfom direct wakeups from the interrupt handler. This allows us to
preserve our single context switch behaviour of the current routine,
with the only downside that we lose the RT priority sorting of wakeups.
In general, direct wakeup latency of multiple clients is about the same
(about 10% better in most cases) with a reduction in total CPU time spent
in the waiter (about 20-50% depending on gen). Average herd behaviour is
improved, but at the cost of not delegating wakeups on task_prio.
v2: Capture fence signaling state for error state and add comments to
warm even the most cold of hearts.
v3: Check if the request is still active before busywaiting
v4: Reduce the amount of pointer misdirection with list_for_each_safe
and using a local i915_request variable inside the loops
v5: Add a missing pluralisation to a purely informative selftest message.
References: 688e6c725816 ("drm/i915: Slaughter the thundering i915_wait_request herd")
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20190129205230.19056-2-chris@chris-wilson.co.uk
2019-01-30 03:52:29 +07:00
|
|
|
bool irq_armed;
|
drm/i915: Slaughter the thundering i915_wait_request herd
One particularly stressful scenario consists of many independent tasks
all competing for GPU time and waiting upon the results (e.g. realtime
transcoding of many, many streams). One bottleneck in particular is that
each client waits on its own results, but every client is woken up after
every batchbuffer - hence the thunder of hooves as then every client must
do its heavyweight dance to read a coherent seqno to see if it is the
lucky one.
Ideally, we only want one client to wake up after the interrupt and
check its request for completion. Since the requests must retire in
order, we can select the first client on the oldest request to be woken.
Once that client has completed his wait, we can then wake up the
next client and so on. However, all clients then incur latency as every
process in the chain may be delayed for scheduling - this may also then
cause some priority inversion. To reduce the latency, when a client
is added or removed from the list, we scan the tree for completed
seqno and wake up all the completed waiters in parallel.
Using igt/benchmarks/gem_latency, we can demonstrate this effect. The
benchmark measures the number of GPU cycles between completion of a
batch and the client waking up from a call to wait-ioctl. With many
concurrent waiters, with each on a different request, we observe that
the wakeup latency before the patch scales nearly linearly with the
number of waiters (before external factors kick in making the scaling much
worse). After applying the patch, we can see that only the single waiter
for the request is being woken up, providing a constant wakeup latency
for every operation. However, the situation is not quite as rosy for
many waiters on the same request, though to the best of my knowledge this
is much less likely in practice. Here, we can observe that the
concurrent waiters incur extra latency from being woken up by the
solitary bottom-half, rather than directly by the interrupt. This
appears to be scheduler induced (having discounted adverse effects from
having a rbtree walk/erase in the wakeup path), each additional
wake_up_process() costs approximately 1us on big core. Another effect of
performing the secondary wakeups from the first bottom-half is the
incurred delay this imposes on high priority threads - rather than
immediately returning to userspace and leaving the interrupt handler to
wake the others.
To offset the delay incurred with additional waiters on a request, we
could use a hybrid scheme that did a quick read in the interrupt handler
and dequeued all the completed waiters (incurring the overhead in the
interrupt handler, not the best plan either as we then incur GPU
submission latency) but we would still have to wake up the bottom-half
every time to do the heavyweight slow read. Or we could only kick the
waiters on the seqno with the same priority as the current task (i.e. in
the realtime waiter scenario, only it is woken up immediately by the
interrupt and simply queues the next waiter before returning to userspace,
minimising its delay at the expense of the chain, and also reducing
contention on its scheduler runqueue). This is effective at avoid long
pauses in the interrupt handler and at avoiding the extra latency in
realtime/high-priority waiters.
v2: Convert from a kworker per engine into a dedicated kthread for the
bottom-half.
v3: Rename request members and tweak comments.
v4: Use a per-engine spinlock in the breadcrumbs bottom-half.
v5: Fix race in locklessly checking waiter status and kicking the task on
adding a new waiter.
v6: Fix deciding when to force the timer to hide missing interrupts.
v7: Move the bottom-half from the kthread to the first client process.
v8: Reword a few comments
v9: Break the busy loop when the interrupt is unmasked or has fired.
v10: Comments, unnecessary churn, better debugging from Tvrtko
v11: Wake all completed waiters on removing the current bottom-half to
reduce the latency of waking up a herd of clients all waiting on the
same request.
v12: Rearrange missed-interrupt fault injection so that it works with
igt/drv_missed_irq_hang
v13: Rename intel_breadcrumb and friends to intel_wait in preparation
for signal handling.
v14: RCU commentary, assert_spin_locked
v15: Hide BUG_ON behind the compiler; report on gem_latency findings.
v16: Sort seqno-groups by priority so that first-waiter has the highest
task priority (and so avoid priority inversion).
v17: Add waiters to post-mortem GPU hang state.
v18: Return early for a completed wait after acquiring the spinlock.
Avoids adding ourselves to the tree if the is already complete, and
skips the awkward question of why we don't do completion wakeups for
waits earlier than or equal to ourselves.
v19: Prepare for init_breadcrumbs to fail. Later patches may want to
allocate during init, so be prepared to propagate back the error code.
Testcase: igt/gem_concurrent_blit
Testcase: igt/benchmarks/gem_latency
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: "Rogozhkin, Dmitry V" <dmitry.v.rogozhkin@intel.com>
Cc: "Gong, Zhipeng" <zhipeng.gong@intel.com>
Cc: Tvrtko Ursulin <tvrtko.ursulin@linux.intel.com>
Cc: Dave Gordon <david.s.gordon@intel.com>
Cc: "Goel, Akash" <akash.goel@intel.com>
Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@linux.intel.com> #v18
Link: http://patchwork.freedesktop.org/patch/msgid/1467390209-3576-6-git-send-email-chris@chris-wilson.co.uk
2016-07-01 23:23:15 +07:00
|
|
|
} breadcrumbs;
|
|
|
|
|
2019-02-23 07:01:02 +07:00
|
|
|
struct intel_engine_pmu {
|
drm/i915/pmu: Expose a PMU interface for perf queries
From: Chris Wilson <chris@chris-wilson.co.uk>
From: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
From: Dmitry Rogozhkin <dmitry.v.rogozhkin@intel.com>
The first goal is to be able to measure GPU (and invidual ring) busyness
without having to poll registers from userspace. (Which not only incurs
holding the forcewake lock indefinitely, perturbing the system, but also
runs the risk of hanging the machine.) As an alternative we can use the
perf event counter interface to sample the ring registers periodically
and send those results to userspace.
Functionality we are exporting to userspace is via the existing perf PMU
API and can be exercised via the existing tools. For example:
perf stat -a -e i915/rcs0-busy/ -I 1000
Will print the render engine busynnes once per second. All the performance
counters can be enumerated (perf list) and have their unit of measure
correctly reported in sysfs.
v1-v2 (Chris Wilson):
v2: Use a common timer for the ring sampling.
v3: (Tvrtko Ursulin)
* Decouple uAPI from i915 engine ids.
* Complete uAPI defines.
* Refactor some code to helpers for clarity.
* Skip sampling disabled engines.
* Expose counters in sysfs.
* Pass in fake regs to avoid null ptr deref in perf core.
* Convert to class/instance uAPI.
* Use shared driver code for rc6 residency, power and frequency.
v4: (Dmitry Rogozhkin)
* Register PMU with .task_ctx_nr=perf_invalid_context
* Expose cpumask for the PMU with the single CPU in the mask
* Properly support pmu->stop(): it should call pmu->read()
* Properly support pmu->del(): it should call stop(event, PERF_EF_UPDATE)
* Introduce refcounting of event subscriptions.
* Make pmu.busy_stats a refcounter to avoid busy stats going away
with some deleted event.
* Expose cpumask for i915 PMU to avoid multiple events creation of
the same type followed by counter aggregation by perf-stat.
* Track CPUs getting online/offline to migrate perf context. If (likely)
cpumask will initially set CPU0, CONFIG_BOOTPARAM_HOTPLUG_CPU0 will be
needed to see effect of CPU status tracking.
* End result is that only global events are supported and perf stat
works correctly.
* Deny perf driver level sampling - it is prohibited for uncore PMU.
v5: (Tvrtko Ursulin)
* Don't hardcode number of engine samplers.
* Rewrite event ref-counting for correctness and simplicity.
* Store initial counter value when starting already enabled events
to correctly report values to all listeners.
* Fix RC6 residency readout.
* Comments, GPL header.
v6:
* Add missing entry to v4 changelog.
* Fix accounting in CPU hotplug case by copying the approach from
arch/x86/events/intel/cstate.c. (Dmitry Rogozhkin)
v7:
* Log failure message only on failure.
* Remove CPU hotplug notification state on unregister.
v8:
* Fix error unwind on failed registration.
* Checkpatch cleanup.
v9:
* Drop the energy metric, it is available via intel_rapl_perf.
(Ville Syrjälä)
* Use HAS_RC6(p). (Chris Wilson)
* Handle unsupported non-engine events. (Dmitry Rogozhkin)
* Rebase for intel_rc6_residency_ns needing caller managed
runtime pm.
* Drop HAS_RC6 checks from the read callback since creating those
events will be rejected at init time already.
* Add counter units to sysfs so perf stat output is nicer.
* Cleanup the attribute tables for brevity and readability.
v10:
* Fixed queued accounting.
v11:
* Move intel_engine_lookup_user to intel_engine_cs.c
* Commit update. (Joonas Lahtinen)
v12:
* More accurate sampling. (Chris Wilson)
* Store and report frequency in MHz for better usability from
perf stat.
* Removed metrics: queued, interrupts, rc6 counters.
* Sample engine busyness based on seqno difference only
for less MMIO (and forcewake) on all platforms. (Chris Wilson)
v13:
* Comment spelling, use mul_u32_u32 to work around potential GCC
issue and somne code alignment changes. (Chris Wilson)
v14:
* Rebase.
v15:
* Rebase for RPS refactoring.
v16:
* Use the dynamic slot in the CPU hotplug state machine so that we are
free to setup our state as multi-instance. Previously we were re-using
the CPUHP_AP_PERF_X86_UNCORE_ONLINE slot which is neither used as
multi-instance, nor owned by our driver to start with.
* Register the CPU hotplug handlers after the PMU, otherwise the callback
will get called before the PMU is initialized which can end up in
perf_pmu_migrate_context with an un-initialized base.
* Added workaround for a probable bug in cpuhp core.
v17:
* Remove workaround for the cpuhp bug.
v18:
* Rebase for drm_i915_gem_engine_class getting upstream before us.
v19:
* Rebase. (trivial)
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Signed-off-by: Dmitry Rogozhkin <dmitry.v.rogozhkin@intel.com>
Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Cc: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Dmitry Rogozhkin <dmitry.v.rogozhkin@intel.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20171121181852.16128-2-tvrtko.ursulin@linux.intel.com
2017-11-22 01:18:45 +07:00
|
|
|
/**
|
|
|
|
* @enable: Bitmask of enable sample events on this engine.
|
|
|
|
*
|
|
|
|
* Bits correspond to sample event types, for instance
|
|
|
|
* I915_SAMPLE_QUEUED is bit 0 etc.
|
|
|
|
*/
|
|
|
|
u32 enable;
|
|
|
|
/**
|
|
|
|
* @enable_count: Reference count for the enabled samplers.
|
|
|
|
*
|
2019-02-05 20:03:53 +07:00
|
|
|
* Index number corresponds to @enum drm_i915_pmu_engine_sample.
|
drm/i915/pmu: Expose a PMU interface for perf queries
From: Chris Wilson <chris@chris-wilson.co.uk>
From: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
From: Dmitry Rogozhkin <dmitry.v.rogozhkin@intel.com>
The first goal is to be able to measure GPU (and invidual ring) busyness
without having to poll registers from userspace. (Which not only incurs
holding the forcewake lock indefinitely, perturbing the system, but also
runs the risk of hanging the machine.) As an alternative we can use the
perf event counter interface to sample the ring registers periodically
and send those results to userspace.
Functionality we are exporting to userspace is via the existing perf PMU
API and can be exercised via the existing tools. For example:
perf stat -a -e i915/rcs0-busy/ -I 1000
Will print the render engine busynnes once per second. All the performance
counters can be enumerated (perf list) and have their unit of measure
correctly reported in sysfs.
v1-v2 (Chris Wilson):
v2: Use a common timer for the ring sampling.
v3: (Tvrtko Ursulin)
* Decouple uAPI from i915 engine ids.
* Complete uAPI defines.
* Refactor some code to helpers for clarity.
* Skip sampling disabled engines.
* Expose counters in sysfs.
* Pass in fake regs to avoid null ptr deref in perf core.
* Convert to class/instance uAPI.
* Use shared driver code for rc6 residency, power and frequency.
v4: (Dmitry Rogozhkin)
* Register PMU with .task_ctx_nr=perf_invalid_context
* Expose cpumask for the PMU with the single CPU in the mask
* Properly support pmu->stop(): it should call pmu->read()
* Properly support pmu->del(): it should call stop(event, PERF_EF_UPDATE)
* Introduce refcounting of event subscriptions.
* Make pmu.busy_stats a refcounter to avoid busy stats going away
with some deleted event.
* Expose cpumask for i915 PMU to avoid multiple events creation of
the same type followed by counter aggregation by perf-stat.
* Track CPUs getting online/offline to migrate perf context. If (likely)
cpumask will initially set CPU0, CONFIG_BOOTPARAM_HOTPLUG_CPU0 will be
needed to see effect of CPU status tracking.
* End result is that only global events are supported and perf stat
works correctly.
* Deny perf driver level sampling - it is prohibited for uncore PMU.
v5: (Tvrtko Ursulin)
* Don't hardcode number of engine samplers.
* Rewrite event ref-counting for correctness and simplicity.
* Store initial counter value when starting already enabled events
to correctly report values to all listeners.
* Fix RC6 residency readout.
* Comments, GPL header.
v6:
* Add missing entry to v4 changelog.
* Fix accounting in CPU hotplug case by copying the approach from
arch/x86/events/intel/cstate.c. (Dmitry Rogozhkin)
v7:
* Log failure message only on failure.
* Remove CPU hotplug notification state on unregister.
v8:
* Fix error unwind on failed registration.
* Checkpatch cleanup.
v9:
* Drop the energy metric, it is available via intel_rapl_perf.
(Ville Syrjälä)
* Use HAS_RC6(p). (Chris Wilson)
* Handle unsupported non-engine events. (Dmitry Rogozhkin)
* Rebase for intel_rc6_residency_ns needing caller managed
runtime pm.
* Drop HAS_RC6 checks from the read callback since creating those
events will be rejected at init time already.
* Add counter units to sysfs so perf stat output is nicer.
* Cleanup the attribute tables for brevity and readability.
v10:
* Fixed queued accounting.
v11:
* Move intel_engine_lookup_user to intel_engine_cs.c
* Commit update. (Joonas Lahtinen)
v12:
* More accurate sampling. (Chris Wilson)
* Store and report frequency in MHz for better usability from
perf stat.
* Removed metrics: queued, interrupts, rc6 counters.
* Sample engine busyness based on seqno difference only
for less MMIO (and forcewake) on all platforms. (Chris Wilson)
v13:
* Comment spelling, use mul_u32_u32 to work around potential GCC
issue and somne code alignment changes. (Chris Wilson)
v14:
* Rebase.
v15:
* Rebase for RPS refactoring.
v16:
* Use the dynamic slot in the CPU hotplug state machine so that we are
free to setup our state as multi-instance. Previously we were re-using
the CPUHP_AP_PERF_X86_UNCORE_ONLINE slot which is neither used as
multi-instance, nor owned by our driver to start with.
* Register the CPU hotplug handlers after the PMU, otherwise the callback
will get called before the PMU is initialized which can end up in
perf_pmu_migrate_context with an un-initialized base.
* Added workaround for a probable bug in cpuhp core.
v17:
* Remove workaround for the cpuhp bug.
v18:
* Rebase for drm_i915_gem_engine_class getting upstream before us.
v19:
* Rebase. (trivial)
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Signed-off-by: Dmitry Rogozhkin <dmitry.v.rogozhkin@intel.com>
Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Cc: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Dmitry Rogozhkin <dmitry.v.rogozhkin@intel.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20171121181852.16128-2-tvrtko.ursulin@linux.intel.com
2017-11-22 01:18:45 +07:00
|
|
|
*/
|
2019-02-05 20:03:53 +07:00
|
|
|
unsigned int enable_count[I915_ENGINE_SAMPLE_COUNT];
|
drm/i915/pmu: Expose a PMU interface for perf queries
From: Chris Wilson <chris@chris-wilson.co.uk>
From: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
From: Dmitry Rogozhkin <dmitry.v.rogozhkin@intel.com>
The first goal is to be able to measure GPU (and invidual ring) busyness
without having to poll registers from userspace. (Which not only incurs
holding the forcewake lock indefinitely, perturbing the system, but also
runs the risk of hanging the machine.) As an alternative we can use the
perf event counter interface to sample the ring registers periodically
and send those results to userspace.
Functionality we are exporting to userspace is via the existing perf PMU
API and can be exercised via the existing tools. For example:
perf stat -a -e i915/rcs0-busy/ -I 1000
Will print the render engine busynnes once per second. All the performance
counters can be enumerated (perf list) and have their unit of measure
correctly reported in sysfs.
v1-v2 (Chris Wilson):
v2: Use a common timer for the ring sampling.
v3: (Tvrtko Ursulin)
* Decouple uAPI from i915 engine ids.
* Complete uAPI defines.
* Refactor some code to helpers for clarity.
* Skip sampling disabled engines.
* Expose counters in sysfs.
* Pass in fake regs to avoid null ptr deref in perf core.
* Convert to class/instance uAPI.
* Use shared driver code for rc6 residency, power and frequency.
v4: (Dmitry Rogozhkin)
* Register PMU with .task_ctx_nr=perf_invalid_context
* Expose cpumask for the PMU with the single CPU in the mask
* Properly support pmu->stop(): it should call pmu->read()
* Properly support pmu->del(): it should call stop(event, PERF_EF_UPDATE)
* Introduce refcounting of event subscriptions.
* Make pmu.busy_stats a refcounter to avoid busy stats going away
with some deleted event.
* Expose cpumask for i915 PMU to avoid multiple events creation of
the same type followed by counter aggregation by perf-stat.
* Track CPUs getting online/offline to migrate perf context. If (likely)
cpumask will initially set CPU0, CONFIG_BOOTPARAM_HOTPLUG_CPU0 will be
needed to see effect of CPU status tracking.
* End result is that only global events are supported and perf stat
works correctly.
* Deny perf driver level sampling - it is prohibited for uncore PMU.
v5: (Tvrtko Ursulin)
* Don't hardcode number of engine samplers.
* Rewrite event ref-counting for correctness and simplicity.
* Store initial counter value when starting already enabled events
to correctly report values to all listeners.
* Fix RC6 residency readout.
* Comments, GPL header.
v6:
* Add missing entry to v4 changelog.
* Fix accounting in CPU hotplug case by copying the approach from
arch/x86/events/intel/cstate.c. (Dmitry Rogozhkin)
v7:
* Log failure message only on failure.
* Remove CPU hotplug notification state on unregister.
v8:
* Fix error unwind on failed registration.
* Checkpatch cleanup.
v9:
* Drop the energy metric, it is available via intel_rapl_perf.
(Ville Syrjälä)
* Use HAS_RC6(p). (Chris Wilson)
* Handle unsupported non-engine events. (Dmitry Rogozhkin)
* Rebase for intel_rc6_residency_ns needing caller managed
runtime pm.
* Drop HAS_RC6 checks from the read callback since creating those
events will be rejected at init time already.
* Add counter units to sysfs so perf stat output is nicer.
* Cleanup the attribute tables for brevity and readability.
v10:
* Fixed queued accounting.
v11:
* Move intel_engine_lookup_user to intel_engine_cs.c
* Commit update. (Joonas Lahtinen)
v12:
* More accurate sampling. (Chris Wilson)
* Store and report frequency in MHz for better usability from
perf stat.
* Removed metrics: queued, interrupts, rc6 counters.
* Sample engine busyness based on seqno difference only
for less MMIO (and forcewake) on all platforms. (Chris Wilson)
v13:
* Comment spelling, use mul_u32_u32 to work around potential GCC
issue and somne code alignment changes. (Chris Wilson)
v14:
* Rebase.
v15:
* Rebase for RPS refactoring.
v16:
* Use the dynamic slot in the CPU hotplug state machine so that we are
free to setup our state as multi-instance. Previously we were re-using
the CPUHP_AP_PERF_X86_UNCORE_ONLINE slot which is neither used as
multi-instance, nor owned by our driver to start with.
* Register the CPU hotplug handlers after the PMU, otherwise the callback
will get called before the PMU is initialized which can end up in
perf_pmu_migrate_context with an un-initialized base.
* Added workaround for a probable bug in cpuhp core.
v17:
* Remove workaround for the cpuhp bug.
v18:
* Rebase for drm_i915_gem_engine_class getting upstream before us.
v19:
* Rebase. (trivial)
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Signed-off-by: Dmitry Rogozhkin <dmitry.v.rogozhkin@intel.com>
Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Cc: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Dmitry Rogozhkin <dmitry.v.rogozhkin@intel.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20171121181852.16128-2-tvrtko.ursulin@linux.intel.com
2017-11-22 01:18:45 +07:00
|
|
|
/**
|
|
|
|
* @sample: Counter values for sampling events.
|
|
|
|
*
|
|
|
|
* Our internal timer stores the current counters in this field.
|
2019-02-05 20:03:53 +07:00
|
|
|
*
|
|
|
|
* Index number corresponds to @enum drm_i915_pmu_engine_sample.
|
drm/i915/pmu: Expose a PMU interface for perf queries
From: Chris Wilson <chris@chris-wilson.co.uk>
From: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
From: Dmitry Rogozhkin <dmitry.v.rogozhkin@intel.com>
The first goal is to be able to measure GPU (and invidual ring) busyness
without having to poll registers from userspace. (Which not only incurs
holding the forcewake lock indefinitely, perturbing the system, but also
runs the risk of hanging the machine.) As an alternative we can use the
perf event counter interface to sample the ring registers periodically
and send those results to userspace.
Functionality we are exporting to userspace is via the existing perf PMU
API and can be exercised via the existing tools. For example:
perf stat -a -e i915/rcs0-busy/ -I 1000
Will print the render engine busynnes once per second. All the performance
counters can be enumerated (perf list) and have their unit of measure
correctly reported in sysfs.
v1-v2 (Chris Wilson):
v2: Use a common timer for the ring sampling.
v3: (Tvrtko Ursulin)
* Decouple uAPI from i915 engine ids.
* Complete uAPI defines.
* Refactor some code to helpers for clarity.
* Skip sampling disabled engines.
* Expose counters in sysfs.
* Pass in fake regs to avoid null ptr deref in perf core.
* Convert to class/instance uAPI.
* Use shared driver code for rc6 residency, power and frequency.
v4: (Dmitry Rogozhkin)
* Register PMU with .task_ctx_nr=perf_invalid_context
* Expose cpumask for the PMU with the single CPU in the mask
* Properly support pmu->stop(): it should call pmu->read()
* Properly support pmu->del(): it should call stop(event, PERF_EF_UPDATE)
* Introduce refcounting of event subscriptions.
* Make pmu.busy_stats a refcounter to avoid busy stats going away
with some deleted event.
* Expose cpumask for i915 PMU to avoid multiple events creation of
the same type followed by counter aggregation by perf-stat.
* Track CPUs getting online/offline to migrate perf context. If (likely)
cpumask will initially set CPU0, CONFIG_BOOTPARAM_HOTPLUG_CPU0 will be
needed to see effect of CPU status tracking.
* End result is that only global events are supported and perf stat
works correctly.
* Deny perf driver level sampling - it is prohibited for uncore PMU.
v5: (Tvrtko Ursulin)
* Don't hardcode number of engine samplers.
* Rewrite event ref-counting for correctness and simplicity.
* Store initial counter value when starting already enabled events
to correctly report values to all listeners.
* Fix RC6 residency readout.
* Comments, GPL header.
v6:
* Add missing entry to v4 changelog.
* Fix accounting in CPU hotplug case by copying the approach from
arch/x86/events/intel/cstate.c. (Dmitry Rogozhkin)
v7:
* Log failure message only on failure.
* Remove CPU hotplug notification state on unregister.
v8:
* Fix error unwind on failed registration.
* Checkpatch cleanup.
v9:
* Drop the energy metric, it is available via intel_rapl_perf.
(Ville Syrjälä)
* Use HAS_RC6(p). (Chris Wilson)
* Handle unsupported non-engine events. (Dmitry Rogozhkin)
* Rebase for intel_rc6_residency_ns needing caller managed
runtime pm.
* Drop HAS_RC6 checks from the read callback since creating those
events will be rejected at init time already.
* Add counter units to sysfs so perf stat output is nicer.
* Cleanup the attribute tables for brevity and readability.
v10:
* Fixed queued accounting.
v11:
* Move intel_engine_lookup_user to intel_engine_cs.c
* Commit update. (Joonas Lahtinen)
v12:
* More accurate sampling. (Chris Wilson)
* Store and report frequency in MHz for better usability from
perf stat.
* Removed metrics: queued, interrupts, rc6 counters.
* Sample engine busyness based on seqno difference only
for less MMIO (and forcewake) on all platforms. (Chris Wilson)
v13:
* Comment spelling, use mul_u32_u32 to work around potential GCC
issue and somne code alignment changes. (Chris Wilson)
v14:
* Rebase.
v15:
* Rebase for RPS refactoring.
v16:
* Use the dynamic slot in the CPU hotplug state machine so that we are
free to setup our state as multi-instance. Previously we were re-using
the CPUHP_AP_PERF_X86_UNCORE_ONLINE slot which is neither used as
multi-instance, nor owned by our driver to start with.
* Register the CPU hotplug handlers after the PMU, otherwise the callback
will get called before the PMU is initialized which can end up in
perf_pmu_migrate_context with an un-initialized base.
* Added workaround for a probable bug in cpuhp core.
v17:
* Remove workaround for the cpuhp bug.
v18:
* Rebase for drm_i915_gem_engine_class getting upstream before us.
v19:
* Rebase. (trivial)
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Signed-off-by: Dmitry Rogozhkin <dmitry.v.rogozhkin@intel.com>
Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Cc: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Dmitry Rogozhkin <dmitry.v.rogozhkin@intel.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20171121181852.16128-2-tvrtko.ursulin@linux.intel.com
2017-11-22 01:18:45 +07:00
|
|
|
*/
|
2019-02-05 20:03:53 +07:00
|
|
|
struct i915_pmu_sample sample[I915_ENGINE_SAMPLE_COUNT];
|
drm/i915/pmu: Expose a PMU interface for perf queries
From: Chris Wilson <chris@chris-wilson.co.uk>
From: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
From: Dmitry Rogozhkin <dmitry.v.rogozhkin@intel.com>
The first goal is to be able to measure GPU (and invidual ring) busyness
without having to poll registers from userspace. (Which not only incurs
holding the forcewake lock indefinitely, perturbing the system, but also
runs the risk of hanging the machine.) As an alternative we can use the
perf event counter interface to sample the ring registers periodically
and send those results to userspace.
Functionality we are exporting to userspace is via the existing perf PMU
API and can be exercised via the existing tools. For example:
perf stat -a -e i915/rcs0-busy/ -I 1000
Will print the render engine busynnes once per second. All the performance
counters can be enumerated (perf list) and have their unit of measure
correctly reported in sysfs.
v1-v2 (Chris Wilson):
v2: Use a common timer for the ring sampling.
v3: (Tvrtko Ursulin)
* Decouple uAPI from i915 engine ids.
* Complete uAPI defines.
* Refactor some code to helpers for clarity.
* Skip sampling disabled engines.
* Expose counters in sysfs.
* Pass in fake regs to avoid null ptr deref in perf core.
* Convert to class/instance uAPI.
* Use shared driver code for rc6 residency, power and frequency.
v4: (Dmitry Rogozhkin)
* Register PMU with .task_ctx_nr=perf_invalid_context
* Expose cpumask for the PMU with the single CPU in the mask
* Properly support pmu->stop(): it should call pmu->read()
* Properly support pmu->del(): it should call stop(event, PERF_EF_UPDATE)
* Introduce refcounting of event subscriptions.
* Make pmu.busy_stats a refcounter to avoid busy stats going away
with some deleted event.
* Expose cpumask for i915 PMU to avoid multiple events creation of
the same type followed by counter aggregation by perf-stat.
* Track CPUs getting online/offline to migrate perf context. If (likely)
cpumask will initially set CPU0, CONFIG_BOOTPARAM_HOTPLUG_CPU0 will be
needed to see effect of CPU status tracking.
* End result is that only global events are supported and perf stat
works correctly.
* Deny perf driver level sampling - it is prohibited for uncore PMU.
v5: (Tvrtko Ursulin)
* Don't hardcode number of engine samplers.
* Rewrite event ref-counting for correctness and simplicity.
* Store initial counter value when starting already enabled events
to correctly report values to all listeners.
* Fix RC6 residency readout.
* Comments, GPL header.
v6:
* Add missing entry to v4 changelog.
* Fix accounting in CPU hotplug case by copying the approach from
arch/x86/events/intel/cstate.c. (Dmitry Rogozhkin)
v7:
* Log failure message only on failure.
* Remove CPU hotplug notification state on unregister.
v8:
* Fix error unwind on failed registration.
* Checkpatch cleanup.
v9:
* Drop the energy metric, it is available via intel_rapl_perf.
(Ville Syrjälä)
* Use HAS_RC6(p). (Chris Wilson)
* Handle unsupported non-engine events. (Dmitry Rogozhkin)
* Rebase for intel_rc6_residency_ns needing caller managed
runtime pm.
* Drop HAS_RC6 checks from the read callback since creating those
events will be rejected at init time already.
* Add counter units to sysfs so perf stat output is nicer.
* Cleanup the attribute tables for brevity and readability.
v10:
* Fixed queued accounting.
v11:
* Move intel_engine_lookup_user to intel_engine_cs.c
* Commit update. (Joonas Lahtinen)
v12:
* More accurate sampling. (Chris Wilson)
* Store and report frequency in MHz for better usability from
perf stat.
* Removed metrics: queued, interrupts, rc6 counters.
* Sample engine busyness based on seqno difference only
for less MMIO (and forcewake) on all platforms. (Chris Wilson)
v13:
* Comment spelling, use mul_u32_u32 to work around potential GCC
issue and somne code alignment changes. (Chris Wilson)
v14:
* Rebase.
v15:
* Rebase for RPS refactoring.
v16:
* Use the dynamic slot in the CPU hotplug state machine so that we are
free to setup our state as multi-instance. Previously we were re-using
the CPUHP_AP_PERF_X86_UNCORE_ONLINE slot which is neither used as
multi-instance, nor owned by our driver to start with.
* Register the CPU hotplug handlers after the PMU, otherwise the callback
will get called before the PMU is initialized which can end up in
perf_pmu_migrate_context with an un-initialized base.
* Added workaround for a probable bug in cpuhp core.
v17:
* Remove workaround for the cpuhp bug.
v18:
* Rebase for drm_i915_gem_engine_class getting upstream before us.
v19:
* Rebase. (trivial)
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Signed-off-by: Dmitry Rogozhkin <dmitry.v.rogozhkin@intel.com>
Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Cc: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Dmitry Rogozhkin <dmitry.v.rogozhkin@intel.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20171121181852.16128-2-tvrtko.ursulin@linux.intel.com
2017-11-22 01:18:45 +07:00
|
|
|
} pmu;
|
|
|
|
|
2015-04-07 22:20:36 +07:00
|
|
|
/*
|
|
|
|
* A pool of objects to use as shadow copies of client batch buffers
|
|
|
|
* when the command parser is enabled. Prevents the client from
|
|
|
|
* modifying the batch contents after software parsing.
|
|
|
|
*/
|
|
|
|
struct i915_gem_batch_pool batch_pool;
|
|
|
|
|
2010-05-21 08:08:55 +07:00
|
|
|
struct intel_hw_status_page status_page;
|
2015-06-20 01:07:01 +07:00
|
|
|
struct i915_ctx_workarounds wa_ctx;
|
2018-12-03 20:33:57 +07:00
|
|
|
struct i915_wa_list ctx_wa_list;
|
2018-12-03 20:33:41 +07:00
|
|
|
struct i915_wa_list wa_list;
|
2018-12-03 19:50:12 +07:00
|
|
|
struct i915_wa_list whitelist;
|
2010-05-21 08:08:55 +07:00
|
|
|
|
2016-07-01 23:23:28 +07:00
|
|
|
u32 irq_keep_mask; /* always keep these interrupts */
|
|
|
|
u32 irq_enable_mask; /* bitmask to enable ring interrupt */
|
2016-07-21 00:16:06 +07:00
|
|
|
void (*irq_enable)(struct intel_engine_cs *engine);
|
|
|
|
void (*irq_disable)(struct intel_engine_cs *engine);
|
2010-05-21 08:08:55 +07:00
|
|
|
|
2016-07-21 00:16:06 +07:00
|
|
|
int (*init_hw)(struct intel_engine_cs *engine);
|
2018-05-17 01:33:51 +07:00
|
|
|
|
|
|
|
struct {
|
2019-01-25 20:22:28 +07:00
|
|
|
void (*prepare)(struct intel_engine_cs *engine);
|
|
|
|
void (*reset)(struct intel_engine_cs *engine, bool stalled);
|
2018-05-17 01:33:51 +07:00
|
|
|
void (*finish)(struct intel_engine_cs *engine);
|
|
|
|
} reset;
|
2010-05-21 08:08:55 +07:00
|
|
|
|
2017-10-25 21:39:41 +07:00
|
|
|
void (*park)(struct intel_engine_cs *engine);
|
|
|
|
void (*unpark)(struct intel_engine_cs *engine);
|
|
|
|
|
2017-03-17 00:13:03 +07:00
|
|
|
void (*set_default_submission)(struct intel_engine_cs *engine);
|
|
|
|
|
2018-05-18 04:26:32 +07:00
|
|
|
struct intel_context *(*context_pin)(struct intel_engine_cs *engine,
|
|
|
|
struct i915_gem_context *ctx);
|
|
|
|
|
2018-02-21 16:56:36 +07:00
|
|
|
int (*request_alloc)(struct i915_request *rq);
|
|
|
|
int (*init_context)(struct i915_request *rq);
|
2014-08-26 20:44:50 +07:00
|
|
|
|
2018-02-21 16:56:36 +07:00
|
|
|
int (*emit_flush)(struct i915_request *request, u32 mode);
|
2016-08-03 04:50:31 +07:00
|
|
|
#define EMIT_INVALIDATE BIT(0)
|
|
|
|
#define EMIT_FLUSH BIT(1)
|
|
|
|
#define EMIT_BARRIER (EMIT_INVALIDATE | EMIT_FLUSH)
|
2018-02-21 16:56:36 +07:00
|
|
|
int (*emit_bb_start)(struct i915_request *rq,
|
2016-08-03 04:50:31 +07:00
|
|
|
u64 offset, u32 length,
|
|
|
|
unsigned int dispatch_flags);
|
|
|
|
#define I915_DISPATCH_SECURE BIT(0)
|
|
|
|
#define I915_DISPATCH_PINNED BIT(1)
|
2019-01-30 01:54:50 +07:00
|
|
|
int (*emit_init_breadcrumb)(struct i915_request *rq);
|
|
|
|
u32 *(*emit_fini_breadcrumb)(struct i915_request *rq,
|
|
|
|
u32 *cs);
|
|
|
|
unsigned int emit_fini_breadcrumb_dw;
|
2016-09-09 20:11:54 +07:00
|
|
|
|
|
|
|
/* Pass the request to the hardware queue (e.g. directly into
|
|
|
|
* the legacy ringbuffer or to the end of an execlist).
|
|
|
|
*
|
|
|
|
* This is called from an atomic context with irqs disabled; must
|
|
|
|
* be irq safe.
|
|
|
|
*/
|
2018-02-21 16:56:36 +07:00
|
|
|
void (*submit_request)(struct i915_request *rq);
|
2016-09-09 20:11:54 +07:00
|
|
|
|
2018-10-01 21:47:54 +07:00
|
|
|
/*
|
|
|
|
* Call when the priority on a request has changed and it and its
|
2016-11-15 03:41:01 +07:00
|
|
|
* dependencies may need rescheduling. Note the request itself may
|
|
|
|
* not be ready to run!
|
|
|
|
*/
|
2018-04-19 01:40:52 +07:00
|
|
|
void (*schedule)(struct i915_request *request,
|
|
|
|
const struct i915_sched_attr *attr);
|
2016-11-15 03:41:01 +07:00
|
|
|
|
2017-09-16 00:31:00 +07:00
|
|
|
/*
|
|
|
|
* Cancel all requests on the hardware, or queued for execution.
|
|
|
|
* This should only cancel the ready requests that have been
|
|
|
|
* submitted to the engine (via the engine->submit_request callback).
|
|
|
|
* This is called when marking the device as wedged.
|
|
|
|
*/
|
|
|
|
void (*cancel_requests)(struct intel_engine_cs *engine);
|
|
|
|
|
2016-07-21 00:16:06 +07:00
|
|
|
void (*cleanup)(struct intel_engine_cs *engine);
|
2014-04-30 04:52:28 +07:00
|
|
|
|
2017-09-22 19:43:03 +07:00
|
|
|
struct intel_engine_execlists execlists;
|
2014-07-24 23:04:27 +07:00
|
|
|
|
drm/i915: Unify active context tracking between legacy/execlists/guc
The requests conversion introduced a nasty bug where we could generate a
new request in the middle of constructing a request if we needed to idle
the system in order to evict space for a context. The request to idle
would be executed (and waited upon) before the current one, creating a
minor havoc in the seqno accounting, as we will consider the current
request to already be completed (prior to deferred seqno assignment) but
ring->last_retired_head would have been updated and still could allow
us to overwrite the current request before execution.
We also employed two different mechanisms to track the active context
until it was switched out. The legacy method allowed for waiting upon an
active context (it could forcibly evict any vma, including context's),
but the execlists method took a step backwards by pinning the vma for
the entire active lifespan of the context (the only way to evict was to
idle the entire GPU, not individual contexts). However, to circumvent
the tricky issue of locking (i.e. we cannot take struct_mutex at the
time of i915_gem_request_submit(), where we would want to move the
previous context onto the active tracker and unpin it), we take the
execlists approach and keep the contexts pinned until retirement.
The benefit of the execlists approach, more important for execlists than
legacy, was the reduction in work in pinning the context for each
request - as the context was kept pinned until idle, it could short
circuit the pinning for all active contexts.
We introduce new engine vfuncs to pin and unpin the context
respectively. The context is pinned at the start of the request, and
only unpinned when the following request is retired (this ensures that
the context is idle and coherent in main memory before we unpin it). We
move the engine->last_context tracking into the retirement itself
(rather than during request submission) in order to allow the submission
to be reordered or unwound without undue difficultly.
And finally an ulterior motive for unifying context handling was to
prepare for mock requests.
v2: Rename to last_retired_context, split out legacy_context tracking
for MI_SET_CONTEXT.
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/20161218153724.8439-3-chris@chris-wilson.co.uk
2016-12-18 22:37:20 +07:00
|
|
|
/* Contexts are pinned whilst they are active on the GPU. The last
|
|
|
|
* context executed remains active whilst the GPU is idle - the
|
|
|
|
* switch away and write to the context object only occurs on the
|
|
|
|
* next execution. Contexts are only unpinned on retirement of the
|
|
|
|
* following request ensuring that we can always write to the object
|
|
|
|
* on the context switch even after idling. Across suspend, we switch
|
|
|
|
* to the kernel context and trash it as the save may not happen
|
|
|
|
* before the hardware is powered down.
|
|
|
|
*/
|
2018-05-18 04:26:32 +07:00
|
|
|
struct intel_context *last_retired_context;
|
drm/i915: Unify active context tracking between legacy/execlists/guc
The requests conversion introduced a nasty bug where we could generate a
new request in the middle of constructing a request if we needed to idle
the system in order to evict space for a context. The request to idle
would be executed (and waited upon) before the current one, creating a
minor havoc in the seqno accounting, as we will consider the current
request to already be completed (prior to deferred seqno assignment) but
ring->last_retired_head would have been updated and still could allow
us to overwrite the current request before execution.
We also employed two different mechanisms to track the active context
until it was switched out. The legacy method allowed for waiting upon an
active context (it could forcibly evict any vma, including context's),
but the execlists method took a step backwards by pinning the vma for
the entire active lifespan of the context (the only way to evict was to
idle the entire GPU, not individual contexts). However, to circumvent
the tricky issue of locking (i.e. we cannot take struct_mutex at the
time of i915_gem_request_submit(), where we would want to move the
previous context onto the active tracker and unpin it), we take the
execlists approach and keep the contexts pinned until retirement.
The benefit of the execlists approach, more important for execlists than
legacy, was the reduction in work in pinning the context for each
request - as the context was kept pinned until idle, it could short
circuit the pinning for all active contexts.
We introduce new engine vfuncs to pin and unpin the context
respectively. The context is pinned at the start of the request, and
only unpinned when the following request is retired (this ensures that
the context is idle and coherent in main memory before we unpin it). We
move the engine->last_context tracking into the retirement itself
(rather than during request submission) in order to allow the submission
to be reordered or unwound without undue difficultly.
And finally an ulterior motive for unifying context handling was to
prepare for mock requests.
v2: Rename to last_retired_context, split out legacy_context tracking
for MI_SET_CONTEXT.
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/20161218153724.8439-3-chris@chris-wilson.co.uk
2016-12-18 22:37:20 +07:00
|
|
|
|
2017-03-13 09:47:11 +07:00
|
|
|
/* status_notifier: list of callbacks for context-switch changes */
|
|
|
|
struct atomic_notifier_head context_status_notifier;
|
|
|
|
|
2016-08-03 04:50:21 +07:00
|
|
|
struct intel_engine_hangcheck hangcheck;
|
2013-05-24 21:16:07 +07:00
|
|
|
|
2017-11-29 15:24:09 +07:00
|
|
|
#define I915_ENGINE_NEEDS_CMD_PARSER BIT(0)
|
2017-11-29 17:28:05 +07:00
|
|
|
#define I915_ENGINE_SUPPORTS_STATS BIT(1)
|
2018-04-04 01:35:37 +07:00
|
|
|
#define I915_ENGINE_HAS_PREEMPTION BIT(2)
|
2019-03-02 00:09:00 +07:00
|
|
|
#define I915_ENGINE_HAS_SEMAPHORES BIT(3)
|
2017-11-29 15:24:09 +07:00
|
|
|
unsigned int flags;
|
2014-05-11 04:10:43 +07:00
|
|
|
|
2014-02-19 01:15:46 +07:00
|
|
|
/*
|
2014-05-11 04:10:43 +07:00
|
|
|
* Table of commands the command parser needs to know about
|
2016-07-27 15:07:26 +07:00
|
|
|
* for this engine.
|
2014-02-19 01:15:46 +07:00
|
|
|
*/
|
2014-05-11 04:10:43 +07:00
|
|
|
DECLARE_HASHTABLE(cmd_hash, I915_CMD_HASH_ORDER);
|
2014-02-19 01:15:46 +07:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Table of registers allowed in commands that read/write registers.
|
|
|
|
*/
|
2016-03-07 14:30:27 +07:00
|
|
|
const struct drm_i915_reg_table *reg_tables;
|
|
|
|
int reg_table_count;
|
2014-02-19 01:15:46 +07:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Returns the bitmask for the length field of the specified command.
|
|
|
|
* Return 0 for an unrecognized/invalid command.
|
|
|
|
*
|
2016-07-27 15:07:26 +07:00
|
|
|
* If the command parser finds an entry for a command in the engine's
|
2014-02-19 01:15:46 +07:00
|
|
|
* cmd_tables, it gets the command's length based on the table entry.
|
2016-07-27 15:07:26 +07:00
|
|
|
* If not, it calls this function to determine the per-engine length
|
|
|
|
* field encoding for the command (i.e. different opcode ranges use
|
|
|
|
* certain bits to encode the command length in the header).
|
2014-02-19 01:15:46 +07:00
|
|
|
*/
|
|
|
|
u32 (*get_cmd_length_mask)(u32 cmd_header);
|
2017-11-22 01:18:48 +07:00
|
|
|
|
|
|
|
struct {
|
|
|
|
/**
|
|
|
|
* @lock: Lock protecting the below fields.
|
|
|
|
*/
|
2018-04-26 14:47:16 +07:00
|
|
|
seqlock_t lock;
|
2017-11-22 01:18:48 +07:00
|
|
|
/**
|
|
|
|
* @enabled: Reference count indicating number of listeners.
|
|
|
|
*/
|
|
|
|
unsigned int enabled;
|
|
|
|
/**
|
|
|
|
* @active: Number of contexts currently scheduled in.
|
|
|
|
*/
|
|
|
|
unsigned int active;
|
|
|
|
/**
|
|
|
|
* @enabled_at: Timestamp when busy stats were enabled.
|
|
|
|
*/
|
|
|
|
ktime_t enabled_at;
|
|
|
|
/**
|
|
|
|
* @start: Timestamp of the last idle to active transition.
|
|
|
|
*
|
|
|
|
* Idle is defined as active == 0, active is active > 0.
|
|
|
|
*/
|
|
|
|
ktime_t start;
|
|
|
|
/**
|
|
|
|
* @total: Total time this engine was busy.
|
|
|
|
*
|
|
|
|
* Accumulated time not counting the most recent block in cases
|
|
|
|
* where engine is currently busy (active > 0).
|
|
|
|
*/
|
|
|
|
ktime_t total;
|
|
|
|
} stats;
|
2010-05-21 08:08:55 +07:00
|
|
|
};
|
|
|
|
|
2018-04-04 01:35:37 +07:00
|
|
|
static inline bool
|
|
|
|
intel_engine_needs_cmd_parser(const struct intel_engine_cs *engine)
|
2017-11-29 15:24:09 +07:00
|
|
|
{
|
|
|
|
return engine->flags & I915_ENGINE_NEEDS_CMD_PARSER;
|
|
|
|
}
|
|
|
|
|
2018-04-04 01:35:37 +07:00
|
|
|
static inline bool
|
|
|
|
intel_engine_supports_stats(const struct intel_engine_cs *engine)
|
2017-11-29 17:28:05 +07:00
|
|
|
{
|
|
|
|
return engine->flags & I915_ENGINE_SUPPORTS_STATS;
|
|
|
|
}
|
|
|
|
|
2018-04-04 01:35:37 +07:00
|
|
|
static inline bool
|
|
|
|
intel_engine_has_preemption(const struct intel_engine_cs *engine)
|
|
|
|
{
|
|
|
|
return engine->flags & I915_ENGINE_HAS_PREEMPTION;
|
|
|
|
}
|
|
|
|
|
2019-03-02 00:09:00 +07:00
|
|
|
static inline bool
|
|
|
|
intel_engine_has_semaphores(const struct intel_engine_cs *engine)
|
|
|
|
{
|
|
|
|
return engine->flags & I915_ENGINE_HAS_SEMAPHORES;
|
|
|
|
}
|
|
|
|
|
2019-02-26 17:24:00 +07:00
|
|
|
void intel_engines_set_scheduler_caps(struct drm_i915_private *i915);
|
|
|
|
|
2018-04-04 01:35:37 +07:00
|
|
|
static inline bool __execlists_need_preempt(int prio, int last)
|
|
|
|
{
|
2019-02-04 15:41:05 +07:00
|
|
|
/*
|
|
|
|
* Allow preemption of low -> normal -> high, but we do
|
|
|
|
* not allow low priority tasks to preempt other low priority
|
|
|
|
* tasks under the impression that latency for low priority
|
|
|
|
* tasks does not matter (as much as background throughput),
|
|
|
|
* so kiss.
|
|
|
|
*
|
|
|
|
* More naturally we would write
|
|
|
|
* prio >= max(0, last);
|
|
|
|
* except that we wish to prevent triggering preemption at the same
|
|
|
|
* priority level: the task that is running should remain running
|
|
|
|
* to preserve FIFO ordering of dependencies.
|
|
|
|
*/
|
|
|
|
return prio > max(I915_PRIORITY_NORMAL - 1, last);
|
2018-04-04 01:35:37 +07:00
|
|
|
}
|
|
|
|
|
2017-10-24 04:32:36 +07:00
|
|
|
static inline void
|
|
|
|
execlists_set_active(struct intel_engine_execlists *execlists,
|
|
|
|
unsigned int bit)
|
|
|
|
{
|
|
|
|
__set_bit(bit, (unsigned long *)&execlists->active);
|
|
|
|
}
|
|
|
|
|
2018-03-31 20:06:26 +07:00
|
|
|
static inline bool
|
|
|
|
execlists_set_active_once(struct intel_engine_execlists *execlists,
|
|
|
|
unsigned int bit)
|
|
|
|
{
|
|
|
|
return !__test_and_set_bit(bit, (unsigned long *)&execlists->active);
|
|
|
|
}
|
|
|
|
|
2017-10-24 04:32:36 +07:00
|
|
|
static inline void
|
|
|
|
execlists_clear_active(struct intel_engine_execlists *execlists,
|
|
|
|
unsigned int bit)
|
|
|
|
{
|
|
|
|
__clear_bit(bit, (unsigned long *)&execlists->active);
|
|
|
|
}
|
|
|
|
|
2018-07-16 19:54:24 +07:00
|
|
|
static inline void
|
|
|
|
execlists_clear_all_active(struct intel_engine_execlists *execlists)
|
|
|
|
{
|
|
|
|
execlists->active = 0;
|
|
|
|
}
|
|
|
|
|
2017-10-24 04:32:36 +07:00
|
|
|
static inline bool
|
|
|
|
execlists_is_active(const struct intel_engine_execlists *execlists,
|
|
|
|
unsigned int bit)
|
|
|
|
{
|
|
|
|
return test_bit(bit, (unsigned long *)&execlists->active);
|
|
|
|
}
|
|
|
|
|
2018-03-31 20:06:26 +07:00
|
|
|
void execlists_user_begin(struct intel_engine_execlists *execlists,
|
|
|
|
const struct execlist_port *port);
|
|
|
|
void execlists_user_end(struct intel_engine_execlists *execlists);
|
|
|
|
|
drm/i915/guc: Preemption! With GuC
Pretty similar to what we have on execlists.
We're reusing most of the GEM code, however, due to GuC quirks we need a
couple of extra bits.
Preemption is implemented as GuC action, and actions can be pretty slow.
Because of that, we're using a mutex to serialize them. Since we're
requesting preemption from the tasklet, the task of creating a workitem
and wrapping it in GuC action is delegated to a worker.
To distinguish that preemption has finished, we're using additional
piece of HWSP, and since we're not getting context switch interrupts,
we're also adding a user interrupt.
The fact that our special preempt context has completed unfortunately
doesn't mean that we're ready to submit new work. We also need to wait
for GuC to finish its own processing.
v2: Don't compile out the wait for GuC, handle workqueue flush on reset,
no need for ordered workqueue, put on a reviewer hat when looking at my own
patches (Chris)
Move struct work around in intel_guc, move user interruput outside of
conditional (Michał)
Keep ring around rather than chase though intel_context
v3: Extract WA for flushing ggtt writes to a helper (Chris)
Keep work_struct in intel_guc rather than engine (Michał)
Use ordered workqueue for inject_preempt worker to avoid GuC quirks.
v4: Drop now unused INTEL_GUC_PREEMPT_OPTION_IMMEDIATE (Daniele)
Drop stray newlines, use container_of for intel_guc in worker,
check for presence of workqueue when flushing it, rather than
enable_guc_submission modparam, reorder preempt postprocessing (Chris)
v5: Make wq NULL after destroying it
v6: Swap struct guc_preempt_work members (Michał)
Signed-off-by: Michał Winiarski <michal.winiarski@intel.com>
Cc: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Jeff McGee <jeff.mcgee@intel.com>
Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
Cc: Oscar Mateo <oscar.mateo@intel.com>
Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Link: https://patchwork.freedesktop.org/patch/msgid/20171026133558.19580-1-michal.winiarski@intel.com
2017-10-26 20:35:58 +07:00
|
|
|
void
|
|
|
|
execlists_cancel_port_requests(struct intel_engine_execlists * const execlists);
|
|
|
|
|
|
|
|
void
|
|
|
|
execlists_unwind_incomplete_requests(struct intel_engine_execlists *execlists);
|
|
|
|
|
2017-09-22 19:43:07 +07:00
|
|
|
static inline unsigned int
|
|
|
|
execlists_num_ports(const struct intel_engine_execlists * const execlists)
|
|
|
|
{
|
|
|
|
return execlists->port_mask + 1;
|
|
|
|
}
|
|
|
|
|
2018-03-31 20:06:26 +07:00
|
|
|
static inline struct execlist_port *
|
2017-09-22 19:43:06 +07:00
|
|
|
execlists_port_complete(struct intel_engine_execlists * const execlists,
|
|
|
|
struct execlist_port * const port)
|
|
|
|
{
|
2017-09-22 19:43:07 +07:00
|
|
|
const unsigned int m = execlists->port_mask;
|
2017-09-22 19:43:06 +07:00
|
|
|
|
|
|
|
GEM_BUG_ON(port_index(port, execlists) != 0);
|
2017-10-24 04:32:36 +07:00
|
|
|
GEM_BUG_ON(!execlists_is_active(execlists, EXECLISTS_ACTIVE_USER));
|
2017-09-22 19:43:06 +07:00
|
|
|
|
2017-09-22 19:43:07 +07:00
|
|
|
memmove(port, port + 1, m * sizeof(struct execlist_port));
|
|
|
|
memset(port + m, 0, sizeof(struct execlist_port));
|
2018-03-31 20:06:26 +07:00
|
|
|
|
|
|
|
return port;
|
2017-09-22 19:43:06 +07:00
|
|
|
}
|
|
|
|
|
2010-05-21 08:08:55 +07:00
|
|
|
static inline u32
|
2018-02-12 17:24:15 +07:00
|
|
|
intel_read_status_page(const struct intel_engine_cs *engine, int reg)
|
2010-05-21 08:08:55 +07:00
|
|
|
{
|
2012-04-27 04:28:16 +07:00
|
|
|
/* Ensure that the compiler doesn't optimize away the load. */
|
2019-01-28 17:23:55 +07:00
|
|
|
return READ_ONCE(engine->status_page.addr[reg]);
|
2010-05-21 08:08:55 +07:00
|
|
|
}
|
|
|
|
|
2012-12-19 16:13:05 +07:00
|
|
|
static inline void
|
2017-03-24 23:35:38 +07:00
|
|
|
intel_write_status_page(struct intel_engine_cs *engine, int reg, u32 value)
|
2012-12-19 16:13:05 +07:00
|
|
|
{
|
2017-03-24 23:35:38 +07:00
|
|
|
/* Writing into the status page should be done sparingly. Since
|
|
|
|
* we do when we are uncertain of the device state, we take a bit
|
|
|
|
* of extra paranoia to try and ensure that the HWS takes the value
|
|
|
|
* we give and that it doesn't end up trapped inside the CPU!
|
|
|
|
*/
|
|
|
|
if (static_cpu_has(X86_FEATURE_CLFLUSH)) {
|
|
|
|
mb();
|
2019-01-28 17:23:55 +07:00
|
|
|
clflush(&engine->status_page.addr[reg]);
|
|
|
|
engine->status_page.addr[reg] = value;
|
|
|
|
clflush(&engine->status_page.addr[reg]);
|
2017-03-24 23:35:38 +07:00
|
|
|
mb();
|
|
|
|
} else {
|
2019-01-28 17:23:55 +07:00
|
|
|
WRITE_ONCE(engine->status_page.addr[reg], value);
|
2017-03-24 23:35:38 +07:00
|
|
|
}
|
2012-12-19 16:13:05 +07:00
|
|
|
}
|
|
|
|
|
2016-01-18 14:19:47 +07:00
|
|
|
/*
|
2011-01-14 02:06:50 +07:00
|
|
|
* Reads a dword out of the status page, which is written to from the command
|
|
|
|
* queue by automatic updates, MI_REPORT_HEAD, MI_STORE_DATA_INDEX, or
|
|
|
|
* MI_STORE_DATA_IMM.
|
|
|
|
*
|
|
|
|
* The following dwords have a reserved meaning:
|
|
|
|
* 0x00: ISR copy, updated when an ISR bit not set in the HWSTAM changes.
|
|
|
|
* 0x04: ring 0 head pointer
|
|
|
|
* 0x05: ring 1 head pointer (915-class)
|
|
|
|
* 0x06: ring 2 head pointer (915-class)
|
|
|
|
* 0x10-0x1b: Context status DWords (GM45)
|
|
|
|
* 0x1f: Last written status offset. (GM45)
|
2015-02-18 18:48:21 +07:00
|
|
|
* 0x20-0x2f: Reserved (Gen6+)
|
2011-01-14 02:06:50 +07:00
|
|
|
*
|
2015-02-18 18:48:21 +07:00
|
|
|
* The area from dword 0x30 to 0x3ff is available for driver usage.
|
2011-01-14 02:06:50 +07:00
|
|
|
*/
|
2019-01-25 19:00:05 +07:00
|
|
|
#define I915_GEM_HWS_PREEMPT 0x32
|
|
|
|
#define I915_GEM_HWS_PREEMPT_ADDR (I915_GEM_HWS_PREEMPT * sizeof(u32))
|
2019-02-26 16:49:19 +07:00
|
|
|
#define I915_GEM_HWS_HANGCHECK 0x34
|
|
|
|
#define I915_GEM_HWS_HANGCHECK_ADDR (I915_GEM_HWS_HANGCHECK * sizeof(u32))
|
2019-01-29 01:18:09 +07:00
|
|
|
#define I915_GEM_HWS_SEQNO 0x40
|
|
|
|
#define I915_GEM_HWS_SEQNO_ADDR (I915_GEM_HWS_SEQNO * sizeof(u32))
|
|
|
|
#define I915_GEM_HWS_SCRATCH 0x80
|
2019-01-25 19:00:05 +07:00
|
|
|
#define I915_GEM_HWS_SCRATCH_ADDR (I915_GEM_HWS_SCRATCH * sizeof(u32))
|
2011-01-14 02:06:50 +07:00
|
|
|
|
2017-09-13 20:35:34 +07:00
|
|
|
#define I915_HWS_CSB_BUF0_INDEX 0x10
|
2017-09-13 15:56:05 +07:00
|
|
|
#define I915_HWS_CSB_WRITE_INDEX 0x1f
|
|
|
|
#define CNL_HWS_CSB_WRITE_INDEX 0x2f
|
2017-09-13 20:35:34 +07:00
|
|
|
|
2016-08-03 04:50:21 +07:00
|
|
|
struct intel_ring *
|
2018-05-02 23:38:38 +07:00
|
|
|
intel_engine_create_ring(struct intel_engine_cs *engine,
|
2018-05-02 23:38:39 +07:00
|
|
|
struct i915_timeline *timeline,
|
2018-05-02 23:38:38 +07:00
|
|
|
int size);
|
2018-07-27 22:55:01 +07:00
|
|
|
int intel_ring_pin(struct intel_ring *ring);
|
2017-04-25 20:00:49 +07:00
|
|
|
void intel_ring_reset(struct intel_ring *ring, u32 tail);
|
2017-05-04 20:08:45 +07:00
|
|
|
unsigned int intel_ring_update_space(struct intel_ring *ring);
|
2016-08-03 04:50:23 +07:00
|
|
|
void intel_ring_unpin(struct intel_ring *ring);
|
2016-08-03 04:50:21 +07:00
|
|
|
void intel_ring_free(struct intel_ring *ring);
|
2014-07-24 23:04:15 +07:00
|
|
|
|
2016-08-03 04:50:21 +07:00
|
|
|
void intel_engine_stop(struct intel_engine_cs *engine);
|
|
|
|
void intel_engine_cleanup(struct intel_engine_cs *engine);
|
2011-03-20 08:14:27 +07:00
|
|
|
|
2016-09-09 20:11:53 +07:00
|
|
|
void intel_legacy_submission_resume(struct drm_i915_private *dev_priv);
|
|
|
|
|
2018-02-21 16:56:36 +07:00
|
|
|
int __must_check intel_ring_cacheline_align(struct i915_request *rq);
|
2016-07-20 19:31:55 +07:00
|
|
|
|
2018-02-21 16:56:36 +07:00
|
|
|
u32 __must_check *intel_ring_begin(struct i915_request *rq, unsigned int n);
|
2016-07-20 19:31:55 +07:00
|
|
|
|
2018-02-21 16:56:36 +07:00
|
|
|
static inline void intel_ring_advance(struct i915_request *rq, u32 *cs)
|
2013-08-11 04:16:32 +07:00
|
|
|
{
|
2016-08-03 04:50:30 +07:00
|
|
|
/* Dummy function.
|
|
|
|
*
|
|
|
|
* This serves as a placeholder in the code so that the reader
|
|
|
|
* can compare against the preceding intel_ring_begin() and
|
|
|
|
* check that the number of dwords emitted matches the space
|
|
|
|
* reserved for the command packet (i.e. the value passed to
|
|
|
|
* intel_ring_begin()).
|
2016-08-03 04:50:29 +07:00
|
|
|
*/
|
2018-02-21 16:56:36 +07:00
|
|
|
GEM_BUG_ON((rq->ring->vaddr + rq->ring->emit) != cs);
|
2016-08-03 04:50:30 +07:00
|
|
|
}
|
|
|
|
|
2018-02-21 16:56:36 +07:00
|
|
|
static inline u32 intel_ring_wrap(const struct intel_ring *ring, u32 pos)
|
2017-03-27 20:00:07 +07:00
|
|
|
{
|
|
|
|
return pos & (ring->size - 1);
|
|
|
|
}
|
|
|
|
|
2018-06-11 18:08:45 +07:00
|
|
|
static inline bool
|
|
|
|
intel_ring_offset_valid(const struct intel_ring *ring,
|
|
|
|
unsigned int pos)
|
|
|
|
{
|
|
|
|
if (pos & -ring->size) /* must be strictly within the ring */
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (!IS_ALIGNED(pos, 8)) /* must be qword aligned */
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-02-21 16:56:36 +07:00
|
|
|
static inline u32 intel_ring_offset(const struct i915_request *rq, void *addr)
|
2016-08-03 04:50:30 +07:00
|
|
|
{
|
|
|
|
/* Don't write ring->size (equivalent to 0) as that hangs some GPUs. */
|
2018-02-21 16:56:36 +07:00
|
|
|
u32 offset = addr - rq->ring->vaddr;
|
|
|
|
GEM_BUG_ON(offset > rq->ring->size);
|
|
|
|
return intel_ring_wrap(rq->ring, offset);
|
2013-08-11 04:16:32 +07:00
|
|
|
}
|
2016-07-20 19:31:55 +07:00
|
|
|
|
2017-03-27 20:14:12 +07:00
|
|
|
static inline void
|
|
|
|
assert_ring_tail_valid(const struct intel_ring *ring, unsigned int tail)
|
|
|
|
{
|
2018-06-11 18:08:45 +07:00
|
|
|
GEM_BUG_ON(!intel_ring_offset_valid(ring, tail));
|
2017-05-04 20:08:44 +07:00
|
|
|
|
|
|
|
/*
|
|
|
|
* "Ring Buffer Use"
|
|
|
|
* Gen2 BSpec "1. Programming Environment" / 1.4.4.6
|
|
|
|
* Gen3 BSpec "1c Memory Interface Functions" / 2.3.4.5
|
|
|
|
* Gen4+ BSpec "1c Memory Interface and Command Stream" / 5.3.4.5
|
|
|
|
* "If the Ring Buffer Head Pointer and the Tail Pointer are on the
|
|
|
|
* same cacheline, the Head Pointer must not be greater than the Tail
|
|
|
|
* Pointer."
|
|
|
|
*
|
|
|
|
* We use ring->head as the last known location of the actual RING_HEAD,
|
|
|
|
* it may have advanced but in the worst case it is equally the same
|
|
|
|
* as ring->head and so we should never program RING_TAIL to advance
|
|
|
|
* into the same cacheline as ring->head.
|
|
|
|
*/
|
|
|
|
#define cacheline(a) round_down(a, CACHELINE_BYTES)
|
|
|
|
GEM_BUG_ON(cacheline(tail) == cacheline(ring->head) &&
|
|
|
|
tail < ring->head);
|
|
|
|
#undef cacheline
|
2017-03-27 20:14:12 +07:00
|
|
|
}
|
|
|
|
|
2017-04-25 20:00:49 +07:00
|
|
|
static inline unsigned int
|
|
|
|
intel_ring_set_tail(struct intel_ring *ring, unsigned int tail)
|
|
|
|
{
|
|
|
|
/* Whilst writes to the tail are strictly order, there is no
|
|
|
|
* serialisation between readers and the writers. The tail may be
|
2018-02-21 16:56:36 +07:00
|
|
|
* read by i915_request_retire() just as it is being updated
|
2017-04-25 20:00:49 +07:00
|
|
|
* by execlists, as although the breadcrumb is complete, the context
|
|
|
|
* switch hasn't been seen.
|
|
|
|
*/
|
|
|
|
assert_ring_tail_valid(ring, tail);
|
|
|
|
ring->tail = tail;
|
|
|
|
return tail;
|
|
|
|
}
|
2013-08-11 04:16:32 +07:00
|
|
|
|
2019-02-07 14:18:22 +07:00
|
|
|
static inline unsigned int
|
|
|
|
__intel_ring_space(unsigned int head, unsigned int tail, unsigned int size)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* "If the Ring Buffer Head Pointer and the Tail Pointer are on the
|
|
|
|
* same cacheline, the Head Pointer must not be greater than the Tail
|
|
|
|
* Pointer."
|
|
|
|
*/
|
|
|
|
GEM_BUG_ON(!is_power_of_2(size));
|
|
|
|
return (head - tail - CACHELINE_BYTES) & (size - 1);
|
|
|
|
}
|
|
|
|
|
2019-01-29 01:18:09 +07:00
|
|
|
int intel_engine_setup_common(struct intel_engine_cs *engine);
|
2016-07-13 22:03:41 +07:00
|
|
|
int intel_engine_init_common(struct intel_engine_cs *engine);
|
2016-08-03 19:19:16 +07:00
|
|
|
void intel_engine_cleanup_common(struct intel_engine_cs *engine);
|
2016-07-13 22:03:41 +07:00
|
|
|
|
2016-07-13 22:03:37 +07:00
|
|
|
int intel_init_render_ring_buffer(struct intel_engine_cs *engine);
|
|
|
|
int intel_init_bsd_ring_buffer(struct intel_engine_cs *engine);
|
|
|
|
int intel_init_blt_ring_buffer(struct intel_engine_cs *engine);
|
|
|
|
int intel_init_vebox_ring_buffer(struct intel_engine_cs *engine);
|
2010-05-21 08:08:55 +07:00
|
|
|
|
2018-05-17 01:33:55 +07:00
|
|
|
int intel_engine_stop_cs(struct intel_engine_cs *engine);
|
2018-08-15 00:18:57 +07:00
|
|
|
void intel_engine_cancel_stop_cs(struct intel_engine_cs *engine);
|
2018-05-17 01:33:55 +07:00
|
|
|
|
2018-12-18 17:27:12 +07:00
|
|
|
void intel_engine_set_hwsp_writemask(struct intel_engine_cs *engine, u32 mask);
|
|
|
|
|
2018-02-12 17:24:15 +07:00
|
|
|
u64 intel_engine_get_active_head(const struct intel_engine_cs *engine);
|
|
|
|
u64 intel_engine_get_last_batch_head(const struct intel_engine_cs *engine);
|
2016-10-05 03:11:31 +07:00
|
|
|
|
2016-10-12 16:05:17 +07:00
|
|
|
void intel_engine_get_instdone(struct intel_engine_cs *engine,
|
|
|
|
struct intel_instdone *instdone);
|
|
|
|
|
drm/i915: Replace global breadcrumbs with per-context interrupt tracking
A few years ago, see commit 688e6c725816 ("drm/i915: Slaughter the
thundering i915_wait_request herd"), the issue of handling multiple
clients waiting in parallel was brought to our attention. The
requirement was that every client should be woken immediately upon its
request being signaled, without incurring any cpu overhead.
To handle certain fragility of our hw meant that we could not do a
simple check inside the irq handler (some generations required almost
unbounded delays before we could be sure of seqno coherency) and so
request completion checking required delegation.
Before commit 688e6c725816, the solution was simple. Every client
waiting on a request would be woken on every interrupt and each would do
a heavyweight check to see if their request was complete. Commit
688e6c725816 introduced an rbtree so that only the earliest waiter on
the global timeline would woken, and would wake the next and so on.
(Along with various complications to handle requests being reordered
along the global timeline, and also a requirement for kthread to provide
a delegate for fence signaling that had no process context.)
The global rbtree depends on knowing the execution timeline (and global
seqno). Without knowing that order, we must instead check all contexts
queued to the HW to see which may have advanced. We trim that list by
only checking queued contexts that are being waited on, but still we
keep a list of all active contexts and their active signalers that we
inspect from inside the irq handler. By moving the waiters onto the fence
signal list, we can combine the client wakeup with the dma_fence
signaling (a dramatic reduction in complexity, but does require the HW
being coherent, the seqno must be visible from the cpu before the
interrupt is raised - we keep a timer backup just in case).
Having previously fixed all the issues with irq-seqno serialisation (by
inserting delays onto the GPU after each request instead of random delays
on the CPU after each interrupt), we can rely on the seqno state to
perfom direct wakeups from the interrupt handler. This allows us to
preserve our single context switch behaviour of the current routine,
with the only downside that we lose the RT priority sorting of wakeups.
In general, direct wakeup latency of multiple clients is about the same
(about 10% better in most cases) with a reduction in total CPU time spent
in the waiter (about 20-50% depending on gen). Average herd behaviour is
improved, but at the cost of not delegating wakeups on task_prio.
v2: Capture fence signaling state for error state and add comments to
warm even the most cold of hearts.
v3: Check if the request is still active before busywaiting
v4: Reduce the amount of pointer misdirection with list_for_each_safe
and using a local i915_request variable inside the loops
v5: Add a missing pluralisation to a purely informative selftest message.
References: 688e6c725816 ("drm/i915: Slaughter the thundering i915_wait_request herd")
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20190129205230.19056-2-chris@chris-wilson.co.uk
2019-01-30 03:52:29 +07:00
|
|
|
void intel_engine_init_breadcrumbs(struct intel_engine_cs *engine);
|
|
|
|
void intel_engine_fini_breadcrumbs(struct intel_engine_cs *engine);
|
drm/i915: Slaughter the thundering i915_wait_request herd
One particularly stressful scenario consists of many independent tasks
all competing for GPU time and waiting upon the results (e.g. realtime
transcoding of many, many streams). One bottleneck in particular is that
each client waits on its own results, but every client is woken up after
every batchbuffer - hence the thunder of hooves as then every client must
do its heavyweight dance to read a coherent seqno to see if it is the
lucky one.
Ideally, we only want one client to wake up after the interrupt and
check its request for completion. Since the requests must retire in
order, we can select the first client on the oldest request to be woken.
Once that client has completed his wait, we can then wake up the
next client and so on. However, all clients then incur latency as every
process in the chain may be delayed for scheduling - this may also then
cause some priority inversion. To reduce the latency, when a client
is added or removed from the list, we scan the tree for completed
seqno and wake up all the completed waiters in parallel.
Using igt/benchmarks/gem_latency, we can demonstrate this effect. The
benchmark measures the number of GPU cycles between completion of a
batch and the client waking up from a call to wait-ioctl. With many
concurrent waiters, with each on a different request, we observe that
the wakeup latency before the patch scales nearly linearly with the
number of waiters (before external factors kick in making the scaling much
worse). After applying the patch, we can see that only the single waiter
for the request is being woken up, providing a constant wakeup latency
for every operation. However, the situation is not quite as rosy for
many waiters on the same request, though to the best of my knowledge this
is much less likely in practice. Here, we can observe that the
concurrent waiters incur extra latency from being woken up by the
solitary bottom-half, rather than directly by the interrupt. This
appears to be scheduler induced (having discounted adverse effects from
having a rbtree walk/erase in the wakeup path), each additional
wake_up_process() costs approximately 1us on big core. Another effect of
performing the secondary wakeups from the first bottom-half is the
incurred delay this imposes on high priority threads - rather than
immediately returning to userspace and leaving the interrupt handler to
wake the others.
To offset the delay incurred with additional waiters on a request, we
could use a hybrid scheme that did a quick read in the interrupt handler
and dequeued all the completed waiters (incurring the overhead in the
interrupt handler, not the best plan either as we then incur GPU
submission latency) but we would still have to wake up the bottom-half
every time to do the heavyweight slow read. Or we could only kick the
waiters on the seqno with the same priority as the current task (i.e. in
the realtime waiter scenario, only it is woken up immediately by the
interrupt and simply queues the next waiter before returning to userspace,
minimising its delay at the expense of the chain, and also reducing
contention on its scheduler runqueue). This is effective at avoid long
pauses in the interrupt handler and at avoiding the extra latency in
realtime/high-priority waiters.
v2: Convert from a kworker per engine into a dedicated kthread for the
bottom-half.
v3: Rename request members and tweak comments.
v4: Use a per-engine spinlock in the breadcrumbs bottom-half.
v5: Fix race in locklessly checking waiter status and kicking the task on
adding a new waiter.
v6: Fix deciding when to force the timer to hide missing interrupts.
v7: Move the bottom-half from the kthread to the first client process.
v8: Reword a few comments
v9: Break the busy loop when the interrupt is unmasked or has fired.
v10: Comments, unnecessary churn, better debugging from Tvrtko
v11: Wake all completed waiters on removing the current bottom-half to
reduce the latency of waking up a herd of clients all waiting on the
same request.
v12: Rearrange missed-interrupt fault injection so that it works with
igt/drv_missed_irq_hang
v13: Rename intel_breadcrumb and friends to intel_wait in preparation
for signal handling.
v14: RCU commentary, assert_spin_locked
v15: Hide BUG_ON behind the compiler; report on gem_latency findings.
v16: Sort seqno-groups by priority so that first-waiter has the highest
task priority (and so avoid priority inversion).
v17: Add waiters to post-mortem GPU hang state.
v18: Return early for a completed wait after acquiring the spinlock.
Avoids adding ourselves to the tree if the is already complete, and
skips the awkward question of why we don't do completion wakeups for
waits earlier than or equal to ourselves.
v19: Prepare for init_breadcrumbs to fail. Later patches may want to
allocate during init, so be prepared to propagate back the error code.
Testcase: igt/gem_concurrent_blit
Testcase: igt/benchmarks/gem_latency
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: "Rogozhkin, Dmitry V" <dmitry.v.rogozhkin@intel.com>
Cc: "Gong, Zhipeng" <zhipeng.gong@intel.com>
Cc: Tvrtko Ursulin <tvrtko.ursulin@linux.intel.com>
Cc: Dave Gordon <david.s.gordon@intel.com>
Cc: "Goel, Akash" <akash.goel@intel.com>
Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@linux.intel.com> #v18
Link: http://patchwork.freedesktop.org/patch/msgid/1467390209-3576-6-git-send-email-chris@chris-wilson.co.uk
2016-07-01 23:23:15 +07:00
|
|
|
|
drm/i915: Replace global breadcrumbs with per-context interrupt tracking
A few years ago, see commit 688e6c725816 ("drm/i915: Slaughter the
thundering i915_wait_request herd"), the issue of handling multiple
clients waiting in parallel was brought to our attention. The
requirement was that every client should be woken immediately upon its
request being signaled, without incurring any cpu overhead.
To handle certain fragility of our hw meant that we could not do a
simple check inside the irq handler (some generations required almost
unbounded delays before we could be sure of seqno coherency) and so
request completion checking required delegation.
Before commit 688e6c725816, the solution was simple. Every client
waiting on a request would be woken on every interrupt and each would do
a heavyweight check to see if their request was complete. Commit
688e6c725816 introduced an rbtree so that only the earliest waiter on
the global timeline would woken, and would wake the next and so on.
(Along with various complications to handle requests being reordered
along the global timeline, and also a requirement for kthread to provide
a delegate for fence signaling that had no process context.)
The global rbtree depends on knowing the execution timeline (and global
seqno). Without knowing that order, we must instead check all contexts
queued to the HW to see which may have advanced. We trim that list by
only checking queued contexts that are being waited on, but still we
keep a list of all active contexts and their active signalers that we
inspect from inside the irq handler. By moving the waiters onto the fence
signal list, we can combine the client wakeup with the dma_fence
signaling (a dramatic reduction in complexity, but does require the HW
being coherent, the seqno must be visible from the cpu before the
interrupt is raised - we keep a timer backup just in case).
Having previously fixed all the issues with irq-seqno serialisation (by
inserting delays onto the GPU after each request instead of random delays
on the CPU after each interrupt), we can rely on the seqno state to
perfom direct wakeups from the interrupt handler. This allows us to
preserve our single context switch behaviour of the current routine,
with the only downside that we lose the RT priority sorting of wakeups.
In general, direct wakeup latency of multiple clients is about the same
(about 10% better in most cases) with a reduction in total CPU time spent
in the waiter (about 20-50% depending on gen). Average herd behaviour is
improved, but at the cost of not delegating wakeups on task_prio.
v2: Capture fence signaling state for error state and add comments to
warm even the most cold of hearts.
v3: Check if the request is still active before busywaiting
v4: Reduce the amount of pointer misdirection with list_for_each_safe
and using a local i915_request variable inside the loops
v5: Add a missing pluralisation to a purely informative selftest message.
References: 688e6c725816 ("drm/i915: Slaughter the thundering i915_wait_request herd")
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20190129205230.19056-2-chris@chris-wilson.co.uk
2019-01-30 03:52:29 +07:00
|
|
|
void intel_engine_pin_breadcrumbs_irq(struct intel_engine_cs *engine);
|
|
|
|
void intel_engine_unpin_breadcrumbs_irq(struct intel_engine_cs *engine);
|
drm/i915: Slaughter the thundering i915_wait_request herd
One particularly stressful scenario consists of many independent tasks
all competing for GPU time and waiting upon the results (e.g. realtime
transcoding of many, many streams). One bottleneck in particular is that
each client waits on its own results, but every client is woken up after
every batchbuffer - hence the thunder of hooves as then every client must
do its heavyweight dance to read a coherent seqno to see if it is the
lucky one.
Ideally, we only want one client to wake up after the interrupt and
check its request for completion. Since the requests must retire in
order, we can select the first client on the oldest request to be woken.
Once that client has completed his wait, we can then wake up the
next client and so on. However, all clients then incur latency as every
process in the chain may be delayed for scheduling - this may also then
cause some priority inversion. To reduce the latency, when a client
is added or removed from the list, we scan the tree for completed
seqno and wake up all the completed waiters in parallel.
Using igt/benchmarks/gem_latency, we can demonstrate this effect. The
benchmark measures the number of GPU cycles between completion of a
batch and the client waking up from a call to wait-ioctl. With many
concurrent waiters, with each on a different request, we observe that
the wakeup latency before the patch scales nearly linearly with the
number of waiters (before external factors kick in making the scaling much
worse). After applying the patch, we can see that only the single waiter
for the request is being woken up, providing a constant wakeup latency
for every operation. However, the situation is not quite as rosy for
many waiters on the same request, though to the best of my knowledge this
is much less likely in practice. Here, we can observe that the
concurrent waiters incur extra latency from being woken up by the
solitary bottom-half, rather than directly by the interrupt. This
appears to be scheduler induced (having discounted adverse effects from
having a rbtree walk/erase in the wakeup path), each additional
wake_up_process() costs approximately 1us on big core. Another effect of
performing the secondary wakeups from the first bottom-half is the
incurred delay this imposes on high priority threads - rather than
immediately returning to userspace and leaving the interrupt handler to
wake the others.
To offset the delay incurred with additional waiters on a request, we
could use a hybrid scheme that did a quick read in the interrupt handler
and dequeued all the completed waiters (incurring the overhead in the
interrupt handler, not the best plan either as we then incur GPU
submission latency) but we would still have to wake up the bottom-half
every time to do the heavyweight slow read. Or we could only kick the
waiters on the seqno with the same priority as the current task (i.e. in
the realtime waiter scenario, only it is woken up immediately by the
interrupt and simply queues the next waiter before returning to userspace,
minimising its delay at the expense of the chain, and also reducing
contention on its scheduler runqueue). This is effective at avoid long
pauses in the interrupt handler and at avoiding the extra latency in
realtime/high-priority waiters.
v2: Convert from a kworker per engine into a dedicated kthread for the
bottom-half.
v3: Rename request members and tweak comments.
v4: Use a per-engine spinlock in the breadcrumbs bottom-half.
v5: Fix race in locklessly checking waiter status and kicking the task on
adding a new waiter.
v6: Fix deciding when to force the timer to hide missing interrupts.
v7: Move the bottom-half from the kthread to the first client process.
v8: Reword a few comments
v9: Break the busy loop when the interrupt is unmasked or has fired.
v10: Comments, unnecessary churn, better debugging from Tvrtko
v11: Wake all completed waiters on removing the current bottom-half to
reduce the latency of waking up a herd of clients all waiting on the
same request.
v12: Rearrange missed-interrupt fault injection so that it works with
igt/drv_missed_irq_hang
v13: Rename intel_breadcrumb and friends to intel_wait in preparation
for signal handling.
v14: RCU commentary, assert_spin_locked
v15: Hide BUG_ON behind the compiler; report on gem_latency findings.
v16: Sort seqno-groups by priority so that first-waiter has the highest
task priority (and so avoid priority inversion).
v17: Add waiters to post-mortem GPU hang state.
v18: Return early for a completed wait after acquiring the spinlock.
Avoids adding ourselves to the tree if the is already complete, and
skips the awkward question of why we don't do completion wakeups for
waits earlier than or equal to ourselves.
v19: Prepare for init_breadcrumbs to fail. Later patches may want to
allocate during init, so be prepared to propagate back the error code.
Testcase: igt/gem_concurrent_blit
Testcase: igt/benchmarks/gem_latency
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: "Rogozhkin, Dmitry V" <dmitry.v.rogozhkin@intel.com>
Cc: "Gong, Zhipeng" <zhipeng.gong@intel.com>
Cc: Tvrtko Ursulin <tvrtko.ursulin@linux.intel.com>
Cc: Dave Gordon <david.s.gordon@intel.com>
Cc: "Goel, Akash" <akash.goel@intel.com>
Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@linux.intel.com> #v18
Link: http://patchwork.freedesktop.org/patch/msgid/1467390209-3576-6-git-send-email-chris@chris-wilson.co.uk
2016-07-01 23:23:15 +07:00
|
|
|
|
drm/i915: Replace global breadcrumbs with per-context interrupt tracking
A few years ago, see commit 688e6c725816 ("drm/i915: Slaughter the
thundering i915_wait_request herd"), the issue of handling multiple
clients waiting in parallel was brought to our attention. The
requirement was that every client should be woken immediately upon its
request being signaled, without incurring any cpu overhead.
To handle certain fragility of our hw meant that we could not do a
simple check inside the irq handler (some generations required almost
unbounded delays before we could be sure of seqno coherency) and so
request completion checking required delegation.
Before commit 688e6c725816, the solution was simple. Every client
waiting on a request would be woken on every interrupt and each would do
a heavyweight check to see if their request was complete. Commit
688e6c725816 introduced an rbtree so that only the earliest waiter on
the global timeline would woken, and would wake the next and so on.
(Along with various complications to handle requests being reordered
along the global timeline, and also a requirement for kthread to provide
a delegate for fence signaling that had no process context.)
The global rbtree depends on knowing the execution timeline (and global
seqno). Without knowing that order, we must instead check all contexts
queued to the HW to see which may have advanced. We trim that list by
only checking queued contexts that are being waited on, but still we
keep a list of all active contexts and their active signalers that we
inspect from inside the irq handler. By moving the waiters onto the fence
signal list, we can combine the client wakeup with the dma_fence
signaling (a dramatic reduction in complexity, but does require the HW
being coherent, the seqno must be visible from the cpu before the
interrupt is raised - we keep a timer backup just in case).
Having previously fixed all the issues with irq-seqno serialisation (by
inserting delays onto the GPU after each request instead of random delays
on the CPU after each interrupt), we can rely on the seqno state to
perfom direct wakeups from the interrupt handler. This allows us to
preserve our single context switch behaviour of the current routine,
with the only downside that we lose the RT priority sorting of wakeups.
In general, direct wakeup latency of multiple clients is about the same
(about 10% better in most cases) with a reduction in total CPU time spent
in the waiter (about 20-50% depending on gen). Average herd behaviour is
improved, but at the cost of not delegating wakeups on task_prio.
v2: Capture fence signaling state for error state and add comments to
warm even the most cold of hearts.
v3: Check if the request is still active before busywaiting
v4: Reduce the amount of pointer misdirection with list_for_each_safe
and using a local i915_request variable inside the loops
v5: Add a missing pluralisation to a purely informative selftest message.
References: 688e6c725816 ("drm/i915: Slaughter the thundering i915_wait_request herd")
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20190129205230.19056-2-chris@chris-wilson.co.uk
2019-01-30 03:52:29 +07:00
|
|
|
bool intel_engine_signal_breadcrumbs(struct intel_engine_cs *engine);
|
|
|
|
void intel_engine_disarm_breadcrumbs(struct intel_engine_cs *engine);
|
drm/i915: Slaughter the thundering i915_wait_request herd
One particularly stressful scenario consists of many independent tasks
all competing for GPU time and waiting upon the results (e.g. realtime
transcoding of many, many streams). One bottleneck in particular is that
each client waits on its own results, but every client is woken up after
every batchbuffer - hence the thunder of hooves as then every client must
do its heavyweight dance to read a coherent seqno to see if it is the
lucky one.
Ideally, we only want one client to wake up after the interrupt and
check its request for completion. Since the requests must retire in
order, we can select the first client on the oldest request to be woken.
Once that client has completed his wait, we can then wake up the
next client and so on. However, all clients then incur latency as every
process in the chain may be delayed for scheduling - this may also then
cause some priority inversion. To reduce the latency, when a client
is added or removed from the list, we scan the tree for completed
seqno and wake up all the completed waiters in parallel.
Using igt/benchmarks/gem_latency, we can demonstrate this effect. The
benchmark measures the number of GPU cycles between completion of a
batch and the client waking up from a call to wait-ioctl. With many
concurrent waiters, with each on a different request, we observe that
the wakeup latency before the patch scales nearly linearly with the
number of waiters (before external factors kick in making the scaling much
worse). After applying the patch, we can see that only the single waiter
for the request is being woken up, providing a constant wakeup latency
for every operation. However, the situation is not quite as rosy for
many waiters on the same request, though to the best of my knowledge this
is much less likely in practice. Here, we can observe that the
concurrent waiters incur extra latency from being woken up by the
solitary bottom-half, rather than directly by the interrupt. This
appears to be scheduler induced (having discounted adverse effects from
having a rbtree walk/erase in the wakeup path), each additional
wake_up_process() costs approximately 1us on big core. Another effect of
performing the secondary wakeups from the first bottom-half is the
incurred delay this imposes on high priority threads - rather than
immediately returning to userspace and leaving the interrupt handler to
wake the others.
To offset the delay incurred with additional waiters on a request, we
could use a hybrid scheme that did a quick read in the interrupt handler
and dequeued all the completed waiters (incurring the overhead in the
interrupt handler, not the best plan either as we then incur GPU
submission latency) but we would still have to wake up the bottom-half
every time to do the heavyweight slow read. Or we could only kick the
waiters on the seqno with the same priority as the current task (i.e. in
the realtime waiter scenario, only it is woken up immediately by the
interrupt and simply queues the next waiter before returning to userspace,
minimising its delay at the expense of the chain, and also reducing
contention on its scheduler runqueue). This is effective at avoid long
pauses in the interrupt handler and at avoiding the extra latency in
realtime/high-priority waiters.
v2: Convert from a kworker per engine into a dedicated kthread for the
bottom-half.
v3: Rename request members and tweak comments.
v4: Use a per-engine spinlock in the breadcrumbs bottom-half.
v5: Fix race in locklessly checking waiter status and kicking the task on
adding a new waiter.
v6: Fix deciding when to force the timer to hide missing interrupts.
v7: Move the bottom-half from the kthread to the first client process.
v8: Reword a few comments
v9: Break the busy loop when the interrupt is unmasked or has fired.
v10: Comments, unnecessary churn, better debugging from Tvrtko
v11: Wake all completed waiters on removing the current bottom-half to
reduce the latency of waking up a herd of clients all waiting on the
same request.
v12: Rearrange missed-interrupt fault injection so that it works with
igt/drv_missed_irq_hang
v13: Rename intel_breadcrumb and friends to intel_wait in preparation
for signal handling.
v14: RCU commentary, assert_spin_locked
v15: Hide BUG_ON behind the compiler; report on gem_latency findings.
v16: Sort seqno-groups by priority so that first-waiter has the highest
task priority (and so avoid priority inversion).
v17: Add waiters to post-mortem GPU hang state.
v18: Return early for a completed wait after acquiring the spinlock.
Avoids adding ourselves to the tree if the is already complete, and
skips the awkward question of why we don't do completion wakeups for
waits earlier than or equal to ourselves.
v19: Prepare for init_breadcrumbs to fail. Later patches may want to
allocate during init, so be prepared to propagate back the error code.
Testcase: igt/gem_concurrent_blit
Testcase: igt/benchmarks/gem_latency
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: "Rogozhkin, Dmitry V" <dmitry.v.rogozhkin@intel.com>
Cc: "Gong, Zhipeng" <zhipeng.gong@intel.com>
Cc: Tvrtko Ursulin <tvrtko.ursulin@linux.intel.com>
Cc: Dave Gordon <david.s.gordon@intel.com>
Cc: "Goel, Akash" <akash.goel@intel.com>
Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@linux.intel.com> #v18
Link: http://patchwork.freedesktop.org/patch/msgid/1467390209-3576-6-git-send-email-chris@chris-wilson.co.uk
2016-07-01 23:23:15 +07:00
|
|
|
|
drm/i915: Replace global breadcrumbs with per-context interrupt tracking
A few years ago, see commit 688e6c725816 ("drm/i915: Slaughter the
thundering i915_wait_request herd"), the issue of handling multiple
clients waiting in parallel was brought to our attention. The
requirement was that every client should be woken immediately upon its
request being signaled, without incurring any cpu overhead.
To handle certain fragility of our hw meant that we could not do a
simple check inside the irq handler (some generations required almost
unbounded delays before we could be sure of seqno coherency) and so
request completion checking required delegation.
Before commit 688e6c725816, the solution was simple. Every client
waiting on a request would be woken on every interrupt and each would do
a heavyweight check to see if their request was complete. Commit
688e6c725816 introduced an rbtree so that only the earliest waiter on
the global timeline would woken, and would wake the next and so on.
(Along with various complications to handle requests being reordered
along the global timeline, and also a requirement for kthread to provide
a delegate for fence signaling that had no process context.)
The global rbtree depends on knowing the execution timeline (and global
seqno). Without knowing that order, we must instead check all contexts
queued to the HW to see which may have advanced. We trim that list by
only checking queued contexts that are being waited on, but still we
keep a list of all active contexts and their active signalers that we
inspect from inside the irq handler. By moving the waiters onto the fence
signal list, we can combine the client wakeup with the dma_fence
signaling (a dramatic reduction in complexity, but does require the HW
being coherent, the seqno must be visible from the cpu before the
interrupt is raised - we keep a timer backup just in case).
Having previously fixed all the issues with irq-seqno serialisation (by
inserting delays onto the GPU after each request instead of random delays
on the CPU after each interrupt), we can rely on the seqno state to
perfom direct wakeups from the interrupt handler. This allows us to
preserve our single context switch behaviour of the current routine,
with the only downside that we lose the RT priority sorting of wakeups.
In general, direct wakeup latency of multiple clients is about the same
(about 10% better in most cases) with a reduction in total CPU time spent
in the waiter (about 20-50% depending on gen). Average herd behaviour is
improved, but at the cost of not delegating wakeups on task_prio.
v2: Capture fence signaling state for error state and add comments to
warm even the most cold of hearts.
v3: Check if the request is still active before busywaiting
v4: Reduce the amount of pointer misdirection with list_for_each_safe
and using a local i915_request variable inside the loops
v5: Add a missing pluralisation to a purely informative selftest message.
References: 688e6c725816 ("drm/i915: Slaughter the thundering i915_wait_request herd")
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20190129205230.19056-2-chris@chris-wilson.co.uk
2019-01-30 03:52:29 +07:00
|
|
|
static inline void
|
|
|
|
intel_engine_queue_breadcrumbs(struct intel_engine_cs *engine)
|
drm/i915: Slaughter the thundering i915_wait_request herd
One particularly stressful scenario consists of many independent tasks
all competing for GPU time and waiting upon the results (e.g. realtime
transcoding of many, many streams). One bottleneck in particular is that
each client waits on its own results, but every client is woken up after
every batchbuffer - hence the thunder of hooves as then every client must
do its heavyweight dance to read a coherent seqno to see if it is the
lucky one.
Ideally, we only want one client to wake up after the interrupt and
check its request for completion. Since the requests must retire in
order, we can select the first client on the oldest request to be woken.
Once that client has completed his wait, we can then wake up the
next client and so on. However, all clients then incur latency as every
process in the chain may be delayed for scheduling - this may also then
cause some priority inversion. To reduce the latency, when a client
is added or removed from the list, we scan the tree for completed
seqno and wake up all the completed waiters in parallel.
Using igt/benchmarks/gem_latency, we can demonstrate this effect. The
benchmark measures the number of GPU cycles between completion of a
batch and the client waking up from a call to wait-ioctl. With many
concurrent waiters, with each on a different request, we observe that
the wakeup latency before the patch scales nearly linearly with the
number of waiters (before external factors kick in making the scaling much
worse). After applying the patch, we can see that only the single waiter
for the request is being woken up, providing a constant wakeup latency
for every operation. However, the situation is not quite as rosy for
many waiters on the same request, though to the best of my knowledge this
is much less likely in practice. Here, we can observe that the
concurrent waiters incur extra latency from being woken up by the
solitary bottom-half, rather than directly by the interrupt. This
appears to be scheduler induced (having discounted adverse effects from
having a rbtree walk/erase in the wakeup path), each additional
wake_up_process() costs approximately 1us on big core. Another effect of
performing the secondary wakeups from the first bottom-half is the
incurred delay this imposes on high priority threads - rather than
immediately returning to userspace and leaving the interrupt handler to
wake the others.
To offset the delay incurred with additional waiters on a request, we
could use a hybrid scheme that did a quick read in the interrupt handler
and dequeued all the completed waiters (incurring the overhead in the
interrupt handler, not the best plan either as we then incur GPU
submission latency) but we would still have to wake up the bottom-half
every time to do the heavyweight slow read. Or we could only kick the
waiters on the seqno with the same priority as the current task (i.e. in
the realtime waiter scenario, only it is woken up immediately by the
interrupt and simply queues the next waiter before returning to userspace,
minimising its delay at the expense of the chain, and also reducing
contention on its scheduler runqueue). This is effective at avoid long
pauses in the interrupt handler and at avoiding the extra latency in
realtime/high-priority waiters.
v2: Convert from a kworker per engine into a dedicated kthread for the
bottom-half.
v3: Rename request members and tweak comments.
v4: Use a per-engine spinlock in the breadcrumbs bottom-half.
v5: Fix race in locklessly checking waiter status and kicking the task on
adding a new waiter.
v6: Fix deciding when to force the timer to hide missing interrupts.
v7: Move the bottom-half from the kthread to the first client process.
v8: Reword a few comments
v9: Break the busy loop when the interrupt is unmasked or has fired.
v10: Comments, unnecessary churn, better debugging from Tvrtko
v11: Wake all completed waiters on removing the current bottom-half to
reduce the latency of waking up a herd of clients all waiting on the
same request.
v12: Rearrange missed-interrupt fault injection so that it works with
igt/drv_missed_irq_hang
v13: Rename intel_breadcrumb and friends to intel_wait in preparation
for signal handling.
v14: RCU commentary, assert_spin_locked
v15: Hide BUG_ON behind the compiler; report on gem_latency findings.
v16: Sort seqno-groups by priority so that first-waiter has the highest
task priority (and so avoid priority inversion).
v17: Add waiters to post-mortem GPU hang state.
v18: Return early for a completed wait after acquiring the spinlock.
Avoids adding ourselves to the tree if the is already complete, and
skips the awkward question of why we don't do completion wakeups for
waits earlier than or equal to ourselves.
v19: Prepare for init_breadcrumbs to fail. Later patches may want to
allocate during init, so be prepared to propagate back the error code.
Testcase: igt/gem_concurrent_blit
Testcase: igt/benchmarks/gem_latency
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: "Rogozhkin, Dmitry V" <dmitry.v.rogozhkin@intel.com>
Cc: "Gong, Zhipeng" <zhipeng.gong@intel.com>
Cc: Tvrtko Ursulin <tvrtko.ursulin@linux.intel.com>
Cc: Dave Gordon <david.s.gordon@intel.com>
Cc: "Goel, Akash" <akash.goel@intel.com>
Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@linux.intel.com> #v18
Link: http://patchwork.freedesktop.org/patch/msgid/1467390209-3576-6-git-send-email-chris@chris-wilson.co.uk
2016-07-01 23:23:15 +07:00
|
|
|
{
|
drm/i915: Replace global breadcrumbs with per-context interrupt tracking
A few years ago, see commit 688e6c725816 ("drm/i915: Slaughter the
thundering i915_wait_request herd"), the issue of handling multiple
clients waiting in parallel was brought to our attention. The
requirement was that every client should be woken immediately upon its
request being signaled, without incurring any cpu overhead.
To handle certain fragility of our hw meant that we could not do a
simple check inside the irq handler (some generations required almost
unbounded delays before we could be sure of seqno coherency) and so
request completion checking required delegation.
Before commit 688e6c725816, the solution was simple. Every client
waiting on a request would be woken on every interrupt and each would do
a heavyweight check to see if their request was complete. Commit
688e6c725816 introduced an rbtree so that only the earliest waiter on
the global timeline would woken, and would wake the next and so on.
(Along with various complications to handle requests being reordered
along the global timeline, and also a requirement for kthread to provide
a delegate for fence signaling that had no process context.)
The global rbtree depends on knowing the execution timeline (and global
seqno). Without knowing that order, we must instead check all contexts
queued to the HW to see which may have advanced. We trim that list by
only checking queued contexts that are being waited on, but still we
keep a list of all active contexts and their active signalers that we
inspect from inside the irq handler. By moving the waiters onto the fence
signal list, we can combine the client wakeup with the dma_fence
signaling (a dramatic reduction in complexity, but does require the HW
being coherent, the seqno must be visible from the cpu before the
interrupt is raised - we keep a timer backup just in case).
Having previously fixed all the issues with irq-seqno serialisation (by
inserting delays onto the GPU after each request instead of random delays
on the CPU after each interrupt), we can rely on the seqno state to
perfom direct wakeups from the interrupt handler. This allows us to
preserve our single context switch behaviour of the current routine,
with the only downside that we lose the RT priority sorting of wakeups.
In general, direct wakeup latency of multiple clients is about the same
(about 10% better in most cases) with a reduction in total CPU time spent
in the waiter (about 20-50% depending on gen). Average herd behaviour is
improved, but at the cost of not delegating wakeups on task_prio.
v2: Capture fence signaling state for error state and add comments to
warm even the most cold of hearts.
v3: Check if the request is still active before busywaiting
v4: Reduce the amount of pointer misdirection with list_for_each_safe
and using a local i915_request variable inside the loops
v5: Add a missing pluralisation to a purely informative selftest message.
References: 688e6c725816 ("drm/i915: Slaughter the thundering i915_wait_request herd")
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20190129205230.19056-2-chris@chris-wilson.co.uk
2019-01-30 03:52:29 +07:00
|
|
|
irq_work_queue(&engine->breadcrumbs.irq_work);
|
drm/i915: Slaughter the thundering i915_wait_request herd
One particularly stressful scenario consists of many independent tasks
all competing for GPU time and waiting upon the results (e.g. realtime
transcoding of many, many streams). One bottleneck in particular is that
each client waits on its own results, but every client is woken up after
every batchbuffer - hence the thunder of hooves as then every client must
do its heavyweight dance to read a coherent seqno to see if it is the
lucky one.
Ideally, we only want one client to wake up after the interrupt and
check its request for completion. Since the requests must retire in
order, we can select the first client on the oldest request to be woken.
Once that client has completed his wait, we can then wake up the
next client and so on. However, all clients then incur latency as every
process in the chain may be delayed for scheduling - this may also then
cause some priority inversion. To reduce the latency, when a client
is added or removed from the list, we scan the tree for completed
seqno and wake up all the completed waiters in parallel.
Using igt/benchmarks/gem_latency, we can demonstrate this effect. The
benchmark measures the number of GPU cycles between completion of a
batch and the client waking up from a call to wait-ioctl. With many
concurrent waiters, with each on a different request, we observe that
the wakeup latency before the patch scales nearly linearly with the
number of waiters (before external factors kick in making the scaling much
worse). After applying the patch, we can see that only the single waiter
for the request is being woken up, providing a constant wakeup latency
for every operation. However, the situation is not quite as rosy for
many waiters on the same request, though to the best of my knowledge this
is much less likely in practice. Here, we can observe that the
concurrent waiters incur extra latency from being woken up by the
solitary bottom-half, rather than directly by the interrupt. This
appears to be scheduler induced (having discounted adverse effects from
having a rbtree walk/erase in the wakeup path), each additional
wake_up_process() costs approximately 1us on big core. Another effect of
performing the secondary wakeups from the first bottom-half is the
incurred delay this imposes on high priority threads - rather than
immediately returning to userspace and leaving the interrupt handler to
wake the others.
To offset the delay incurred with additional waiters on a request, we
could use a hybrid scheme that did a quick read in the interrupt handler
and dequeued all the completed waiters (incurring the overhead in the
interrupt handler, not the best plan either as we then incur GPU
submission latency) but we would still have to wake up the bottom-half
every time to do the heavyweight slow read. Or we could only kick the
waiters on the seqno with the same priority as the current task (i.e. in
the realtime waiter scenario, only it is woken up immediately by the
interrupt and simply queues the next waiter before returning to userspace,
minimising its delay at the expense of the chain, and also reducing
contention on its scheduler runqueue). This is effective at avoid long
pauses in the interrupt handler and at avoiding the extra latency in
realtime/high-priority waiters.
v2: Convert from a kworker per engine into a dedicated kthread for the
bottom-half.
v3: Rename request members and tweak comments.
v4: Use a per-engine spinlock in the breadcrumbs bottom-half.
v5: Fix race in locklessly checking waiter status and kicking the task on
adding a new waiter.
v6: Fix deciding when to force the timer to hide missing interrupts.
v7: Move the bottom-half from the kthread to the first client process.
v8: Reword a few comments
v9: Break the busy loop when the interrupt is unmasked or has fired.
v10: Comments, unnecessary churn, better debugging from Tvrtko
v11: Wake all completed waiters on removing the current bottom-half to
reduce the latency of waking up a herd of clients all waiting on the
same request.
v12: Rearrange missed-interrupt fault injection so that it works with
igt/drv_missed_irq_hang
v13: Rename intel_breadcrumb and friends to intel_wait in preparation
for signal handling.
v14: RCU commentary, assert_spin_locked
v15: Hide BUG_ON behind the compiler; report on gem_latency findings.
v16: Sort seqno-groups by priority so that first-waiter has the highest
task priority (and so avoid priority inversion).
v17: Add waiters to post-mortem GPU hang state.
v18: Return early for a completed wait after acquiring the spinlock.
Avoids adding ourselves to the tree if the is already complete, and
skips the awkward question of why we don't do completion wakeups for
waits earlier than or equal to ourselves.
v19: Prepare for init_breadcrumbs to fail. Later patches may want to
allocate during init, so be prepared to propagate back the error code.
Testcase: igt/gem_concurrent_blit
Testcase: igt/benchmarks/gem_latency
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: "Rogozhkin, Dmitry V" <dmitry.v.rogozhkin@intel.com>
Cc: "Gong, Zhipeng" <zhipeng.gong@intel.com>
Cc: Tvrtko Ursulin <tvrtko.ursulin@linux.intel.com>
Cc: Dave Gordon <david.s.gordon@intel.com>
Cc: "Goel, Akash" <akash.goel@intel.com>
Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@linux.intel.com> #v18
Link: http://patchwork.freedesktop.org/patch/msgid/1467390209-3576-6-git-send-email-chris@chris-wilson.co.uk
2016-07-01 23:23:15 +07:00
|
|
|
}
|
|
|
|
|
drm/i915: Replace global breadcrumbs with per-context interrupt tracking
A few years ago, see commit 688e6c725816 ("drm/i915: Slaughter the
thundering i915_wait_request herd"), the issue of handling multiple
clients waiting in parallel was brought to our attention. The
requirement was that every client should be woken immediately upon its
request being signaled, without incurring any cpu overhead.
To handle certain fragility of our hw meant that we could not do a
simple check inside the irq handler (some generations required almost
unbounded delays before we could be sure of seqno coherency) and so
request completion checking required delegation.
Before commit 688e6c725816, the solution was simple. Every client
waiting on a request would be woken on every interrupt and each would do
a heavyweight check to see if their request was complete. Commit
688e6c725816 introduced an rbtree so that only the earliest waiter on
the global timeline would woken, and would wake the next and so on.
(Along with various complications to handle requests being reordered
along the global timeline, and also a requirement for kthread to provide
a delegate for fence signaling that had no process context.)
The global rbtree depends on knowing the execution timeline (and global
seqno). Without knowing that order, we must instead check all contexts
queued to the HW to see which may have advanced. We trim that list by
only checking queued contexts that are being waited on, but still we
keep a list of all active contexts and their active signalers that we
inspect from inside the irq handler. By moving the waiters onto the fence
signal list, we can combine the client wakeup with the dma_fence
signaling (a dramatic reduction in complexity, but does require the HW
being coherent, the seqno must be visible from the cpu before the
interrupt is raised - we keep a timer backup just in case).
Having previously fixed all the issues with irq-seqno serialisation (by
inserting delays onto the GPU after each request instead of random delays
on the CPU after each interrupt), we can rely on the seqno state to
perfom direct wakeups from the interrupt handler. This allows us to
preserve our single context switch behaviour of the current routine,
with the only downside that we lose the RT priority sorting of wakeups.
In general, direct wakeup latency of multiple clients is about the same
(about 10% better in most cases) with a reduction in total CPU time spent
in the waiter (about 20-50% depending on gen). Average herd behaviour is
improved, but at the cost of not delegating wakeups on task_prio.
v2: Capture fence signaling state for error state and add comments to
warm even the most cold of hearts.
v3: Check if the request is still active before busywaiting
v4: Reduce the amount of pointer misdirection with list_for_each_safe
and using a local i915_request variable inside the loops
v5: Add a missing pluralisation to a purely informative selftest message.
References: 688e6c725816 ("drm/i915: Slaughter the thundering i915_wait_request herd")
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20190129205230.19056-2-chris@chris-wilson.co.uk
2019-01-30 03:52:29 +07:00
|
|
|
bool intel_engine_breadcrumbs_irq(struct intel_engine_cs *engine);
|
drm/i915: Slaughter the thundering i915_wait_request herd
One particularly stressful scenario consists of many independent tasks
all competing for GPU time and waiting upon the results (e.g. realtime
transcoding of many, many streams). One bottleneck in particular is that
each client waits on its own results, but every client is woken up after
every batchbuffer - hence the thunder of hooves as then every client must
do its heavyweight dance to read a coherent seqno to see if it is the
lucky one.
Ideally, we only want one client to wake up after the interrupt and
check its request for completion. Since the requests must retire in
order, we can select the first client on the oldest request to be woken.
Once that client has completed his wait, we can then wake up the
next client and so on. However, all clients then incur latency as every
process in the chain may be delayed for scheduling - this may also then
cause some priority inversion. To reduce the latency, when a client
is added or removed from the list, we scan the tree for completed
seqno and wake up all the completed waiters in parallel.
Using igt/benchmarks/gem_latency, we can demonstrate this effect. The
benchmark measures the number of GPU cycles between completion of a
batch and the client waking up from a call to wait-ioctl. With many
concurrent waiters, with each on a different request, we observe that
the wakeup latency before the patch scales nearly linearly with the
number of waiters (before external factors kick in making the scaling much
worse). After applying the patch, we can see that only the single waiter
for the request is being woken up, providing a constant wakeup latency
for every operation. However, the situation is not quite as rosy for
many waiters on the same request, though to the best of my knowledge this
is much less likely in practice. Here, we can observe that the
concurrent waiters incur extra latency from being woken up by the
solitary bottom-half, rather than directly by the interrupt. This
appears to be scheduler induced (having discounted adverse effects from
having a rbtree walk/erase in the wakeup path), each additional
wake_up_process() costs approximately 1us on big core. Another effect of
performing the secondary wakeups from the first bottom-half is the
incurred delay this imposes on high priority threads - rather than
immediately returning to userspace and leaving the interrupt handler to
wake the others.
To offset the delay incurred with additional waiters on a request, we
could use a hybrid scheme that did a quick read in the interrupt handler
and dequeued all the completed waiters (incurring the overhead in the
interrupt handler, not the best plan either as we then incur GPU
submission latency) but we would still have to wake up the bottom-half
every time to do the heavyweight slow read. Or we could only kick the
waiters on the seqno with the same priority as the current task (i.e. in
the realtime waiter scenario, only it is woken up immediately by the
interrupt and simply queues the next waiter before returning to userspace,
minimising its delay at the expense of the chain, and also reducing
contention on its scheduler runqueue). This is effective at avoid long
pauses in the interrupt handler and at avoiding the extra latency in
realtime/high-priority waiters.
v2: Convert from a kworker per engine into a dedicated kthread for the
bottom-half.
v3: Rename request members and tweak comments.
v4: Use a per-engine spinlock in the breadcrumbs bottom-half.
v5: Fix race in locklessly checking waiter status and kicking the task on
adding a new waiter.
v6: Fix deciding when to force the timer to hide missing interrupts.
v7: Move the bottom-half from the kthread to the first client process.
v8: Reword a few comments
v9: Break the busy loop when the interrupt is unmasked or has fired.
v10: Comments, unnecessary churn, better debugging from Tvrtko
v11: Wake all completed waiters on removing the current bottom-half to
reduce the latency of waking up a herd of clients all waiting on the
same request.
v12: Rearrange missed-interrupt fault injection so that it works with
igt/drv_missed_irq_hang
v13: Rename intel_breadcrumb and friends to intel_wait in preparation
for signal handling.
v14: RCU commentary, assert_spin_locked
v15: Hide BUG_ON behind the compiler; report on gem_latency findings.
v16: Sort seqno-groups by priority so that first-waiter has the highest
task priority (and so avoid priority inversion).
v17: Add waiters to post-mortem GPU hang state.
v18: Return early for a completed wait after acquiring the spinlock.
Avoids adding ourselves to the tree if the is already complete, and
skips the awkward question of why we don't do completion wakeups for
waits earlier than or equal to ourselves.
v19: Prepare for init_breadcrumbs to fail. Later patches may want to
allocate during init, so be prepared to propagate back the error code.
Testcase: igt/gem_concurrent_blit
Testcase: igt/benchmarks/gem_latency
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: "Rogozhkin, Dmitry V" <dmitry.v.rogozhkin@intel.com>
Cc: "Gong, Zhipeng" <zhipeng.gong@intel.com>
Cc: Tvrtko Ursulin <tvrtko.ursulin@linux.intel.com>
Cc: Dave Gordon <david.s.gordon@intel.com>
Cc: "Goel, Akash" <akash.goel@intel.com>
Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@linux.intel.com> #v18
Link: http://patchwork.freedesktop.org/patch/msgid/1467390209-3576-6-git-send-email-chris@chris-wilson.co.uk
2016-07-01 23:23:15 +07:00
|
|
|
|
2016-10-07 13:53:26 +07:00
|
|
|
void intel_engine_reset_breadcrumbs(struct intel_engine_cs *engine);
|
drm/i915: Slaughter the thundering i915_wait_request herd
One particularly stressful scenario consists of many independent tasks
all competing for GPU time and waiting upon the results (e.g. realtime
transcoding of many, many streams). One bottleneck in particular is that
each client waits on its own results, but every client is woken up after
every batchbuffer - hence the thunder of hooves as then every client must
do its heavyweight dance to read a coherent seqno to see if it is the
lucky one.
Ideally, we only want one client to wake up after the interrupt and
check its request for completion. Since the requests must retire in
order, we can select the first client on the oldest request to be woken.
Once that client has completed his wait, we can then wake up the
next client and so on. However, all clients then incur latency as every
process in the chain may be delayed for scheduling - this may also then
cause some priority inversion. To reduce the latency, when a client
is added or removed from the list, we scan the tree for completed
seqno and wake up all the completed waiters in parallel.
Using igt/benchmarks/gem_latency, we can demonstrate this effect. The
benchmark measures the number of GPU cycles between completion of a
batch and the client waking up from a call to wait-ioctl. With many
concurrent waiters, with each on a different request, we observe that
the wakeup latency before the patch scales nearly linearly with the
number of waiters (before external factors kick in making the scaling much
worse). After applying the patch, we can see that only the single waiter
for the request is being woken up, providing a constant wakeup latency
for every operation. However, the situation is not quite as rosy for
many waiters on the same request, though to the best of my knowledge this
is much less likely in practice. Here, we can observe that the
concurrent waiters incur extra latency from being woken up by the
solitary bottom-half, rather than directly by the interrupt. This
appears to be scheduler induced (having discounted adverse effects from
having a rbtree walk/erase in the wakeup path), each additional
wake_up_process() costs approximately 1us on big core. Another effect of
performing the secondary wakeups from the first bottom-half is the
incurred delay this imposes on high priority threads - rather than
immediately returning to userspace and leaving the interrupt handler to
wake the others.
To offset the delay incurred with additional waiters on a request, we
could use a hybrid scheme that did a quick read in the interrupt handler
and dequeued all the completed waiters (incurring the overhead in the
interrupt handler, not the best plan either as we then incur GPU
submission latency) but we would still have to wake up the bottom-half
every time to do the heavyweight slow read. Or we could only kick the
waiters on the seqno with the same priority as the current task (i.e. in
the realtime waiter scenario, only it is woken up immediately by the
interrupt and simply queues the next waiter before returning to userspace,
minimising its delay at the expense of the chain, and also reducing
contention on its scheduler runqueue). This is effective at avoid long
pauses in the interrupt handler and at avoiding the extra latency in
realtime/high-priority waiters.
v2: Convert from a kworker per engine into a dedicated kthread for the
bottom-half.
v3: Rename request members and tweak comments.
v4: Use a per-engine spinlock in the breadcrumbs bottom-half.
v5: Fix race in locklessly checking waiter status and kicking the task on
adding a new waiter.
v6: Fix deciding when to force the timer to hide missing interrupts.
v7: Move the bottom-half from the kthread to the first client process.
v8: Reword a few comments
v9: Break the busy loop when the interrupt is unmasked or has fired.
v10: Comments, unnecessary churn, better debugging from Tvrtko
v11: Wake all completed waiters on removing the current bottom-half to
reduce the latency of waking up a herd of clients all waiting on the
same request.
v12: Rearrange missed-interrupt fault injection so that it works with
igt/drv_missed_irq_hang
v13: Rename intel_breadcrumb and friends to intel_wait in preparation
for signal handling.
v14: RCU commentary, assert_spin_locked
v15: Hide BUG_ON behind the compiler; report on gem_latency findings.
v16: Sort seqno-groups by priority so that first-waiter has the highest
task priority (and so avoid priority inversion).
v17: Add waiters to post-mortem GPU hang state.
v18: Return early for a completed wait after acquiring the spinlock.
Avoids adding ourselves to the tree if the is already complete, and
skips the awkward question of why we don't do completion wakeups for
waits earlier than or equal to ourselves.
v19: Prepare for init_breadcrumbs to fail. Later patches may want to
allocate during init, so be prepared to propagate back the error code.
Testcase: igt/gem_concurrent_blit
Testcase: igt/benchmarks/gem_latency
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: "Rogozhkin, Dmitry V" <dmitry.v.rogozhkin@intel.com>
Cc: "Gong, Zhipeng" <zhipeng.gong@intel.com>
Cc: Tvrtko Ursulin <tvrtko.ursulin@linux.intel.com>
Cc: Dave Gordon <david.s.gordon@intel.com>
Cc: "Goel, Akash" <akash.goel@intel.com>
Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@linux.intel.com> #v18
Link: http://patchwork.freedesktop.org/patch/msgid/1467390209-3576-6-git-send-email-chris@chris-wilson.co.uk
2016-07-01 23:23:15 +07:00
|
|
|
void intel_engine_fini_breadcrumbs(struct intel_engine_cs *engine);
|
|
|
|
|
drm/i915: Replace global breadcrumbs with per-context interrupt tracking
A few years ago, see commit 688e6c725816 ("drm/i915: Slaughter the
thundering i915_wait_request herd"), the issue of handling multiple
clients waiting in parallel was brought to our attention. The
requirement was that every client should be woken immediately upon its
request being signaled, without incurring any cpu overhead.
To handle certain fragility of our hw meant that we could not do a
simple check inside the irq handler (some generations required almost
unbounded delays before we could be sure of seqno coherency) and so
request completion checking required delegation.
Before commit 688e6c725816, the solution was simple. Every client
waiting on a request would be woken on every interrupt and each would do
a heavyweight check to see if their request was complete. Commit
688e6c725816 introduced an rbtree so that only the earliest waiter on
the global timeline would woken, and would wake the next and so on.
(Along with various complications to handle requests being reordered
along the global timeline, and also a requirement for kthread to provide
a delegate for fence signaling that had no process context.)
The global rbtree depends on knowing the execution timeline (and global
seqno). Without knowing that order, we must instead check all contexts
queued to the HW to see which may have advanced. We trim that list by
only checking queued contexts that are being waited on, but still we
keep a list of all active contexts and their active signalers that we
inspect from inside the irq handler. By moving the waiters onto the fence
signal list, we can combine the client wakeup with the dma_fence
signaling (a dramatic reduction in complexity, but does require the HW
being coherent, the seqno must be visible from the cpu before the
interrupt is raised - we keep a timer backup just in case).
Having previously fixed all the issues with irq-seqno serialisation (by
inserting delays onto the GPU after each request instead of random delays
on the CPU after each interrupt), we can rely on the seqno state to
perfom direct wakeups from the interrupt handler. This allows us to
preserve our single context switch behaviour of the current routine,
with the only downside that we lose the RT priority sorting of wakeups.
In general, direct wakeup latency of multiple clients is about the same
(about 10% better in most cases) with a reduction in total CPU time spent
in the waiter (about 20-50% depending on gen). Average herd behaviour is
improved, but at the cost of not delegating wakeups on task_prio.
v2: Capture fence signaling state for error state and add comments to
warm even the most cold of hearts.
v3: Check if the request is still active before busywaiting
v4: Reduce the amount of pointer misdirection with list_for_each_safe
and using a local i915_request variable inside the loops
v5: Add a missing pluralisation to a purely informative selftest message.
References: 688e6c725816 ("drm/i915: Slaughter the thundering i915_wait_request herd")
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20190129205230.19056-2-chris@chris-wilson.co.uk
2019-01-30 03:52:29 +07:00
|
|
|
void intel_engine_print_breadcrumbs(struct intel_engine_cs *engine,
|
|
|
|
struct drm_printer *p);
|
|
|
|
|
2017-02-16 19:23:25 +07:00
|
|
|
static inline u32 *gen8_emit_pipe_control(u32 *batch, u32 flags, u32 offset)
|
|
|
|
{
|
|
|
|
memset(batch, 0, 6 * sizeof(u32));
|
|
|
|
|
|
|
|
batch[0] = GFX_OP_PIPE_CONTROL(6);
|
|
|
|
batch[1] = flags;
|
|
|
|
batch[2] = offset;
|
|
|
|
|
|
|
|
return batch + 6;
|
|
|
|
}
|
|
|
|
|
2017-10-26 03:00:15 +07:00
|
|
|
static inline u32 *
|
2018-12-28 22:31:13 +07:00
|
|
|
gen8_emit_ggtt_write_rcs(u32 *cs, u32 value, u32 gtt_offset, u32 flags)
|
2017-10-26 03:00:15 +07:00
|
|
|
{
|
|
|
|
/* We're using qword write, offset should be aligned to 8 bytes. */
|
|
|
|
GEM_BUG_ON(!IS_ALIGNED(gtt_offset, 8));
|
|
|
|
|
|
|
|
/* w/a for post sync ops following a GPGPU operation we
|
|
|
|
* need a prior CS_STALL, which is emitted by the flush
|
|
|
|
* following the batch.
|
|
|
|
*/
|
|
|
|
*cs++ = GFX_OP_PIPE_CONTROL(6);
|
2018-12-28 22:31:13 +07:00
|
|
|
*cs++ = flags | PIPE_CONTROL_QW_WRITE | PIPE_CONTROL_GLOBAL_GTT_IVB;
|
2017-10-26 03:00:15 +07:00
|
|
|
*cs++ = gtt_offset;
|
|
|
|
*cs++ = 0;
|
|
|
|
*cs++ = value;
|
|
|
|
/* We're thrashing one dword of HWS. */
|
|
|
|
*cs++ = 0;
|
|
|
|
|
|
|
|
return cs;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline u32 *
|
|
|
|
gen8_emit_ggtt_write(u32 *cs, u32 value, u32 gtt_offset)
|
|
|
|
{
|
|
|
|
/* w/a: bit 5 needs to be zero for MI_FLUSH_DW address. */
|
|
|
|
GEM_BUG_ON(gtt_offset & (1 << 5));
|
|
|
|
/* Offset should be aligned to 8 bytes for both (QW/DW) write types */
|
|
|
|
GEM_BUG_ON(!IS_ALIGNED(gtt_offset, 8));
|
|
|
|
|
|
|
|
*cs++ = (MI_FLUSH_DW + 1) | MI_FLUSH_DW_OP_STOREDW;
|
|
|
|
*cs++ = gtt_offset | MI_FLUSH_DW_USE_GTT;
|
|
|
|
*cs++ = 0;
|
|
|
|
*cs++ = value;
|
|
|
|
|
|
|
|
return cs;
|
|
|
|
}
|
|
|
|
|
2019-01-25 20:22:28 +07:00
|
|
|
static inline void intel_engine_reset(struct intel_engine_cs *engine,
|
|
|
|
bool stalled)
|
|
|
|
{
|
|
|
|
if (engine->reset.reset)
|
|
|
|
engine->reset.reset(engine, stalled);
|
|
|
|
}
|
|
|
|
|
2019-01-03 18:21:04 +07:00
|
|
|
void intel_engines_sanitize(struct drm_i915_private *i915, bool force);
|
2018-06-17 03:25:34 +07:00
|
|
|
|
2017-03-03 19:19:46 +07:00
|
|
|
bool intel_engine_is_idle(struct intel_engine_cs *engine);
|
2017-03-03 19:19:47 +07:00
|
|
|
bool intel_engines_are_idle(struct drm_i915_private *dev_priv);
|
2017-03-03 19:19:46 +07:00
|
|
|
|
2018-05-18 04:26:31 +07:00
|
|
|
void intel_engine_lost_context(struct intel_engine_cs *engine);
|
2017-10-25 05:08:55 +07:00
|
|
|
|
2017-10-25 21:39:41 +07:00
|
|
|
void intel_engines_park(struct drm_i915_private *i915);
|
|
|
|
void intel_engines_unpark(struct drm_i915_private *i915);
|
|
|
|
|
2017-03-17 00:13:03 +07:00
|
|
|
void intel_engines_reset_default_submission(struct drm_i915_private *i915);
|
2017-11-10 21:26:33 +07:00
|
|
|
unsigned int intel_engines_has_context_isolation(struct drm_i915_private *i915);
|
2017-03-17 00:13:03 +07:00
|
|
|
|
2017-09-06 22:28:59 +07:00
|
|
|
bool intel_engine_can_store_dword(struct intel_engine_cs *engine);
|
2017-08-16 15:52:04 +07:00
|
|
|
|
2017-12-08 08:23:00 +07:00
|
|
|
__printf(3, 4)
|
|
|
|
void intel_engine_dump(struct intel_engine_cs *engine,
|
|
|
|
struct drm_printer *m,
|
|
|
|
const char *header, ...);
|
2017-10-09 18:02:57 +07:00
|
|
|
|
drm/i915/pmu: Expose a PMU interface for perf queries
From: Chris Wilson <chris@chris-wilson.co.uk>
From: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
From: Dmitry Rogozhkin <dmitry.v.rogozhkin@intel.com>
The first goal is to be able to measure GPU (and invidual ring) busyness
without having to poll registers from userspace. (Which not only incurs
holding the forcewake lock indefinitely, perturbing the system, but also
runs the risk of hanging the machine.) As an alternative we can use the
perf event counter interface to sample the ring registers periodically
and send those results to userspace.
Functionality we are exporting to userspace is via the existing perf PMU
API and can be exercised via the existing tools. For example:
perf stat -a -e i915/rcs0-busy/ -I 1000
Will print the render engine busynnes once per second. All the performance
counters can be enumerated (perf list) and have their unit of measure
correctly reported in sysfs.
v1-v2 (Chris Wilson):
v2: Use a common timer for the ring sampling.
v3: (Tvrtko Ursulin)
* Decouple uAPI from i915 engine ids.
* Complete uAPI defines.
* Refactor some code to helpers for clarity.
* Skip sampling disabled engines.
* Expose counters in sysfs.
* Pass in fake regs to avoid null ptr deref in perf core.
* Convert to class/instance uAPI.
* Use shared driver code for rc6 residency, power and frequency.
v4: (Dmitry Rogozhkin)
* Register PMU with .task_ctx_nr=perf_invalid_context
* Expose cpumask for the PMU with the single CPU in the mask
* Properly support pmu->stop(): it should call pmu->read()
* Properly support pmu->del(): it should call stop(event, PERF_EF_UPDATE)
* Introduce refcounting of event subscriptions.
* Make pmu.busy_stats a refcounter to avoid busy stats going away
with some deleted event.
* Expose cpumask for i915 PMU to avoid multiple events creation of
the same type followed by counter aggregation by perf-stat.
* Track CPUs getting online/offline to migrate perf context. If (likely)
cpumask will initially set CPU0, CONFIG_BOOTPARAM_HOTPLUG_CPU0 will be
needed to see effect of CPU status tracking.
* End result is that only global events are supported and perf stat
works correctly.
* Deny perf driver level sampling - it is prohibited for uncore PMU.
v5: (Tvrtko Ursulin)
* Don't hardcode number of engine samplers.
* Rewrite event ref-counting for correctness and simplicity.
* Store initial counter value when starting already enabled events
to correctly report values to all listeners.
* Fix RC6 residency readout.
* Comments, GPL header.
v6:
* Add missing entry to v4 changelog.
* Fix accounting in CPU hotplug case by copying the approach from
arch/x86/events/intel/cstate.c. (Dmitry Rogozhkin)
v7:
* Log failure message only on failure.
* Remove CPU hotplug notification state on unregister.
v8:
* Fix error unwind on failed registration.
* Checkpatch cleanup.
v9:
* Drop the energy metric, it is available via intel_rapl_perf.
(Ville Syrjälä)
* Use HAS_RC6(p). (Chris Wilson)
* Handle unsupported non-engine events. (Dmitry Rogozhkin)
* Rebase for intel_rc6_residency_ns needing caller managed
runtime pm.
* Drop HAS_RC6 checks from the read callback since creating those
events will be rejected at init time already.
* Add counter units to sysfs so perf stat output is nicer.
* Cleanup the attribute tables for brevity and readability.
v10:
* Fixed queued accounting.
v11:
* Move intel_engine_lookup_user to intel_engine_cs.c
* Commit update. (Joonas Lahtinen)
v12:
* More accurate sampling. (Chris Wilson)
* Store and report frequency in MHz for better usability from
perf stat.
* Removed metrics: queued, interrupts, rc6 counters.
* Sample engine busyness based on seqno difference only
for less MMIO (and forcewake) on all platforms. (Chris Wilson)
v13:
* Comment spelling, use mul_u32_u32 to work around potential GCC
issue and somne code alignment changes. (Chris Wilson)
v14:
* Rebase.
v15:
* Rebase for RPS refactoring.
v16:
* Use the dynamic slot in the CPU hotplug state machine so that we are
free to setup our state as multi-instance. Previously we were re-using
the CPUHP_AP_PERF_X86_UNCORE_ONLINE slot which is neither used as
multi-instance, nor owned by our driver to start with.
* Register the CPU hotplug handlers after the PMU, otherwise the callback
will get called before the PMU is initialized which can end up in
perf_pmu_migrate_context with an un-initialized base.
* Added workaround for a probable bug in cpuhp core.
v17:
* Remove workaround for the cpuhp bug.
v18:
* Rebase for drm_i915_gem_engine_class getting upstream before us.
v19:
* Rebase. (trivial)
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Signed-off-by: Dmitry Rogozhkin <dmitry.v.rogozhkin@intel.com>
Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Cc: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Dmitry Rogozhkin <dmitry.v.rogozhkin@intel.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20171121181852.16128-2-tvrtko.ursulin@linux.intel.com
2017-11-22 01:18:45 +07:00
|
|
|
struct intel_engine_cs *
|
|
|
|
intel_engine_lookup_user(struct drm_i915_private *i915, u8 class, u8 instance);
|
|
|
|
|
2017-11-22 01:18:48 +07:00
|
|
|
static inline void intel_engine_context_in(struct intel_engine_cs *engine)
|
|
|
|
{
|
|
|
|
unsigned long flags;
|
|
|
|
|
|
|
|
if (READ_ONCE(engine->stats.enabled) == 0)
|
|
|
|
return;
|
|
|
|
|
2018-04-26 14:47:16 +07:00
|
|
|
write_seqlock_irqsave(&engine->stats.lock, flags);
|
2017-11-22 01:18:48 +07:00
|
|
|
|
|
|
|
if (engine->stats.enabled > 0) {
|
|
|
|
if (engine->stats.active++ == 0)
|
|
|
|
engine->stats.start = ktime_get();
|
|
|
|
GEM_BUG_ON(engine->stats.active == 0);
|
|
|
|
}
|
|
|
|
|
2018-04-26 14:47:16 +07:00
|
|
|
write_sequnlock_irqrestore(&engine->stats.lock, flags);
|
2017-11-22 01:18:48 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline void intel_engine_context_out(struct intel_engine_cs *engine)
|
|
|
|
{
|
|
|
|
unsigned long flags;
|
|
|
|
|
|
|
|
if (READ_ONCE(engine->stats.enabled) == 0)
|
|
|
|
return;
|
|
|
|
|
2018-04-26 14:47:16 +07:00
|
|
|
write_seqlock_irqsave(&engine->stats.lock, flags);
|
2017-11-22 01:18:48 +07:00
|
|
|
|
|
|
|
if (engine->stats.enabled > 0) {
|
|
|
|
ktime_t last;
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
engine->stats.total = ktime_add(engine->stats.total,
|
|
|
|
last);
|
|
|
|
} else if (engine->stats.active == 0) {
|
|
|
|
/*
|
|
|
|
* After turning on engine stats, context out might be
|
|
|
|
* 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);
|
|
|
|
|
|
|
|
engine->stats.total = ktime_add(engine->stats.total,
|
|
|
|
last);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-26 14:47:16 +07:00
|
|
|
write_sequnlock_irqrestore(&engine->stats.lock, flags);
|
2017-11-22 01:18:48 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
int intel_enable_engine_stats(struct intel_engine_cs *engine);
|
|
|
|
void intel_disable_engine_stats(struct intel_engine_cs *engine);
|
|
|
|
|
|
|
|
ktime_t intel_engine_get_busy_time(struct intel_engine_cs *engine);
|
|
|
|
|
2019-03-06 01:03:32 +07:00
|
|
|
struct i915_request *
|
|
|
|
intel_engine_find_active_request(struct intel_engine_cs *engine);
|
|
|
|
|
2018-07-16 20:21:54 +07:00
|
|
|
#if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
|
|
|
|
|
|
|
|
static inline bool inject_preempt_hang(struct intel_engine_execlists *execlists)
|
|
|
|
{
|
|
|
|
if (!execlists->preempt_hang.inject_hang)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
complete(&execlists->preempt_hang.completion);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
static inline bool inject_preempt_hang(struct intel_engine_execlists *execlists)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2019-02-26 16:49:19 +07:00
|
|
|
static inline u32
|
|
|
|
intel_engine_next_hangcheck_seqno(struct intel_engine_cs *engine)
|
|
|
|
{
|
|
|
|
return engine->hangcheck.next_seqno =
|
|
|
|
next_pseudo_random32(engine->hangcheck.next_seqno);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline u32
|
|
|
|
intel_engine_get_hangcheck_seqno(struct intel_engine_cs *engine)
|
|
|
|
{
|
|
|
|
return intel_read_status_page(engine, I915_GEM_HWS_HANGCHECK);
|
|
|
|
}
|
|
|
|
|
2010-05-21 08:08:55 +07:00
|
|
|
#endif /* _INTEL_RINGBUFFER_H_ */
|