License cleanup: add SPDX GPL-2.0 license identifier to files with no license
Many source files in the tree are missing licensing information, which
makes it harder for compliance tools to determine the correct license.
By default all files without license information are under the default
license of the kernel, which is GPL version 2.
Update the files which contain no license information with the 'GPL-2.0'
SPDX license identifier. The SPDX identifier is a legally binding
shorthand, which can be used instead of the full boiler plate text.
This patch is based on work done by Thomas Gleixner and Kate Stewart and
Philippe Ombredanne.
How this work was done:
Patches were generated and checked against linux-4.14-rc6 for a subset of
the use cases:
- file had no licensing information it it.
- file was a */uapi/* one with no licensing information in it,
- file was a */uapi/* one with existing licensing information,
Further patches will be generated in subsequent months to fix up cases
where non-standard license headers were used, and references to license
had to be inferred by heuristics based on keywords.
The analysis to determine which SPDX License Identifier to be applied to
a file was done in a spreadsheet of side by side results from of the
output of two independent scanners (ScanCode & Windriver) producing SPDX
tag:value files created by Philippe Ombredanne. Philippe prepared the
base worksheet, and did an initial spot review of a few 1000 files.
The 4.13 kernel was the starting point of the analysis with 60,537 files
assessed. Kate Stewart did a file by file comparison of the scanner
results in the spreadsheet to determine which SPDX license identifier(s)
to be applied to the file. She confirmed any determination that was not
immediately clear with lawyers working with the Linux Foundation.
Criteria used to select files for SPDX license identifier tagging was:
- Files considered eligible had to be source code files.
- Make and config files were included as candidates if they contained >5
lines of source
- File already had some variant of a license header in it (even if <5
lines).
All documentation files were explicitly excluded.
The following heuristics were used to determine which SPDX license
identifiers to apply.
- when both scanners couldn't find any license traces, file was
considered to have no license information in it, and the top level
COPYING file license applied.
For non */uapi/* files that summary was:
SPDX license identifier # files
---------------------------------------------------|-------
GPL-2.0 11139
and resulted in the first patch in this series.
If that file was a */uapi/* path one, it was "GPL-2.0 WITH
Linux-syscall-note" otherwise it was "GPL-2.0". Results of that was:
SPDX license identifier # files
---------------------------------------------------|-------
GPL-2.0 WITH Linux-syscall-note 930
and resulted in the second patch in this series.
- if a file had some form of licensing information in it, and was one
of the */uapi/* ones, it was denoted with the Linux-syscall-note if
any GPL family license was found in the file or had no licensing in
it (per prior point). Results summary:
SPDX license identifier # files
---------------------------------------------------|------
GPL-2.0 WITH Linux-syscall-note 270
GPL-2.0+ WITH Linux-syscall-note 169
((GPL-2.0 WITH Linux-syscall-note) OR BSD-2-Clause) 21
((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) 17
LGPL-2.1+ WITH Linux-syscall-note 15
GPL-1.0+ WITH Linux-syscall-note 14
((GPL-2.0+ WITH Linux-syscall-note) OR BSD-3-Clause) 5
LGPL-2.0+ WITH Linux-syscall-note 4
LGPL-2.1 WITH Linux-syscall-note 3
((GPL-2.0 WITH Linux-syscall-note) OR MIT) 3
((GPL-2.0 WITH Linux-syscall-note) AND MIT) 1
and that resulted in the third patch in this series.
- when the two scanners agreed on the detected license(s), that became
the concluded license(s).
- when there was disagreement between the two scanners (one detected a
license but the other didn't, or they both detected different
licenses) a manual inspection of the file occurred.
- In most cases a manual inspection of the information in the file
resulted in a clear resolution of the license that should apply (and
which scanner probably needed to revisit its heuristics).
- When it was not immediately clear, the license identifier was
confirmed with lawyers working with the Linux Foundation.
- If there was any question as to the appropriate license identifier,
the file was flagged for further research and to be revisited later
in time.
In total, over 70 hours of logged manual review was done on the
spreadsheet to determine the SPDX license identifiers to apply to the
source files by Kate, Philippe, Thomas and, in some cases, confirmation
by lawyers working with the Linux Foundation.
Kate also obtained a third independent scan of the 4.13 code base from
FOSSology, and compared selected files where the other two scanners
disagreed against that SPDX file, to see if there was new insights. The
Windriver scanner is based on an older version of FOSSology in part, so
they are related.
Thomas did random spot checks in about 500 files from the spreadsheets
for the uapi headers and agreed with SPDX license identifier in the
files he inspected. For the non-uapi files Thomas did random spot checks
in about 15000 files.
In initial set of patches against 4.14-rc6, 3 files were found to have
copy/paste license identifier errors, and have been fixed to reflect the
correct identifier.
Additionally Philippe spent 10 hours this week doing a detailed manual
inspection and review of the 12,461 patched files from the initial patch
version early this week with:
- a full scancode scan run, collecting the matched texts, detected
license ids and scores
- reviewing anything where there was a license detected (about 500+
files) to ensure that the applied SPDX license was correct
- reviewing anything where there was no detection but the patch license
was not GPL-2.0 WITH Linux-syscall-note to ensure that the applied
SPDX license was correct
This produced a worksheet with 20 files needing minor correction. This
worksheet was then exported into 3 different .csv files for the
different types of files to be modified.
These .csv files were then reviewed by Greg. Thomas wrote a script to
parse the csv files and add the proper SPDX tag to the file, in the
format that the file expected. This script was further refined by Greg
based on the output to detect more types of files automatically and to
distinguish between header and source .c files (which need different
comment types.) Finally Greg ran the script using the .csv files to
generate the patches.
Reviewed-by: Kate Stewart <kstewart@linuxfoundation.org>
Reviewed-by: Philippe Ombredanne <pombredanne@nexb.com>
Reviewed-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2017-11-01 22:07:57 +08:00
|
|
|
/* SPDX-License-Identifier: GPL-2.0 */
|
2010-05-21 09:08:55 +08:00
|
|
|
#ifndef _INTEL_RINGBUFFER_H_
|
|
|
|
#define _INTEL_RINGBUFFER_H_
|
|
|
|
|
2014-05-11 05:10:43 +08:00
|
|
|
#include <linux/hashtable.h>
|
2018-04-26 15:47:16 +08:00
|
|
|
#include <linux/seqlock.h>
|
2018-02-21 17:56:36 +08:00
|
|
|
|
2015-04-07 23:20:36 +08:00
|
|
|
#include "i915_gem_batch_pool.h"
|
2016-10-28 20:58:46 +08:00
|
|
|
#include "i915_gem_timeline.h"
|
2018-02-21 17:56:36 +08:00
|
|
|
|
2018-03-14 07:19:20 +08:00
|
|
|
#include "i915_reg.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 02:18:45 +08:00
|
|
|
#include "i915_pmu.h"
|
2018-02-21 17:56:36 +08:00
|
|
|
#include "i915_request.h"
|
2017-02-14 01:15:14 +08:00
|
|
|
#include "i915_selftest.h"
|
2018-03-14 07:19:20 +08:00
|
|
|
#include "intel_gpu_commands.h"
|
2014-05-11 05:10:43 +08:00
|
|
|
|
2017-10-09 19:02:57 +08:00
|
|
|
struct drm_printer;
|
2018-04-19 02:40:52 +08:00
|
|
|
struct i915_sched_attr;
|
2017-10-09 19:02:57 +08:00
|
|
|
|
2014-05-11 05:10:43 +08:00
|
|
|
#define I915_CMD_HASH_ORDER 9
|
|
|
|
|
2014-07-25 00:04:28 +08: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
|
2015-06-20 02:07:01 +08:00
|
|
|
#define CACHELINE_DWORDS (CACHELINE_BYTES / sizeof(uint32_t))
|
2014-07-25 00:04:28 +08:00
|
|
|
|
2016-08-15 17:48:57 +08:00
|
|
|
struct intel_hw_status_page {
|
|
|
|
struct i915_vma *vma;
|
|
|
|
u32 *page_addr;
|
|
|
|
u32 ggtt_offset;
|
2010-05-21 09:08:55 +08:00
|
|
|
};
|
|
|
|
|
2016-07-21 01:16:05 +08: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 17:17:32 +08:00
|
|
|
|
2016-07-21 01:16:05 +08: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 17:17:32 +08:00
|
|
|
|
2016-07-21 01:16:05 +08: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 17:17:32 +08:00
|
|
|
|
2016-07-21 01:16:05 +08: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 17:17:32 +08:00
|
|
|
|
2016-07-21 01:16:05 +08: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 22:29:44 +08:00
|
|
|
|
2016-07-21 01:16:05 +08: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 19:09:41 +08:00
|
|
|
|
2014-07-01 00:53:37 +08: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 05:50:21 +08:00
|
|
|
enum intel_engine_hangcheck_action {
|
2016-11-18 21:09:04 +08:00
|
|
|
ENGINE_IDLE = 0,
|
|
|
|
ENGINE_WAIT,
|
|
|
|
ENGINE_ACTIVE_SEQNO,
|
|
|
|
ENGINE_ACTIVE_HEAD,
|
|
|
|
ENGINE_ACTIVE_SUBUNITS,
|
|
|
|
ENGINE_WAIT_KICK,
|
|
|
|
ENGINE_DEAD,
|
2013-08-11 17:44:01 +08:00
|
|
|
};
|
2013-06-12 17:35:32 +08:00
|
|
|
|
2016-11-18 21:09:04 +08: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 01:04:43 +08:00
|
|
|
|
2016-09-20 21:54:33 +08:00
|
|
|
#define I915_MAX_SLICES 3
|
2018-03-16 20:14:51 +08:00
|
|
|
#define I915_MAX_SUBSLICES 8
|
2016-09-20 21:54:33 +08:00
|
|
|
|
|
|
|
#define instdone_slice_mask(dev_priv__) \
|
|
|
|
(INTEL_GEN(dev_priv__) == 7 ? \
|
|
|
|
1 : INTEL_INFO(dev_priv__)->sseu.slice_mask)
|
|
|
|
|
|
|
|
#define instdone_subslice_mask(dev_priv__) \
|
|
|
|
(INTEL_GEN(dev_priv__) == 7 ? \
|
2018-03-06 20:28:52 +08:00
|
|
|
1 : INTEL_INFO(dev_priv__)->sseu.subslice_mask[0])
|
2016-09-20 21:54:33 +08: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 21:54:32 +08:00
|
|
|
struct intel_instdone {
|
|
|
|
u32 instdone;
|
|
|
|
/* The following exist only in the RCS engine */
|
|
|
|
u32 slice_common;
|
2016-09-20 21:54:33 +08:00
|
|
|
u32 sampler[I915_MAX_SLICES][I915_MAX_SUBSLICES];
|
|
|
|
u32 row[I915_MAX_SLICES][I915_MAX_SUBSLICES];
|
2016-09-20 21:54:32 +08:00
|
|
|
};
|
|
|
|
|
2016-08-03 05:50:21 +08:00
|
|
|
struct intel_engine_hangcheck {
|
2014-03-21 20:41:53 +08:00
|
|
|
u64 acthd;
|
2013-05-24 22:16:07 +08:00
|
|
|
u32 seqno;
|
2016-08-03 05:50:21 +08:00
|
|
|
enum intel_engine_hangcheck_action action;
|
2016-11-18 21:09:04 +08:00
|
|
|
unsigned long action_timestamp;
|
2014-06-06 17:22:29 +08:00
|
|
|
int deadlock;
|
2016-09-20 21:54:32 +08:00
|
|
|
struct intel_instdone instdone;
|
2018-02-21 17:56:36 +08:00
|
|
|
struct i915_request *active_request;
|
2016-11-18 21:09:04 +08:00
|
|
|
bool stalled;
|
2013-05-24 22:16:07 +08:00
|
|
|
};
|
|
|
|
|
2016-08-03 05:50:21 +08:00
|
|
|
struct intel_ring {
|
2016-01-15 23:10:28 +08:00
|
|
|
struct i915_vma *vma;
|
2016-08-15 17:48:57 +08:00
|
|
|
void *vaddr;
|
2014-05-22 21:13:34 +08:00
|
|
|
|
2016-08-04 14:52:36 +08:00
|
|
|
struct list_head request_list;
|
2018-04-30 21:15:03 +08:00
|
|
|
struct list_head active_link;
|
2016-08-04 14:52:36 +08:00
|
|
|
|
2014-05-22 21:13:34 +08:00
|
|
|
u32 head;
|
|
|
|
u32 tail;
|
2017-04-25 21:00:49 +08:00
|
|
|
u32 emit;
|
2017-02-07 01:05:01 +08:00
|
|
|
|
2017-05-04 21:08:44 +08:00
|
|
|
u32 space;
|
|
|
|
u32 size;
|
|
|
|
u32 effective_size;
|
2014-05-22 21:13:34 +08:00
|
|
|
};
|
|
|
|
|
2016-05-24 21:53:34 +08:00
|
|
|
struct i915_gem_context;
|
2016-03-07 15:30:27 +08:00
|
|
|
struct drm_i915_reg_table;
|
2015-01-15 21:10:38 +08:00
|
|
|
|
2015-06-20 02:07:01 +08: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 17:49:04 +08:00
|
|
|
struct i915_ctx_workarounds {
|
2015-06-20 02:07:01 +08:00
|
|
|
struct i915_wa_ctx_bb {
|
|
|
|
u32 offset;
|
|
|
|
u32 size;
|
|
|
|
} indirect_ctx, per_ctx;
|
2016-08-15 17:49:04 +08:00
|
|
|
struct i915_vma *vma;
|
2015-06-20 02:07:01 +08:00
|
|
|
};
|
|
|
|
|
2018-02-21 17:56:36 +08:00
|
|
|
struct i915_request;
|
2016-07-02 00:23:25 +08:00
|
|
|
|
2018-02-28 18:11:52 +08:00
|
|
|
#define I915_MAX_VCS 4
|
|
|
|
#define I915_MAX_VECS 2
|
|
|
|
|
2017-03-02 04:26:15 +08:00
|
|
|
/*
|
|
|
|
* Engine IDs definitions.
|
|
|
|
* Keep instances of the same type engine together.
|
|
|
|
*/
|
|
|
|
enum intel_engine_id {
|
|
|
|
RCS = 0,
|
|
|
|
BCS,
|
|
|
|
VCS,
|
|
|
|
VCS2,
|
2018-02-28 18:11:52 +08:00
|
|
|
VCS3,
|
|
|
|
VCS4,
|
2017-03-02 04:26:15 +08:00
|
|
|
#define _VCS(n) (VCS + (n))
|
2018-02-28 18:11:52 +08:00
|
|
|
VECS,
|
|
|
|
VECS2
|
|
|
|
#define _VECS(n) (VECS + (n))
|
2017-03-02 04:26:15 +08:00
|
|
|
};
|
|
|
|
|
drm/i915: Split execlist priority queue into rbtree + linked list
All the requests at the same priority are executed in FIFO order. They
do not need to be stored in the rbtree themselves, as they are a simple
list within a level. If we move the requests at one priority into a list,
we can then reduce the rbtree to the set of priorities. This should keep
the height of the rbtree small, as the number of active priorities can not
exceed the number of active requests and should be typically only a few.
Currently, we have ~2k possible different priority levels, that may
increase to allow even more fine grained selection. Allocating those in
advance seems a waste (and may be impossible), so we opt for allocating
upon first use, and freeing after its requests are depleted. To avoid
the possibility of an allocation failure causing us to lose a request,
we preallocate the default priority (0) and bump any request to that
priority if we fail to allocate it the appropriate plist. Having a
request (that is ready to run, so not leading to corruption) execute
out-of-order is better than leaking the request (and its dependency
tree) entirely.
There should be a benefit to reducing execlists_dequeue() to principally
using a simple list (and reducing the frequency of both rbtree iteration
and balancing on erase) but for typical workloads, request coalescing
should be small enough that we don't notice any change. The main gain is
from improving PI calls to schedule, and the explicit list within a
level should make request unwinding simpler (we just need to insert at
the head of the list rather than the tail and not have to make the
rbtree search more complicated).
v2: Avoid use-after-free when deleting a depleted priolist
v3: Michał found the solution to handling the allocation failure
gracefully. If we disable all priority scheduling following the
allocation failure, those requests will be executed in fifo and we will
ensure that this request and its dependencies are in strict fifo (even
when it doesn't realise it is only a single list). Normal scheduling is
restored once we know the device is idle, until the next failure!
Suggested-by: Michał Wajdeczko <michal.wajdeczko@intel.com>
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Michał Winiarski <michal.winiarski@intel.com>
Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
Reviewed-by: Michał Winiarski <michal.winiarski@intel.com>
Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/20170517121007.27224-8-chris@chris-wilson.co.uk
2017-05-17 20:10:03 +08:00
|
|
|
struct i915_priolist {
|
|
|
|
struct rb_node node;
|
|
|
|
struct list_head requests;
|
|
|
|
int priority;
|
|
|
|
};
|
|
|
|
|
2017-09-22 20:43:03 +08: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 21:32:37 +08:00
|
|
|
* @tasklet: softirq tasklet for bottom handler
|
2017-09-22 20:43:03 +08:00
|
|
|
*/
|
2017-11-16 21:32:37 +08:00
|
|
|
struct tasklet_struct tasklet;
|
2017-09-22 20:43:03 +08: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 06:24:34 +08:00
|
|
|
/**
|
2018-03-03 00:14:59 +08: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 06:24:34 +08:00
|
|
|
*/
|
2018-03-03 00:14:59 +08: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 06:24:34 +08:00
|
|
|
|
2017-09-22 20:43:03 +08: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 17:56:36 +08:00
|
|
|
struct i915_request *request_count;
|
2017-09-22 20:43:03 +08: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 20:43:06 +08:00
|
|
|
#define port_index(p, execlists) ((p) - (execlists)->port)
|
2017-09-22 20:43:03 +08:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @context_id: context ID for port
|
|
|
|
*/
|
|
|
|
GEM_DEBUG_DECL(u32 context_id);
|
2017-09-22 20:43:07 +08: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 04:34:52 +08:00
|
|
|
/**
|
2017-10-24 05:32:36 +08: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 04:34:52 +08:00
|
|
|
*/
|
2017-10-24 05:32:36 +08:00
|
|
|
unsigned int active;
|
|
|
|
#define EXECLISTS_ACTIVE_USER 0
|
|
|
|
#define EXECLISTS_ACTIVE_PREEMPT 1
|
2017-11-20 20:34:58 +08: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 04:34:52 +08:00
|
|
|
|
2017-09-22 20:43:07 +08:00
|
|
|
/**
|
|
|
|
* @port_mask: number of execlist ports - 1
|
|
|
|
*/
|
|
|
|
unsigned int port_mask;
|
2017-09-22 20:43:03 +08:00
|
|
|
|
2018-02-22 22:22:29 +08:00
|
|
|
/**
|
|
|
|
* @queue_priority: Highest pending priority.
|
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
int queue_priority;
|
|
|
|
|
2017-09-22 20:43:03 +08:00
|
|
|
/**
|
|
|
|
* @queue: queue of requests, in priority lists
|
|
|
|
*/
|
|
|
|
struct rb_root queue;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @first: leftmost level in priority @queue
|
|
|
|
*/
|
|
|
|
struct rb_node *first;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @fw_domains: forcewake domains for irq tasklet
|
|
|
|
*/
|
|
|
|
unsigned int fw_domains;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @csb_head: context status buffer head
|
|
|
|
*/
|
|
|
|
unsigned int csb_head;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @csb_use_mmio: access csb through mmio, instead of hwsp
|
|
|
|
*/
|
|
|
|
bool csb_use_mmio;
|
2018-02-08 05:05:44 +08:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @preempt_complete_status: expected CSB upon completing preemption
|
|
|
|
*/
|
|
|
|
u32 preempt_complete_status;
|
2017-09-22 20:43:03 +08:00
|
|
|
};
|
|
|
|
|
2017-04-10 22:34:31 +08:00
|
|
|
#define INTEL_ENGINE_CS_MAX_NAME 8
|
|
|
|
|
2016-05-06 22:40:21 +08:00
|
|
|
struct intel_engine_cs {
|
|
|
|
struct drm_i915_private *i915;
|
2017-04-10 22:34:31 +08:00
|
|
|
char name[INTEL_ENGINE_CS_MAX_NAME];
|
2017-11-10 22:26:27 +08:00
|
|
|
|
2017-03-02 04:26:15 +08:00
|
|
|
enum intel_engine_id id;
|
|
|
|
unsigned int hw_id;
|
2017-04-28 15:53:36 +08:00
|
|
|
unsigned int guc_id;
|
2017-04-10 22:34:29 +08:00
|
|
|
|
2017-11-10 22:26:27 +08:00
|
|
|
u8 uabi_id;
|
|
|
|
u8 uabi_class;
|
|
|
|
|
2017-04-10 22:34:29 +08:00
|
|
|
u8 class;
|
|
|
|
u8 instance;
|
2017-04-28 15:53:36 +08:00
|
|
|
u32 context_size;
|
|
|
|
u32 mmio_base;
|
|
|
|
|
2016-08-03 05:50:21 +08:00
|
|
|
struct intel_ring *buffer;
|
2016-10-28 20:58:46 +08:00
|
|
|
struct intel_timeline *timeline;
|
2010-05-21 09:08:55 +08:00
|
|
|
|
2017-11-10 22:26:33 +08:00
|
|
|
struct drm_i915_gem_object *default_state;
|
2016-10-28 20:58:31 +08:00
|
|
|
|
2017-02-17 23:13:00 +08:00
|
|
|
atomic_t irq_count;
|
2017-01-24 23:18:05 +08:00
|
|
|
unsigned long irq_posted;
|
|
|
|
#define ENGINE_IRQ_BREADCRUMB 0
|
2017-01-24 23:20:21 +08:00
|
|
|
#define ENGINE_IRQ_EXECLIST 1
|
2017-01-24 23:18:05 +08: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-02 00:23:15 +08: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 {
|
2017-03-04 03:08:24 +08:00
|
|
|
spinlock_t irq_lock; /* protects irq_*; irqsafe */
|
|
|
|
struct intel_wait *irq_wait; /* oldest waiter by retirement */
|
|
|
|
|
|
|
|
spinlock_t rb_lock; /* protects the rb and wraps irq_lock */
|
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-02 00:23:15 +08:00
|
|
|
struct rb_root waiters; /* sorted by retirement, priority */
|
2018-02-22 17:25:44 +08:00
|
|
|
struct list_head signals; /* sorted by retirement */
|
2016-07-02 00:23:25 +08:00
|
|
|
struct task_struct *signaler; /* used for fence signalling */
|
2018-02-22 17:25:44 +08: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-02 00:23:15 +08:00
|
|
|
struct timer_list fake_irq; /* used after a missed interrupt */
|
2016-08-10 00:47:51 +08:00
|
|
|
struct timer_list hangcheck; /* detect missed interrupts */
|
|
|
|
|
2017-02-17 23:13:00 +08:00
|
|
|
unsigned int hangcheck_interrupts;
|
2017-10-25 22:39:42 +08:00
|
|
|
unsigned int irq_enabled;
|
2016-07-06 19:39:02 +08:00
|
|
|
|
2017-02-28 04:58:50 +08:00
|
|
|
bool irq_armed : 1;
|
2017-02-14 01:15:14 +08:00
|
|
|
I915_SELFTEST_DECLARE(bool mock : 1);
|
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-02 00:23:15 +08:00
|
|
|
} breadcrumbs;
|
|
|
|
|
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 02:18:45 +08:00
|
|
|
struct {
|
|
|
|
/**
|
|
|
|
* @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.
|
|
|
|
*
|
|
|
|
* Index number corresponds to the bit number from @enable.
|
|
|
|
*/
|
|
|
|
unsigned int enable_count[I915_PMU_SAMPLE_BITS];
|
|
|
|
/**
|
|
|
|
* @sample: Counter values for sampling events.
|
|
|
|
*
|
|
|
|
* Our internal timer stores the current counters in this field.
|
|
|
|
*/
|
2017-11-23 18:07:01 +08:00
|
|
|
#define I915_ENGINE_SAMPLE_MAX (I915_SAMPLE_SEMA + 1)
|
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 02:18:45 +08:00
|
|
|
struct i915_pmu_sample sample[I915_ENGINE_SAMPLE_MAX];
|
|
|
|
} pmu;
|
|
|
|
|
2015-04-07 23:20:36 +08: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 09:08:55 +08:00
|
|
|
struct intel_hw_status_page status_page;
|
2015-06-20 02:07:01 +08:00
|
|
|
struct i915_ctx_workarounds wa_ctx;
|
2016-08-15 17:48:58 +08:00
|
|
|
struct i915_vma *scratch;
|
2010-05-21 09:08:55 +08:00
|
|
|
|
2016-07-02 00:23:28 +08:00
|
|
|
u32 irq_keep_mask; /* always keep these interrupts */
|
|
|
|
u32 irq_enable_mask; /* bitmask to enable ring interrupt */
|
2016-07-21 01:16:06 +08:00
|
|
|
void (*irq_enable)(struct intel_engine_cs *engine);
|
|
|
|
void (*irq_disable)(struct intel_engine_cs *engine);
|
2010-05-21 09:08:55 +08:00
|
|
|
|
2016-07-21 01:16:06 +08:00
|
|
|
int (*init_hw)(struct intel_engine_cs *engine);
|
2016-09-09 21:11:53 +08:00
|
|
|
void (*reset_hw)(struct intel_engine_cs *engine,
|
2018-02-21 17:56:36 +08:00
|
|
|
struct i915_request *rq);
|
2010-05-21 09:08:55 +08:00
|
|
|
|
2017-10-25 22:39:41 +08:00
|
|
|
void (*park)(struct intel_engine_cs *engine);
|
|
|
|
void (*unpark)(struct intel_engine_cs *engine);
|
|
|
|
|
2017-03-17 01:13:03 +08:00
|
|
|
void (*set_default_submission)(struct intel_engine_cs *engine);
|
|
|
|
|
2017-05-04 17:33:08 +08:00
|
|
|
struct intel_ring *(*context_pin)(struct intel_engine_cs *engine,
|
|
|
|
struct i915_gem_context *ctx);
|
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 23:37:20 +08:00
|
|
|
void (*context_unpin)(struct intel_engine_cs *engine,
|
|
|
|
struct i915_gem_context *ctx);
|
2018-02-21 17:56:36 +08:00
|
|
|
int (*request_alloc)(struct i915_request *rq);
|
|
|
|
int (*init_context)(struct i915_request *rq);
|
2014-08-26 21:44:50 +08:00
|
|
|
|
2018-02-21 17:56:36 +08:00
|
|
|
int (*emit_flush)(struct i915_request *request, u32 mode);
|
2016-08-03 05:50:31 +08:00
|
|
|
#define EMIT_INVALIDATE BIT(0)
|
|
|
|
#define EMIT_FLUSH BIT(1)
|
|
|
|
#define EMIT_BARRIER (EMIT_INVALIDATE | EMIT_FLUSH)
|
2018-02-21 17:56:36 +08:00
|
|
|
int (*emit_bb_start)(struct i915_request *rq,
|
2016-08-03 05:50:31 +08:00
|
|
|
u64 offset, u32 length,
|
|
|
|
unsigned int dispatch_flags);
|
|
|
|
#define I915_DISPATCH_SECURE BIT(0)
|
|
|
|
#define I915_DISPATCH_PINNED BIT(1)
|
|
|
|
#define I915_DISPATCH_RS BIT(2)
|
2018-02-21 17:56:36 +08:00
|
|
|
void (*emit_breadcrumb)(struct i915_request *rq, u32 *cs);
|
2016-10-28 20:58:51 +08:00
|
|
|
int emit_breadcrumb_sz;
|
2016-09-09 21:11:54 +08: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 17:56:36 +08:00
|
|
|
void (*submit_request)(struct i915_request *rq);
|
2016-09-09 21:11:54 +08:00
|
|
|
|
2016-11-15 04:41:01 +08:00
|
|
|
/* Call when the priority on a request has changed and it and its
|
|
|
|
* dependencies may need rescheduling. Note the request itself may
|
|
|
|
* not be ready to run!
|
|
|
|
*
|
|
|
|
* Called under the struct_mutex.
|
|
|
|
*/
|
2018-04-19 02:40:52 +08:00
|
|
|
void (*schedule)(struct i915_request *request,
|
|
|
|
const struct i915_sched_attr *attr);
|
2016-11-15 04:41:01 +08:00
|
|
|
|
2017-09-16 01:31:00 +08: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);
|
|
|
|
|
2012-08-09 17:58:30 +08:00
|
|
|
/* Some chipsets are not quite as coherent as advertised and need
|
|
|
|
* an expensive kick to force a true read of the up-to-date seqno.
|
|
|
|
* However, the up-to-date seqno is not always required and the last
|
|
|
|
* seen value is good enough. Note that the seqno will always be
|
|
|
|
* monotonic, even if not coherent.
|
|
|
|
*/
|
2016-07-21 01:16:06 +08:00
|
|
|
void (*irq_seqno_barrier)(struct intel_engine_cs *engine);
|
|
|
|
void (*cleanup)(struct intel_engine_cs *engine);
|
2014-04-30 05:52:28 +08:00
|
|
|
|
2014-07-01 00:53:37 +08:00
|
|
|
/* GEN8 signal/wait table - never trust comments!
|
|
|
|
* signal to signal to signal to signal to signal to
|
|
|
|
* RCS VCS BCS VECS VCS2
|
|
|
|
* --------------------------------------------------------------------
|
|
|
|
* RCS | NOP (0x00) | VCS (0x08) | BCS (0x10) | VECS (0x18) | VCS2 (0x20) |
|
|
|
|
* |-------------------------------------------------------------------
|
|
|
|
* VCS | RCS (0x28) | NOP (0x30) | BCS (0x38) | VECS (0x40) | VCS2 (0x48) |
|
|
|
|
* |-------------------------------------------------------------------
|
|
|
|
* BCS | RCS (0x50) | VCS (0x58) | NOP (0x60) | VECS (0x68) | VCS2 (0x70) |
|
|
|
|
* |-------------------------------------------------------------------
|
|
|
|
* VECS | RCS (0x78) | VCS (0x80) | BCS (0x88) | NOP (0x90) | VCS2 (0x98) |
|
|
|
|
* |-------------------------------------------------------------------
|
|
|
|
* VCS2 | RCS (0xa0) | VCS (0xa8) | BCS (0xb0) | VECS (0xb8) | NOP (0xc0) |
|
|
|
|
* |-------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* Generalization:
|
|
|
|
* f(x, y) := (x->id * NUM_RINGS * seqno_size) + (seqno_size * y->id)
|
|
|
|
* ie. transpose of g(x, y)
|
|
|
|
*
|
|
|
|
* sync from sync from sync from sync from sync from
|
|
|
|
* RCS VCS BCS VECS VCS2
|
|
|
|
* --------------------------------------------------------------------
|
|
|
|
* RCS | NOP (0x00) | VCS (0x28) | BCS (0x50) | VECS (0x78) | VCS2 (0xa0) |
|
|
|
|
* |-------------------------------------------------------------------
|
|
|
|
* VCS | RCS (0x08) | NOP (0x30) | BCS (0x58) | VECS (0x80) | VCS2 (0xa8) |
|
|
|
|
* |-------------------------------------------------------------------
|
|
|
|
* BCS | RCS (0x10) | VCS (0x38) | NOP (0x60) | VECS (0x88) | VCS2 (0xb0) |
|
|
|
|
* |-------------------------------------------------------------------
|
|
|
|
* VECS | RCS (0x18) | VCS (0x40) | BCS (0x68) | NOP (0x90) | VCS2 (0xb8) |
|
|
|
|
* |-------------------------------------------------------------------
|
|
|
|
* VCS2 | RCS (0x20) | VCS (0x48) | BCS (0x70) | VECS (0x98) | NOP (0xc0) |
|
|
|
|
* |-------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* Generalization:
|
|
|
|
* g(x, y) := (y->id * NUM_RINGS * seqno_size) + (seqno_size * x->id)
|
|
|
|
* ie. transpose of f(x, y)
|
|
|
|
*/
|
2014-04-30 05:52:28 +08:00
|
|
|
struct {
|
2016-08-17 00:04:21 +08:00
|
|
|
#define GEN6_SEMAPHORE_LAST VECS_HW
|
|
|
|
#define GEN6_NUM_SEMAPHORES (GEN6_SEMAPHORE_LAST + 1)
|
|
|
|
#define GEN6_SEMAPHORES_MASK GENMASK(GEN6_SEMAPHORE_LAST, 0)
|
drm/i915: Remove obsolete ringbuffer emission for gen8+
Since removing the module parameter to force selection of ringbuffer
emission for gen8, the code is defunct. Remove it.
To put the difference into perspective, a couple of microbenchmarks
(bdw i7-5557u, 20170324):
ring execlists
exec continuous nops on all rings: 1.491us 2.223us
exec sequential nops on each ring: 12.508us 53.682us
single nop + sync: 9.272us 30.291us
vblank_mode=0 glxgears: ~11000fps ~9000fps
Since the earlier submission, gen8 ringbuffer submission has fallen
further and further behind in features. So while ringbuffer may hold the
throughput crown, in terms of interactive latency, execlists is much
better. Alas, we have no convenient metrics for such, other than
demonstrating things we can do with execlists but can not using
legacy ringbuffer submission.
We have made a few improvements to lowlevel execlists throughput,
and ringbuffer currently panics on boot! (bdw i7-5557u, 20171026):
ring execlists
exec continuous nops on all rings: n/a 1.921us
exec sequential nops on each ring: n/a 44.621us
single nop + sync: n/a 21.953us
vblank_mode=0 glxgears: n/a ~18500fps
References: https://bugs.freedesktop.org/show_bug.cgi?id=87725
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Once-upon-a-time-Reviewed-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
Reviewed-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20171120205504.21892-2-chris@chris-wilson.co.uk
2017-11-21 04:55:01 +08:00
|
|
|
struct {
|
|
|
|
/* our mbox written by others */
|
|
|
|
u32 wait[GEN6_NUM_SEMAPHORES];
|
|
|
|
/* mboxes this ring signals to */
|
|
|
|
i915_reg_t signal[GEN6_NUM_SEMAPHORES];
|
|
|
|
} mbox;
|
2014-04-30 05:52:29 +08:00
|
|
|
|
|
|
|
/* AKA wait() */
|
2018-02-21 17:56:36 +08:00
|
|
|
int (*sync_to)(struct i915_request *rq,
|
|
|
|
struct i915_request *signal);
|
|
|
|
u32 *(*signal)(struct i915_request *rq, u32 *cs);
|
2014-04-30 05:52:28 +08:00
|
|
|
} semaphore;
|
2013-05-29 10:22:18 +08:00
|
|
|
|
2017-09-22 20:43:03 +08:00
|
|
|
struct intel_engine_execlists execlists;
|
2014-07-25 00:04:27 +08: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 23:37:20 +08: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.
|
|
|
|
*/
|
|
|
|
struct i915_gem_context *last_retired_context;
|
|
|
|
|
|
|
|
/* We track the current MI_SET_CONTEXT in order to eliminate
|
|
|
|
* redudant context switches. This presumes that requests are not
|
|
|
|
* reordered! Or when they are the tracking is updated along with
|
|
|
|
* the emission of individual requests into the legacy command
|
|
|
|
* stream (ring).
|
|
|
|
*/
|
|
|
|
struct i915_gem_context *legacy_active_context;
|
2017-11-23 23:26:30 +08:00
|
|
|
struct i915_hw_ppgtt *legacy_active_ppgtt;
|
2012-06-05 05:42:43 +08:00
|
|
|
|
2017-03-13 10:47:11 +08:00
|
|
|
/* status_notifier: list of callbacks for context-switch changes */
|
|
|
|
struct atomic_notifier_head context_status_notifier;
|
|
|
|
|
2016-08-03 05:50:21 +08:00
|
|
|
struct intel_engine_hangcheck hangcheck;
|
2013-05-24 22:16:07 +08:00
|
|
|
|
2017-11-29 16:24:09 +08:00
|
|
|
#define I915_ENGINE_NEEDS_CMD_PARSER BIT(0)
|
2017-11-29 18:28:05 +08:00
|
|
|
#define I915_ENGINE_SUPPORTS_STATS BIT(1)
|
2018-04-04 02:35:37 +08:00
|
|
|
#define I915_ENGINE_HAS_PREEMPTION BIT(2)
|
2017-11-29 16:24:09 +08:00
|
|
|
unsigned int flags;
|
2014-05-11 05:10:43 +08:00
|
|
|
|
2014-02-19 02:15:46 +08:00
|
|
|
/*
|
2014-05-11 05:10:43 +08:00
|
|
|
* Table of commands the command parser needs to know about
|
2016-07-27 16:07:26 +08:00
|
|
|
* for this engine.
|
2014-02-19 02:15:46 +08:00
|
|
|
*/
|
2014-05-11 05:10:43 +08:00
|
|
|
DECLARE_HASHTABLE(cmd_hash, I915_CMD_HASH_ORDER);
|
2014-02-19 02:15:46 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Table of registers allowed in commands that read/write registers.
|
|
|
|
*/
|
2016-03-07 15:30:27 +08:00
|
|
|
const struct drm_i915_reg_table *reg_tables;
|
|
|
|
int reg_table_count;
|
2014-02-19 02:15:46 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Returns the bitmask for the length field of the specified command.
|
|
|
|
* Return 0 for an unrecognized/invalid command.
|
|
|
|
*
|
2016-07-27 16:07:26 +08:00
|
|
|
* If the command parser finds an entry for a command in the engine's
|
2014-02-19 02:15:46 +08:00
|
|
|
* cmd_tables, it gets the command's length based on the table entry.
|
2016-07-27 16:07:26 +08: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 02:15:46 +08:00
|
|
|
*/
|
|
|
|
u32 (*get_cmd_length_mask)(u32 cmd_header);
|
2017-11-22 02:18:48 +08:00
|
|
|
|
|
|
|
struct {
|
|
|
|
/**
|
|
|
|
* @lock: Lock protecting the below fields.
|
|
|
|
*/
|
2018-04-26 15:47:16 +08:00
|
|
|
seqlock_t lock;
|
2017-11-22 02:18:48 +08: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 09:08:55 +08:00
|
|
|
};
|
|
|
|
|
2018-04-04 02:35:37 +08:00
|
|
|
static inline bool
|
|
|
|
intel_engine_needs_cmd_parser(const struct intel_engine_cs *engine)
|
2017-11-29 16:24:09 +08:00
|
|
|
{
|
|
|
|
return engine->flags & I915_ENGINE_NEEDS_CMD_PARSER;
|
|
|
|
}
|
|
|
|
|
2018-04-04 02:35:37 +08:00
|
|
|
static inline bool
|
|
|
|
intel_engine_supports_stats(const struct intel_engine_cs *engine)
|
2017-11-29 18:28:05 +08:00
|
|
|
{
|
|
|
|
return engine->flags & I915_ENGINE_SUPPORTS_STATS;
|
|
|
|
}
|
|
|
|
|
2018-04-04 02:35:37 +08:00
|
|
|
static inline bool
|
|
|
|
intel_engine_has_preemption(const struct intel_engine_cs *engine)
|
|
|
|
{
|
|
|
|
return engine->flags & I915_ENGINE_HAS_PREEMPTION;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline bool __execlists_need_preempt(int prio, int last)
|
|
|
|
{
|
|
|
|
return prio > max(0, last);
|
|
|
|
}
|
|
|
|
|
2017-10-24 05:32:36 +08: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 21:06:26 +08: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 05:32:36 +08:00
|
|
|
static inline void
|
|
|
|
execlists_clear_active(struct intel_engine_execlists *execlists,
|
|
|
|
unsigned int bit)
|
|
|
|
{
|
|
|
|
__clear_bit(bit, (unsigned long *)&execlists->active);
|
|
|
|
}
|
|
|
|
|
|
|
|
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 21:06:26 +08: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 21:35:58 +08: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 20:43:07 +08:00
|
|
|
static inline unsigned int
|
|
|
|
execlists_num_ports(const struct intel_engine_execlists * const execlists)
|
|
|
|
{
|
|
|
|
return execlists->port_mask + 1;
|
|
|
|
}
|
|
|
|
|
2018-03-31 21:06:26 +08:00
|
|
|
static inline struct execlist_port *
|
2017-09-22 20:43:06 +08:00
|
|
|
execlists_port_complete(struct intel_engine_execlists * const execlists,
|
|
|
|
struct execlist_port * const port)
|
|
|
|
{
|
2017-09-22 20:43:07 +08:00
|
|
|
const unsigned int m = execlists->port_mask;
|
2017-09-22 20:43:06 +08:00
|
|
|
|
|
|
|
GEM_BUG_ON(port_index(port, execlists) != 0);
|
2017-10-24 05:32:36 +08:00
|
|
|
GEM_BUG_ON(!execlists_is_active(execlists, EXECLISTS_ACTIVE_USER));
|
2017-09-22 20:43:06 +08:00
|
|
|
|
2017-09-22 20:43:07 +08:00
|
|
|
memmove(port, port + 1, m * sizeof(struct execlist_port));
|
|
|
|
memset(port + m, 0, sizeof(struct execlist_port));
|
2018-03-31 21:06:26 +08:00
|
|
|
|
|
|
|
return port;
|
2017-09-22 20:43:06 +08:00
|
|
|
}
|
|
|
|
|
2017-03-25 00:35:40 +08:00
|
|
|
static inline unsigned int
|
2016-07-04 15:08:31 +08:00
|
|
|
intel_engine_flag(const struct intel_engine_cs *engine)
|
2011-12-14 20:57:00 +08:00
|
|
|
{
|
2017-03-25 00:35:40 +08:00
|
|
|
return BIT(engine->id);
|
2011-12-14 20:57:00 +08:00
|
|
|
}
|
|
|
|
|
2010-05-21 09:08:55 +08:00
|
|
|
static inline u32
|
2018-02-12 18:24:15 +08:00
|
|
|
intel_read_status_page(const struct intel_engine_cs *engine, int reg)
|
2010-05-21 09:08:55 +08:00
|
|
|
{
|
2012-04-27 05:28:16 +08:00
|
|
|
/* Ensure that the compiler doesn't optimize away the load. */
|
2016-04-09 17:57:57 +08:00
|
|
|
return READ_ONCE(engine->status_page.page_addr[reg]);
|
2010-05-21 09:08:55 +08:00
|
|
|
}
|
|
|
|
|
2012-12-19 17:13:05 +08:00
|
|
|
static inline void
|
2017-03-25 00:35:38 +08:00
|
|
|
intel_write_status_page(struct intel_engine_cs *engine, int reg, u32 value)
|
2012-12-19 17:13:05 +08:00
|
|
|
{
|
2017-03-25 00:35:38 +08: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();
|
|
|
|
clflush(&engine->status_page.page_addr[reg]);
|
|
|
|
engine->status_page.page_addr[reg] = value;
|
|
|
|
clflush(&engine->status_page.page_addr[reg]);
|
|
|
|
mb();
|
|
|
|
} else {
|
|
|
|
WRITE_ONCE(engine->status_page.page_addr[reg], value);
|
|
|
|
}
|
2012-12-19 17:13:05 +08:00
|
|
|
}
|
|
|
|
|
2016-01-18 15:19:47 +08:00
|
|
|
/*
|
2011-01-14 03:06:50 +08: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 19:48:21 +08:00
|
|
|
* 0x20-0x2f: Reserved (Gen6+)
|
2011-01-14 03:06:50 +08:00
|
|
|
*
|
2015-02-18 19:48:21 +08:00
|
|
|
* The area from dword 0x30 to 0x3ff is available for driver usage.
|
2011-01-14 03:06:50 +08:00
|
|
|
*/
|
2015-02-18 19:48:21 +08:00
|
|
|
#define I915_GEM_HWS_INDEX 0x30
|
2016-01-20 21:43:35 +08:00
|
|
|
#define I915_GEM_HWS_INDEX_ADDR (I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT)
|
2017-10-26 04:00:16 +08:00
|
|
|
#define I915_GEM_HWS_PREEMPT_INDEX 0x32
|
|
|
|
#define I915_GEM_HWS_PREEMPT_ADDR (I915_GEM_HWS_PREEMPT_INDEX << MI_STORE_DWORD_INDEX_SHIFT)
|
2015-02-18 19:48:21 +08:00
|
|
|
#define I915_GEM_HWS_SCRATCH_INDEX 0x40
|
2012-10-27 00:42:42 +08:00
|
|
|
#define I915_GEM_HWS_SCRATCH_ADDR (I915_GEM_HWS_SCRATCH_INDEX << MI_STORE_DWORD_INDEX_SHIFT)
|
2011-01-14 03:06:50 +08:00
|
|
|
|
2017-09-13 21:35:34 +08:00
|
|
|
#define I915_HWS_CSB_BUF0_INDEX 0x10
|
2017-09-13 16:56:05 +08:00
|
|
|
#define I915_HWS_CSB_WRITE_INDEX 0x1f
|
|
|
|
#define CNL_HWS_CSB_WRITE_INDEX 0x2f
|
2017-09-13 21:35:34 +08:00
|
|
|
|
2016-08-03 05:50:21 +08:00
|
|
|
struct intel_ring *
|
|
|
|
intel_engine_create_ring(struct intel_engine_cs *engine, int size);
|
2017-04-03 19:34:25 +08:00
|
|
|
int intel_ring_pin(struct intel_ring *ring,
|
|
|
|
struct drm_i915_private *i915,
|
|
|
|
unsigned int offset_bias);
|
2017-04-25 21:00:49 +08:00
|
|
|
void intel_ring_reset(struct intel_ring *ring, u32 tail);
|
2017-05-04 21:08:45 +08:00
|
|
|
unsigned int intel_ring_update_space(struct intel_ring *ring);
|
2016-08-03 05:50:23 +08:00
|
|
|
void intel_ring_unpin(struct intel_ring *ring);
|
2016-08-03 05:50:21 +08:00
|
|
|
void intel_ring_free(struct intel_ring *ring);
|
2014-07-25 00:04:15 +08:00
|
|
|
|
2016-08-03 05:50:21 +08:00
|
|
|
void intel_engine_stop(struct intel_engine_cs *engine);
|
|
|
|
void intel_engine_cleanup(struct intel_engine_cs *engine);
|
2011-03-20 09:14:27 +08:00
|
|
|
|
2016-09-09 21:11:53 +08:00
|
|
|
void intel_legacy_submission_resume(struct drm_i915_private *dev_priv);
|
|
|
|
|
2018-02-21 17:56:36 +08:00
|
|
|
int __must_check intel_ring_cacheline_align(struct i915_request *rq);
|
2016-07-20 20:31:55 +08:00
|
|
|
|
2017-11-15 23:12:04 +08:00
|
|
|
int intel_ring_wait_for_space(struct intel_ring *ring, unsigned int bytes);
|
2018-02-21 17:56:36 +08:00
|
|
|
u32 __must_check *intel_ring_begin(struct i915_request *rq, unsigned int n);
|
2016-07-20 20:31:55 +08:00
|
|
|
|
2018-02-21 17:56:36 +08:00
|
|
|
static inline void intel_ring_advance(struct i915_request *rq, u32 *cs)
|
2013-08-11 05:16:32 +08:00
|
|
|
{
|
2016-08-03 05:50:30 +08: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 05:50:29 +08:00
|
|
|
*/
|
2018-02-21 17:56:36 +08:00
|
|
|
GEM_BUG_ON((rq->ring->vaddr + rq->ring->emit) != cs);
|
2016-08-03 05:50:30 +08:00
|
|
|
}
|
|
|
|
|
2018-02-21 17:56:36 +08:00
|
|
|
static inline u32 intel_ring_wrap(const struct intel_ring *ring, u32 pos)
|
2017-03-27 21:00:07 +08:00
|
|
|
{
|
|
|
|
return pos & (ring->size - 1);
|
|
|
|
}
|
|
|
|
|
2018-02-21 17:56:36 +08:00
|
|
|
static inline u32 intel_ring_offset(const struct i915_request *rq, void *addr)
|
2016-08-03 05:50:30 +08:00
|
|
|
{
|
|
|
|
/* Don't write ring->size (equivalent to 0) as that hangs some GPUs. */
|
2018-02-21 17:56:36 +08:00
|
|
|
u32 offset = addr - rq->ring->vaddr;
|
|
|
|
GEM_BUG_ON(offset > rq->ring->size);
|
|
|
|
return intel_ring_wrap(rq->ring, offset);
|
2013-08-11 05:16:32 +08:00
|
|
|
}
|
2016-07-20 20:31:55 +08:00
|
|
|
|
2017-03-27 21:14:12 +08:00
|
|
|
static inline void
|
|
|
|
assert_ring_tail_valid(const struct intel_ring *ring, unsigned int tail)
|
|
|
|
{
|
|
|
|
/* We could combine these into a single tail operation, but keeping
|
|
|
|
* them as seperate tests will help identify the cause should one
|
|
|
|
* ever fire.
|
|
|
|
*/
|
|
|
|
GEM_BUG_ON(!IS_ALIGNED(tail, 8));
|
|
|
|
GEM_BUG_ON(tail >= ring->size);
|
2017-05-04 21:08:44 +08: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 21:14:12 +08:00
|
|
|
}
|
|
|
|
|
2017-04-25 21:00:49 +08: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 17:56:36 +08:00
|
|
|
* read by i915_request_retire() just as it is being updated
|
2017-04-25 21:00:49 +08: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 05:16:32 +08:00
|
|
|
|
2016-10-28 20:58:46 +08:00
|
|
|
void intel_engine_init_global_seqno(struct intel_engine_cs *engine, u32 seqno);
|
2010-05-21 09:08:55 +08:00
|
|
|
|
2016-07-13 23:03:41 +08:00
|
|
|
void intel_engine_setup_common(struct intel_engine_cs *engine);
|
|
|
|
int intel_engine_init_common(struct intel_engine_cs *engine);
|
2016-08-15 17:48:59 +08:00
|
|
|
int intel_engine_create_scratch(struct intel_engine_cs *engine, int size);
|
2016-08-03 20:19:16 +08:00
|
|
|
void intel_engine_cleanup_common(struct intel_engine_cs *engine);
|
2016-07-13 23:03:41 +08:00
|
|
|
|
2016-07-13 23:03:37 +08: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 09:08:55 +08:00
|
|
|
|
2018-02-12 18:24:15 +08: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 04:11:31 +08:00
|
|
|
|
2016-07-02 00:23:17 +08:00
|
|
|
static inline u32 intel_engine_get_seqno(struct intel_engine_cs *engine)
|
|
|
|
{
|
|
|
|
return intel_read_status_page(engine, I915_GEM_HWS_INDEX);
|
|
|
|
}
|
2010-09-25 03:20:10 +08:00
|
|
|
|
2016-11-01 18:03:16 +08:00
|
|
|
static inline u32 intel_engine_last_submit(struct intel_engine_cs *engine)
|
|
|
|
{
|
|
|
|
/* We are only peeking at the tail of the submit queue (and not the
|
|
|
|
* queue itself) in order to gain a hint as to the current active
|
|
|
|
* state of the engine. Callers are not expected to be taking
|
|
|
|
* engine->timeline->lock, nor are they expected to be concerned
|
|
|
|
* wtih serialising this hint with anything, so document it as
|
|
|
|
* a hint and nothing more.
|
|
|
|
*/
|
2017-02-23 15:44:08 +08:00
|
|
|
return READ_ONCE(engine->timeline->seqno);
|
2016-11-01 18:03:16 +08:00
|
|
|
}
|
|
|
|
|
2016-10-12 17:05:17 +08:00
|
|
|
void intel_engine_get_instdone(struct intel_engine_cs *engine,
|
|
|
|
struct intel_instdone *instdone);
|
|
|
|
|
drm/i915: Reserve ring buffer space for i915_add_request() commands
It is a bad idea for i915_add_request() to fail. The work will already have been
send to the ring and will be processed, but there will not be any tracking or
management of that work.
The only way the add request call can fail is if it can't write its epilogue
commands to the ring (cache flushing, seqno updates, interrupt signalling). The
reasons for that are mostly down to running out of ring buffer space and the
problems associated with trying to get some more. This patch prevents that
situation from happening in the first place.
When a request is created, it marks sufficient space as reserved for the
epilogue commands. Thus guaranteeing that by the time the epilogue is written,
there will be plenty of space for it. Note that a ring_begin() call is required
to actually reserve the space (and do any potential waiting). However, that is
not currently done at request creation time. This is because the ring_begin()
code can allocate a request. Hence calling begin() from the request allocation
code would lead to infinite recursion! Later patches in this series remove the
need for begin() to do the allocate. At that point, it becomes safe for the
allocate to call begin() and really reserve the space.
Until then, there is a potential for insufficient space to be available at the
point of calling i915_add_request(). However, that would only be in the case
where the request was created and immediately submitted without ever calling
ring_begin() and adding any work to that request. Which should never happen. And
even if it does, and if that request happens to fall down the tiny window of
opportunity for failing due to being out of ring space then does it really
matter because the request wasn't doing anything in the first place?
v2: Updated the 'reserved space too small' warning to include the offending
sizes. Added a 'cancel' operation to clean up when a request is abandoned. Added
re-initialisation of tracking state after a buffer wrap to keep the sanity
checks accurate.
v3: Incremented the reserved size to accommodate Ironlake (after finally
managing to run on an ILK system). Also fixed missing wrap code in LRC mode.
v4: Added extra comment and removed duplicate WARN (feedback from Tomas).
For: VIZ-5115
CC: Tomas Elf <tomas.elf@intel.com>
Signed-off-by: John Harrison <John.C.Harrison@Intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2015-06-18 20:10:09 +08:00
|
|
|
/*
|
|
|
|
* Arbitrary size for largest possible 'add request' sequence. The code paths
|
|
|
|
* are complex and variable. Empirical measurement shows that the worst case
|
2016-04-29 16:07:04 +08:00
|
|
|
* is BDW at 192 bytes (6 + 6 + 36 dwords), then ILK at 136 bytes. However,
|
|
|
|
* we need to allocate double the largest single packet within that emission
|
|
|
|
* to account for tail wraparound (so 6 + 6 + 72 dwords for BDW).
|
drm/i915: Reserve ring buffer space for i915_add_request() commands
It is a bad idea for i915_add_request() to fail. The work will already have been
send to the ring and will be processed, but there will not be any tracking or
management of that work.
The only way the add request call can fail is if it can't write its epilogue
commands to the ring (cache flushing, seqno updates, interrupt signalling). The
reasons for that are mostly down to running out of ring buffer space and the
problems associated with trying to get some more. This patch prevents that
situation from happening in the first place.
When a request is created, it marks sufficient space as reserved for the
epilogue commands. Thus guaranteeing that by the time the epilogue is written,
there will be plenty of space for it. Note that a ring_begin() call is required
to actually reserve the space (and do any potential waiting). However, that is
not currently done at request creation time. This is because the ring_begin()
code can allocate a request. Hence calling begin() from the request allocation
code would lead to infinite recursion! Later patches in this series remove the
need for begin() to do the allocate. At that point, it becomes safe for the
allocate to call begin() and really reserve the space.
Until then, there is a potential for insufficient space to be available at the
point of calling i915_add_request(). However, that would only be in the case
where the request was created and immediately submitted without ever calling
ring_begin() and adding any work to that request. Which should never happen. And
even if it does, and if that request happens to fall down the tiny window of
opportunity for failing due to being out of ring space then does it really
matter because the request wasn't doing anything in the first place?
v2: Updated the 'reserved space too small' warning to include the offending
sizes. Added a 'cancel' operation to clean up when a request is abandoned. Added
re-initialisation of tracking state after a buffer wrap to keep the sanity
checks accurate.
v3: Incremented the reserved size to accommodate Ironlake (after finally
managing to run on an ILK system). Also fixed missing wrap code in LRC mode.
v4: Added extra comment and removed duplicate WARN (feedback from Tomas).
For: VIZ-5115
CC: Tomas Elf <tomas.elf@intel.com>
Signed-off-by: John Harrison <John.C.Harrison@Intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2015-06-18 20:10:09 +08:00
|
|
|
*/
|
2016-04-29 16:07:04 +08:00
|
|
|
#define MIN_SPACE_FOR_ADD_REQUEST 336
|
drm/i915: Reserve ring buffer space for i915_add_request() commands
It is a bad idea for i915_add_request() to fail. The work will already have been
send to the ring and will be processed, but there will not be any tracking or
management of that work.
The only way the add request call can fail is if it can't write its epilogue
commands to the ring (cache flushing, seqno updates, interrupt signalling). The
reasons for that are mostly down to running out of ring buffer space and the
problems associated with trying to get some more. This patch prevents that
situation from happening in the first place.
When a request is created, it marks sufficient space as reserved for the
epilogue commands. Thus guaranteeing that by the time the epilogue is written,
there will be plenty of space for it. Note that a ring_begin() call is required
to actually reserve the space (and do any potential waiting). However, that is
not currently done at request creation time. This is because the ring_begin()
code can allocate a request. Hence calling begin() from the request allocation
code would lead to infinite recursion! Later patches in this series remove the
need for begin() to do the allocate. At that point, it becomes safe for the
allocate to call begin() and really reserve the space.
Until then, there is a potential for insufficient space to be available at the
point of calling i915_add_request(). However, that would only be in the case
where the request was created and immediately submitted without ever calling
ring_begin() and adding any work to that request. Which should never happen. And
even if it does, and if that request happens to fall down the tiny window of
opportunity for failing due to being out of ring space then does it really
matter because the request wasn't doing anything in the first place?
v2: Updated the 'reserved space too small' warning to include the offending
sizes. Added a 'cancel' operation to clean up when a request is abandoned. Added
re-initialisation of tracking state after a buffer wrap to keep the sanity
checks accurate.
v3: Incremented the reserved size to accommodate Ironlake (after finally
managing to run on an ILK system). Also fixed missing wrap code in LRC mode.
v4: Added extra comment and removed duplicate WARN (feedback from Tomas).
For: VIZ-5115
CC: Tomas Elf <tomas.elf@intel.com>
Signed-off-by: John Harrison <John.C.Harrison@Intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
2015-06-18 20:10:09 +08:00
|
|
|
|
2016-04-29 20:18:21 +08:00
|
|
|
static inline u32 intel_hws_seqno_address(struct intel_engine_cs *engine)
|
|
|
|
{
|
2016-08-15 17:48:57 +08:00
|
|
|
return engine->status_page.ggtt_offset + I915_GEM_HWS_INDEX_ADDR;
|
2016-04-29 20:18:21 +08:00
|
|
|
}
|
|
|
|
|
2017-10-26 04:00:16 +08:00
|
|
|
static inline u32 intel_hws_preempt_done_address(struct intel_engine_cs *engine)
|
|
|
|
{
|
|
|
|
return engine->status_page.ggtt_offset + I915_GEM_HWS_PREEMPT_ADDR;
|
|
|
|
}
|
|
|
|
|
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-02 00:23:15 +08:00
|
|
|
/* intel_breadcrumbs.c -- user interrupt bottom-half for waiters */
|
|
|
|
int intel_engine_init_breadcrumbs(struct intel_engine_cs *engine);
|
|
|
|
|
2017-02-28 04:58:48 +08:00
|
|
|
static inline void intel_wait_init(struct intel_wait *wait,
|
2018-02-21 17:56:36 +08:00
|
|
|
struct i915_request *rq)
|
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-02 00:23:15 +08:00
|
|
|
{
|
|
|
|
wait->tsk = current;
|
2017-02-28 04:58:48 +08:00
|
|
|
wait->request = rq;
|
2017-02-23 15:44:14 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline void intel_wait_init_for_seqno(struct intel_wait *wait, u32 seqno)
|
|
|
|
{
|
|
|
|
wait->tsk = current;
|
|
|
|
wait->seqno = seqno;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline bool intel_wait_has_seqno(const struct intel_wait *wait)
|
|
|
|
{
|
|
|
|
return wait->seqno;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline bool
|
|
|
|
intel_wait_update_seqno(struct intel_wait *wait, u32 seqno)
|
|
|
|
{
|
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-02 00:23:15 +08:00
|
|
|
wait->seqno = seqno;
|
2017-02-23 15:44:14 +08:00
|
|
|
return intel_wait_has_seqno(wait);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline bool
|
|
|
|
intel_wait_update_request(struct intel_wait *wait,
|
2018-02-21 17:56:36 +08:00
|
|
|
const struct i915_request *rq)
|
2017-02-23 15:44:14 +08:00
|
|
|
{
|
2018-02-21 17:56:36 +08:00
|
|
|
return intel_wait_update_seqno(wait, i915_request_global_seqno(rq));
|
2017-02-23 15:44:14 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline bool
|
|
|
|
intel_wait_check_seqno(const struct intel_wait *wait, u32 seqno)
|
|
|
|
{
|
|
|
|
return wait->seqno == seqno;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline bool
|
|
|
|
intel_wait_check_request(const struct intel_wait *wait,
|
2018-02-21 17:56:36 +08:00
|
|
|
const struct i915_request *rq)
|
2017-02-23 15:44:14 +08:00
|
|
|
{
|
2018-02-21 17:56:36 +08:00
|
|
|
return intel_wait_check_seqno(wait, i915_request_global_seqno(rq));
|
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-02 00:23:15 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline bool intel_wait_complete(const struct intel_wait *wait)
|
|
|
|
{
|
|
|
|
return RB_EMPTY_NODE(&wait->node);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool intel_engine_add_wait(struct intel_engine_cs *engine,
|
|
|
|
struct intel_wait *wait);
|
|
|
|
void intel_engine_remove_wait(struct intel_engine_cs *engine,
|
|
|
|
struct intel_wait *wait);
|
2018-03-08 22:07:32 +08:00
|
|
|
bool intel_engine_enable_signaling(struct i915_request *request, bool wakeup);
|
2018-02-21 17:56:36 +08:00
|
|
|
void intel_engine_cancel_signaling(struct i915_request *request);
|
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-02 00:23:15 +08:00
|
|
|
|
2016-08-10 00:47:52 +08:00
|
|
|
static inline bool intel_engine_has_waiter(const 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-02 00:23:15 +08:00
|
|
|
{
|
2017-03-04 03:08:24 +08:00
|
|
|
return READ_ONCE(engine->breadcrumbs.irq_wait);
|
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-02 00:23:15 +08:00
|
|
|
}
|
|
|
|
|
2017-02-28 04:58:47 +08:00
|
|
|
unsigned int intel_engine_wakeup(struct intel_engine_cs *engine);
|
|
|
|
#define ENGINE_WAKEUP_WAITER BIT(0)
|
2017-02-28 04:58:50 +08:00
|
|
|
#define ENGINE_WAKEUP_ASLEEP BIT(1)
|
|
|
|
|
2017-10-25 22:39:42 +08:00
|
|
|
void intel_engine_pin_breadcrumbs_irq(struct intel_engine_cs *engine);
|
|
|
|
void intel_engine_unpin_breadcrumbs_irq(struct intel_engine_cs *engine);
|
|
|
|
|
2017-02-28 04:58:50 +08:00
|
|
|
void __intel_engine_disarm_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-02 00:23:15 +08:00
|
|
|
|
2016-10-07 14:53:26 +08: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-02 00:23:15 +08:00
|
|
|
void intel_engine_fini_breadcrumbs(struct intel_engine_cs *engine);
|
|
|
|
|
2017-02-16 20:23:25 +08: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 04:00:15 +08:00
|
|
|
static inline u32 *
|
|
|
|
gen8_emit_ggtt_write_rcs(u32 *cs, u32 value, u32 gtt_offset)
|
|
|
|
{
|
|
|
|
/* 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);
|
|
|
|
*cs++ = PIPE_CONTROL_GLOBAL_GTT_IVB | PIPE_CONTROL_CS_STALL |
|
|
|
|
PIPE_CONTROL_QW_WRITE;
|
|
|
|
*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;
|
|
|
|
}
|
|
|
|
|
2017-03-03 20:19:46 +08:00
|
|
|
bool intel_engine_is_idle(struct intel_engine_cs *engine);
|
2017-03-03 20:19:47 +08:00
|
|
|
bool intel_engines_are_idle(struct drm_i915_private *dev_priv);
|
2017-03-03 20:19:46 +08:00
|
|
|
|
2017-10-25 06:08:55 +08:00
|
|
|
bool intel_engine_has_kernel_context(const struct intel_engine_cs *engine);
|
|
|
|
|
2017-10-25 22:39:41 +08:00
|
|
|
void intel_engines_park(struct drm_i915_private *i915);
|
|
|
|
void intel_engines_unpark(struct drm_i915_private *i915);
|
|
|
|
|
2017-03-17 01:13:03 +08:00
|
|
|
void intel_engines_reset_default_submission(struct drm_i915_private *i915);
|
2017-11-10 22:26:33 +08:00
|
|
|
unsigned int intel_engines_has_context_isolation(struct drm_i915_private *i915);
|
2017-03-17 01:13:03 +08:00
|
|
|
|
2017-09-06 23:28:59 +08:00
|
|
|
bool intel_engine_can_store_dword(struct intel_engine_cs *engine);
|
2017-08-16 16:52:04 +08:00
|
|
|
|
2017-12-08 09:23:00 +08:00
|
|
|
__printf(3, 4)
|
|
|
|
void intel_engine_dump(struct intel_engine_cs *engine,
|
|
|
|
struct drm_printer *m,
|
|
|
|
const char *header, ...);
|
2017-10-09 19:02:57 +08: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 02:18:45 +08:00
|
|
|
struct intel_engine_cs *
|
|
|
|
intel_engine_lookup_user(struct drm_i915_private *i915, u8 class, u8 instance);
|
|
|
|
|
2017-11-22 02:18:48 +08: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 15:47:16 +08:00
|
|
|
write_seqlock_irqsave(&engine->stats.lock, flags);
|
2017-11-22 02:18:48 +08: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 15:47:16 +08:00
|
|
|
write_sequnlock_irqrestore(&engine->stats.lock, flags);
|
2017-11-22 02:18:48 +08: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 15:47:16 +08:00
|
|
|
write_seqlock_irqsave(&engine->stats.lock, flags);
|
2017-11-22 02:18:48 +08: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 15:47:16 +08:00
|
|
|
write_sequnlock_irqrestore(&engine->stats.lock, flags);
|
2017-11-22 02:18:48 +08: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);
|
|
|
|
|
2010-05-21 09:08:55 +08:00
|
|
|
#endif /* _INTEL_RINGBUFFER_H_ */
|