On Tue, Sep 02, 2025 at 12:26:04AM +0530, Arunpravin Paneer Selvam wrote: > Replace the freelist (O(n)) used for free block management with a > red-black tree, providing more efficient O(log n) search, insert, > and delete operations. This improves scalability and performance > when managing large numbers of free blocks per order (e.g., hundreds > or thousands).
Did you consider the interval tree? > @@ -41,23 +43,53 @@ static void drm_block_free(struct drm_buddy *mm, > kmem_cache_free(slab_blocks, block); > } > > -static void list_insert_sorted(struct drm_buddy *mm, > - struct drm_buddy_block *block) > +static void rbtree_insert(struct drm_buddy *mm, > + struct drm_buddy_block *block) > { > + struct rb_root *root = &mm->free_tree[drm_buddy_block_order(block)]; > + struct rb_node **link = &root->rb_node; > + struct rb_node *parent = NULL; > struct drm_buddy_block *node; > - struct list_head *head; > + u64 offset; > + > + offset = drm_buddy_block_offset(block); > > - head = &mm->free_list[drm_buddy_block_order(block)]; > - if (list_empty(head)) { > - list_add(&block->link, head); > - return; > + while (*link) { > + parent = *link; > + node = rb_entry(parent, struct drm_buddy_block, rb); > + > + if (offset < drm_buddy_block_offset(node)) > + link = &parent->rb_left; > + else > + link = &parent->rb_right; > } > > - list_for_each_entry(node, head, link) > - if (drm_buddy_block_offset(block) < > drm_buddy_block_offset(node)) > - break; > + rb_link_node(&block->rb, parent, link); > + rb_insert_color(&block->rb, root); > +} static inline bool __drm_bb_less(const struct drm_buddy_block *a, const struct drm_buddy_block *b) { return drm_buddy_block_offset(a) < drm_buddy_block_offset(b); } #define __node_2_drm_bb(node) rb_entry((node), struct drm_buddy_block, rb) static inline bool rb_drm_bb_less(struct rb_node *a, const struct rb_node *b) { return __drm_bb_less(__node_2_drm_bb(a), __node_2_drm_bb(b)); } static void rbtree_insert(struct drm_buddy *mm, struct drm_buddy_block *block) { rb_add(block->rb, &mm->free_tree[drm_buddy_block_order(block)], rb_drm_bb_less); } > + > +static void rbtree_remove(struct drm_buddy *mm, > + struct drm_buddy_block *block) > +{ > + struct rb_root *root; > + > + root = &mm->free_tree[drm_buddy_block_order(block)]; > + rb_erase(&block->rb, root); > > - __list_add(&block->link, node->link.prev, &node->link); > + RB_CLEAR_NODE(&block->rb); > +} > + > +static inline struct drm_buddy_block * > +rbtree_last_entry(struct drm_buddy *mm, unsigned int order) > +{ > + struct rb_node *node = rb_last(&mm->free_tree[order]); > + > + return node ? rb_entry(node, struct drm_buddy_block, rb) : NULL; > +} rb_add_cached() caches the leftmost entry, if you invert the key, the last is first. > diff --git a/include/linux/rbtree.h b/include/linux/rbtree.h > index 8d2ba3749866..17190bb4837c 100644 > --- a/include/linux/rbtree.h > +++ b/include/linux/rbtree.h > @@ -79,6 +79,62 @@ static inline void rb_link_node_rcu(struct rb_node *node, > struct rb_node *parent > ____ptr ? rb_entry(____ptr, type, member) : NULL; \ > }) > > +/** > + * rbtree_for_each_entry - iterate in-order over rb_root of given type > + * > + * @pos: the 'type *' to use as a loop cursor. > + * @root: 'rb_root *' of the rbtree. > + * @member: the name of the rb_node field within 'type'. > + */ > +#define rbtree_for_each_entry(pos, root, member) \ > + for ((pos) = rb_entry_safe(rb_first(root), typeof(*(pos)), member); \ > + (pos); \ > + (pos) = rb_entry_safe(rb_next(&(pos)->member), typeof(*(pos)), > member)) > + > +/** > + * rbtree_reverse_for_each_entry - iterate in reverse in-order over rb_root > + * of given type > + * > + * @pos: the 'type *' to use as a loop cursor. > + * @root: 'rb_root *' of the rbtree. > + * @member: the name of the rb_node field within 'type'. > + */ > +#define rbtree_reverse_for_each_entry(pos, root, member) \ > + for ((pos) = rb_entry_safe(rb_last(root), typeof(*(pos)), member); \ > + (pos); \ > + (pos) = rb_entry_safe(rb_prev(&(pos)->member), typeof(*(pos)), > member)) > + > +/** > + * rbtree_for_each_entry_safe - iterate in-order over rb_root safe against > removal > + * > + * @pos: the 'type *' to use as a loop cursor > + * @n: another 'type *' to use as temporary storage > + * @root: 'rb_root *' of the rbtree > + * @member: the name of the rb_node field within 'type' > + */ > +#define rbtree_for_each_entry_safe(pos, n, root, member) \ > + for ((pos) = rb_entry_safe(rb_first(root), typeof(*(pos)), member), \ > + (n) = (pos) ? rb_entry_safe(rb_next(&(pos)->member), > typeof(*(pos)), member) : NULL; \ > + (pos); \ > + (pos) = (n), \ > + (n) = (pos) ? rb_entry_safe(rb_next(&(pos)->member), > typeof(*(pos)), member) : NULL) > + > +/** > + * rbtree_reverse_for_each_entry_safe - iterate in reverse in-order over > rb_root > + * safe against removal > + * > + * @pos: the struct type * to use as a loop cursor. > + * @n: another struct type * to use as temporary storage. > + * @root: pointer to struct rb_root to iterate. > + * @member: name of the rb_node field within the struct. > + */ > +#define rbtree_reverse_for_each_entry_safe(pos, n, root, member) \ > + for ((pos) = rb_entry_safe(rb_last(root), typeof(*(pos)), member), \ > + (n) = (pos) ? rb_entry_safe(rb_prev(&(pos)->member), > typeof(*(pos)), member) : NULL; \ > + (pos); \ > + (pos) = (n), \ > + (n) = (pos) ? rb_entry_safe(rb_prev(&(pos)->member), > typeof(*(pos)), member) : NULL) > + Not really a fan of these. That's typically a sign you're doing it wrong. Full tree iteration is actually slower than linked list.