diff options
author | Michel Lespinasse <walken@google.com> | 2012-10-08 19:31:13 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-10-09 03:22:37 -0400 |
commit | 4f035ad67f4633c233cb3642711d49b4efc9c82d (patch) | |
tree | 151fd5ff00a07da479805a01cb8b1d370db72d8f | |
parent | 46b6135a7402ac23c5b25f2bd79b03bab8f98278 (diff) |
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: Michel Lespinasse <walken@google.com>
Acked-by: Rik 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: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | lib/rbtree.c | 98 |
1 files changed, 64 insertions, 34 deletions
diff --git a/lib/rbtree.c b/lib/rbtree.c index 80b092538fa9..938061ecbe61 100644 --- a/lib/rbtree.c +++ b/lib/rbtree.c | |||
@@ -47,9 +47,14 @@ | |||
47 | #define RB_RED 0 | 47 | #define RB_RED 0 |
48 | #define RB_BLACK 1 | 48 | #define RB_BLACK 1 |
49 | 49 | ||
50 | #define rb_color(r) ((r)->__rb_parent_color & 1) | 50 | #define __rb_parent(pc) ((struct rb_node *)(pc & ~3)) |
51 | #define rb_is_red(r) (!rb_color(r)) | 51 | |
52 | #define rb_is_black(r) rb_color(r) | 52 | #define __rb_color(pc) ((pc) & 1) |
53 | #define __rb_is_black(pc) __rb_color(pc) | ||
54 | #define __rb_is_red(pc) (!__rb_color(pc)) | ||
55 | #define rb_color(rb) __rb_color((rb)->__rb_parent_color) | ||
56 | #define rb_is_red(rb) __rb_is_red((rb)->__rb_parent_color) | ||
57 | #define rb_is_black(rb) __rb_is_black((rb)->__rb_parent_color) | ||
53 | 58 | ||
54 | static inline void rb_set_black(struct rb_node *rb) | 59 | static inline void rb_set_black(struct rb_node *rb) |
55 | { | 60 | { |
@@ -378,6 +383,7 @@ void rb_erase(struct rb_node *node, struct rb_root *root) | |||
378 | { | 383 | { |
379 | struct rb_node *child = node->rb_right, *tmp = node->rb_left; | 384 | struct rb_node *child = node->rb_right, *tmp = node->rb_left; |
380 | struct rb_node *parent, *rebalance; | 385 | struct rb_node *parent, *rebalance; |
386 | unsigned long pc; | ||
381 | 387 | ||
382 | if (!tmp) { | 388 | if (!tmp) { |
383 | /* | 389 | /* |
@@ -387,51 +393,75 @@ void rb_erase(struct rb_node *node, struct rb_root *root) | |||
387 | * and node must be black due to 4). We adjust colors locally | 393 | * and node must be black due to 4). We adjust colors locally |
388 | * so as to bypass __rb_erase_color() later on. | 394 | * so as to bypass __rb_erase_color() later on. |
389 | */ | 395 | */ |
390 | 396 | pc = node->__rb_parent_color; | |
391 | parent = rb_parent(node); | 397 | parent = __rb_parent(pc); |
392 | __rb_change_child(node, child, parent, root); | 398 | __rb_change_child(node, child, parent, root); |
393 | if (child) { | 399 | if (child) { |
394 | rb_set_parent_color(child, parent, RB_BLACK); | 400 | child->__rb_parent_color = pc; |
395 | rebalance = NULL; | 401 | rebalance = NULL; |
396 | } else { | 402 | } else |
397 | rebalance = rb_is_black(node) ? parent : NULL; | 403 | rebalance = __rb_is_black(pc) ? parent : NULL; |
398 | } | ||
399 | } else if (!child) { | 404 | } else if (!child) { |
400 | /* Still case 1, but this time the child is node->rb_left */ | 405 | /* Still case 1, but this time the child is node->rb_left */ |
401 | parent = rb_parent(node); | 406 | tmp->__rb_parent_color = pc = node->__rb_parent_color; |
407 | parent = __rb_parent(pc); | ||
402 | __rb_change_child(node, tmp, parent, root); | 408 | __rb_change_child(node, tmp, parent, root); |
403 | rb_set_parent_color(tmp, parent, RB_BLACK); | ||
404 | rebalance = NULL; | 409 | rebalance = NULL; |
405 | } else { | 410 | } else { |
406 | struct rb_node *old = node, *left; | 411 | struct rb_node *successor = child, *child2; |
407 | 412 | tmp = child->rb_left; | |
408 | node = child; | 413 | if (!tmp) { |
409 | while ((left = node->rb_left) != NULL) | 414 | /* |
410 | node = left; | 415 | * Case 2: node's successor is its right child |
411 | 416 | * | |
412 | __rb_change_child(old, node, rb_parent(old), root); | 417 | * (n) (s) |
413 | 418 | * / \ / \ | |
414 | child = node->rb_right; | 419 | * (x) (s) -> (x) (c) |
415 | parent = rb_parent(node); | 420 | * \ |
416 | 421 | * (c) | |
417 | if (parent == old) { | 422 | */ |
418 | parent = node; | 423 | parent = child; |
424 | child2 = child->rb_right; | ||
419 | } else { | 425 | } else { |
420 | parent->rb_left = child; | 426 | /* |
421 | 427 | * Case 3: node's successor is leftmost under | |
422 | node->rb_right = old->rb_right; | 428 | * node's right child subtree |
423 | rb_set_parent(old->rb_right, node); | 429 | * |
430 | * (n) (s) | ||
431 | * / \ / \ | ||
432 | * (x) (y) -> (x) (y) | ||
433 | * / / | ||
434 | * (p) (p) | ||
435 | * / / | ||
436 | * (s) (c) | ||
437 | * \ | ||
438 | * (c) | ||
439 | */ | ||
440 | do { | ||
441 | parent = successor; | ||
442 | successor = tmp; | ||
443 | tmp = tmp->rb_left; | ||
444 | } while (tmp); | ||
445 | parent->rb_left = child2 = successor->rb_right; | ||
446 | successor->rb_right = child; | ||
447 | rb_set_parent(child, successor); | ||
424 | } | 448 | } |
425 | 449 | ||
426 | if (child) { | 450 | successor->rb_left = tmp = node->rb_left; |
427 | rb_set_parent_color(child, parent, RB_BLACK); | 451 | rb_set_parent(tmp, successor); |
452 | |||
453 | pc = node->__rb_parent_color; | ||
454 | tmp = __rb_parent(pc); | ||
455 | __rb_change_child(node, successor, tmp, root); | ||
456 | if (child2) { | ||
457 | successor->__rb_parent_color = pc; | ||
458 | rb_set_parent_color(child2, parent, RB_BLACK); | ||
428 | rebalance = NULL; | 459 | rebalance = NULL; |
429 | } else { | 460 | } else { |
430 | rebalance = rb_is_black(node) ? parent : NULL; | 461 | unsigned long pc2 = successor->__rb_parent_color; |
462 | successor->__rb_parent_color = pc; | ||
463 | rebalance = __rb_is_black(pc2) ? parent : NULL; | ||
431 | } | 464 | } |
432 | node->__rb_parent_color = old->__rb_parent_color; | ||
433 | node->rb_left = old->rb_left; | ||
434 | rb_set_parent(old->rb_left, node); | ||
435 | } | 465 | } |
436 | 466 | ||
437 | if (rebalance) | 467 | if (rebalance) |