Skip to content

Commit 5640e81

Browse files
arunpravin24ChristianKoenigAMD
authored andcommitted
drm: Optimize drm buddy top-down allocation method
We are observing performance drop in many usecases which include games, 3D benchmark applications,etc.. To solve this problem, We are strictly not allowing top down flag enabled allocations to steal the memory space from cpu visible region. The idea is, we are sorting each order list entries in ascending order and compare the last entry of each order list in the freelist and return the max block. This patch improves the 3D benchmark scores and solves fragmentation issues. All drm buddy selftests are verfied. drm_buddy: pass:6 fail:0 skip:0 total:6 Signed-off-by: Arunpravin Paneer Selvam <[email protected]> Acked-by: Christian König <[email protected]> Acked-by: Alex Deucher <[email protected]> Reviewed-by: Matthew Auld <[email protected]> Link: https://patchwork.freedesktop.org/patch/msgid/[email protected] Signed-off-by: Christian König <[email protected]> CC: Cc: [email protected] # 5.18+
1 parent 040b35c commit 5640e81

File tree

1 file changed

+54
-27
lines changed

1 file changed

+54
-27
lines changed

drivers/gpu/drm/drm_buddy.c

Lines changed: 54 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,25 @@ static void drm_block_free(struct drm_buddy *mm,
3838
kmem_cache_free(slab_blocks, block);
3939
}
4040

41+
static void list_insert_sorted(struct drm_buddy *mm,
42+
struct drm_buddy_block *block)
43+
{
44+
struct drm_buddy_block *node;
45+
struct list_head *head;
46+
47+
head = &mm->free_list[drm_buddy_block_order(block)];
48+
if (list_empty(head)) {
49+
list_add(&block->link, head);
50+
return;
51+
}
52+
53+
list_for_each_entry(node, head, link)
54+
if (drm_buddy_block_offset(block) < drm_buddy_block_offset(node))
55+
break;
56+
57+
__list_add(&block->link, node->link.prev, &node->link);
58+
}
59+
4160
static void mark_allocated(struct drm_buddy_block *block)
4261
{
4362
block->header &= ~DRM_BUDDY_HEADER_STATE;
@@ -52,8 +71,7 @@ static void mark_free(struct drm_buddy *mm,
5271
block->header &= ~DRM_BUDDY_HEADER_STATE;
5372
block->header |= DRM_BUDDY_FREE;
5473

55-
list_add(&block->link,
56-
&mm->free_list[drm_buddy_block_order(block)]);
74+
list_insert_sorted(mm, block);
5775
}
5876

5977
static void mark_split(struct drm_buddy_block *block)
@@ -387,20 +405,26 @@ alloc_range_bias(struct drm_buddy *mm,
387405
}
388406

389407
static struct drm_buddy_block *
390-
get_maxblock(struct list_head *head)
408+
get_maxblock(struct drm_buddy *mm, unsigned int order)
391409
{
392410
struct drm_buddy_block *max_block = NULL, *node;
411+
unsigned int i;
393412

394-
max_block = list_first_entry_or_null(head,
395-
struct drm_buddy_block,
396-
link);
397-
if (!max_block)
398-
return NULL;
413+
for (i = order; i <= mm->max_order; ++i) {
414+
if (!list_empty(&mm->free_list[i])) {
415+
node = list_last_entry(&mm->free_list[i],
416+
struct drm_buddy_block,
417+
link);
418+
if (!max_block) {
419+
max_block = node;
420+
continue;
421+
}
399422

400-
list_for_each_entry(node, head, link) {
401-
if (drm_buddy_block_offset(node) >
402-
drm_buddy_block_offset(max_block))
403-
max_block = node;
423+
if (drm_buddy_block_offset(node) >
424+
drm_buddy_block_offset(max_block)) {
425+
max_block = node;
426+
}
427+
}
404428
}
405429

406430
return max_block;
@@ -412,20 +436,23 @@ alloc_from_freelist(struct drm_buddy *mm,
412436
unsigned long flags)
413437
{
414438
struct drm_buddy_block *block = NULL;
415-
unsigned int i;
439+
unsigned int tmp;
416440
int err;
417441

418-
for (i = order; i <= mm->max_order; ++i) {
419-
if (flags & DRM_BUDDY_TOPDOWN_ALLOCATION) {
420-
block = get_maxblock(&mm->free_list[i]);
421-
if (block)
422-
break;
423-
} else {
424-
block = list_first_entry_or_null(&mm->free_list[i],
425-
struct drm_buddy_block,
426-
link);
427-
if (block)
428-
break;
442+
if (flags & DRM_BUDDY_TOPDOWN_ALLOCATION) {
443+
block = get_maxblock(mm, order);
444+
if (block)
445+
/* Store the obtained block order */
446+
tmp = drm_buddy_block_order(block);
447+
} else {
448+
for (tmp = order; tmp <= mm->max_order; ++tmp) {
449+
if (!list_empty(&mm->free_list[tmp])) {
450+
block = list_last_entry(&mm->free_list[tmp],
451+
struct drm_buddy_block,
452+
link);
453+
if (block)
454+
break;
455+
}
429456
}
430457
}
431458

@@ -434,18 +461,18 @@ alloc_from_freelist(struct drm_buddy *mm,
434461

435462
BUG_ON(!drm_buddy_block_is_free(block));
436463

437-
while (i != order) {
464+
while (tmp != order) {
438465
err = split_block(mm, block);
439466
if (unlikely(err))
440467
goto err_undo;
441468

442469
block = block->right;
443-
i--;
470+
tmp--;
444471
}
445472
return block;
446473

447474
err_undo:
448-
if (i != order)
475+
if (tmp != order)
449476
__drm_buddy_free(mm, block);
450477
return ERR_PTR(err);
451478
}

0 commit comments

Comments
 (0)