[RFC PATCH v3 15/21] drm/exec: Add a snapshot capability

Christian König christian.koenig at amd.com
Wed May 22 11:27:03 UTC 2024


Am 21.05.24 um 09:16 schrieb Thomas Hellström:
> When validating a buffer object for submission, we might need to lock
> a number of object for eviction to make room for the validation.
>
> This makes it pretty likely that validation will eventually succeed,
> since eventually the validating process will hold most dma_resv locks
> of the buffer objects residing in the memory type being validated for.
>
> However, once validation of a single object has succeeded it might not
> be beneficial to hold on to those locks anymore, and the validator
> would want to drop the locks of all objects taken during validation.

Exactly avoiding that was one of the goals of developing the drm_exec 
object.

When objects are unlocked after evicting them it just gives concurrent 
operations an opportunity to lock them and re-validate them into the 
contended domain.

So why should that approach here be beneficial at all?

Regards,
Christian.

>
> Introduce a drm_exec snapshot functionality that can be used to
> record the locks held at a certain time, and a restore functionality
> that restores the drm_exec state to the snapshot by dropping all
> locks.
>
> Snapshots can be nested if needed.
>
> Cc: Christian König <christian.koenig at amd.com>
> Cc: Somalapuram Amaranath <Amaranath.Somalapuram at amd.com>
> Cc: Matthew Brost <matthew.brost at intel.com>
> Cc: <dri-devel at lists.freedesktop.org>
> Signed-off-by: Thomas Hellström <thomas.hellstrom at linux.intel.com>
> ---
>   drivers/gpu/drm/drm_exec.c | 55 +++++++++++++++++++++++++++++++++++++-
>   include/drm/drm_exec.h     | 23 +++++++++++++++-
>   2 files changed, 76 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/gpu/drm/drm_exec.c b/drivers/gpu/drm/drm_exec.c
> index 1383680ffa4a..9eea5d0d3a98 100644
> --- a/drivers/gpu/drm/drm_exec.c
> +++ b/drivers/gpu/drm/drm_exec.c
> @@ -57,6 +57,7 @@ static void drm_exec_unlock_all(struct drm_exec *exec)
>   	struct drm_gem_object *obj;
>   	unsigned long index;
>   
> +	WARN_ON(exec->snap);
>   	drm_exec_for_each_locked_object_reverse(exec, index, obj) {
>   		dma_resv_unlock(obj->resv);
>   		drm_gem_object_put(obj);
> @@ -90,6 +91,7 @@ void drm_exec_init(struct drm_exec *exec, u32 flags, unsigned nr)
>   	exec->num_objects = 0;
>   	exec->contended = DRM_EXEC_DUMMY;
>   	exec->prelocked = NULL;
> +	exec->snap = NULL;
>   }
>   EXPORT_SYMBOL(drm_exec_init);
>   
> @@ -301,7 +303,6 @@ int drm_exec_lock_obj(struct drm_exec *exec, struct drm_gem_object *obj)
>   		goto error_unlock;
>   
>   	return 0;
> -
>   error_unlock:
>   	dma_resv_unlock(obj->resv);
>   	return ret;
> @@ -395,5 +396,57 @@ int drm_exec_prepare_array(struct drm_exec *exec,
>   }
>   EXPORT_SYMBOL(drm_exec_prepare_array);
>   
> +/**
> + * drm_exec_restore() - Restore the drm_exec state to the point of a snapshot.
> + * @exec: The drm_exec object with the state.
> + * @snap: The snapshot state.
> + *
> + * Restores the drm_exec object by means of unlocking and dropping references
> + * to objects locked after the snapshot.
> + */
> +void drm_exec_restore(struct drm_exec *exec, struct drm_exec_snapshot *snap)
> +{
> +	struct drm_gem_object *obj;
> +	unsigned int index;
> +
> +	exec->snap = snap->saved_snap;
> +
> +	drm_exec_for_each_locked_object_reverse(exec, index, obj) {
> +		if (index + 1 == snap->num_locked)
> +			break;
> +
> +		dma_resv_unlock(obj->resv);
> +		drm_gem_object_put(obj);
> +		exec->objects[index] = NULL;
> +	}
> +
> +	exec->num_objects = snap->num_locked;
> +
> +	if (!exec->prelocked)
> +		exec->prelocked = snap->prelocked;
> +	else
> +		drm_gem_object_put(snap->prelocked);
> +}
> +EXPORT_SYMBOL(drm_exec_restore);
> +
> +/**
> + * drm_exec_snapshot() - Take a snapshot of the drm_exec state
> + * @exec: The drm_exec object with the state.
> + * @snap: The snapshot state.
> + *
> + * Records the @exec state in @snap. The @snap object is typically allocated
> + * in the stack of the caller.
> + */
> +void drm_exec_snapshot(struct drm_exec *exec, struct drm_exec_snapshot *snap)
> +{
> +	snap->num_locked = exec->num_objects;
> +	snap->prelocked = exec->prelocked;
> +	if (snap->prelocked)
> +		drm_gem_object_get(snap->prelocked);
> +	snap->saved_snap = exec->snap;
> +	exec->snap = snap;
> +}
> +EXPORT_SYMBOL(drm_exec_snapshot);
> +
>   MODULE_DESCRIPTION("DRM execution context");
>   MODULE_LICENSE("Dual MIT/GPL");
> diff --git a/include/drm/drm_exec.h b/include/drm/drm_exec.h
> index ea0f2117ee0c..0ce4d749511b 100644
> --- a/include/drm/drm_exec.h
> +++ b/include/drm/drm_exec.h
> @@ -19,7 +19,6 @@ struct drm_exec {
>   	 * @flags: Flags to control locking behavior
>   	 */
>   	u32                     flags;
> -
>   	/**
>   	 * @ticket: WW ticket used for acquiring locks
>   	 */
> @@ -49,6 +48,25 @@ struct drm_exec {
>   	 * @prelocked: already locked GEM object due to contention
>   	 */
>   	struct drm_gem_object *prelocked;
> +
> +	/**
> +	 * @snap: Pointer to the last snapshot taken or NULL if none.
> +	 */
> +	struct drm_exec_snapshot *snap;
> +};
> +
> +/**
> + * struct drm_exec_snapshot - drm_exec snapshot information
> + */
> +struct drm_exec_snapshot {
> +	/** @saved_snap: Pointer to the previous snapshot or NULL. */
> +	struct drm_exec_snapshot *saved_snap;
> +
> +	/** @prelocked: Refcounted pointer to the prelocked object at snapshot time. */
> +	struct drm_gem_object *prelocked;
> +
> +	/** @num_locked: Number of locked objects at snapshot time. */
> +	unsigned long num_locked;
>   };
>   
>   int drm_exec_handle_contended(struct drm_exec *exec);
> @@ -160,5 +178,8 @@ int drm_exec_prepare_array(struct drm_exec *exec,
>   			   struct drm_gem_object **objects,
>   			   unsigned int num_objects,
>   			   unsigned int num_fences);
> +void drm_exec_snapshot(struct drm_exec *exec, struct drm_exec_snapshot *snap);
> +void drm_exec_restore(struct drm_exec *exec, struct drm_exec_snapshot *snap);
> +
>   
>   #endif



More information about the dri-devel mailing list