Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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 <Arunpravin.PaneerSelvam@amd.com>
Acked-by: Christian König <christian.koenig@amd.com>
Acked-by: Alex Deucher <alexander.deucher@amd.com>
Reviewed-by: Matthew Auld <matthew.auld@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20230112120027.3072-1-Arunpravin.PaneerSelvam@amd.com
Signed-off-by: Christian König <christian.koenig@amd.com>
CC: Cc: stable@vger.kernel.org # 5.18+

authored by

Arunpravin Paneer Selvam and committed by
Christian König
5640e816 040b35c1

+54 -27
+54 -27
drivers/gpu/drm/drm_buddy.c
··· 38 38 kmem_cache_free(slab_blocks, block); 39 39 } 40 40 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 + 41 60 static void mark_allocated(struct drm_buddy_block *block) 42 61 { 43 62 block->header &= ~DRM_BUDDY_HEADER_STATE; ··· 71 52 block->header &= ~DRM_BUDDY_HEADER_STATE; 72 53 block->header |= DRM_BUDDY_FREE; 73 54 74 - list_add(&block->link, 75 - &mm->free_list[drm_buddy_block_order(block)]); 55 + list_insert_sorted(mm, block); 76 56 } 77 57 78 58 static void mark_split(struct drm_buddy_block *block) ··· 405 387 } 406 388 407 389 static struct drm_buddy_block * 408 - get_maxblock(struct list_head *head) 390 + get_maxblock(struct drm_buddy *mm, unsigned int order) 409 391 { 410 392 struct drm_buddy_block *max_block = NULL, *node; 393 + unsigned int i; 411 394 412 - max_block = list_first_entry_or_null(head, 413 - struct drm_buddy_block, 414 - link); 415 - if (!max_block) 416 - return NULL; 395 + for (i = order; i <= mm->max_order; ++i) { 396 + if (!list_empty(&mm->free_list[i])) { 397 + node = list_last_entry(&mm->free_list[i], 398 + struct drm_buddy_block, 399 + link); 400 + if (!max_block) { 401 + max_block = node; 402 + continue; 403 + } 417 404 418 - list_for_each_entry(node, head, link) { 419 - if (drm_buddy_block_offset(node) > 420 - drm_buddy_block_offset(max_block)) 421 - max_block = node; 405 + if (drm_buddy_block_offset(node) > 406 + drm_buddy_block_offset(max_block)) { 407 + max_block = node; 408 + } 409 + } 422 410 } 423 411 424 412 return max_block; ··· 436 412 unsigned long flags) 437 413 { 438 414 struct drm_buddy_block *block = NULL; 439 - unsigned int i; 415 + unsigned int tmp; 440 416 int err; 441 417 442 - for (i = order; i <= mm->max_order; ++i) { 443 - if (flags & DRM_BUDDY_TOPDOWN_ALLOCATION) { 444 - block = get_maxblock(&mm->free_list[i]); 445 - if (block) 446 - break; 447 - } else { 448 - block = list_first_entry_or_null(&mm->free_list[i], 449 - struct drm_buddy_block, 450 - link); 451 - if (block) 452 - break; 418 + if (flags & DRM_BUDDY_TOPDOWN_ALLOCATION) { 419 + block = get_maxblock(mm, order); 420 + if (block) 421 + /* Store the obtained block order */ 422 + tmp = drm_buddy_block_order(block); 423 + } else { 424 + for (tmp = order; tmp <= mm->max_order; ++tmp) { 425 + if (!list_empty(&mm->free_list[tmp])) { 426 + block = list_last_entry(&mm->free_list[tmp], 427 + struct drm_buddy_block, 428 + link); 429 + if (block) 430 + break; 431 + } 453 432 } 454 433 } 455 434 ··· 461 434 462 435 BUG_ON(!drm_buddy_block_is_free(block)); 463 436 464 - while (i != order) { 437 + while (tmp != order) { 465 438 err = split_block(mm, block); 466 439 if (unlikely(err)) 467 440 goto err_undo; 468 441 469 442 block = block->right; 470 - i--; 443 + tmp--; 471 444 } 472 445 return block; 473 446 474 447 err_undo: 475 - if (i != order) 448 + if (tmp != order) 476 449 __drm_buddy_free(mm, block); 477 450 return ERR_PTR(err); 478 451 }