[PATCH 1/2] drm/ttm: improve idle/busy handling v4

Christian König ckoenig.leichtzumerken at gmail.com
Tue Feb 27 08:33:54 UTC 2024


Am 27.02.24 um 09:12 schrieb Matthew Auld:
> On 26/02/2024 20:21, Thomas Hellström wrote:
>> Hi, Christian
>>
>> On Fri, 2024-02-23 at 15:30 +0100, Christian König wrote:
>>> Am 06.02.24 um 13:56 schrieb Christian König:
>>>> Am 06.02.24 um 13:53 schrieb Thomas Hellström:
>>>>> Hi, Christian,
>>>>>
>>>>> On Fri, 2024-01-26 at 15:09 +0100, Christian König wrote:
>>>>>> Previously we would never try to move a BO into the preferred
>>>>>> placements
>>>>>> when it ever landed in a busy placement since those were
>>>>>> considered
>>>>>> compatible.
>>>>>>
>>>>>> Rework the whole handling and finally unify the idle and busy
>>>>>> handling.
>>>>>> ttm_bo_validate() is now responsible to try idle placement
>>>>>> first and
>>>>>> then
>>>>>> use the busy placement if that didn't worked.
>>>>>>
>>>>>> Drawback is that we now always try the idle placement first for
>>>>>> each
>>>>>> validation which might cause some additional CPU overhead on
>>>>>> overcommit.
>>>>>>
>>>>>> v2: fix kerneldoc warning and coding style
>>>>>> v3: take care of XE as well
>>>>>> v4: keep the ttm_bo_mem_space functionality as it is for now,
>>>>>> only
>>>>>> add
>>>>>>       new handling for ttm_bo_validate as suggested by Thomas
>>>>>>
>>>>>> Signed-off-by: Christian König <christian.koenig at amd.com>
>>>>>> Reviewed-by: Zack Rusin <zack.rusin at broadcom.com> v3
>>>>> Sending this through xe CI, will try to review asap.
>>>>
>>>> Take your time. At the moment people are bombarding me with work
>>>> and I
>>>> have only two hands and one head as well :(
>>>
>>> So I've digged myself out of that hole and would rather like to get
>>> this
>>> new feature into 6.9.
>>>
>>> Any time to review it? I can also plan some time to review your LRU
>>> changes next week.
>>>
>>> Thanks,
>>> Christian.
>>
>> Sorry for the late response. Was planning to review but saw that there
>> was still an xe CI failure.
>>
>> https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-129579v1/bat-atsm-2/igt@xe_evict_ccs@evict-overcommit-parallel-nofree-samefd.html 
>>
>>
>> I haven't really had time to look into what might be causing this,
>> though.
> Maybe in ttm_bo_alloc_resource():
>
> @@ -772,7 +772,7 @@ static int ttm_bo_alloc_resource(struct 
> ttm_buffer_object *bo,
>
>                 do {
>                         ret = ttm_resource_alloc(bo, place, res);
> -                       if (unlikely(ret != -ENOSPC))
> +                       if (unlikely(ret && ret != -ENOSPC))
>                                 return ret;
>                         if (likely(!ret) || !force_space)
>                                 break;
>
> Otherwise we allocate VRAM but never correctly synchronise against the 
> move fence, since we missed adding it to the BO. When we trigger async 
> evictions that would explain the above test failure where we detect 
> VRAM corruption, since someone else is still using the VRAM we 
> allocated. What do you think?

Yup, that looks like the right thing to do. Thanks.

Give me a moment to fix that.

Christian.

>
>>
>> /Thomas
>>
>>>
>>>>
>>>> Christian.
>>>>
>>>>>
>>>>> /Thomas
>>>>>
>>>>>
>>>>>> ---
>>>>>>    drivers/gpu/drm/ttm/ttm_bo.c       | 231 +++++++++++++-------
>>>>>> -------
>>>>>> -- 
>>>>>>    drivers/gpu/drm/ttm/ttm_resource.c |  16 +-
>>>>>>    include/drm/ttm/ttm_resource.h     |   3 +-
>>>>>>    3 files changed, 121 insertions(+), 129 deletions(-)
>>>>>>
>>>>>> diff --git a/drivers/gpu/drm/ttm/ttm_bo.c
>>>>>> b/drivers/gpu/drm/ttm/ttm_bo.c
>>>>>> index ba3f09e2d7e6..b12f435542a9 100644
>>>>>> --- a/drivers/gpu/drm/ttm/ttm_bo.c
>>>>>> +++ b/drivers/gpu/drm/ttm/ttm_bo.c
>>>>>> @@ -724,64 +724,36 @@ static int ttm_bo_add_move_fence(struct
>>>>>> ttm_buffer_object *bo,
>>>>>>        return ret;
>>>>>>    }
>>>>>>    -/*
>>>>>> - * Repeatedly evict memory from the LRU for @mem_type until we
>>>>>> create enough
>>>>>> - * space, or we've evicted everything and there isn't enough
>>>>>> space.
>>>>>> - */
>>>>>> -static int ttm_bo_mem_force_space(struct ttm_buffer_object
>>>>>> *bo,
>>>>>> -                  const struct ttm_place *place,
>>>>>> -                  struct ttm_resource **mem,
>>>>>> -                  struct ttm_operation_ctx *ctx)
>>>>>> -{
>>>>>> -    struct ttm_device *bdev = bo->bdev;
>>>>>> -    struct ttm_resource_manager *man;
>>>>>> -    struct ww_acquire_ctx *ticket;
>>>>>> -    int ret;
>>>>>> -
>>>>>> -    man = ttm_manager_type(bdev, place->mem_type);
>>>>>> -    ticket = dma_resv_locking_ctx(bo->base.resv);
>>>>>> -    do {
>>>>>> -        ret = ttm_resource_alloc(bo, place, mem);
>>>>>> -        if (likely(!ret))
>>>>>> -            break;
>>>>>> -        if (unlikely(ret != -ENOSPC))
>>>>>> -            return ret;
>>>>>> -        ret = ttm_mem_evict_first(bdev, man, place, ctx,
>>>>>> -                      ticket);
>>>>>> -        if (unlikely(ret != 0))
>>>>>> -            return ret;
>>>>>> -    } while (1);
>>>>>> -
>>>>>> -    return ttm_bo_add_move_fence(bo, man, *mem, ctx-
>>>>>>> no_wait_gpu);
>>>>>> -}
>>>>>> -
>>>>>>    /**
>>>>>> - * ttm_bo_mem_space
>>>>>> + * ttm_bo_alloc_resource - Allocate backing store for a BO
>>>>>>     *
>>>>>> - * @bo: Pointer to a struct ttm_buffer_object. the data of
>>>>>> which
>>>>>> - * we want to allocate space for.
>>>>>> - * @placement: Proposed new placement for the buffer object.
>>>>>> - * @mem: A struct ttm_resource.
>>>>>> + * @bo: Pointer to a struct ttm_buffer_object of which we want
>>>>>> a
>>>>>> resource for
>>>>>> + * @placement: Proposed new placement for the buffer object
>>>>>>     * @ctx: if and how to sleep, lock buffers and alloc memory
>>>>>> + * @force_space: If we should evict buffers to force space
>>>>>> + * @res: The resulting struct ttm_resource.
>>>>>>     *
>>>>>> - * Allocate memory space for the buffer object pointed to by
>>>>>> @bo,
>>>>>> using
>>>>>> - * the placement flags in @placement, potentially evicting
>>>>>> other
>>>>>> idle buffer objects.
>>>>>> - * This function may sleep while waiting for space to become
>>>>>> available.
>>>>>> + * Allocates a resource for the buffer object pointed to by
>>>>>> @bo,
>>>>>> using the
>>>>>> + * placement flags in @placement, potentially evicting other
>>>>>> buffer
>>>>>> objects when
>>>>>> + * @force_space is true.
>>>>>> + * This function may sleep while waiting for resources to
>>>>>> become
>>>>>> available.
>>>>>>     * Returns:
>>>>>> - * -EBUSY: No space available (only if no_wait == 1).
>>>>>> + * -EBUSY: No space available (only if no_wait == true).
>>>>>>     * -ENOSPC: Could not allocate space for the buffer object,
>>>>>> either
>>>>>> due to
>>>>>>     * fragmentation or concurrent allocators.
>>>>>>     * -ERESTARTSYS: An interruptible sleep was interrupted by a
>>>>>> signal.
>>>>>>     */
>>>>>> -int ttm_bo_mem_space(struct ttm_buffer_object *bo,
>>>>>> -            struct ttm_placement *placement,
>>>>>> -            struct ttm_resource **mem,
>>>>>> -            struct ttm_operation_ctx *ctx)
>>>>>> +static int ttm_bo_alloc_resource(struct ttm_buffer_object *bo,
>>>>>> +                 struct ttm_placement *placement,
>>>>>> +                 struct ttm_operation_ctx *ctx,
>>>>>> +                 bool force_space,
>>>>>> +                 struct ttm_resource **res)
>>>>>>    {
>>>>>>        struct ttm_device *bdev = bo->bdev;
>>>>>> -    bool type_found = false;
>>>>>> +    struct ww_acquire_ctx *ticket;
>>>>>>        int i, ret;
>>>>>>    +    ticket = dma_resv_locking_ctx(bo->base.resv);
>>>>>>        ret = dma_resv_reserve_fences(bo->base.resv, 1);
>>>>>>        if (unlikely(ret))
>>>>>>            return ret;
>>>>>> @@ -790,98 +762,73 @@ int ttm_bo_mem_space(struct
>>>>>> ttm_buffer_object
>>>>>> *bo,
>>>>>>            const struct ttm_place *place = &placement-
>>>>>>> placement[i];
>>>>>>            struct ttm_resource_manager *man;
>>>>>>    -        if (place->flags & TTM_PL_FLAG_FALLBACK)
>>>>>> -            continue;
>>>>>> -
>>>>>>            man = ttm_manager_type(bdev, place->mem_type);
>>>>>>            if (!man || !ttm_resource_manager_used(man))
>>>>>>                continue;
>>>>>>    -        type_found = true;
>>>>>> -        ret = ttm_resource_alloc(bo, place, mem);
>>>>>> -        if (ret == -ENOSPC)
>>>>>> +        if (place->flags & (force_space ?
>>>>>> TTM_PL_FLAG_DESIRED :
>>>>>> +                    TTM_PL_FLAG_FALLBACK))
>>>>>> +            continue;
>>>>>> +
>>>>>> +        do {
>>>>>> +            ret = ttm_resource_alloc(bo, place, res);
>>>>>> +            if (unlikely(ret != -ENOSPC))
>>>>>> +                return ret;
>>>>>> +            if (likely(!ret) || !force_space)
>>>>>> +                break;
>>>>>> +
>>>>>> +            ret = ttm_mem_evict_first(bdev, man, place,
>>>>>> ctx,
>>>>>> +                          ticket);
>>>>>> +            if (unlikely(ret == -EBUSY))
>>>>>> +                break;
>>>>>> +            if (unlikely(ret))
>>>>>> +                return ret;
>>>>>> +        } while (1);
>>>>>> +        if (ret)
>>>>>>                continue;
>>>>>> -        if (unlikely(ret))
>>>>>> -            goto error;
>>>>>>    -        ret = ttm_bo_add_move_fence(bo, man, *mem, ctx-
>>>>>>> no_wait_gpu);
>>>>>> +        ret = ttm_bo_add_move_fence(bo, man, *res, ctx-
>>>>>>> no_wait_gpu);
>>>>>>            if (unlikely(ret)) {
>>>>>> -            ttm_resource_free(bo, mem);
>>>>>> +            ttm_resource_free(bo, res);
>>>>>>                if (ret == -EBUSY)
>>>>>>                    continue;
>>>>>>    -            goto error;
>>>>>> +            return ret;
>>>>>>            }
>>>>>>            return 0;
>>>>>>        }
>>>>>>    -    for (i = 0; i < placement->num_placement; ++i) {
>>>>>> -        const struct ttm_place *place = &placement-
>>>>>>> placement[i];
>>>>>> -        struct ttm_resource_manager *man;
>>>>>> -
>>>>>> -        if (place->flags & TTM_PL_FLAG_DESIRED)
>>>>>> -            continue;
>>>>>> -
>>>>>> -        man = ttm_manager_type(bdev, place->mem_type);
>>>>>> -        if (!man || !ttm_resource_manager_used(man))
>>>>>> -            continue;
>>>>>> -
>>>>>> -        type_found = true;
>>>>>> -        ret = ttm_bo_mem_force_space(bo, place, mem, ctx);
>>>>>> -        if (likely(!ret))
>>>>>> -            return 0;
>>>>>> -
>>>>>> -        if (ret && ret != -EBUSY)
>>>>>> -            goto error;
>>>>>> -    }
>>>>>> -
>>>>>> -    ret = -ENOSPC;
>>>>>> -    if (!type_found) {
>>>>>> -        pr_err(TTM_PFX "No compatible memory type found\n");
>>>>>> -        ret = -EINVAL;
>>>>>> -    }
>>>>>> -
>>>>>> -error:
>>>>>> -    return ret;
>>>>>> +    return -ENOSPC;
>>>>>>    }
>>>>>> -EXPORT_SYMBOL(ttm_bo_mem_space);
>>>>>>    -static int ttm_bo_move_buffer(struct ttm_buffer_object *bo,
>>>>>> -                  struct ttm_placement *placement,
>>>>>> -                  struct ttm_operation_ctx *ctx)
>>>>>> +/*
>>>>>> + * ttm_bo_mem_space - Wrapper around ttm_bo_alloc_resource
>>>>>> + *
>>>>>> + * @bo: Pointer to a struct ttm_buffer_object of which we want
>>>>>> a
>>>>>> resource for
>>>>>> + * @placement: Proposed new placement for the buffer object
>>>>>> + * @res: The resulting struct ttm_resource.
>>>>>> + * @ctx: if and how to sleep, lock buffers and alloc memory
>>>>>> + *
>>>>>> + * Tries both idle allocation and forcefully eviction of
>>>>>> buffers.
>>>>>> See
>>>>>> + * ttm_bo_alloc_resource for details.
>>>>>> + */
>>>>>> +int ttm_bo_mem_space(struct ttm_buffer_object *bo,
>>>>>> +             struct ttm_placement *placement,
>>>>>> +             struct ttm_resource **res,
>>>>>> +             struct ttm_operation_ctx *ctx)
>>>>>>    {
>>>>>> -    struct ttm_resource *mem;
>>>>>> -    struct ttm_place hop;
>>>>>> +    bool force_space = false;
>>>>>>        int ret;
>>>>>>    -    dma_resv_assert_held(bo->base.resv);
>>>>>> +    do {
>>>>>> +        ret = ttm_bo_alloc_resource(bo, placement, ctx,
>>>>>> +                        force_space, res);
>>>>>> +        force_space = !force_space;
>>>>>> +    } while (ret == -ENOSPC && force_space);
>>>>>>    -    /*
>>>>>> -     * Determine where to move the buffer.
>>>>>> -     *
>>>>>> -     * If driver determines move is going to need
>>>>>> -     * an extra step then it will return -EMULTIHOP
>>>>>> -     * and the buffer will be moved to the temporary
>>>>>> -     * stop and the driver will be called to make
>>>>>> -     * the second hop.
>>>>>> -     */
>>>>>> -    ret = ttm_bo_mem_space(bo, placement, &mem, ctx);
>>>>>> -    if (ret)
>>>>>> -        return ret;
>>>>>> -bounce:
>>>>>> -    ret = ttm_bo_handle_move_mem(bo, mem, false, ctx, &hop);
>>>>>> -    if (ret == -EMULTIHOP) {
>>>>>> -        ret = ttm_bo_bounce_temp_buffer(bo, &mem, ctx,
>>>>>> &hop);
>>>>>> -        if (ret)
>>>>>> -            goto out;
>>>>>> -        /* try and move to final place now. */
>>>>>> -        goto bounce;
>>>>>> -    }
>>>>>> -out:
>>>>>> -    if (ret)
>>>>>> -        ttm_resource_free(bo, &mem);
>>>>>>        return ret;
>>>>>>    }
>>>>>> +EXPORT_SYMBOL(ttm_bo_mem_space);
>>>>>>      /**
>>>>>>     * ttm_bo_validate
>>>>>> @@ -902,6 +849,9 @@ int ttm_bo_validate(struct
>>>>>> ttm_buffer_object *bo,
>>>>>>                struct ttm_placement *placement,
>>>>>>                struct ttm_operation_ctx *ctx)
>>>>>>    {
>>>>>> +    struct ttm_resource *res;
>>>>>> +    struct ttm_place hop;
>>>>>> +    bool force_space;
>>>>>>        int ret;
>>>>>>          dma_resv_assert_held(bo->base.resv);
>>>>>> @@ -912,20 +862,53 @@ int ttm_bo_validate(struct
>>>>>> ttm_buffer_object
>>>>>> *bo,
>>>>>>        if (!placement->num_placement)
>>>>>>            return ttm_bo_pipeline_gutting(bo);
>>>>>>    -    /* Check whether we need to move buffer. */
>>>>>> -    if (bo->resource && ttm_resource_compatible(bo->resource,
>>>>>> placement))
>>>>>> -        return 0;
>>>>>> +    force_space = false;
>>>>>> +    do {
>>>>>> +        /* Check whether we need to move buffer. */
>>>>>> +        if (bo->resource &&
>>>>>> +            ttm_resource_compatible(bo->resource, placement,
>>>>>> +                        force_space))
>>>>>> +            return 0;
>>>>>>    -    /* Moving of pinned BOs is forbidden */
>>>>>> -    if (bo->pin_count)
>>>>>> -        return -EINVAL;
>>>>>> +        /* Moving of pinned BOs is forbidden */
>>>>>> +        if (bo->pin_count)
>>>>>> +            return -EINVAL;
>>>>>> +
>>>>>> +        /*
>>>>>> +         * Determine where to move the buffer.
>>>>>> +         *
>>>>>> +         * If driver determines move is going to need
>>>>>> +         * an extra step then it will return -EMULTIHOP
>>>>>> +         * and the buffer will be moved to the temporary
>>>>>> +         * stop and the driver will be called to make
>>>>>> +         * the second hop.
>>>>>> +         */
>>>>>> +        ret = ttm_bo_alloc_resource(bo, placement, ctx,
>>>>>> force_space,
>>>>>> +                        &res);
>>>>>> +        force_space = !force_space;
>>>>>> +        if (ret == -ENOSPC)
>>>>>> +            continue;
>>>>>> +        if (ret)
>>>>>> +            return ret;
>>>>>> +
>>>>>> +bounce:
>>>>>> +        ret = ttm_bo_handle_move_mem(bo, res, false, ctx,
>>>>>> &hop);
>>>>>> +        if (ret == -EMULTIHOP) {
>>>>>> +            ret = ttm_bo_bounce_temp_buffer(bo, &res,
>>>>>> ctx, &hop);
>>>>>> +            /* try and move to final place now. */
>>>>>> +            if (!ret)
>>>>>> +                goto bounce;
>>>>>> +        }
>>>>>> +        if (ret) {
>>>>>> +            ttm_resource_free(bo, &res);
>>>>>> +            return ret;
>>>>>> +        }
>>>>>> +
>>>>>> +    } while (ret && force_space);
>>>>>>    -    ret = ttm_bo_move_buffer(bo, placement, ctx);
>>>>>>        /* For backward compatibility with userspace */
>>>>>>        if (ret == -ENOSPC)
>>>>>>            return -ENOMEM;
>>>>>> -    if (ret)
>>>>>> -        return ret;
>>>>>>          /*
>>>>>>         * We might need to add a TTM.
>>>>>> diff --git a/drivers/gpu/drm/ttm/ttm_resource.c
>>>>>> b/drivers/gpu/drm/ttm/ttm_resource.c
>>>>>> index fb14f7716cf8..65155f2013ca 100644
>>>>>> --- a/drivers/gpu/drm/ttm/ttm_resource.c
>>>>>> +++ b/drivers/gpu/drm/ttm/ttm_resource.c
>>>>>> @@ -295,11 +295,13 @@ bool ttm_resource_intersects(struct
>>>>>> ttm_device
>>>>>> *bdev,
>>>>>>     *
>>>>>>     * @res: the resource to check
>>>>>>     * @placement: the placement to check against
>>>>>> + * @evicting: true if the caller is doing evictions
>>>>>>     *
>>>>>>     * Returns true if the placement is compatible.
>>>>>>     */
>>>>>>    bool ttm_resource_compatible(struct ttm_resource *res,
>>>>>> -                 struct ttm_placement *placement)
>>>>>> +                 struct ttm_placement *placement,
>>>>>> +                 bool evicting)
>>>>>>    {
>>>>>>        struct ttm_buffer_object *bo = res->bo;
>>>>>>        struct ttm_device *bdev = bo->bdev;
>>>>>> @@ -315,14 +317,20 @@ bool ttm_resource_compatible(struct
>>>>>> ttm_resource *res,
>>>>>>            if (res->mem_type != place->mem_type)
>>>>>>                continue;
>>>>>>    +        if (place->flags & (evicting ? TTM_PL_FLAG_DESIRED :
>>>>>> +                    TTM_PL_FLAG_FALLBACK))
>>>>>> +            continue;
>>>>>> +
>>>>>> +        if (place->flags & TTM_PL_FLAG_CONTIGUOUS &&
>>>>>> +            !(res->placement & TTM_PL_FLAG_CONTIGUOUS))
>>>>>> +            continue;
>>>>>> +
>>>>>>            man = ttm_manager_type(bdev, res->mem_type);
>>>>>>            if (man->func->compatible &&
>>>>>>                !man->func->compatible(man, res, place, bo-
>>>>>>> base.size))
>>>>>>                continue;
>>>>>>    -        if ((!(place->flags & TTM_PL_FLAG_CONTIGUOUS) ||
>>>>>> -             (res->placement & TTM_PL_FLAG_CONTIGUOUS)))
>>>>>> -            return true;
>>>>>> +        return true;
>>>>>>        }
>>>>>>        return false;
>>>>>>    }
>>>>>> diff --git a/include/drm/ttm/ttm_resource.h
>>>>>> b/include/drm/ttm/ttm_resource.h
>>>>>> index 1afa13f0c22b..7561023db43d 100644
>>>>>> --- a/include/drm/ttm/ttm_resource.h
>>>>>> +++ b/include/drm/ttm/ttm_resource.h
>>>>>> @@ -366,7 +366,8 @@ bool ttm_resource_intersects(struct
>>>>>> ttm_device
>>>>>> *bdev,
>>>>>>                     const struct ttm_place *place,
>>>>>>                     size_t size);
>>>>>>    bool ttm_resource_compatible(struct ttm_resource *res,
>>>>>> -                 struct ttm_placement *placement);
>>>>>> +                 struct ttm_placement *placement,
>>>>>> +                 bool evicting);
>>>>>>    void ttm_resource_set_bo(struct ttm_resource *res,
>>>>>>                 struct ttm_buffer_object *bo);
>>>>
>>>
>>



More information about the Nouveau mailing list