rbtree: optimize root-check during rebalancing loop
authorDavidlohr Bueso <dave@stgolabs.net>
Fri, 8 Sep 2017 23:14:39 +0000 (16:14 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 9 Sep 2017 01:26:48 +0000 (18:26 -0700)
The only times the nil-parent (root node) condition is true is when the
node is the first in the tree, or after fixing rbtree rule #4 and the
case 1 rebalancing made the node the root.  Such conditions do not apply
most of the time:

(i) The common case in an rbtree is to have more than a single node,
    so this is only true for the first rb_insert().

(ii) While there is a chance only one first rotation is needed, cases
    where the node's uncle is black (cases 2,3) are more common as we can
    have the following scenarios during the rotation looping:

    case1 only, case1+1, case2+3, case1+2+3, case3 only, etc.

This patch, therefore, adds an unlikely() optimization to this
conditional.  When profiling with CONFIG_PROFILE_ANNOTATED_BRANCHES, a
kernel build shows that the incorrect rate is less than 15%, and for
workloads that involve insert mostly trees overtime tend to have less
than 2% incorrect rate.

Link: http://lkml.kernel.org/r/20170719014603.19029-3-dave@stgolabs.net
Signed-off-by: Davidlohr Bueso <dbueso@suse.de>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
lib/rbtree.c

index d102d9d2ffaa640f4406dc59a576fa79e7e396b1..e7cce12f404fb073f3c8d8dda08b1f068713a99f 100644 (file)
@@ -105,16 +105,25 @@ __rb_insert(struct rb_node *node, struct rb_root *root,
 
        while (true) {
                /*
-                * Loop invariant: node is red
-                *
-                * If there is a black parent, we are done.
-                * Otherwise, take some corrective action as we don't
-                * want a red root or two consecutive red nodes.
+                * Loop invariant: node is red.
                 */
-               if (!parent) {
+               if (unlikely(!parent)) {
+                       /*
+                        * The inserted node is root. Either this is the
+                        * first node, or we recursed at Case 1 below and
+                        * are no longer violating 4).
+                        */
                        rb_set_parent_color(node, NULL, RB_BLACK);
                        break;
-               } else if (rb_is_black(parent))
+               }
+
+               /*
+                * If there is a black parent, we are done.
+                * Otherwise, take some corrective action as,
+                * per 4), we don't want a red root or two
+                * consecutive red nodes.
+                */
+               if(rb_is_black(parent))
                        break;
 
                gparent = rb_red_parent(parent);