Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4f035ad6 authored by Michel Lespinasse's avatar Michel Lespinasse Committed by Linus Torvalds
Browse files

rbtree: low level optimizations in rb_erase()



Various minor optimizations in rb_erase():
- Avoid multiple loading of node->__rb_parent_color when computing parent
  and color information (possibly not in close sequence, as there might
  be further branches in the algorithm)
- In the 1-child subcase of case 1, copy the __rb_parent_color field from
  the erased node to the child instead of recomputing it from the desired
  parent and color
- When searching for the erased node's successor, differentiate between
  cases 2 and 3 based on whether any left links were followed. This avoids
  a condition later down.
- In case 3, keep a pointer to the erased node's right child so we don't
  have to refetch it later to adjust its parent.
- In the no-childs subcase of cases 2 and 3, place the rebalance assigment
  last so that the compiler can remove the following if(rebalance) test.

Also, added some comments to illustrate cases 2 and 3.

Signed-off-by: default avatarMichel Lespinasse <walken@google.com>
Acked-by: default avatarRik van Riel <riel@redhat.com>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Andrea Arcangeli <aarcange@redhat.com>
Cc: David Woodhouse <dwmw2@infradead.org>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 46b6135a
Loading
Loading
Loading
Loading
+64 −34
Original line number Original line Diff line number Diff line
@@ -47,9 +47,14 @@
#define	RB_RED		0
#define	RB_RED		0
#define	RB_BLACK	1
#define	RB_BLACK	1


#define rb_color(r)   ((r)->__rb_parent_color & 1)
#define __rb_parent(pc)    ((struct rb_node *)(pc & ~3))
#define rb_is_red(r)   (!rb_color(r))

#define rb_is_black(r) rb_color(r)
#define __rb_color(pc)     ((pc) & 1)
#define __rb_is_black(pc)  __rb_color(pc)
#define __rb_is_red(pc)    (!__rb_color(pc))
#define rb_color(rb)       __rb_color((rb)->__rb_parent_color)
#define rb_is_red(rb)      __rb_is_red((rb)->__rb_parent_color)
#define rb_is_black(rb)    __rb_is_black((rb)->__rb_parent_color)


static inline void rb_set_black(struct rb_node *rb)
static inline void rb_set_black(struct rb_node *rb)
{
{
@@ -378,6 +383,7 @@ void rb_erase(struct rb_node *node, struct rb_root *root)
{
{
	struct rb_node *child = node->rb_right, *tmp = node->rb_left;
	struct rb_node *child = node->rb_right, *tmp = node->rb_left;
	struct rb_node *parent, *rebalance;
	struct rb_node *parent, *rebalance;
	unsigned long pc;


	if (!tmp) {
	if (!tmp) {
		/*
		/*
@@ -387,51 +393,75 @@ void rb_erase(struct rb_node *node, struct rb_root *root)
		 * and node must be black due to 4). We adjust colors locally
		 * and node must be black due to 4). We adjust colors locally
		 * so as to bypass __rb_erase_color() later on.
		 * so as to bypass __rb_erase_color() later on.
		 */
		 */

		pc = node->__rb_parent_color;
		parent = rb_parent(node);
		parent = __rb_parent(pc);
		__rb_change_child(node, child, parent, root);
		__rb_change_child(node, child, parent, root);
		if (child) {
		if (child) {
			rb_set_parent_color(child, parent, RB_BLACK);
			child->__rb_parent_color = pc;
			rebalance = NULL;
			rebalance = NULL;
		} else {
		} else
			rebalance = rb_is_black(node) ? parent : NULL;
			rebalance = __rb_is_black(pc) ? parent : NULL;
		}
	} else if (!child) {
	} else if (!child) {
		/* Still case 1, but this time the child is node->rb_left */
		/* Still case 1, but this time the child is node->rb_left */
		parent = rb_parent(node);
		tmp->__rb_parent_color = pc = node->__rb_parent_color;
		parent = __rb_parent(pc);
		__rb_change_child(node, tmp, parent, root);
		__rb_change_child(node, tmp, parent, root);
		rb_set_parent_color(tmp, parent, RB_BLACK);
		rebalance = NULL;
		rebalance = NULL;
	} else {
	} else {
		struct rb_node *old = node, *left;
		struct rb_node *successor = child, *child2;

		tmp = child->rb_left;
		node = child;
		if (!tmp) {
		while ((left = node->rb_left) != NULL)
			/*
			node = left;
			 * Case 2: node's successor is its right child

			 *
		__rb_change_child(old, node, rb_parent(old), root);
			 *    (n)          (s)

			 *    / \          / \
		child = node->rb_right;
			 *  (x) (s)  ->  (x) (c)
		parent = rb_parent(node);
			 *        \

			 *        (c)
		if (parent == old) {
			 */
			parent = node;
			parent = child;
			child2 = child->rb_right;
		} else {
		} else {
			parent->rb_left = child;
			/*

			 * Case 3: node's successor is leftmost under
			node->rb_right = old->rb_right;
			 * node's right child subtree
			rb_set_parent(old->rb_right, node);
			 *
		}
			 *    (n)          (s)

			 *    / \          / \
		if (child) {
			 *  (x) (y)  ->  (x) (y)
			rb_set_parent_color(child, parent, RB_BLACK);
			 *      /            /
			 *    (p)          (p)
			 *    /            /
			 *  (s)          (c)
			 *    \
			 *    (c)
			 */
			do {
				parent = successor;
				successor = tmp;
				tmp = tmp->rb_left;
			} while (tmp);
			parent->rb_left = child2 = successor->rb_right;
			successor->rb_right = child;
			rb_set_parent(child, successor);
		}

		successor->rb_left = tmp = node->rb_left;
		rb_set_parent(tmp, successor);

		pc = node->__rb_parent_color;
		tmp = __rb_parent(pc);
		__rb_change_child(node, successor, tmp, root);
		if (child2) {
			successor->__rb_parent_color = pc;
			rb_set_parent_color(child2, parent, RB_BLACK);
			rebalance = NULL;
			rebalance = NULL;
		} else {
		} else {
			rebalance = rb_is_black(node) ? parent : NULL;
			unsigned long pc2 = successor->__rb_parent_color;
			successor->__rb_parent_color = pc;
			rebalance = __rb_is_black(pc2) ? parent : NULL;
		}
		}
		node->__rb_parent_color = old->__rb_parent_color;
		node->rb_left = old->rb_left;
		rb_set_parent(old->rb_left, node);
	}
	}


	if (rebalance)
	if (rebalance)