From: Matthew Auld <matthew.auld@intel.com>
To: "Christian König" <ckoenig.leichtzumerken@gmail.com>,
"Christian König" <christian.koenig@amd.com>,
"Arunpravin Paneer Selvam" <Arunpravin.PaneerSelvam@amd.com>,
dri-devel@lists.freedesktop.org, amd-gfx@lists.freedesktop.org,
intel-gfx@lists.freedesktop.org
Cc: alexander.deucher@amd.com, felix.kuehling@amd.com,
mario.limonciello@amd.com
Subject: Re: [PATCH v6 3/3] drm/buddy: Add defragmentation support
Date: Fri, 16 Feb 2024 14:47:14 +0000 [thread overview]
Message-ID: <8224c34a-aca5-415e-9d6f-c061471f0cff@intel.com> (raw)
In-Reply-To: <26d13e0c-c52a-4681-bea8-4a631b514edd@gmail.com>
On 16/02/2024 14:02, Christian König wrote:
> Am 16.02.24 um 14:21 schrieb Matthew Auld:
>> On 16/02/2024 12:33, Christian König wrote:
>>> Am 16.02.24 um 13:23 schrieb Matthew Auld:
>>>> On 08/02/2024 15:50, Arunpravin Paneer Selvam wrote:
>>>>> Add a function to support defragmentation.
>>>>>
>>>>> v1: Defragment the memory beginning from min_order
>>>>> till the required memory space is available.
>>>>>
>>>>> Signed-off-by: Arunpravin Paneer Selvam
>>>>> <Arunpravin.PaneerSelvam@amd.com>
>>>>> Suggested-by: Matthew Auld <matthew.auld@intel.com>
>>>>> ---
>>>>> drivers/gpu/drm/drm_buddy.c | 67
>>>>> +++++++++++++++++++++++++++++++------
>>>>> include/drm/drm_buddy.h | 3 ++
>>>>
>>>> No users?
>>>
>>> Other question is how can a buddy allocator fragment in the first place?
>>
>> The fragmentation is due to pages now being tracked as dirty/clear.
>> Should the allocator merge together a page that is dirty with a page
>> that is cleared? When should it do that? User wants to be able to keep
>> the two separate if possible. For example, freeing one single dirty
>> page can dirty a huge swathe of your already cleared pages if they are
>> merged together. Or do you have some some other ideas here?
>
> Sorry, that was not what I meant. I should probably have been clearer.
>
> That dirty and clean pages are now kept separated is obvious, but why do
> you need to de-fragment them at some point?
Ah, right. At the very least we need to do something similar to this at
fini(), just to ensure we properly merge everything back together so we
can correctly tear down the mm. Outside of that the thinking was that it
might be useful to call when allocating larger min page-sizes. You might
now be failing the allocation due to fragmentation, and so in some cases
might be better off running some kind of defrag step first, instead of
failing the allocation and trying to evict stuff. Anyway, if that is not
a concern for amdgpu, then we just need to handle the fini() case and
can keep this internal.
>
> Christian.
>
>>
>>>
>>> Christian.
>>>
>>>>
>>>>> 2 files changed, 59 insertions(+), 11 deletions(-)
>>>>>
>>>>> diff --git a/drivers/gpu/drm/drm_buddy.c b/drivers/gpu/drm/drm_buddy.c
>>>>> index 33ad0cfbd54c..fac423d2cb73 100644
>>>>> --- a/drivers/gpu/drm/drm_buddy.c
>>>>> +++ b/drivers/gpu/drm/drm_buddy.c
>>>>> @@ -276,10 +276,12 @@ drm_get_buddy(struct drm_buddy_block *block)
>>>>> }
>>>>> EXPORT_SYMBOL(drm_get_buddy);
>>>>> -static void __drm_buddy_free(struct drm_buddy *mm,
>>>>> - struct drm_buddy_block *block)
>>>>> +static unsigned int __drm_buddy_free(struct drm_buddy *mm,
>>>>> + struct drm_buddy_block *block,
>>>>> + bool defrag)
>>>>> {
>>>>> struct drm_buddy_block *parent;
>>>>> + unsigned int order;
>>>>> while ((parent = block->parent)) {
>>>>> struct drm_buddy_block *buddy;
>>>>> @@ -289,12 +291,14 @@ static void __drm_buddy_free(struct drm_buddy
>>>>> *mm,
>>>>> if (!drm_buddy_block_is_free(buddy))
>>>>> break;
>>>>> - if (drm_buddy_block_is_clear(block) !=
>>>>> - drm_buddy_block_is_clear(buddy))
>>>>> - break;
>>>>> + if (!defrag) {
>>>>> + if (drm_buddy_block_is_clear(block) !=
>>>>> + drm_buddy_block_is_clear(buddy))
>>>>> + break;
>>>>> - if (drm_buddy_block_is_clear(block))
>>>>> - mark_cleared(parent);
>>>>> + if (drm_buddy_block_is_clear(block))
>>>>> + mark_cleared(parent);
>>>>> + }
>>>>
>>>> Maybe check if the two blocks are incompatible and chuck a warn if
>>>> they are not? Main thing is not to hide issues with split blocks
>>>> that should have been merged before.
>>>>
>>>>> list_del(&buddy->link);
>>>>> @@ -304,8 +308,49 @@ static void __drm_buddy_free(struct
>>>>> drm_buddy *mm,
>>>>> block = parent;
>>>>> }
>>>>> + order = drm_buddy_block_order(block);
>>>>> mark_free(mm, block);
>>>>> +
>>>>> + return order;
>>>>> +}
>>>>> +
>>>>> +/**
>>>>> + * drm_buddy_defrag - Defragmentation routine
>>>>> + *
>>>>> + * @mm: DRM buddy manager
>>>>> + * @min_order: minimum order in the freelist to begin
>>>>> + * the defragmentation process
>>>>> + *
>>>>> + * Driver calls the defragmentation function when the
>>>>> + * requested memory allocation returns -ENOSPC.
>>>>> + */
>>>>> +void drm_buddy_defrag(struct drm_buddy *mm,
>>>>> + unsigned int min_order)
>>>>
>>>> Just wondering if we need "full defag" also? We would probably need
>>>> to call this at fini() anyway.
>>>>
>>>>> +{
>>>>> + struct drm_buddy_block *block;
>>>>> + struct list_head *list;
>>>>> + unsigned int order;
>>>>> + int i;
>>>>> +
>>>>> + if (min_order > mm->max_order)
>>>>> + return;
>>>>> +
>>>>> + for (i = min_order - 1; i >= 0; i--) {
>>>>
>>>> Need to be careful with min_order = 0 ?
>>>>
>>>>> + list = &mm->free_list[i];
>>>>> + if (list_empty(list))
>>>>> + continue;
>>>>> +
>>>>> + list_for_each_entry_reverse(block, list, link) {
>>>>
>>>> Don't we need the safe_reverse() variant here, since this is
>>>> removing from the list?
>>>>
>>>>> + if (!block->parent)
>>>>> + continue;
>>>>> +
>>>>> + order = __drm_buddy_free(mm, block, 1);
>>>>> + if (order >= min_order)
>>>>> + return;
>>>>> + }
>>>>> + }
>>>>> }
>>>>> +EXPORT_SYMBOL(drm_buddy_defrag);
>>>>> /**
>>>>> * drm_buddy_free_block - free a block
>>>>> @@ -321,7 +366,7 @@ void drm_buddy_free_block(struct drm_buddy *mm,
>>>>> if (drm_buddy_block_is_clear(block))
>>>>> mm->clear_avail += drm_buddy_block_size(mm, block);
>>>>> - __drm_buddy_free(mm, block);
>>>>> + __drm_buddy_free(mm, block, 0);
>>>>> }
>>>>> EXPORT_SYMBOL(drm_buddy_free_block);
>>>>> @@ -470,7 +515,7 @@ __alloc_range_bias(struct drm_buddy *mm,
>>>>> if (buddy &&
>>>>> (drm_buddy_block_is_free(block) &&
>>>>> drm_buddy_block_is_free(buddy)))
>>>>> - __drm_buddy_free(mm, block);
>>>>> + __drm_buddy_free(mm, block, 0);
>>>>> return ERR_PTR(err);
>>>>> }
>>>>> @@ -588,7 +633,7 @@ alloc_from_freelist(struct drm_buddy *mm,
>>>>> err_undo:
>>>>> if (tmp != order)
>>>>> - __drm_buddy_free(mm, block);
>>>>> + __drm_buddy_free(mm, block, 0);
>>>>> return ERR_PTR(err);
>>>>> }
>>>>> @@ -668,7 +713,7 @@ static int __alloc_range(struct drm_buddy *mm,
>>>>> if (buddy &&
>>>>> (drm_buddy_block_is_free(block) &&
>>>>> drm_buddy_block_is_free(buddy)))
>>>>> - __drm_buddy_free(mm, block);
>>>>> + __drm_buddy_free(mm, block, 0);
>>>>> err_free:
>>>>> if (err == -ENOSPC && total_allocated_on_err) {
>>>>> diff --git a/include/drm/drm_buddy.h b/include/drm/drm_buddy.h
>>>>> index d81c596dfa38..d0f63e7b5915 100644
>>>>> --- a/include/drm/drm_buddy.h
>>>>> +++ b/include/drm/drm_buddy.h
>>>>> @@ -166,6 +166,9 @@ void drm_buddy_free_list(struct drm_buddy *mm,
>>>>> struct list_head *objects,
>>>>> unsigned int flags);
>>>>> +void drm_buddy_defrag(struct drm_buddy *mm,
>>>>> + unsigned int min_order);
>>>>> +
>>>>> void drm_buddy_print(struct drm_buddy *mm, struct drm_printer *p);
>>>>> void drm_buddy_block_print(struct drm_buddy *mm,
>>>>> struct drm_buddy_block *block,
>>>
>
next prev parent reply other threads:[~2024-02-16 14:47 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-02-08 15:49 [PATCH v6 1/3] drm/buddy: Implement tracking clear page feature Arunpravin Paneer Selvam
2024-02-08 15:49 ` [PATCH v6 2/3] drm/amdgpu: Enable clear page functionality Arunpravin Paneer Selvam
2024-02-08 15:50 ` [PATCH v6 3/3] drm/buddy: Add defragmentation support Arunpravin Paneer Selvam
2024-02-16 12:23 ` Matthew Auld
2024-02-16 12:33 ` Christian König
2024-02-16 13:21 ` Matthew Auld
2024-02-16 14:02 ` Christian König
2024-02-16 14:47 ` Matthew Auld [this message]
2024-02-16 15:08 ` Christian König
2024-02-16 11:49 ` [PATCH v6 1/3] drm/buddy: Implement tracking clear page feature Arunpravin Paneer Selvam
2024-02-16 12:03 ` Matthew Auld
2024-02-21 12:23 ` Paneer Selvam, Arunpravin
2024-02-21 12:40 ` Paneer Selvam, Arunpravin
2024-02-21 17:54 ` Matthew Auld
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=8224c34a-aca5-415e-9d6f-c061471f0cff@intel.com \
--to=matthew.auld@intel.com \
--cc=Arunpravin.PaneerSelvam@amd.com \
--cc=alexander.deucher@amd.com \
--cc=amd-gfx@lists.freedesktop.org \
--cc=christian.koenig@amd.com \
--cc=ckoenig.leichtzumerken@gmail.com \
--cc=dri-devel@lists.freedesktop.org \
--cc=felix.kuehling@amd.com \
--cc=intel-gfx@lists.freedesktop.org \
--cc=mario.limonciello@amd.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox