[PATCH 1/8] drm: execution context for GEM buffers v2
Christian König
christian.koenig at amd.com
Mon May 9 15:01:33 UTC 2022
Am 09.05.22 um 16:31 schrieb Daniel Vetter:
> On Wed, May 04, 2022 at 09:47:32AM +0200, Christian König wrote:
>> [SNIP]
>> +/* Make sure we have enough room and add an object the container */
>> +static int drm_exec_objects_add(struct drm_exec_objects *container,
>> + struct drm_gem_object *obj)
>> +{
>> + if (unlikely(container->num_objects == container->max_objects)) {
>> + size_t size = container->max_objects * sizeof(void *);
>> + void *tmp;
>> +
>> + tmp = kvrealloc(container->objects, size, size + PAGE_SIZE,
>> + GFP_KERNEL);
>> + if (!tmp)
>> + return -ENOMEM;
>> +
>> + container->objects = tmp;
>> + container->max_objects += PAGE_SIZE / sizeof(void *);
> Might be worth it to inquire the actual allocation size here, since if
> it's kmalloc the generic buckets only cover doubling of sizes, so once
> it's big it goes up a lot quicker than PAGE_SIZE.
>
> But also krealloc checks this internally already so maybe better to not
> break the abstraction.
How can I actually do this? ksize() only works with kmalloc().
Or do we had a function to figure out if vmalloc or kmalloc was used by
kvrealloc()?
>> [SNIP]
>> +/**
>> + * drm_exec_cleanup - cleanup when contention is detected
>> + * @exec: the drm_exec object to cleanup
>> + *
>> + * Cleanup the current state and return true if we should stay inside the retry
>> + * loop, false if there wasn't any contention detected and we can keep the
>> + * objects locked.
>> + */
>> +bool drm_exec_cleanup(struct drm_exec *exec)
>> +{
>> + if (likely(!exec->contended)) {
>> + ww_acquire_done(&exec->ticket);
>> + return false;
>> + }
>> +
>> + if (likely(exec->contended == DRM_EXEC_DUMMY)) {
>> + exec->contended = NULL;
>> + ww_acquire_init(&exec->ticket, &reservation_ww_class);
> Not sure why this is here instead of in _init()? I thought you're playing
> some really dangerous tricks with re-initting the acquire ctx, which would
> at least be questionable, but does not look like that.
That was my initial design, but the problem with this approach is that
all locks taken between drm_exec_init() and the loop suddenly have a
lockdep dependency on reservation_ww_class. And that in turn goes boom
immediately.
Took me a moment to realize what's wrong with that as well.
> [SNIP]
> +/**
> + * drm_exec_has_duplicates - check for duplicated GEM object
> + * @exec: drm_exec object
> + *
> + * Return true if the drm_exec object has encountered some already locked GEM
> + * objects while trying to lock them. This can happen if multiple GEM objects
> + * share the same underlying resv object.
> + */
> +static inline bool drm_exec_has_duplicates(struct drm_exec *exec)
> +{
> + return exec->duplicates.num_objects > 0;
> Definitely an aside, but in our i915 efforts to get rid of temporary pins
> we run into some fun where the eviction code couldn't differentiate from
> memory we need reserved for the CS and memory we just keep locked because
> we evicted it and fun stuff like that. So maybe we need a bit more
> tracking here eventually, but that's only when we have this somehow glued
> into ttm eviction code.
Hehe, yeah that's what I was thinking about as well. But then I though
one step at a time.
> Also the even more massive step would be to glue this into dma-buf so you
> can do dynamic dma-buf eviction and still keep track of all the buffers. I
> think with some clever pointer tagging and a bit more indirection we could
> nest drm_exec structures (so that a driver could insert it's entire
> drm_exec structure with a drm_exec-level callback for handling refcounting
> and stuff like that).
I considered in which component to put this quite a bit as well, but
then intentionally decided against DMA-buf.
One major reason was that not all buffers which needs to be locked this
way are actually exported as DMA-buf.
Another reason is that DMA-buf doesn't necessary need a concept of an
execution context. As far as I can see that's something GPU/DRM driver
specific.
> So anyway I think this all looks good, just one more thing before I think
> we should land this:
>
> gem helpers in drm_gem_lock_reservations() has something which is
> practically compatible already, except that you bulk-add the entire set of
> objects. I think if you add a bulk-prepare function then we could also
> replace all those. Maybe even nicer if the bulk-prepare takes the array of
> handles and does the handle lookup too, but at least something which can
> subsititue drm_gem_lock_reservations with drm_exec would be nice to
> validate the helpers a bit more and really make sure we only have one of
> them left.
I was considering that as well, but then also thought one step at a
time. Not sure if it's possible to look up handles without running into
some locking fun, thought.
Thanks for the review,
Christian.
>
> Thoughts?
> -Daniel
>
>> +}
>> +
>> +void drm_exec_init(struct drm_exec *exec, bool interruptible);
>> +void drm_exec_fini(struct drm_exec *exec);
>> +bool drm_exec_cleanup(struct drm_exec *exec);
>> +int drm_exec_prepare_obj(struct drm_exec *exec, struct drm_gem_object *obj,
>> + unsigned int num_fences);
>> +
>> +#endif
>> --
>> 2.25.1
>>
More information about the amd-gfx
mailing list