Commit c1696bf8 authored by Arunpravin Paneer Selvam's avatar Arunpravin Paneer Selvam Committed by Christian König

drm/tests: Add a test case for drm buddy clear allocation

Add a new test case for the drm buddy clear and dirty
allocation.

v2:(Matthew)
  - make size as u32
  - rename PAGE_SIZE with SZ_4K
  - dont fragment the address space for all the order allocation
    iterations. we can do it once and just increment and allocate
    the size.
  - create new mm with non power-of-two size to ensure the multi-root
    force_merge during fini.

v3:
  - add randomness in size calculation(Matthew)
Signed-off-by: default avatarArunpravin Paneer Selvam <Arunpravin.PaneerSelvam@amd.com>
Reviewed-by: default avatarMatthew Auld <matthew.auld@intel.com>
Suggested-by: default avatarMatthew Auld <matthew.auld@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20240419063538.11957-3-Arunpravin.PaneerSelvam@amd.comSigned-off-by: default avatarChristian König <christian.koenig@amd.com>
parent a68c7eaa
......@@ -224,6 +224,148 @@ static void drm_test_buddy_alloc_range_bias(struct kunit *test)
drm_buddy_fini(&mm);
}
static void drm_test_buddy_alloc_clear(struct kunit *test)
{
unsigned long n_pages, total, i = 0;
DRM_RND_STATE(prng, random_seed);
const unsigned long ps = SZ_4K;
struct drm_buddy_block *block;
const int max_order = 12;
LIST_HEAD(allocated);
struct drm_buddy mm;
unsigned int order;
u32 mm_size, size;
LIST_HEAD(dirty);
LIST_HEAD(clean);
mm_size = SZ_4K << max_order;
KUNIT_EXPECT_FALSE(test, drm_buddy_init(&mm, mm_size, ps));
KUNIT_EXPECT_EQ(test, mm.max_order, max_order);
/*
* Idea is to allocate and free some random portion of the address space,
* returning those pages as non-dirty and randomly alternate between
* requesting dirty and non-dirty pages (not going over the limit
* we freed as non-dirty), putting that into two separate lists.
* Loop over both lists at the end checking that the dirty list
* is indeed all dirty pages and vice versa. Free it all again,
* keeping the dirty/clear status.
*/
KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, mm_size,
5 * ps, ps, &allocated,
DRM_BUDDY_TOPDOWN_ALLOCATION),
"buddy_alloc hit an error size=%lu\n", 5 * ps);
drm_buddy_free_list(&mm, &allocated, DRM_BUDDY_CLEARED);
n_pages = 10;
do {
unsigned long flags;
struct list_head *list;
int slot = i % 2;
if (slot == 0) {
list = &dirty;
flags = 0;
} else {
list = &clean;
flags = DRM_BUDDY_CLEAR_ALLOCATION;
}
KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, mm_size,
ps, ps, list,
flags),
"buddy_alloc hit an error size=%lu\n", ps);
} while (++i < n_pages);
list_for_each_entry(block, &clean, link)
KUNIT_EXPECT_EQ(test, drm_buddy_block_is_clear(block), true);
list_for_each_entry(block, &dirty, link)
KUNIT_EXPECT_EQ(test, drm_buddy_block_is_clear(block), false);
drm_buddy_free_list(&mm, &clean, DRM_BUDDY_CLEARED);
/*
* Trying to go over the clear limit for some allocation.
* The allocation should never fail with reasonable page-size.
*/
KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, mm_size,
10 * ps, ps, &clean,
DRM_BUDDY_CLEAR_ALLOCATION),
"buddy_alloc hit an error size=%lu\n", 10 * ps);
drm_buddy_free_list(&mm, &clean, DRM_BUDDY_CLEARED);
drm_buddy_free_list(&mm, &dirty, 0);
drm_buddy_fini(&mm);
KUNIT_EXPECT_FALSE(test, drm_buddy_init(&mm, mm_size, ps));
/*
* Create a new mm. Intentionally fragment the address space by creating
* two alternating lists. Free both lists, one as dirty the other as clean.
* Try to allocate double the previous size with matching min_page_size. The
* allocation should never fail as it calls the force_merge. Also check that
* the page is always dirty after force_merge. Free the page as dirty, then
* repeat the whole thing, increment the order until we hit the max_order.
*/
i = 0;
n_pages = mm_size / ps;
do {
struct list_head *list;
int slot = i % 2;
if (slot == 0)
list = &dirty;
else
list = &clean;
KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, mm_size,
ps, ps, list, 0),
"buddy_alloc hit an error size=%lu\n", ps);
} while (++i < n_pages);
drm_buddy_free_list(&mm, &clean, DRM_BUDDY_CLEARED);
drm_buddy_free_list(&mm, &dirty, 0);
order = 1;
do {
size = SZ_4K << order;
KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, mm_size,
size, size, &allocated,
DRM_BUDDY_CLEAR_ALLOCATION),
"buddy_alloc hit an error size=%u\n", size);
total = 0;
list_for_each_entry(block, &allocated, link) {
if (size != mm_size)
KUNIT_EXPECT_EQ(test, drm_buddy_block_is_clear(block), false);
total += drm_buddy_block_size(&mm, block);
}
KUNIT_EXPECT_EQ(test, total, size);
drm_buddy_free_list(&mm, &allocated, 0);
} while (++order <= max_order);
drm_buddy_fini(&mm);
/*
* Create a new mm with a non power-of-two size. Allocate a random size, free as
* cleared and then call fini. This will ensure the multi-root force merge during
* fini.
*/
mm_size = 12 * SZ_4K;
size = max(round_up(prandom_u32_state(&prng) % mm_size, ps), ps);
KUNIT_EXPECT_FALSE(test, drm_buddy_init(&mm, mm_size, ps));
KUNIT_ASSERT_FALSE_MSG(test, drm_buddy_alloc_blocks(&mm, 0, mm_size,
size, ps, &allocated,
DRM_BUDDY_TOPDOWN_ALLOCATION),
"buddy_alloc hit an error size=%u\n", size);
drm_buddy_free_list(&mm, &allocated, DRM_BUDDY_CLEARED);
drm_buddy_fini(&mm);
}
static void drm_test_buddy_alloc_contiguous(struct kunit *test)
{
const unsigned long ps = SZ_4K, mm_size = 16 * 3 * SZ_4K;
......@@ -584,6 +726,7 @@ static struct kunit_case drm_buddy_tests[] = {
KUNIT_CASE(drm_test_buddy_alloc_pessimistic),
KUNIT_CASE(drm_test_buddy_alloc_pathological),
KUNIT_CASE(drm_test_buddy_alloc_contiguous),
KUNIT_CASE(drm_test_buddy_alloc_clear),
KUNIT_CASE(drm_test_buddy_alloc_range_bias),
{}
};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment