From: John Harrison John.C.Harrison@Intel.com
Compute workloads are inherently not pre-emptible on current hardware. Thus the pre-emption timeout was disabled as a workaround to prevent unwanted resets. Instead, the hang detection was left to the heartbeat and its (longer) timeout. This is undesirable with GuC submission as the heartbeat is a full GT reset rather than a per engine reset and so is much more destructive. Instead, just bump the pre-emption timeout to a big value. Also, update the heartbeat to allow such a long pre-emption delay in the final heartbeat period.
v2: Add clamping helpers. v3: Remove long timeout algorithm and replace with hard coded value (review feedback from Tvrtko). Also, fix execlist selftest failure and fix bug in compute enabling patch related to pre-emption timeouts.
Signed-off-by: John Harrison John.C.Harrison@Intel.com
John Harrison (4): drm/i915/guc: Limit scheduling properties to avoid overflow drm/i915: Fix compute pre-emption w/a to apply to compute engines drm/i915: Make the heartbeat play nice with long pre-emption timeouts drm/i915: Improve long running OCL w/a for GuC submission
drivers/gpu/drm/i915/Kconfig.profile | 26 +++++- drivers/gpu/drm/i915/gt/intel_engine.h | 6 ++ drivers/gpu/drm/i915/gt/intel_engine_cs.c | 92 +++++++++++++++++-- .../gpu/drm/i915/gt/intel_engine_heartbeat.c | 18 ++++ drivers/gpu/drm/i915/gt/sysfs_engines.c | 25 +++-- drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h | 9 ++ 6 files changed, 153 insertions(+), 23 deletions(-)
From: John Harrison John.C.Harrison@Intel.com
GuC converts the pre-emption timeout and timeslice quantum values into clock ticks internally. That significantly reduces the point of 32bit overflow. On current platforms, worst case scenario is approximately 110 seconds. Rather than allowing the user to set higher values and then get confused by early timeouts, add limits when setting these values.
v2: Add helper functins for clamping (review feedback from Tvrtko).
Signed-off-by: John Harrison John.C.Harrison@Intel.com Reviewed-by: Daniele Ceraolo Spurio daniele.ceraolospurio@intel.com (v1) --- drivers/gpu/drm/i915/gt/intel_engine.h | 6 ++ drivers/gpu/drm/i915/gt/intel_engine_cs.c | 69 +++++++++++++++++++++ drivers/gpu/drm/i915/gt/sysfs_engines.c | 25 +++++--- drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h | 9 +++ 4 files changed, 99 insertions(+), 10 deletions(-)
diff --git a/drivers/gpu/drm/i915/gt/intel_engine.h b/drivers/gpu/drm/i915/gt/intel_engine.h index 1c0ab05c3c40..d7044c4e526e 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine.h +++ b/drivers/gpu/drm/i915/gt/intel_engine.h @@ -351,4 +351,10 @@ intel_engine_get_hung_context(struct intel_engine_cs *engine) return engine->hung_ce; }
+u64 intel_clamp_heartbeat_interval_ms(struct intel_engine_cs *engine, u64 value); +u64 intel_clamp_max_busywait_duration_ns(struct intel_engine_cs *engine, u64 value); +u64 intel_clamp_preempt_timeout_ms(struct intel_engine_cs *engine, u64 value); +u64 intel_clamp_stop_timeout_ms(struct intel_engine_cs *engine, u64 value); +u64 intel_clamp_timeslice_duration_ms(struct intel_engine_cs *engine, u64 value); + #endif /* _INTEL_RINGBUFFER_H_ */ diff --git a/drivers/gpu/drm/i915/gt/intel_engine_cs.c b/drivers/gpu/drm/i915/gt/intel_engine_cs.c index 7447411a5b26..22e70e4e007c 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/gt/intel_engine_cs.c @@ -442,6 +442,26 @@ static int intel_engine_setup(struct intel_gt *gt, enum intel_engine_id id, engine->flags |= I915_ENGINE_HAS_EU_PRIORITY; }
+ /* Cap properties according to any system limits */ +#define CLAMP_PROP(field) \ + do { \ + u64 clamp = intel_clamp_##field(engine, engine->props.field); \ + if (clamp != engine->props.field) { \ + drm_notice(&engine->i915->drm, \ + "Warning, clamping %s to %lld to prevent overflow\n", \ + #field, clamp); \ + engine->props.field = clamp; \ + } \ + } while (0) + + CLAMP_PROP(heartbeat_interval_ms); + CLAMP_PROP(max_busywait_duration_ns); + CLAMP_PROP(preempt_timeout_ms); + CLAMP_PROP(stop_timeout_ms); + CLAMP_PROP(timeslice_duration_ms); + +#undef CLAMP_PROP + engine->defaults = engine->props; /* never to change again */
engine->context_size = intel_engine_context_size(gt, engine->class); @@ -464,6 +484,55 @@ static int intel_engine_setup(struct intel_gt *gt, enum intel_engine_id id, return 0; }
+u64 intel_clamp_heartbeat_interval_ms(struct intel_engine_cs *engine, u64 value) +{ + value = min_t(u64, value, jiffies_to_msecs(MAX_SCHEDULE_TIMEOUT)); + + return value; +} + +u64 intel_clamp_max_busywait_duration_ns(struct intel_engine_cs *engine, u64 value) +{ + value = min(value, jiffies_to_nsecs(2)); + + return value; +} + +u64 intel_clamp_preempt_timeout_ms(struct intel_engine_cs *engine, u64 value) +{ + /* + * NB: The GuC API only supports 32bit values. However, the limit is further + * reduced due to internal calculations which would otherwise overflow. + */ + if (intel_guc_submission_is_wanted(&engine->gt->uc.guc)) + value = min_t(u64, value, GUC_POLICY_MAX_PREEMPT_TIMEOUT_MS); + + value = min_t(u64, value, jiffies_to_msecs(MAX_SCHEDULE_TIMEOUT)); + + return value; +} + +u64 intel_clamp_stop_timeout_ms(struct intel_engine_cs *engine, u64 value) +{ + value = min_t(u64, value, jiffies_to_msecs(MAX_SCHEDULE_TIMEOUT)); + + return value; +} + +u64 intel_clamp_timeslice_duration_ms(struct intel_engine_cs *engine, u64 value) +{ + /* + * NB: The GuC API only supports 32bit values. However, the limit is further + * reduced due to internal calculations which would otherwise overflow. + */ + if (intel_guc_submission_is_wanted(&engine->gt->uc.guc)) + value = min_t(u64, value, GUC_POLICY_MAX_EXEC_QUANTUM_MS); + + value = min_t(u64, value, jiffies_to_msecs(MAX_SCHEDULE_TIMEOUT)); + + return value; +} + static void __setup_engine_capabilities(struct intel_engine_cs *engine) { struct drm_i915_private *i915 = engine->i915; diff --git a/drivers/gpu/drm/i915/gt/sysfs_engines.c b/drivers/gpu/drm/i915/gt/sysfs_engines.c index 967031056202..f2d9858d827c 100644 --- a/drivers/gpu/drm/i915/gt/sysfs_engines.c +++ b/drivers/gpu/drm/i915/gt/sysfs_engines.c @@ -144,7 +144,7 @@ max_spin_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) { struct intel_engine_cs *engine = kobj_to_engine(kobj); - unsigned long long duration; + unsigned long long duration, clamped; int err;
/* @@ -168,7 +168,8 @@ max_spin_store(struct kobject *kobj, struct kobj_attribute *attr, if (err) return err;
- if (duration > jiffies_to_nsecs(2)) + clamped = intel_clamp_max_busywait_duration_ns(engine, duration); + if (duration != clamped) return -EINVAL;
WRITE_ONCE(engine->props.max_busywait_duration_ns, duration); @@ -203,7 +204,7 @@ timeslice_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) { struct intel_engine_cs *engine = kobj_to_engine(kobj); - unsigned long long duration; + unsigned long long duration, clamped; int err;
/* @@ -218,7 +219,8 @@ timeslice_store(struct kobject *kobj, struct kobj_attribute *attr, if (err) return err;
- if (duration > jiffies_to_msecs(MAX_SCHEDULE_TIMEOUT)) + clamped = intel_clamp_timeslice_duration_ms(engine, duration); + if (duration != clamped) return -EINVAL;
WRITE_ONCE(engine->props.timeslice_duration_ms, duration); @@ -256,7 +258,7 @@ stop_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) { struct intel_engine_cs *engine = kobj_to_engine(kobj); - unsigned long long duration; + unsigned long long duration, clamped; int err;
/* @@ -272,7 +274,8 @@ stop_store(struct kobject *kobj, struct kobj_attribute *attr, if (err) return err;
- if (duration > jiffies_to_msecs(MAX_SCHEDULE_TIMEOUT)) + clamped = intel_clamp_stop_timeout_ms(engine, duration); + if (duration != clamped) return -EINVAL;
WRITE_ONCE(engine->props.stop_timeout_ms, duration); @@ -306,7 +309,7 @@ preempt_timeout_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) { struct intel_engine_cs *engine = kobj_to_engine(kobj); - unsigned long long timeout; + unsigned long long timeout, clamped; int err;
/* @@ -322,7 +325,8 @@ preempt_timeout_store(struct kobject *kobj, struct kobj_attribute *attr, if (err) return err;
- if (timeout > jiffies_to_msecs(MAX_SCHEDULE_TIMEOUT)) + clamped = intel_clamp_preempt_timeout_ms(engine, timeout); + if (timeout != clamped) return -EINVAL;
WRITE_ONCE(engine->props.preempt_timeout_ms, timeout); @@ -362,7 +366,7 @@ heartbeat_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) { struct intel_engine_cs *engine = kobj_to_engine(kobj); - unsigned long long delay; + unsigned long long delay, clamped; int err;
/* @@ -379,7 +383,8 @@ heartbeat_store(struct kobject *kobj, struct kobj_attribute *attr, if (err) return err;
- if (delay >= jiffies_to_msecs(MAX_SCHEDULE_TIMEOUT)) + clamped = intel_clamp_heartbeat_interval_ms(engine, delay); + if (delay != clamped) return -EINVAL;
err = intel_engine_set_heartbeat(engine, delay); diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h b/drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h index 4b300b6cc0f9..a2d574f2fdd5 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h @@ -262,6 +262,15 @@ struct guc_lrc_desc {
#define GLOBAL_POLICY_DEFAULT_DPC_PROMOTE_TIME_US 500000
+/* + * GuC converts the timeout to clock ticks internally. Different platforms have + * different GuC clocks. Thus, the maximum value before overflow is platform + * dependent. Current worst case scenario is about 110s. So, limit to 100s to be + * safe. + */ +#define GUC_POLICY_MAX_EXEC_QUANTUM_MS (100 * 1000) +#define GUC_POLICY_MAX_PREEMPT_TIMEOUT_MS (100 * 1000) + struct guc_policies { u32 submission_queue_depth[GUC_MAX_ENGINE_CLASSES]; /* In micro seconds. How much time to allow before DPC processing is
On 03/03/2022 22:37, John.C.Harrison@Intel.com wrote:
From: John Harrison John.C.Harrison@Intel.com
GuC converts the pre-emption timeout and timeslice quantum values into clock ticks internally. That significantly reduces the point of 32bit overflow. On current platforms, worst case scenario is approximately 110 seconds. Rather than allowing the user to set higher values and then get confused by early timeouts, add limits when setting these values.
v2: Add helper functins for clamping (review feedback from Tvrtko).
Signed-off-by: John Harrison John.C.Harrison@Intel.com Reviewed-by: Daniele Ceraolo Spurio daniele.ceraolospurio@intel.com (v1)
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c index b3a429a92c0d..8208164c25e7 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c @@ -2218,13 +2218,24 @@ static inline u32 get_children_join_value(struct intel_context *ce, static void guc_context_policy_init(struct intel_engine_cs *engine, struct guc_lrc_desc *desc) { + struct drm_device *drm = &engine->i915->drm; + desc->policy_flags = 0;
if (engine->flags & I915_ENGINE_WANT_FORCED_PREEMPTION) desc->policy_flags |= CONTEXT_POLICY_FLAG_PREEMPT_TO_IDLE;
/* NB: For both of these, zero means disabled. */ + if (overflows_type(engine->props.timeslice_duration_ms * 1000, + desc->execution_quantum)) + drm_warn_once(drm, "GuC interface cannot support %lums timeslice!\n", + engine->props.timeslice_duration_ms); desc->execution_quantum = engine->props.timeslice_duration_ms * 1000; + + if (overflows_type(engine->props.preempt_timeout_ms * 1000, + desc->preemption_timeout)) + drm_warn_once(drm, "GuC interface cannot support %lums preemption timeout!\n", + engine->props.preempt_timeout_ms); desc->preemption_timeout = engine->props.preempt_timeout_ms * 1000; }
With that:
Reviewed-by: Tvrtko Ursulin tvrtko.ursulin@intel.com
Regards,
Tvrtko
drivers/gpu/drm/i915/gt/intel_engine.h | 6 ++ drivers/gpu/drm/i915/gt/intel_engine_cs.c | 69 +++++++++++++++++++++ drivers/gpu/drm/i915/gt/sysfs_engines.c | 25 +++++--- drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h | 9 +++ 4 files changed, 99 insertions(+), 10 deletions(-)
diff --git a/drivers/gpu/drm/i915/gt/intel_engine.h b/drivers/gpu/drm/i915/gt/intel_engine.h index 1c0ab05c3c40..d7044c4e526e 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine.h +++ b/drivers/gpu/drm/i915/gt/intel_engine.h @@ -351,4 +351,10 @@ intel_engine_get_hung_context(struct intel_engine_cs *engine) return engine->hung_ce; }
+u64 intel_clamp_heartbeat_interval_ms(struct intel_engine_cs *engine, u64 value); +u64 intel_clamp_max_busywait_duration_ns(struct intel_engine_cs *engine, u64 value); +u64 intel_clamp_preempt_timeout_ms(struct intel_engine_cs *engine, u64 value); +u64 intel_clamp_stop_timeout_ms(struct intel_engine_cs *engine, u64 value); +u64 intel_clamp_timeslice_duration_ms(struct intel_engine_cs *engine, u64 value);
- #endif /* _INTEL_RINGBUFFER_H_ */
diff --git a/drivers/gpu/drm/i915/gt/intel_engine_cs.c b/drivers/gpu/drm/i915/gt/intel_engine_cs.c index 7447411a5b26..22e70e4e007c 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/gt/intel_engine_cs.c @@ -442,6 +442,26 @@ static int intel_engine_setup(struct intel_gt *gt, enum intel_engine_id id, engine->flags |= I915_ENGINE_HAS_EU_PRIORITY; }
- /* Cap properties according to any system limits */
+#define CLAMP_PROP(field) \
- do { \
u64 clamp = intel_clamp_##field(engine, engine->props.field); \
if (clamp != engine->props.field) { \
drm_notice(&engine->i915->drm, \
"Warning, clamping %s to %lld to prevent overflow\n", \
#field, clamp); \
engine->props.field = clamp; \
} \
- } while (0)
- CLAMP_PROP(heartbeat_interval_ms);
- CLAMP_PROP(max_busywait_duration_ns);
- CLAMP_PROP(preempt_timeout_ms);
- CLAMP_PROP(stop_timeout_ms);
- CLAMP_PROP(timeslice_duration_ms);
+#undef CLAMP_PROP
engine->defaults = engine->props; /* never to change again */
engine->context_size = intel_engine_context_size(gt, engine->class);
@@ -464,6 +484,55 @@ static int intel_engine_setup(struct intel_gt *gt, enum intel_engine_id id, return 0; }
+u64 intel_clamp_heartbeat_interval_ms(struct intel_engine_cs *engine, u64 value) +{
- value = min_t(u64, value, jiffies_to_msecs(MAX_SCHEDULE_TIMEOUT));
- return value;
+}
+u64 intel_clamp_max_busywait_duration_ns(struct intel_engine_cs *engine, u64 value) +{
- value = min(value, jiffies_to_nsecs(2));
- return value;
+}
+u64 intel_clamp_preempt_timeout_ms(struct intel_engine_cs *engine, u64 value) +{
- /*
* NB: The GuC API only supports 32bit values. However, the limit is further
* reduced due to internal calculations which would otherwise overflow.
*/
- if (intel_guc_submission_is_wanted(&engine->gt->uc.guc))
value = min_t(u64, value, GUC_POLICY_MAX_PREEMPT_TIMEOUT_MS);
- value = min_t(u64, value, jiffies_to_msecs(MAX_SCHEDULE_TIMEOUT));
- return value;
+}
+u64 intel_clamp_stop_timeout_ms(struct intel_engine_cs *engine, u64 value) +{
- value = min_t(u64, value, jiffies_to_msecs(MAX_SCHEDULE_TIMEOUT));
- return value;
+}
+u64 intel_clamp_timeslice_duration_ms(struct intel_engine_cs *engine, u64 value) +{
- /*
* NB: The GuC API only supports 32bit values. However, the limit is further
* reduced due to internal calculations which would otherwise overflow.
*/
- if (intel_guc_submission_is_wanted(&engine->gt->uc.guc))
value = min_t(u64, value, GUC_POLICY_MAX_EXEC_QUANTUM_MS);
- value = min_t(u64, value, jiffies_to_msecs(MAX_SCHEDULE_TIMEOUT));
- return value;
+}
- static void __setup_engine_capabilities(struct intel_engine_cs *engine) { struct drm_i915_private *i915 = engine->i915;
diff --git a/drivers/gpu/drm/i915/gt/sysfs_engines.c b/drivers/gpu/drm/i915/gt/sysfs_engines.c index 967031056202..f2d9858d827c 100644 --- a/drivers/gpu/drm/i915/gt/sysfs_engines.c +++ b/drivers/gpu/drm/i915/gt/sysfs_engines.c @@ -144,7 +144,7 @@ max_spin_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) { struct intel_engine_cs *engine = kobj_to_engine(kobj);
- unsigned long long duration;
unsigned long long duration, clamped; int err;
/*
@@ -168,7 +168,8 @@ max_spin_store(struct kobject *kobj, struct kobj_attribute *attr, if (err) return err;
- if (duration > jiffies_to_nsecs(2))
clamped = intel_clamp_max_busywait_duration_ns(engine, duration);
if (duration != clamped) return -EINVAL;
WRITE_ONCE(engine->props.max_busywait_duration_ns, duration);
@@ -203,7 +204,7 @@ timeslice_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) { struct intel_engine_cs *engine = kobj_to_engine(kobj);
- unsigned long long duration;
unsigned long long duration, clamped; int err;
/*
@@ -218,7 +219,8 @@ timeslice_store(struct kobject *kobj, struct kobj_attribute *attr, if (err) return err;
- if (duration > jiffies_to_msecs(MAX_SCHEDULE_TIMEOUT))
clamped = intel_clamp_timeslice_duration_ms(engine, duration);
if (duration != clamped) return -EINVAL;
WRITE_ONCE(engine->props.timeslice_duration_ms, duration);
@@ -256,7 +258,7 @@ stop_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) { struct intel_engine_cs *engine = kobj_to_engine(kobj);
- unsigned long long duration;
unsigned long long duration, clamped; int err;
/*
@@ -272,7 +274,8 @@ stop_store(struct kobject *kobj, struct kobj_attribute *attr, if (err) return err;
- if (duration > jiffies_to_msecs(MAX_SCHEDULE_TIMEOUT))
clamped = intel_clamp_stop_timeout_ms(engine, duration);
if (duration != clamped) return -EINVAL;
WRITE_ONCE(engine->props.stop_timeout_ms, duration);
@@ -306,7 +309,7 @@ preempt_timeout_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) { struct intel_engine_cs *engine = kobj_to_engine(kobj);
- unsigned long long timeout;
unsigned long long timeout, clamped; int err;
/*
@@ -322,7 +325,8 @@ preempt_timeout_store(struct kobject *kobj, struct kobj_attribute *attr, if (err) return err;
- if (timeout > jiffies_to_msecs(MAX_SCHEDULE_TIMEOUT))
clamped = intel_clamp_preempt_timeout_ms(engine, timeout);
if (timeout != clamped) return -EINVAL;
WRITE_ONCE(engine->props.preempt_timeout_ms, timeout);
@@ -362,7 +366,7 @@ heartbeat_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) { struct intel_engine_cs *engine = kobj_to_engine(kobj);
- unsigned long long delay;
unsigned long long delay, clamped; int err;
/*
@@ -379,7 +383,8 @@ heartbeat_store(struct kobject *kobj, struct kobj_attribute *attr, if (err) return err;
- if (delay >= jiffies_to_msecs(MAX_SCHEDULE_TIMEOUT))
clamped = intel_clamp_heartbeat_interval_ms(engine, delay);
if (delay != clamped) return -EINVAL;
err = intel_engine_set_heartbeat(engine, delay);
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h b/drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h index 4b300b6cc0f9..a2d574f2fdd5 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h @@ -262,6 +262,15 @@ struct guc_lrc_desc {
#define GLOBAL_POLICY_DEFAULT_DPC_PROMOTE_TIME_US 500000
+/*
- GuC converts the timeout to clock ticks internally. Different platforms have
- different GuC clocks. Thus, the maximum value before overflow is platform
- dependent. Current worst case scenario is about 110s. So, limit to 100s to be
- safe.
- */
+#define GUC_POLICY_MAX_EXEC_QUANTUM_MS (100 * 1000) +#define GUC_POLICY_MAX_PREEMPT_TIMEOUT_MS (100 * 1000)
- struct guc_policies { u32 submission_queue_depth[GUC_MAX_ENGINE_CLASSES]; /* In micro seconds. How much time to allow before DPC processing is
On 3/8/2022 01:43, Tvrtko Ursulin wrote:
On 03/03/2022 22:37, John.C.Harrison@Intel.com wrote:
From: John Harrison John.C.Harrison@Intel.com
GuC converts the pre-emption timeout and timeslice quantum values into clock ticks internally. That significantly reduces the point of 32bit overflow. On current platforms, worst case scenario is approximately 110 seconds. Rather than allowing the user to set higher values and then get confused by early timeouts, add limits when setting these values.
v2: Add helper functins for clamping (review feedback from Tvrtko).
Signed-off-by: John Harrison John.C.Harrison@Intel.com Reviewed-by: Daniele Ceraolo Spurio daniele.ceraolospurio@intel.com (v1)
diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c index b3a429a92c0d..8208164c25e7 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c @@ -2218,13 +2218,24 @@ static inline u32 get_children_join_value(struct intel_context *ce, static void guc_context_policy_init(struct intel_engine_cs *engine, struct guc_lrc_desc *desc) { + struct drm_device *drm = &engine->i915->drm;
desc->policy_flags = 0;
if (engine->flags & I915_ENGINE_WANT_FORCED_PREEMPTION) desc->policy_flags |= CONTEXT_POLICY_FLAG_PREEMPT_TO_IDLE;
/* NB: For both of these, zero means disabled. */ + if (overflows_type(engine->props.timeslice_duration_ms * 1000, + desc->execution_quantum)) + drm_warn_once(drm, "GuC interface cannot support %lums timeslice!\n",
- engine->props.timeslice_duration_ms);
desc->execution_quantum = engine->props.timeslice_duration_ms
- 1000;
+ if (overflows_type(engine->props.preempt_timeout_ms * 1000, + desc->preemption_timeout)) + drm_warn_once(drm, "GuC interface cannot support %lums preemption timeout!\n",
- engine->props.preempt_timeout_ms);
desc->preemption_timeout = engine->props.preempt_timeout_ms * 1000; }
As previously explained, this is wrong. If the check must be present then it should be a BUG_ON as it is indicative of an internal driver failure. There is already a top level helper function for ensuring all range checks are done and the value is valid. If that is broken then that is a bug and should have been caught in pre-merge testing or code review. It is not possible for a bad value to get beyond that helper function. That is the whole point of the helper. We do not double bag every other value check in the driver. Once you have passed input validation, the values are assumed to be correct. Otherwise we would have every other line of code be a value check! And if somehow a bad value did make it through, simply printing a once shot warning is pointless. You are still going to get undefined behaviour potentially leading to a totally broken system. E.g. your very big timeout has overflowed and become extremely small, thus no batch buffer can ever complete because they all get reset before they have even finished the context switch in. That is a fundamentally broken system.
John.
With that:
Reviewed-by: Tvrtko Ursulin tvrtko.ursulin@intel.com
Regards,
Tvrtko
drivers/gpu/drm/i915/gt/intel_engine.h | 6 ++ drivers/gpu/drm/i915/gt/intel_engine_cs.c | 69 +++++++++++++++++++++ drivers/gpu/drm/i915/gt/sysfs_engines.c | 25 +++++--- drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h | 9 +++ 4 files changed, 99 insertions(+), 10 deletions(-)
diff --git a/drivers/gpu/drm/i915/gt/intel_engine.h b/drivers/gpu/drm/i915/gt/intel_engine.h index 1c0ab05c3c40..d7044c4e526e 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine.h +++ b/drivers/gpu/drm/i915/gt/intel_engine.h @@ -351,4 +351,10 @@ intel_engine_get_hung_context(struct intel_engine_cs *engine) return engine->hung_ce; } +u64 intel_clamp_heartbeat_interval_ms(struct intel_engine_cs *engine, u64 value); +u64 intel_clamp_max_busywait_duration_ns(struct intel_engine_cs *engine, u64 value); +u64 intel_clamp_preempt_timeout_ms(struct intel_engine_cs *engine, u64 value); +u64 intel_clamp_stop_timeout_ms(struct intel_engine_cs *engine, u64 value); +u64 intel_clamp_timeslice_duration_ms(struct intel_engine_cs *engine, u64 value);
#endif /* _INTEL_RINGBUFFER_H_ */ diff --git a/drivers/gpu/drm/i915/gt/intel_engine_cs.c b/drivers/gpu/drm/i915/gt/intel_engine_cs.c index 7447411a5b26..22e70e4e007c 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/gt/intel_engine_cs.c @@ -442,6 +442,26 @@ static int intel_engine_setup(struct intel_gt *gt, enum intel_engine_id id, engine->flags |= I915_ENGINE_HAS_EU_PRIORITY; } + /* Cap properties according to any system limits */ +#define CLAMP_PROP(field) \ + do { \ + u64 clamp = intel_clamp_##field(engine, engine->props.field); \ + if (clamp != engine->props.field) { \ + drm_notice(&engine->i915->drm, \ + "Warning, clamping %s to %lld to prevent overflow\n", \ + #field, clamp); \ + engine->props.field = clamp; \ + } \ + } while (0)
+ CLAMP_PROP(heartbeat_interval_ms); + CLAMP_PROP(max_busywait_duration_ns); + CLAMP_PROP(preempt_timeout_ms); + CLAMP_PROP(stop_timeout_ms); + CLAMP_PROP(timeslice_duration_ms);
+#undef CLAMP_PROP
engine->defaults = engine->props; /* never to change again */ engine->context_size = intel_engine_context_size(gt, engine->class); @@ -464,6 +484,55 @@ static int intel_engine_setup(struct intel_gt *gt, enum intel_engine_id id, return 0; } +u64 intel_clamp_heartbeat_interval_ms(struct intel_engine_cs *engine, u64 value) +{ + value = min_t(u64, value, jiffies_to_msecs(MAX_SCHEDULE_TIMEOUT));
+ return value; +}
+u64 intel_clamp_max_busywait_duration_ns(struct intel_engine_cs *engine, u64 value) +{ + value = min(value, jiffies_to_nsecs(2));
+ return value; +}
+u64 intel_clamp_preempt_timeout_ms(struct intel_engine_cs *engine, u64 value) +{ + /* + * NB: The GuC API only supports 32bit values. However, the limit is further + * reduced due to internal calculations which would otherwise overflow. + */ + if (intel_guc_submission_is_wanted(&engine->gt->uc.guc)) + value = min_t(u64, value, GUC_POLICY_MAX_PREEMPT_TIMEOUT_MS);
+ value = min_t(u64, value, jiffies_to_msecs(MAX_SCHEDULE_TIMEOUT));
+ return value; +}
+u64 intel_clamp_stop_timeout_ms(struct intel_engine_cs *engine, u64 value) +{ + value = min_t(u64, value, jiffies_to_msecs(MAX_SCHEDULE_TIMEOUT));
+ return value; +}
+u64 intel_clamp_timeslice_duration_ms(struct intel_engine_cs *engine, u64 value) +{ + /* + * NB: The GuC API only supports 32bit values. However, the limit is further + * reduced due to internal calculations which would otherwise overflow. + */ + if (intel_guc_submission_is_wanted(&engine->gt->uc.guc)) + value = min_t(u64, value, GUC_POLICY_MAX_EXEC_QUANTUM_MS);
+ value = min_t(u64, value, jiffies_to_msecs(MAX_SCHEDULE_TIMEOUT));
+ return value; +}
static void __setup_engine_capabilities(struct intel_engine_cs *engine) { struct drm_i915_private *i915 = engine->i915; diff --git a/drivers/gpu/drm/i915/gt/sysfs_engines.c b/drivers/gpu/drm/i915/gt/sysfs_engines.c index 967031056202..f2d9858d827c 100644 --- a/drivers/gpu/drm/i915/gt/sysfs_engines.c +++ b/drivers/gpu/drm/i915/gt/sysfs_engines.c @@ -144,7 +144,7 @@ max_spin_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) { struct intel_engine_cs *engine = kobj_to_engine(kobj); - unsigned long long duration; + unsigned long long duration, clamped; int err; /* @@ -168,7 +168,8 @@ max_spin_store(struct kobject *kobj, struct kobj_attribute *attr, if (err) return err; - if (duration > jiffies_to_nsecs(2)) + clamped = intel_clamp_max_busywait_duration_ns(engine, duration); + if (duration != clamped) return -EINVAL; WRITE_ONCE(engine->props.max_busywait_duration_ns, duration); @@ -203,7 +204,7 @@ timeslice_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) { struct intel_engine_cs *engine = kobj_to_engine(kobj); - unsigned long long duration; + unsigned long long duration, clamped; int err; /* @@ -218,7 +219,8 @@ timeslice_store(struct kobject *kobj, struct kobj_attribute *attr, if (err) return err; - if (duration > jiffies_to_msecs(MAX_SCHEDULE_TIMEOUT)) + clamped = intel_clamp_timeslice_duration_ms(engine, duration); + if (duration != clamped) return -EINVAL; WRITE_ONCE(engine->props.timeslice_duration_ms, duration); @@ -256,7 +258,7 @@ stop_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) { struct intel_engine_cs *engine = kobj_to_engine(kobj); - unsigned long long duration; + unsigned long long duration, clamped; int err; /* @@ -272,7 +274,8 @@ stop_store(struct kobject *kobj, struct kobj_attribute *attr, if (err) return err; - if (duration > jiffies_to_msecs(MAX_SCHEDULE_TIMEOUT)) + clamped = intel_clamp_stop_timeout_ms(engine, duration); + if (duration != clamped) return -EINVAL; WRITE_ONCE(engine->props.stop_timeout_ms, duration); @@ -306,7 +309,7 @@ preempt_timeout_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) { struct intel_engine_cs *engine = kobj_to_engine(kobj); - unsigned long long timeout; + unsigned long long timeout, clamped; int err; /* @@ -322,7 +325,8 @@ preempt_timeout_store(struct kobject *kobj, struct kobj_attribute *attr, if (err) return err; - if (timeout > jiffies_to_msecs(MAX_SCHEDULE_TIMEOUT)) + clamped = intel_clamp_preempt_timeout_ms(engine, timeout); + if (timeout != clamped) return -EINVAL; WRITE_ONCE(engine->props.preempt_timeout_ms, timeout); @@ -362,7 +366,7 @@ heartbeat_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) { struct intel_engine_cs *engine = kobj_to_engine(kobj); - unsigned long long delay; + unsigned long long delay, clamped; int err; /* @@ -379,7 +383,8 @@ heartbeat_store(struct kobject *kobj, struct kobj_attribute *attr, if (err) return err; - if (delay >= jiffies_to_msecs(MAX_SCHEDULE_TIMEOUT)) + clamped = intel_clamp_heartbeat_interval_ms(engine, delay); + if (delay != clamped) return -EINVAL; err = intel_engine_set_heartbeat(engine, delay); diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h b/drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h index 4b300b6cc0f9..a2d574f2fdd5 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_fwif.h @@ -262,6 +262,15 @@ struct guc_lrc_desc { #define GLOBAL_POLICY_DEFAULT_DPC_PROMOTE_TIME_US 500000 +/*
- GuC converts the timeout to clock ticks internally. Different
platforms have
- different GuC clocks. Thus, the maximum value before overflow is
platform
- dependent. Current worst case scenario is about 110s. So, limit
to 100s to be
- safe.
- */
+#define GUC_POLICY_MAX_EXEC_QUANTUM_MS (100 * 1000) +#define GUC_POLICY_MAX_PREEMPT_TIMEOUT_MS (100 * 1000)
struct guc_policies { u32 submission_queue_depth[GUC_MAX_ENGINE_CLASSES]; /* In micro seconds. How much time to allow before DPC processing is
From: John Harrison John.C.Harrison@Intel.com
An earlier patch added support for compute engines. However, it missed enabling the anti-pre-emption w/a for the new engine class. So move the 'compute capable' flag earlier and use it for the pre-emption w/a test.
Fixes: c674c5b9342e ("drm/i915/xehp: CCS should use RCS setup functions") Cc: Tvrtko Ursulin tvrtko.ursulin@linux.intel.com Cc: Daniele Ceraolo Spurio daniele.ceraolospurio@intel.com Cc: Aravind Iddamsetty aravind.iddamsetty@intel.com Cc: Matt Roper matthew.d.roper@intel.com Cc: Tvrtko Ursulin tvrtko.ursulin@intel.com Cc: Daniel Vetter daniel.vetter@ffwll.ch Cc: Maarten Lankhorst maarten.lankhorst@linux.intel.com Cc: Lucas De Marchi lucas.demarchi@intel.com Cc: John Harrison John.C.Harrison@Intel.com Cc: Jason Ekstrand jason@jlekstrand.net Cc: "Michał Winiarski" michal.winiarski@intel.com Cc: Matthew Brost matthew.brost@intel.com Cc: Chris Wilson chris@chris-wilson.co.uk Cc: Tejas Upadhyay tejaskumarx.surendrakumar.upadhyay@intel.com Cc: Umesh Nerlige Ramappa umesh.nerlige.ramappa@intel.com Cc: "Thomas Hellström" thomas.hellstrom@linux.intel.com Cc: Stuart Summers stuart.summers@intel.com Cc: Matthew Auld matthew.auld@intel.com Cc: Jani Nikula jani.nikula@intel.com Cc: Ramalingam C ramalingam.c@intel.com Cc: Akeem G Abodunrin akeem.g.abodunrin@intel.com Signed-off-by: John Harrison John.C.Harrison@Intel.com --- drivers/gpu/drm/i915/gt/intel_engine_cs.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/drivers/gpu/drm/i915/gt/intel_engine_cs.c b/drivers/gpu/drm/i915/gt/intel_engine_cs.c index 22e70e4e007c..4185c7338581 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/gt/intel_engine_cs.c @@ -421,6 +421,12 @@ static int intel_engine_setup(struct intel_gt *gt, enum intel_engine_id id, engine->logical_mask = BIT(logical_instance); __sprint_engine_name(engine);
+ /* features common between engines sharing EUs */ + if (engine->class == RENDER_CLASS || engine->class == COMPUTE_CLASS) { + engine->flags |= I915_ENGINE_HAS_RCS_REG_STATE; + engine->flags |= I915_ENGINE_HAS_EU_PRIORITY; + } + engine->props.heartbeat_interval_ms = CONFIG_DRM_I915_HEARTBEAT_INTERVAL; engine->props.max_busywait_duration_ns = @@ -433,15 +439,9 @@ static int intel_engine_setup(struct intel_gt *gt, enum intel_engine_id id, CONFIG_DRM_I915_TIMESLICE_DURATION;
/* Override to uninterruptible for OpenCL workloads. */ - if (GRAPHICS_VER(i915) == 12 && engine->class == RENDER_CLASS) + if (GRAPHICS_VER(i915) == 12 && (engine->flags & I915_ENGINE_HAS_RCS_REG_STATE)) engine->props.preempt_timeout_ms = 0;
- /* features common between engines sharing EUs */ - if (engine->class == RENDER_CLASS || engine->class == COMPUTE_CLASS) { - engine->flags |= I915_ENGINE_HAS_RCS_REG_STATE; - engine->flags |= I915_ENGINE_HAS_EU_PRIORITY; - } - /* Cap properties according to any system limits */ #define CLAMP_PROP(field) \ do { \
On Thu, Mar 03, 2022 at 02:37:35PM -0800, John.C.Harrison@Intel.com wrote:
From: John Harrison John.C.Harrison@Intel.com
An earlier patch added support for compute engines. However, it missed enabling the anti-pre-emption w/a for the new engine class. So move the 'compute capable' flag earlier and use it for the pre-emption w/a test.
Fixes: c674c5b9342e ("drm/i915/xehp: CCS should use RCS setup functions") Cc: Tvrtko Ursulin tvrtko.ursulin@linux.intel.com Cc: Daniele Ceraolo Spurio daniele.ceraolospurio@intel.com Cc: Aravind Iddamsetty aravind.iddamsetty@intel.com Cc: Matt Roper matthew.d.roper@intel.com Cc: Tvrtko Ursulin tvrtko.ursulin@intel.com Cc: Daniel Vetter daniel.vetter@ffwll.ch Cc: Maarten Lankhorst maarten.lankhorst@linux.intel.com Cc: Lucas De Marchi lucas.demarchi@intel.com Cc: John Harrison John.C.Harrison@Intel.com Cc: Jason Ekstrand jason@jlekstrand.net Cc: "Michał Winiarski" michal.winiarski@intel.com Cc: Matthew Brost matthew.brost@intel.com Cc: Chris Wilson chris@chris-wilson.co.uk Cc: Tejas Upadhyay tejaskumarx.surendrakumar.upadhyay@intel.com Cc: Umesh Nerlige Ramappa umesh.nerlige.ramappa@intel.com Cc: "Thomas Hellström" thomas.hellstrom@linux.intel.com Cc: Stuart Summers stuart.summers@intel.com Cc: Matthew Auld matthew.auld@intel.com Cc: Jani Nikula jani.nikula@intel.com Cc: Ramalingam C ramalingam.c@intel.com Cc: Akeem G Abodunrin akeem.g.abodunrin@intel.com Signed-off-by: John Harrison John.C.Harrison@Intel.com
Reviewed-by: Matt Roper matthew.d.roper@intel.com
drivers/gpu/drm/i915/gt/intel_engine_cs.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/drivers/gpu/drm/i915/gt/intel_engine_cs.c b/drivers/gpu/drm/i915/gt/intel_engine_cs.c index 22e70e4e007c..4185c7338581 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/gt/intel_engine_cs.c @@ -421,6 +421,12 @@ static int intel_engine_setup(struct intel_gt *gt, enum intel_engine_id id, engine->logical_mask = BIT(logical_instance); __sprint_engine_name(engine);
- /* features common between engines sharing EUs */
- if (engine->class == RENDER_CLASS || engine->class == COMPUTE_CLASS) {
engine->flags |= I915_ENGINE_HAS_RCS_REG_STATE;
engine->flags |= I915_ENGINE_HAS_EU_PRIORITY;
- }
- engine->props.heartbeat_interval_ms = CONFIG_DRM_I915_HEARTBEAT_INTERVAL; engine->props.max_busywait_duration_ns =
@@ -433,15 +439,9 @@ static int intel_engine_setup(struct intel_gt *gt, enum intel_engine_id id, CONFIG_DRM_I915_TIMESLICE_DURATION;
/* Override to uninterruptible for OpenCL workloads. */
- if (GRAPHICS_VER(i915) == 12 && engine->class == RENDER_CLASS)
- if (GRAPHICS_VER(i915) == 12 && (engine->flags & I915_ENGINE_HAS_RCS_REG_STATE)) engine->props.preempt_timeout_ms = 0;
- /* features common between engines sharing EUs */
- if (engine->class == RENDER_CLASS || engine->class == COMPUTE_CLASS) {
engine->flags |= I915_ENGINE_HAS_RCS_REG_STATE;
engine->flags |= I915_ENGINE_HAS_EU_PRIORITY;
- }
- /* Cap properties according to any system limits */
#define CLAMP_PROP(field) \ do { \ -- 2.25.1
From: John Harrison John.C.Harrison@Intel.com
Compute workloads are inherently not pre-emptible for long periods on current hardware. As a workaround for this, the pre-emption timeout for compute capable engines was disabled. This is undesirable with GuC submission as it prevents per engine reset of hung contexts. Hence the next patch will re-enable the timeout but bumped up by an order of magnitude.
However, the heartbeat might not respect that. Depending upon current activity, a pre-emption to the heartbeat pulse might not even be attempted until the last heartbeat period. Which means that only one period is granted for the pre-emption to occur. With the aforesaid bump, the pre-emption timeout could be significantly larger than this heartbeat period.
So adjust the heartbeat code to take the pre-emption timeout into account. When it reaches the final (high priority) period, it now ensures the delay before hitting reset is bigger than the pre-emption timeout.
v2: Fix for selftests which adjust the heartbeat period manually.
Signed-off-by: John Harrison John.C.Harrison@Intel.com --- .../gpu/drm/i915/gt/intel_engine_heartbeat.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+)
diff --git a/drivers/gpu/drm/i915/gt/intel_engine_heartbeat.c b/drivers/gpu/drm/i915/gt/intel_engine_heartbeat.c index a3698f611f45..0dc53def8e42 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine_heartbeat.c +++ b/drivers/gpu/drm/i915/gt/intel_engine_heartbeat.c @@ -22,9 +22,27 @@
static bool next_heartbeat(struct intel_engine_cs *engine) { + struct i915_request *rq; long delay;
delay = READ_ONCE(engine->props.heartbeat_interval_ms); + + rq = engine->heartbeat.systole; + + if (rq && rq->sched.attr.priority >= I915_PRIORITY_BARRIER && + delay == engine->defaults.heartbeat_interval_ms) { + long longer; + + /* + * The final try is at the highest priority possible. Up until now + * a pre-emption might not even have been attempted. So make sure + * this last attempt allows enough time for a pre-emption to occur. + */ + longer = READ_ONCE(engine->props.preempt_timeout_ms) * 2; + if (longer > delay) + delay = longer; + } + if (!delay) return false;
From: John Harrison John.C.Harrison@Intel.com
A workaround was added to the driver to allow OpenCL workloads to run 'forever' by disabling pre-emption on the RCS engine for Gen12. It is not totally unbound as the heartbeat will kick in eventually and cause a reset of the hung engine.
However, this does not work well in GuC submission mode. In GuC mode, the pre-emption timeout is how GuC detects hung contexts and triggers a per engine reset. Thus, disabling the timeout means also losing all per engine reset ability. A full GT reset will still occur when the heartbeat finally expires, but that is a much more destructive and undesirable mechanism.
The purpose of the workaround is actually to give OpenCL tasks longer to reach a pre-emption point after a pre-emption request has been issued. This is necessary because Gen12 does not support mid-thread pre-emption and OpenCL can have long running threads.
So, rather than disabling the timeout completely, just set it to a 'long' value.
v2: Review feedback from Tvrtko - must hard code the 'long' value instead of determining it algorithmically. So make it an extra CONFIG definition. Also, remove the execlist centric comment from the existing pre-emption timeout CONFIG option given that it applies to more than just execlists.
Signed-off-by: John Harrison John.C.Harrison@Intel.com Reviewed-by: Daniele Ceraolo Spurio daniele.ceraolospurio@intel.com (v1) Acked-by: Michal Mrozek michal.mrozek@intel.com --- drivers/gpu/drm/i915/Kconfig.profile | 26 +++++++++++++++++++---- drivers/gpu/drm/i915/gt/intel_engine_cs.c | 9 ++++++-- 2 files changed, 29 insertions(+), 6 deletions(-)
diff --git a/drivers/gpu/drm/i915/Kconfig.profile b/drivers/gpu/drm/i915/Kconfig.profile index 39328567c200..7cc38d25ee5c 100644 --- a/drivers/gpu/drm/i915/Kconfig.profile +++ b/drivers/gpu/drm/i915/Kconfig.profile @@ -57,10 +57,28 @@ config DRM_I915_PREEMPT_TIMEOUT default 640 # milliseconds help How long to wait (in milliseconds) for a preemption event to occur - when submitting a new context via execlists. If the current context - does not hit an arbitration point and yield to HW before the timer - expires, the HW will be reset to allow the more important context - to execute. + when submitting a new context. If the current context does not hit + an arbitration point and yield to HW before the timer expires, the + HW will be reset to allow the more important context to execute. + + This is adjustable via + /sys/class/drm/card?/engine/*/preempt_timeout_ms + + May be 0 to disable the timeout. + + The compiled in default may get overridden at driver probe time on + certain platforms and certain engines which will be reflected in the + sysfs control. + +config DRM_I915_PREEMPT_TIMEOUT_COMPUTE + int "Preempt timeout for compute engines (ms, jiffy granularity)" + default 7500 # milliseconds + help + How long to wait (in milliseconds) for a preemption event to occur + when submitting a new context to a compute capable engine. If the + current context does not hit an arbitration point and yield to HW + before the timer expires, the HW will be reset to allow the more + important context to execute.
This is adjustable via /sys/class/drm/card?/engine/*/preempt_timeout_ms diff --git a/drivers/gpu/drm/i915/gt/intel_engine_cs.c b/drivers/gpu/drm/i915/gt/intel_engine_cs.c index 4185c7338581..cc0954ad836a 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/gt/intel_engine_cs.c @@ -438,9 +438,14 @@ static int intel_engine_setup(struct intel_gt *gt, enum intel_engine_id id, engine->props.timeslice_duration_ms = CONFIG_DRM_I915_TIMESLICE_DURATION;
- /* Override to uninterruptible for OpenCL workloads. */ + /* + * Mid-thread pre-emption is not available in Gen12. Unfortunately, + * some OpenCL workloads run quite long threads. That means they get + * reset due to not pre-empting in a timely manner. So, bump the + * pre-emption timeout value to be much higher for compute engines. + */ if (GRAPHICS_VER(i915) == 12 && (engine->flags & I915_ENGINE_HAS_RCS_REG_STATE)) - engine->props.preempt_timeout_ms = 0; + engine->props.preempt_timeout_ms = CONFIG_DRM_I915_PREEMPT_TIMEOUT_COMPUTE;
/* Cap properties according to any system limits */ #define CLAMP_PROP(field) \
Acked-by: Michal Mrozek michal.mrozek@intel.com
-----Original Message----- From: Harrison, John C john.c.harrison@intel.com Sent: Thursday, March 3, 2022 11:38 PM To: Intel-GFX@Lists.FreeDesktop.Org Cc: DRI-Devel@Lists.FreeDesktop.Org; Harrison, John C john.c.harrison@intel.com; Ceraolo Spurio, Daniele daniele.ceraolospurio@intel.com; Mrozek, Michal michal.mrozek@intel.com Subject: [PATCH v3 4/4] drm/i915: Improve long running OCL w/a for GuC submission
From: John Harrison John.C.Harrison@Intel.com
A workaround was added to the driver to allow OpenCL workloads to run 'forever' by disabling pre-emption on the RCS engine for Gen12. It is not totally unbound as the heartbeat will kick in eventually and cause a reset of the hung engine.
However, this does not work well in GuC submission mode. In GuC mode, the pre-emption timeout is how GuC detects hung contexts and triggers a per engine reset. Thus, disabling the timeout means also losing all per engine reset ability. A full GT reset will still occur when the heartbeat finally expires, but that is a much more destructive and undesirable mechanism.
The purpose of the workaround is actually to give OpenCL tasks longer to reach a pre-emption point after a pre-emption request has been issued. This is necessary because Gen12 does not support mid-thread pre-emption and OpenCL can have long running threads.
So, rather than disabling the timeout completely, just set it to a 'long' value.
v2: Review feedback from Tvrtko - must hard code the 'long' value instead of determining it algorithmically. So make it an extra CONFIG definition. Also, remove the execlist centric comment from the existing pre-emption timeout CONFIG option given that it applies to more than just execlists.
Signed-off-by: John Harrison John.C.Harrison@Intel.com Reviewed-by: Daniele Ceraolo Spurio daniele.ceraolospurio@intel.com (v1) Acked-by: Michal Mrozek michal.mrozek@intel.com --- drivers/gpu/drm/i915/Kconfig.profile | 26 +++++++++++++++++++---- drivers/gpu/drm/i915/gt/intel_engine_cs.c | 9 ++++++-- 2 files changed, 29 insertions(+), 6 deletions(-)
diff --git a/drivers/gpu/drm/i915/Kconfig.profile b/drivers/gpu/drm/i915/Kconfig.profile index 39328567c200..7cc38d25ee5c 100644 --- a/drivers/gpu/drm/i915/Kconfig.profile +++ b/drivers/gpu/drm/i915/Kconfig.profile @@ -57,10 +57,28 @@ config DRM_I915_PREEMPT_TIMEOUT default 640 # milliseconds help How long to wait (in milliseconds) for a preemption event to occur - when submitting a new context via execlists. If the current context - does not hit an arbitration point and yield to HW before the timer - expires, the HW will be reset to allow the more important context - to execute. + when submitting a new context. If the current context does not hit + an arbitration point and yield to HW before the timer expires, the + HW will be reset to allow the more important context to execute. + + This is adjustable via + /sys/class/drm/card?/engine/*/preempt_timeout_ms + + May be 0 to disable the timeout. + + The compiled in default may get overridden at driver probe time on + certain platforms and certain engines which will be reflected in the + sysfs control. + +config DRM_I915_PREEMPT_TIMEOUT_COMPUTE + int "Preempt timeout for compute engines (ms, jiffy granularity)" + default 7500 # milliseconds + help + How long to wait (in milliseconds) for a preemption event to occur + when submitting a new context to a compute capable engine. If the + current context does not hit an arbitration point and yield to HW + before the timer expires, the HW will be reset to allow the more + important context to execute.
This is adjustable via /sys/class/drm/card?/engine/*/preempt_timeout_ms diff --git a/drivers/gpu/drm/i915/gt/intel_engine_cs.c b/drivers/gpu/drm/i915/gt/intel_engine_cs.c index 4185c7338581..cc0954ad836a 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/gt/intel_engine_cs.c @@ -438,9 +438,14 @@ static int intel_engine_setup(struct intel_gt *gt, enum intel_engine_id id, engine->props.timeslice_duration_ms = CONFIG_DRM_I915_TIMESLICE_DURATION;
- /* Override to uninterruptible for OpenCL workloads. */ + /* + * Mid-thread pre-emption is not available in Gen12. Unfortunately, + * some OpenCL workloads run quite long threads. That means they get + * reset due to not pre-empting in a timely manner. So, bump the + * pre-emption timeout value to be much higher for compute engines. + */ if (GRAPHICS_VER(i915) == 12 && (engine->flags & I915_ENGINE_HAS_RCS_REG_STATE)) - engine->props.preempt_timeout_ms = 0; + engine->props.preempt_timeout_ms = +CONFIG_DRM_I915_PREEMPT_TIMEOUT_COMPUTE;
/* Cap properties according to any system limits */ #define CLAMP_PROP(field) \ -- 2.25.1
On 03/03/2022 22:37, John.C.Harrison@Intel.com wrote:
From: John Harrison John.C.Harrison@Intel.com
A workaround was added to the driver to allow OpenCL workloads to run 'forever' by disabling pre-emption on the RCS engine for Gen12. It is not totally unbound as the heartbeat will kick in eventually and cause a reset of the hung engine.
However, this does not work well in GuC submission mode. In GuC mode, the pre-emption timeout is how GuC detects hung contexts and triggers a per engine reset. Thus, disabling the timeout means also losing all per engine reset ability. A full GT reset will still occur when the heartbeat finally expires, but that is a much more destructive and undesirable mechanism.
The purpose of the workaround is actually to give OpenCL tasks longer to reach a pre-emption point after a pre-emption request has been issued. This is necessary because Gen12 does not support mid-thread pre-emption and OpenCL can have long running threads.
So, rather than disabling the timeout completely, just set it to a 'long' value.
v2: Review feedback from Tvrtko - must hard code the 'long' value instead of determining it algorithmically. So make it an extra CONFIG definition. Also, remove the execlist centric comment from the existing pre-emption timeout CONFIG option given that it applies to more than just execlists.
Signed-off-by: John Harrison John.C.Harrison@Intel.com Reviewed-by: Daniele Ceraolo Spurio daniele.ceraolospurio@intel.com (v1) Acked-by: Michal Mrozek michal.mrozek@intel.com
drivers/gpu/drm/i915/Kconfig.profile | 26 +++++++++++++++++++---- drivers/gpu/drm/i915/gt/intel_engine_cs.c | 9 ++++++-- 2 files changed, 29 insertions(+), 6 deletions(-)
diff --git a/drivers/gpu/drm/i915/Kconfig.profile b/drivers/gpu/drm/i915/Kconfig.profile index 39328567c200..7cc38d25ee5c 100644 --- a/drivers/gpu/drm/i915/Kconfig.profile +++ b/drivers/gpu/drm/i915/Kconfig.profile @@ -57,10 +57,28 @@ config DRM_I915_PREEMPT_TIMEOUT default 640 # milliseconds help How long to wait (in milliseconds) for a preemption event to occur
when submitting a new context via execlists. If the current context
does not hit an arbitration point and yield to HW before the timer
expires, the HW will be reset to allow the more important context
to execute.
when submitting a new context. If the current context does not hit
an arbitration point and yield to HW before the timer expires, the
HW will be reset to allow the more important context to execute.
This is adjustable via
/sys/class/drm/card?/engine/*/preempt_timeout_ms
May be 0 to disable the timeout.
The compiled in default may get overridden at driver probe time on
certain platforms and certain engines which will be reflected in the
sysfs control.
+config DRM_I915_PREEMPT_TIMEOUT_COMPUTE
int "Preempt timeout for compute engines (ms, jiffy granularity)"
default 7500 # milliseconds
help
How long to wait (in milliseconds) for a preemption event to occur
when submitting a new context to a compute capable engine. If the
current context does not hit an arbitration point and yield to HW
before the timer expires, the HW will be reset to allow the more
important context to execute.
This is adjustable via /sys/class/drm/card?/engine/*/preempt_timeout_ms
diff --git a/drivers/gpu/drm/i915/gt/intel_engine_cs.c b/drivers/gpu/drm/i915/gt/intel_engine_cs.c index 4185c7338581..cc0954ad836a 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/gt/intel_engine_cs.c @@ -438,9 +438,14 @@ static int intel_engine_setup(struct intel_gt *gt, enum intel_engine_id id, engine->props.timeslice_duration_ms = CONFIG_DRM_I915_TIMESLICE_DURATION;
- /* Override to uninterruptible for OpenCL workloads. */
- /*
* Mid-thread pre-emption is not available in Gen12. Unfortunately,
* some OpenCL workloads run quite long threads. That means they get
* reset due to not pre-empting in a timely manner. So, bump the
* pre-emption timeout value to be much higher for compute engines.
if (GRAPHICS_VER(i915) == 12 && (engine->flags & I915_ENGINE_HAS_RCS_REG_STATE))*/
engine->props.preempt_timeout_ms = 0;
engine->props.preempt_timeout_ms = CONFIG_DRM_I915_PREEMPT_TIMEOUT_COMPUTE;
I wouldn't go as far as adding a config option since as it is it only applies to Gen12 but Kconfig text says nothing about that. And I am not saying you should add a Gen12 specific config option, that would be weird. So IMO just drop it.
Regards,
Tvrtko
/* Cap properties according to any system limits */ #define CLAMP_PROP(field) \
On 3/8/2022 01:41, Tvrtko Ursulin wrote:
On 03/03/2022 22:37, John.C.Harrison@Intel.com wrote:
From: John Harrison John.C.Harrison@Intel.com
A workaround was added to the driver to allow OpenCL workloads to run 'forever' by disabling pre-emption on the RCS engine for Gen12. It is not totally unbound as the heartbeat will kick in eventually and cause a reset of the hung engine.
However, this does not work well in GuC submission mode. In GuC mode, the pre-emption timeout is how GuC detects hung contexts and triggers a per engine reset. Thus, disabling the timeout means also losing all per engine reset ability. A full GT reset will still occur when the heartbeat finally expires, but that is a much more destructive and undesirable mechanism.
The purpose of the workaround is actually to give OpenCL tasks longer to reach a pre-emption point after a pre-emption request has been issued. This is necessary because Gen12 does not support mid-thread pre-emption and OpenCL can have long running threads.
So, rather than disabling the timeout completely, just set it to a 'long' value.
v2: Review feedback from Tvrtko - must hard code the 'long' value instead of determining it algorithmically. So make it an extra CONFIG definition. Also, remove the execlist centric comment from the existing pre-emption timeout CONFIG option given that it applies to more than just execlists.
Signed-off-by: John Harrison John.C.Harrison@Intel.com Reviewed-by: Daniele Ceraolo Spurio daniele.ceraolospurio@intel.com (v1) Acked-by: Michal Mrozek michal.mrozek@intel.com
drivers/gpu/drm/i915/Kconfig.profile | 26 +++++++++++++++++++---- drivers/gpu/drm/i915/gt/intel_engine_cs.c | 9 ++++++-- 2 files changed, 29 insertions(+), 6 deletions(-)
diff --git a/drivers/gpu/drm/i915/Kconfig.profile b/drivers/gpu/drm/i915/Kconfig.profile index 39328567c200..7cc38d25ee5c 100644 --- a/drivers/gpu/drm/i915/Kconfig.profile +++ b/drivers/gpu/drm/i915/Kconfig.profile @@ -57,10 +57,28 @@ config DRM_I915_PREEMPT_TIMEOUT default 640 # milliseconds help How long to wait (in milliseconds) for a preemption event to occur - when submitting a new context via execlists. If the current context - does not hit an arbitration point and yield to HW before the timer - expires, the HW will be reset to allow the more important context - to execute. + when submitting a new context. If the current context does not hit + an arbitration point and yield to HW before the timer expires, the + HW will be reset to allow the more important context to execute.
+ This is adjustable via + /sys/class/drm/card?/engine/*/preempt_timeout_ms
+ May be 0 to disable the timeout.
+ The compiled in default may get overridden at driver probe time on + certain platforms and certain engines which will be reflected in the + sysfs control.
+config DRM_I915_PREEMPT_TIMEOUT_COMPUTE + int "Preempt timeout for compute engines (ms, jiffy granularity)" + default 7500 # milliseconds + help + How long to wait (in milliseconds) for a preemption event to occur + when submitting a new context to a compute capable engine. If the + current context does not hit an arbitration point and yield to HW + before the timer expires, the HW will be reset to allow the more + important context to execute. This is adjustable via /sys/class/drm/card?/engine/*/preempt_timeout_ms diff --git a/drivers/gpu/drm/i915/gt/intel_engine_cs.c b/drivers/gpu/drm/i915/gt/intel_engine_cs.c index 4185c7338581..cc0954ad836a 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/gt/intel_engine_cs.c @@ -438,9 +438,14 @@ static int intel_engine_setup(struct intel_gt *gt, enum intel_engine_id id, engine->props.timeslice_duration_ms = CONFIG_DRM_I915_TIMESLICE_DURATION; - /* Override to uninterruptible for OpenCL workloads. */ + /* + * Mid-thread pre-emption is not available in Gen12. Unfortunately, + * some OpenCL workloads run quite long threads. That means they get + * reset due to not pre-empting in a timely manner. So, bump the + * pre-emption timeout value to be much higher for compute engines. + */ if (GRAPHICS_VER(i915) == 12 && (engine->flags & I915_ENGINE_HAS_RCS_REG_STATE)) - engine->props.preempt_timeout_ms = 0; + engine->props.preempt_timeout_ms = CONFIG_DRM_I915_PREEMPT_TIMEOUT_COMPUTE;
I wouldn't go as far as adding a config option since as it is it only applies to Gen12 but Kconfig text says nothing about that. And I am not saying you should add a Gen12 specific config option, that would be weird. So IMO just drop it.
You were the one arguing that the driver was illegally overriding the user's explicitly chosen settings, including the compile time config options. Just having a hardcoded magic number in the driver is the absolute worst kind of override there is.
And technically, the config option is not Gen12 specific. It is actually compute specific, hence the name. It just so happens that only Gen12 onwards has compute engines. I can add an extra line to the Kconfig description if you want "NB: compute engines only exist on Gen12 but do include the RCS engine on Gen12".
John.
Regards,
Tvrtko
/* Cap properties according to any system limits */ #define CLAMP_PROP(field) \
On 09/03/2022 21:16, John Harrison wrote:
On 3/8/2022 01:41, Tvrtko Ursulin wrote:
On 03/03/2022 22:37, John.C.Harrison@Intel.com wrote:
From: John Harrison John.C.Harrison@Intel.com
A workaround was added to the driver to allow OpenCL workloads to run 'forever' by disabling pre-emption on the RCS engine for Gen12. It is not totally unbound as the heartbeat will kick in eventually and cause a reset of the hung engine.
However, this does not work well in GuC submission mode. In GuC mode, the pre-emption timeout is how GuC detects hung contexts and triggers a per engine reset. Thus, disabling the timeout means also losing all per engine reset ability. A full GT reset will still occur when the heartbeat finally expires, but that is a much more destructive and undesirable mechanism.
The purpose of the workaround is actually to give OpenCL tasks longer to reach a pre-emption point after a pre-emption request has been issued. This is necessary because Gen12 does not support mid-thread pre-emption and OpenCL can have long running threads.
So, rather than disabling the timeout completely, just set it to a 'long' value.
v2: Review feedback from Tvrtko - must hard code the 'long' value instead of determining it algorithmically. So make it an extra CONFIG definition. Also, remove the execlist centric comment from the existing pre-emption timeout CONFIG option given that it applies to more than just execlists.
Signed-off-by: John Harrison John.C.Harrison@Intel.com Reviewed-by: Daniele Ceraolo Spurio daniele.ceraolospurio@intel.com (v1) Acked-by: Michal Mrozek michal.mrozek@intel.com
drivers/gpu/drm/i915/Kconfig.profile | 26 +++++++++++++++++++---- drivers/gpu/drm/i915/gt/intel_engine_cs.c | 9 ++++++-- 2 files changed, 29 insertions(+), 6 deletions(-)
diff --git a/drivers/gpu/drm/i915/Kconfig.profile b/drivers/gpu/drm/i915/Kconfig.profile index 39328567c200..7cc38d25ee5c 100644 --- a/drivers/gpu/drm/i915/Kconfig.profile +++ b/drivers/gpu/drm/i915/Kconfig.profile @@ -57,10 +57,28 @@ config DRM_I915_PREEMPT_TIMEOUT default 640 # milliseconds help How long to wait (in milliseconds) for a preemption event to occur - when submitting a new context via execlists. If the current context - does not hit an arbitration point and yield to HW before the timer - expires, the HW will be reset to allow the more important context - to execute. + when submitting a new context. If the current context does not hit + an arbitration point and yield to HW before the timer expires, the + HW will be reset to allow the more important context to execute.
+ This is adjustable via + /sys/class/drm/card?/engine/*/preempt_timeout_ms
+ May be 0 to disable the timeout.
+ The compiled in default may get overridden at driver probe time on + certain platforms and certain engines which will be reflected in the + sysfs control.
+config DRM_I915_PREEMPT_TIMEOUT_COMPUTE + int "Preempt timeout for compute engines (ms, jiffy granularity)" + default 7500 # milliseconds + help + How long to wait (in milliseconds) for a preemption event to occur + when submitting a new context to a compute capable engine. If the + current context does not hit an arbitration point and yield to HW + before the timer expires, the HW will be reset to allow the more + important context to execute. This is adjustable via /sys/class/drm/card?/engine/*/preempt_timeout_ms diff --git a/drivers/gpu/drm/i915/gt/intel_engine_cs.c b/drivers/gpu/drm/i915/gt/intel_engine_cs.c index 4185c7338581..cc0954ad836a 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/gt/intel_engine_cs.c @@ -438,9 +438,14 @@ static int intel_engine_setup(struct intel_gt *gt, enum intel_engine_id id, engine->props.timeslice_duration_ms = CONFIG_DRM_I915_TIMESLICE_DURATION; - /* Override to uninterruptible for OpenCL workloads. */ + /* + * Mid-thread pre-emption is not available in Gen12. Unfortunately, + * some OpenCL workloads run quite long threads. That means they get + * reset due to not pre-empting in a timely manner. So, bump the + * pre-emption timeout value to be much higher for compute engines. + */ if (GRAPHICS_VER(i915) == 12 && (engine->flags & I915_ENGINE_HAS_RCS_REG_STATE)) - engine->props.preempt_timeout_ms = 0; + engine->props.preempt_timeout_ms = CONFIG_DRM_I915_PREEMPT_TIMEOUT_COMPUTE;
I wouldn't go as far as adding a config option since as it is it only applies to Gen12 but Kconfig text says nothing about that. And I am not saying you should add a Gen12 specific config option, that would be weird. So IMO just drop it.
You were the one arguing that the driver was illegally overriding the user's explicitly chosen settings, including the compile time config
This is a bit out of context and illegally don't think used, so misrepresents the earlier discussion. And I certainly did not suggest a kconfig option.
options. Just having a hardcoded magic number in the driver is the absolute worst kind of override there is.
And technically, the config option is not Gen12 specific. It is actually compute specific, hence the name. It just so happens that only Gen12 onwards has compute engines. I can add an extra line to the Kconfig description if you want "NB: compute engines only exist on Gen12 but do include the RCS engine on Gen12".
I am not unconditionally against it but it feels it creates more problems than gives solutions.
In kconfig help you say "compute *capable* engine". Here you say only Gen12 has compute engines. Well before Gen12 render is compute capable, but then how implemented it does not apply which is not good.
Given the runtime override has the only purpose of working around broken hardware then I'd still say to drop it. But if you can come up with help text which won't be misleading and still not overly complicated I am not opposing it.
Regards,
Tvrtko
On 3/10/2022 01:27, Tvrtko Ursulin wrote:
On 09/03/2022 21:16, John Harrison wrote:
On 3/8/2022 01:41, Tvrtko Ursulin wrote:
On 03/03/2022 22:37, John.C.Harrison@Intel.com wrote:
From: John Harrison John.C.Harrison@Intel.com
A workaround was added to the driver to allow OpenCL workloads to run 'forever' by disabling pre-emption on the RCS engine for Gen12. It is not totally unbound as the heartbeat will kick in eventually and cause a reset of the hung engine.
However, this does not work well in GuC submission mode. In GuC mode, the pre-emption timeout is how GuC detects hung contexts and triggers a per engine reset. Thus, disabling the timeout means also losing all per engine reset ability. A full GT reset will still occur when the heartbeat finally expires, but that is a much more destructive and undesirable mechanism.
The purpose of the workaround is actually to give OpenCL tasks longer to reach a pre-emption point after a pre-emption request has been issued. This is necessary because Gen12 does not support mid-thread pre-emption and OpenCL can have long running threads.
So, rather than disabling the timeout completely, just set it to a 'long' value.
v2: Review feedback from Tvrtko - must hard code the 'long' value instead of determining it algorithmically. So make it an extra CONFIG definition. Also, remove the execlist centric comment from the existing pre-emption timeout CONFIG option given that it applies to more than just execlists.
Signed-off-by: John Harrison John.C.Harrison@Intel.com Reviewed-by: Daniele Ceraolo Spurio daniele.ceraolospurio@intel.com (v1) Acked-by: Michal Mrozek michal.mrozek@intel.com
drivers/gpu/drm/i915/Kconfig.profile | 26 +++++++++++++++++++---- drivers/gpu/drm/i915/gt/intel_engine_cs.c | 9 ++++++-- 2 files changed, 29 insertions(+), 6 deletions(-)
diff --git a/drivers/gpu/drm/i915/Kconfig.profile b/drivers/gpu/drm/i915/Kconfig.profile index 39328567c200..7cc38d25ee5c 100644 --- a/drivers/gpu/drm/i915/Kconfig.profile +++ b/drivers/gpu/drm/i915/Kconfig.profile @@ -57,10 +57,28 @@ config DRM_I915_PREEMPT_TIMEOUT default 640 # milliseconds help How long to wait (in milliseconds) for a preemption event to occur - when submitting a new context via execlists. If the current context - does not hit an arbitration point and yield to HW before the timer - expires, the HW will be reset to allow the more important context - to execute. + when submitting a new context. If the current context does not hit + an arbitration point and yield to HW before the timer expires, the + HW will be reset to allow the more important context to execute.
+ This is adjustable via + /sys/class/drm/card?/engine/*/preempt_timeout_ms
+ May be 0 to disable the timeout.
+ The compiled in default may get overridden at driver probe time on + certain platforms and certain engines which will be reflected in the + sysfs control.
+config DRM_I915_PREEMPT_TIMEOUT_COMPUTE + int "Preempt timeout for compute engines (ms, jiffy granularity)" + default 7500 # milliseconds + help + How long to wait (in milliseconds) for a preemption event to occur + when submitting a new context to a compute capable engine. If the + current context does not hit an arbitration point and yield to HW + before the timer expires, the HW will be reset to allow the more + important context to execute. This is adjustable via /sys/class/drm/card?/engine/*/preempt_timeout_ms diff --git a/drivers/gpu/drm/i915/gt/intel_engine_cs.c b/drivers/gpu/drm/i915/gt/intel_engine_cs.c index 4185c7338581..cc0954ad836a 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/gt/intel_engine_cs.c @@ -438,9 +438,14 @@ static int intel_engine_setup(struct intel_gt *gt, enum intel_engine_id id, engine->props.timeslice_duration_ms = CONFIG_DRM_I915_TIMESLICE_DURATION; - /* Override to uninterruptible for OpenCL workloads. */ + /* + * Mid-thread pre-emption is not available in Gen12. Unfortunately, + * some OpenCL workloads run quite long threads. That means they get + * reset due to not pre-empting in a timely manner. So, bump the + * pre-emption timeout value to be much higher for compute engines. + */ if (GRAPHICS_VER(i915) == 12 && (engine->flags & I915_ENGINE_HAS_RCS_REG_STATE)) - engine->props.preempt_timeout_ms = 0; + engine->props.preempt_timeout_ms = CONFIG_DRM_I915_PREEMPT_TIMEOUT_COMPUTE;
I wouldn't go as far as adding a config option since as it is it only applies to Gen12 but Kconfig text says nothing about that. And I am not saying you should add a Gen12 specific config option, that would be weird. So IMO just drop it.
You were the one arguing that the driver was illegally overriding the user's explicitly chosen settings, including the compile time config
This is a bit out of context and illegally don't think used, so misrepresents the earlier discussion. And I certainly did not suggest a kconfig option.
My recollection is that you clearly stated the i915 driver should not be overriding the user's settings. To me, that makes any override an illegal operation.
You did not suggest a Kconfig option but the settings in question are all coming from existing Kconfig options. Putting an explicit "timeout = 7500;" in the code is the worst of all worlds. It is an override of a user setting and it is an unmodifiable magic number. The first you have stated is not allowed and the second is one of the biggest no-no's of any code review. Magic number randomly splatted in the code? Nack, do it properly.
So in this case, I don't see that there is much choice except to add a new Kconfig option for the override.
options. Just having a hardcoded magic number in the driver is the absolute worst kind of override there is.
And technically, the config option is not Gen12 specific. It is actually compute specific, hence the name. It just so happens that only Gen12 onwards has compute engines. I can add an extra line to the Kconfig description if you want "NB: compute engines only exist on Gen12 but do include the RCS engine on Gen12".
I am not unconditionally against it but it feels it creates more problems than gives solutions.
In kconfig help you say "compute *capable* engine". Here you say only Gen12 has compute engines. Well before Gen12 render is compute capable, but then how implemented it does not apply which is not good.
Sorry, yes. For some reason I was thinking compute came in with Gen12.
Given the runtime override has the only purpose of working around broken hardware then I'd still say to drop it. But if you can come up with help text which won't be misleading and still not overly complicated I am not opposing it.
So "when submitting a new context to a compute capable engine on Gen12 and later platforms"? And maybe add a _GEN12 suffix to the config name itself?
John.
Regards,
Tvrtko
On 10/03/2022 20:24, John Harrison wrote:
On 3/10/2022 01:27, Tvrtko Ursulin wrote:
On 09/03/2022 21:16, John Harrison wrote:
On 3/8/2022 01:41, Tvrtko Ursulin wrote:
On 03/03/2022 22:37, John.C.Harrison@Intel.com wrote:
From: John Harrison John.C.Harrison@Intel.com
A workaround was added to the driver to allow OpenCL workloads to run 'forever' by disabling pre-emption on the RCS engine for Gen12. It is not totally unbound as the heartbeat will kick in eventually and cause a reset of the hung engine.
However, this does not work well in GuC submission mode. In GuC mode, the pre-emption timeout is how GuC detects hung contexts and triggers a per engine reset. Thus, disabling the timeout means also losing all per engine reset ability. A full GT reset will still occur when the heartbeat finally expires, but that is a much more destructive and undesirable mechanism.
The purpose of the workaround is actually to give OpenCL tasks longer to reach a pre-emption point after a pre-emption request has been issued. This is necessary because Gen12 does not support mid-thread pre-emption and OpenCL can have long running threads.
So, rather than disabling the timeout completely, just set it to a 'long' value.
v2: Review feedback from Tvrtko - must hard code the 'long' value instead of determining it algorithmically. So make it an extra CONFIG definition. Also, remove the execlist centric comment from the existing pre-emption timeout CONFIG option given that it applies to more than just execlists.
Signed-off-by: John Harrison John.C.Harrison@Intel.com Reviewed-by: Daniele Ceraolo Spurio daniele.ceraolospurio@intel.com (v1) Acked-by: Michal Mrozek michal.mrozek@intel.com
drivers/gpu/drm/i915/Kconfig.profile | 26 +++++++++++++++++++---- drivers/gpu/drm/i915/gt/intel_engine_cs.c | 9 ++++++-- 2 files changed, 29 insertions(+), 6 deletions(-)
diff --git a/drivers/gpu/drm/i915/Kconfig.profile b/drivers/gpu/drm/i915/Kconfig.profile index 39328567c200..7cc38d25ee5c 100644 --- a/drivers/gpu/drm/i915/Kconfig.profile +++ b/drivers/gpu/drm/i915/Kconfig.profile @@ -57,10 +57,28 @@ config DRM_I915_PREEMPT_TIMEOUT default 640 # milliseconds help How long to wait (in milliseconds) for a preemption event to occur - when submitting a new context via execlists. If the current context - does not hit an arbitration point and yield to HW before the timer - expires, the HW will be reset to allow the more important context - to execute. + when submitting a new context. If the current context does not hit + an arbitration point and yield to HW before the timer expires, the + HW will be reset to allow the more important context to execute.
+ This is adjustable via + /sys/class/drm/card?/engine/*/preempt_timeout_ms
+ May be 0 to disable the timeout.
+ The compiled in default may get overridden at driver probe time on + certain platforms and certain engines which will be reflected in the + sysfs control.
+config DRM_I915_PREEMPT_TIMEOUT_COMPUTE + int "Preempt timeout for compute engines (ms, jiffy granularity)" + default 7500 # milliseconds + help + How long to wait (in milliseconds) for a preemption event to occur + when submitting a new context to a compute capable engine. If the + current context does not hit an arbitration point and yield to HW + before the timer expires, the HW will be reset to allow the more + important context to execute. This is adjustable via /sys/class/drm/card?/engine/*/preempt_timeout_ms diff --git a/drivers/gpu/drm/i915/gt/intel_engine_cs.c b/drivers/gpu/drm/i915/gt/intel_engine_cs.c index 4185c7338581..cc0954ad836a 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/gt/intel_engine_cs.c @@ -438,9 +438,14 @@ static int intel_engine_setup(struct intel_gt *gt, enum intel_engine_id id, engine->props.timeslice_duration_ms = CONFIG_DRM_I915_TIMESLICE_DURATION; - /* Override to uninterruptible for OpenCL workloads. */ + /* + * Mid-thread pre-emption is not available in Gen12. Unfortunately, + * some OpenCL workloads run quite long threads. That means they get + * reset due to not pre-empting in a timely manner. So, bump the + * pre-emption timeout value to be much higher for compute engines. + */ if (GRAPHICS_VER(i915) == 12 && (engine->flags & I915_ENGINE_HAS_RCS_REG_STATE)) - engine->props.preempt_timeout_ms = 0; + engine->props.preempt_timeout_ms = CONFIG_DRM_I915_PREEMPT_TIMEOUT_COMPUTE;
I wouldn't go as far as adding a config option since as it is it only applies to Gen12 but Kconfig text says nothing about that. And I am not saying you should add a Gen12 specific config option, that would be weird. So IMO just drop it.
You were the one arguing that the driver was illegally overriding the user's explicitly chosen settings, including the compile time config
This is a bit out of context and illegally don't think used, so misrepresents the earlier discussion. And I certainly did not suggest a kconfig option.
My recollection is that you clearly stated the i915 driver should not be overriding the user's settings. To me, that makes any override an illegal operation.
You did not suggest a Kconfig option but the settings in question are all coming from existing Kconfig options. Putting an explicit "timeout = 7500;" in the code is the worst of all worlds. It is an override of a user setting and it is an unmodifiable magic number. The first you have stated is not allowed and the second is one of the biggest no-no's of any code review. Magic number randomly splatted in the code? Nack, do it properly.
So in this case, I don't see that there is much choice except to add a new Kconfig option for the override.
From memory, I don't think I said override is not allowed. I used the override argument in a different context. But honestly I don't feel like digging that up at this point since this is just going on for too long.
In principle adding kconfig options should be avoided and in this case question is cost vs benefit. What is the benefit? Who will tune it, why, and using what knowledge?
I have asked if we can get compute UMD to give us some numbers relating to typical desktop workloads but did not get anything.
Currently we override to zero, which is what they wanted. Now we are thinking of overriding to 7.5s, which they acked, but it's not very transparent what is the thinking behind it.
It simply looks we said 7.5s because that's what gives similar worst case before reset compared to existing out of the box setup, while allowing GuC engine resets to actually work.
I'd personally go for 2.5s, for the same weak reasons of it being similar to existing timeout, and extension of every heartbeat interval. But you thought 2.5s was too short, I guess, or preferred to view heartbeat as decoupled timeline (barring the last one which *has* to couple). Which is fine by me. So we agreed to compromise on that and moved on.
So meh. What we end up with is not worse than it was and not having a kconfig saves you a complication...
options. Just having a hardcoded magic number in the driver is the absolute worst kind of override there is.
And technically, the config option is not Gen12 specific. It is actually compute specific, hence the name. It just so happens that only Gen12 onwards has compute engines. I can add an extra line to the Kconfig description if you want "NB: compute engines only exist on Gen12 but do include the RCS engine on Gen12".
I am not unconditionally against it but it feels it creates more problems than gives solutions.
In kconfig help you say "compute *capable* engine". Here you say only Gen12 has compute engines. Well before Gen12 render is compute capable, but then how implemented it does not apply which is not good.
Sorry, yes. For some reason I was thinking compute came in with Gen12.
Given the runtime override has the only purpose of working around broken hardware then I'd still say to drop it. But if you can come up with help text which won't be misleading and still not overly complicated I am not opposing it.
So "when submitting a new context to a compute capable engine on Gen12 and later platforms"? And maybe add a _GEN12 suffix to the config name itself?
..."and later" would be wrong, you'd have to change it at some point. Not least that the patch as proposed does "== 12", not ">= 12". And we can't use the term Gen right? List all the affected platform names? Keep patching up the help text as platforms are added? Or do we know the end point already?
In summary, I will not oppose it if we can have a kconfig text which is accurate, useful and not a maintenance burden.
Regards,
Tvrtko
On 11/03/2022 10:07, Tvrtko Ursulin wrote:
On 10/03/2022 20:24, John Harrison wrote:
On 3/10/2022 01:27, Tvrtko Ursulin wrote:
On 09/03/2022 21:16, John Harrison wrote:
On 3/8/2022 01:41, Tvrtko Ursulin wrote:
On 03/03/2022 22:37, John.C.Harrison@Intel.com wrote:
From: John Harrison John.C.Harrison@Intel.com
A workaround was added to the driver to allow OpenCL workloads to run 'forever' by disabling pre-emption on the RCS engine for Gen12. It is not totally unbound as the heartbeat will kick in eventually and cause a reset of the hung engine.
However, this does not work well in GuC submission mode. In GuC mode, the pre-emption timeout is how GuC detects hung contexts and triggers a per engine reset. Thus, disabling the timeout means also losing all per engine reset ability. A full GT reset will still occur when the heartbeat finally expires, but that is a much more destructive and undesirable mechanism.
The purpose of the workaround is actually to give OpenCL tasks longer to reach a pre-emption point after a pre-emption request has been issued. This is necessary because Gen12 does not support mid-thread pre-emption and OpenCL can have long running threads.
So, rather than disabling the timeout completely, just set it to a 'long' value.
v2: Review feedback from Tvrtko - must hard code the 'long' value instead of determining it algorithmically. So make it an extra CONFIG definition. Also, remove the execlist centric comment from the existing pre-emption timeout CONFIG option given that it applies to more than just execlists.
Signed-off-by: John Harrison John.C.Harrison@Intel.com Reviewed-by: Daniele Ceraolo Spurio daniele.ceraolospurio@intel.com (v1) Acked-by: Michal Mrozek michal.mrozek@intel.com
drivers/gpu/drm/i915/Kconfig.profile | 26 +++++++++++++++++++---- drivers/gpu/drm/i915/gt/intel_engine_cs.c | 9 ++++++-- 2 files changed, 29 insertions(+), 6 deletions(-)
diff --git a/drivers/gpu/drm/i915/Kconfig.profile b/drivers/gpu/drm/i915/Kconfig.profile index 39328567c200..7cc38d25ee5c 100644 --- a/drivers/gpu/drm/i915/Kconfig.profile +++ b/drivers/gpu/drm/i915/Kconfig.profile @@ -57,10 +57,28 @@ config DRM_I915_PREEMPT_TIMEOUT default 640 # milliseconds help How long to wait (in milliseconds) for a preemption event to occur - when submitting a new context via execlists. If the current context - does not hit an arbitration point and yield to HW before the timer - expires, the HW will be reset to allow the more important context - to execute. + when submitting a new context. If the current context does not hit + an arbitration point and yield to HW before the timer expires, the + HW will be reset to allow the more important context to execute.
+ This is adjustable via + /sys/class/drm/card?/engine/*/preempt_timeout_ms
+ May be 0 to disable the timeout.
+ The compiled in default may get overridden at driver probe time on + certain platforms and certain engines which will be reflected in the + sysfs control.
+config DRM_I915_PREEMPT_TIMEOUT_COMPUTE + int "Preempt timeout for compute engines (ms, jiffy granularity)" + default 7500 # milliseconds + help + How long to wait (in milliseconds) for a preemption event to occur + when submitting a new context to a compute capable engine. If the + current context does not hit an arbitration point and yield to HW + before the timer expires, the HW will be reset to allow the more + important context to execute. This is adjustable via /sys/class/drm/card?/engine/*/preempt_timeout_ms diff --git a/drivers/gpu/drm/i915/gt/intel_engine_cs.c b/drivers/gpu/drm/i915/gt/intel_engine_cs.c index 4185c7338581..cc0954ad836a 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/gt/intel_engine_cs.c @@ -438,9 +438,14 @@ static int intel_engine_setup(struct intel_gt *gt, enum intel_engine_id id, engine->props.timeslice_duration_ms = CONFIG_DRM_I915_TIMESLICE_DURATION; - /* Override to uninterruptible for OpenCL workloads. */ + /* + * Mid-thread pre-emption is not available in Gen12. Unfortunately, + * some OpenCL workloads run quite long threads. That means they get + * reset due to not pre-empting in a timely manner. So, bump the + * pre-emption timeout value to be much higher for compute engines. + */ if (GRAPHICS_VER(i915) == 12 && (engine->flags & I915_ENGINE_HAS_RCS_REG_STATE)) - engine->props.preempt_timeout_ms = 0; + engine->props.preempt_timeout_ms = CONFIG_DRM_I915_PREEMPT_TIMEOUT_COMPUTE;
I wouldn't go as far as adding a config option since as it is it only applies to Gen12 but Kconfig text says nothing about that. And I am not saying you should add a Gen12 specific config option, that would be weird. So IMO just drop it.
You were the one arguing that the driver was illegally overriding the user's explicitly chosen settings, including the compile time config
This is a bit out of context and illegally don't think used, so misrepresents the earlier discussion. And I certainly did not suggest a kconfig option.
My recollection is that you clearly stated the i915 driver should not be overriding the user's settings. To me, that makes any override an illegal operation.
You did not suggest a Kconfig option but the settings in question are all coming from existing Kconfig options. Putting an explicit "timeout = 7500;" in the code is the worst of all worlds. It is an override of a user setting and it is an unmodifiable magic number. The first you have stated is not allowed and the second is one of the biggest no-no's of any code review. Magic number randomly splatted in the code? Nack, do it properly.
So in this case, I don't see that there is much choice except to add a new Kconfig option for the override.
From memory, I don't think I said override is not allowed. I used the override argument in a different context. But honestly I don't feel like digging that up at this point since this is just going on for too long.
In principle adding kconfig options should be avoided and in this case question is cost vs benefit. What is the benefit? Who will tune it, why, and using what knowledge?
I have asked if we can get compute UMD to give us some numbers relating to typical desktop workloads but did not get anything.
Currently we override to zero, which is what they wanted. Now we are thinking of overriding to 7.5s, which they acked, but it's not very transparent what is the thinking behind it.
It simply looks we said 7.5s because that's what gives similar worst case before reset compared to existing out of the box setup, while allowing GuC engine resets to actually work.
I'd personally go for 2.5s, for the same weak reasons of it being similar to existing timeout, and extension of every heartbeat interval. But you thought 2.5s was too short, I guess, or preferred to view heartbeat as decoupled timeline (barring the last one which *has* to couple). Which is fine by me. So we agreed to compromise on that and moved on.
So meh. What we end up with is not worse than it was and not having a kconfig saves you a complication...
options. Just having a hardcoded magic number in the driver is the absolute worst kind of override there is.
And technically, the config option is not Gen12 specific. It is actually compute specific, hence the name. It just so happens that only Gen12 onwards has compute engines. I can add an extra line to the Kconfig description if you want "NB: compute engines only exist on Gen12 but do include the RCS engine on Gen12".
I am not unconditionally against it but it feels it creates more problems than gives solutions.
In kconfig help you say "compute *capable* engine". Here you say only Gen12 has compute engines. Well before Gen12 render is compute capable, but then how implemented it does not apply which is not good.
Sorry, yes. For some reason I was thinking compute came in with Gen12.
Given the runtime override has the only purpose of working around broken hardware then I'd still say to drop it. But if you can come up with help text which won't be misleading and still not overly complicated I am not opposing it.
So "when submitting a new context to a compute capable engine on Gen12 and later platforms"? And maybe add a _GEN12 suffix to the config name itself?
..."and later" would be wrong, you'd have to change it at some point. Not least that the patch as proposed does "== 12", not ">= 12". And we can't use the term Gen right? List all the affected platform names? Keep patching up the help text as platforms are added? Or do we know the end point already?
In summary, I will not oppose it if we can have a kconfig text which is accurate, useful and not a maintenance burden.
Maybe avoid listing specifics and provide some guidance:
""" config DRM_I915_OVERRIDE_PREEMPT_TIMEOUT int "Override preempt timeout (ms, jiffy granularity)" default 7500 # milliseconds help On certain platforms and engines where supported preemption granularity is reduced due hardware limitations, a longer timeout than DRM_I915_PREEMPT_TIMEOUT (see respective help text) is required.
Shorter timeouts will have more chance of terminating legitimate workloads, while longer can have detrimental effect on desktop interactivity and ability to terminate hanging workloads in reasonable time.
Usage of the override timeout will be logged during driver probe for each affected engine. """
If approach is acceptable also feel free to reword and improve my English.
Not sure whether to have compute in the name of kconfig. But I do like override in the name, so if you add compute I think also keeping override is good since it works well with not having to mention platform specifics in kconfig and it signifies it is special case. Or maybe "workaround"?
Regards,
Tvrtko
dri-devel@lists.freedesktop.org