[igt-dev] [PATCH 1/7] drm/i915: Use seqlock in engine stats

Chris Wilson chris at chris-wilson.co.uk
Tue Apr 17 12:47:58 UTC 2018


Quoting Tvrtko Ursulin (2018-04-17 13:27:30)
> From: Tvrtko Ursulin <tvrtko.ursulin at intel.com>
> 
> We can convert engine stats from a spinlock to seqlock to ensure interrupt
> processing is never even a tiny bit delayed by parallel readers.
> 
> There is a smidgen bit more cost on the write lock side, and an extremely
> unlikely chance that readers will have to retry a few times in face of
> heavy interrupt load.Bbut it should be extremely unlikely given how
> lightweight read side section is compared to the interrupt processing side,
> and also compared to the rest of the code paths which can lead into it.

Also mention that readers are informative only, its the writers that are
doing the work/submission.

> Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin at intel.com>
> Suggested-by: Chris Wilson <chris at chris-wilson.co.uk>
> Cc: Chris Wilson <chris at chris-wilson.co.uk>
> ---
>  drivers/gpu/drm/i915/intel_engine_cs.c  | 19 ++++++++++---------
>  drivers/gpu/drm/i915/intel_ringbuffer.h | 11 ++++++-----
>  2 files changed, 16 insertions(+), 14 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/intel_engine_cs.c b/drivers/gpu/drm/i915/intel_engine_cs.c
> index e4992c2e23a4..de61d3d1653d 100644
> --- a/drivers/gpu/drm/i915/intel_engine_cs.c
> +++ b/drivers/gpu/drm/i915/intel_engine_cs.c
> @@ -306,7 +306,7 @@ intel_engine_setup(struct drm_i915_private *dev_priv,
>         /* Nothing to do here, execute in order of dependencies */
>         engine->schedule = NULL;
>  
> -       spin_lock_init(&engine->stats.lock);
> +       seqlock_init(&engine->stats.lock);
>  
>         ATOMIC_INIT_NOTIFIER_HEAD(&engine->context_status_notifier);
>  
> @@ -2065,7 +2065,7 @@ int intel_enable_engine_stats(struct intel_engine_cs *engine)
>                 return -ENODEV;
>  
>         tasklet_disable(&execlists->tasklet);
> -       spin_lock_irqsave(&engine->stats.lock, flags);
> +       write_seqlock_irqsave(&engine->stats.lock, flags);
>  
>         if (unlikely(engine->stats.enabled == ~0)) {
>                 err = -EBUSY;
> @@ -2089,7 +2089,7 @@ int intel_enable_engine_stats(struct intel_engine_cs *engine)
>         }
>  
>  unlock:
> -       spin_unlock_irqrestore(&engine->stats.lock, flags);
> +       write_sequnlock_irqrestore(&engine->stats.lock, flags);
>         tasklet_enable(&execlists->tasklet);
>  
>         return err;
> @@ -2118,12 +2118,13 @@ static ktime_t __intel_engine_get_busy_time(struct intel_engine_cs *engine)
>   */
>  ktime_t intel_engine_get_busy_time(struct intel_engine_cs *engine)
>  {
> +       unsigned int seq;
>         ktime_t total;
> -       unsigned long flags;
>  
> -       spin_lock_irqsave(&engine->stats.lock, flags);
> -       total = __intel_engine_get_busy_time(engine);
> -       spin_unlock_irqrestore(&engine->stats.lock, flags);
> +       do {
> +               seq = read_seqbegin(&engine->stats.lock);
> +               total = __intel_engine_get_busy_time(engine);
> +       } while (read_seqretry(&engine->stats.lock, seq));
>  
>         return total;
>  }
> @@ -2141,13 +2142,13 @@ void intel_disable_engine_stats(struct intel_engine_cs *engine)
>         if (!intel_engine_supports_stats(engine))
>                 return;
>  
> -       spin_lock_irqsave(&engine->stats.lock, flags);
> +       write_seqlock_irqsave(&engine->stats.lock, flags);
>         WARN_ON_ONCE(engine->stats.enabled == 0);
>         if (--engine->stats.enabled == 0) {
>                 engine->stats.total = __intel_engine_get_busy_time(engine);
>                 engine->stats.active = 0;
>         }
> -       spin_unlock_irqrestore(&engine->stats.lock, flags);
> +       write_sequnlock_irqrestore(&engine->stats.lock, flags);
>  }
>  
>  #if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
> diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h
> index d50b31eb43a5..f24ea9826037 100644
> --- a/drivers/gpu/drm/i915/intel_ringbuffer.h
> +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h
> @@ -3,6 +3,7 @@
>  #define _INTEL_RINGBUFFER_H_
>  
>  #include <linux/hashtable.h>
> +#include <linux/seqlock.h>
>  
>  #include "i915_gem_batch_pool.h"
>  #include "i915_gem_timeline.h"
> @@ -610,7 +611,7 @@ struct intel_engine_cs {
>                 /**
>                  * @lock: Lock protecting the below fields.
>                  */
> -               spinlock_t lock;
> +               seqlock_t lock;
>                 /**
>                  * @enabled: Reference count indicating number of listeners.
>                  */
> @@ -1082,7 +1083,7 @@ static inline void intel_engine_context_in(struct intel_engine_cs *engine)
>         if (READ_ONCE(engine->stats.enabled) == 0)
>                 return;
>  
> -       spin_lock_irqsave(&engine->stats.lock, flags);
> +       write_seqlock_irqsave(&engine->stats.lock, flags);
>  
>         if (engine->stats.enabled > 0) {
>                 if (engine->stats.active++ == 0)
> @@ -1090,7 +1091,7 @@ static inline void intel_engine_context_in(struct intel_engine_cs *engine)
>                 GEM_BUG_ON(engine->stats.active == 0);
>         }
>  
> -       spin_unlock_irqrestore(&engine->stats.lock, flags);
> +       write_sequnlock_irqrestore(&engine->stats.lock, flags);
>  }
>  
>  static inline void intel_engine_context_out(struct intel_engine_cs *engine)
> @@ -1100,7 +1101,7 @@ static inline void intel_engine_context_out(struct intel_engine_cs *engine)
>         if (READ_ONCE(engine->stats.enabled) == 0)
>                 return;
>  
> -       spin_lock_irqsave(&engine->stats.lock, flags);
> +       write_seqlock_irqsave(&engine->stats.lock, flags);
>  
>         if (engine->stats.enabled > 0) {
>                 ktime_t last;
> @@ -1127,7 +1128,7 @@ static inline void intel_engine_context_out(struct intel_engine_cs *engine)
>                 }
>         }
>  
> -       spin_unlock_irqrestore(&engine->stats.lock, flags);
> +       write_sequnlock_irqrestore(&engine->stats.lock, flags);
>  }

Reviewed-by: Chris Wilson <chris at chris-wilson.co.uk>

I think that's good enough as a stand-alone patch, even though we were
unable to realise the no irq_disable gains.
-Chris


More information about the igt-dev mailing list