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) |
