aboutsummaryrefslogtreecommitdiffstats
path: root/lib/rbtree_test.c
diff options
context:
space:
mode:
authorMichel Lespinasse <walken@google.com>2012-10-08 19:31:17 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2012-10-09 03:22:37 -0400
commit14b94af0b251a2c80885b60538166fb7d04a642e (patch)
treeef447d340435c441f8c3e54eb8f26f747aa73108 /lib/rbtree_test.c
parentdadf93534f125b9eda486b471446a8456a603d27 (diff)
rbtree: faster augmented rbtree manipulation
Introduce new augmented rbtree APIs that allow minimal recalculation of augmented node information. A new callback is added to the rbtree insertion and erase rebalancing functions, to be called on each tree rotations. Such rotations preserve the subtree's root augmented value, but require recalculation of the one child that was previously located at the subtree root. In the insertion case, the handcoded search phase must be updated to maintain the augmented information on insertion, and then the rbtree coloring/rebalancing algorithms keep it up to date. In the erase case, things are more complicated since it is library code that manipulates the rbtree in order to remove internal nodes. This requires a couple additional callbacks to copy a subtree's augmented value when a new root is stitched in, and to recompute augmented values down the ancestry path when a node is removed from the tree. In order to preserve maximum speed for the non-augmented case, we provide two versions of each tree manipulation function. rb_insert_augmented() is the augmented equivalent of rb_insert_color(), and rb_erase_augmented() is the augmented equivalent of rb_erase(). 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>
Diffstat (limited to 'lib/rbtree_test.c')
-rw-r--r--lib/rbtree_test.c58
1 files changed, 44 insertions, 14 deletions
diff --git a/lib/rbtree_test.c b/lib/rbtree_test.c
index 66e41d4bfc39..e28345df09bf 100644
--- a/lib/rbtree_test.c
+++ b/lib/rbtree_test.c
@@ -61,35 +61,65 @@ static inline u32 augment_recompute(struct test_node *node)
61 return max; 61 return max;
62} 62}
63 63
64static void augment_callback(struct rb_node *rb, void *unused) 64static void augment_propagate(struct rb_node *rb, struct rb_node *stop)
65{ 65{
66 struct test_node *node = rb_entry(rb, struct test_node, rb); 66 while (rb != stop) {
67 node->augmented = augment_recompute(node); 67 struct test_node *node = rb_entry(rb, struct test_node, rb);
68 u32 augmented = augment_recompute(node);
69 if (node->augmented == augmented)
70 break;
71 node->augmented = augmented;
72 rb = rb_parent(&node->rb);
73 }
74}
75
76static void augment_copy(struct rb_node *rb_old, struct rb_node *rb_new)
77{
78 struct test_node *old = rb_entry(rb_old, struct test_node, rb);
79 struct test_node *new = rb_entry(rb_new, struct test_node, rb);
80 new->augmented = old->augmented;
68} 81}
69 82
83static void augment_rotate(struct rb_node *rb_old, struct rb_node *rb_new)
84{
85 struct test_node *old = rb_entry(rb_old, struct test_node, rb);
86 struct test_node *new = rb_entry(rb_new, struct test_node, rb);
87
88 /* Rotation doesn't change subtree's augmented value */
89 new->augmented = old->augmented;
90 old->augmented = augment_recompute(old);
91}
92
93static const struct rb_augment_callbacks augment_callbacks = {
94 augment_propagate, augment_copy, augment_rotate
95};
96
70static void insert_augmented(struct test_node *node, struct rb_root *root) 97static void insert_augmented(struct test_node *node, struct rb_root *root)
71{ 98{
72 struct rb_node **new = &root->rb_node, *parent = NULL; 99 struct rb_node **new = &root->rb_node, *rb_parent = NULL;
73 u32 key = node->key; 100 u32 key = node->key;
101 u32 val = node->val;
102 struct test_node *parent;
74 103
75 while (*new) { 104 while (*new) {
76 parent = *new; 105 rb_parent = *new;
77 if (key < rb_entry(parent, struct test_node, rb)->key) 106 parent = rb_entry(rb_parent, struct test_node, rb);
78 new = &parent->rb_left; 107 if (parent->augmented < val)
108 parent->augmented = val;
109 if (key < parent->key)
110 new = &parent->rb.rb_left;
79 else 111 else
80 new = &parent->rb_right; 112 new = &parent->rb.rb_right;
81 } 113 }
82 114
83 rb_link_node(&node->rb, parent, new); 115 node->augmented = val;
84 rb_insert_color(&node->rb, root); 116 rb_link_node(&node->rb, rb_parent, new);
85 rb_augment_insert(&node->rb, augment_callback, NULL); 117 rb_insert_augmented(&node->rb, root, &augment_callbacks);
86} 118}
87 119
88static void erase_augmented(struct test_node *node, struct rb_root *root) 120static void erase_augmented(struct test_node *node, struct rb_root *root)
89{ 121{
90 struct rb_node *deepest = rb_augment_erase_begin(&node->rb); 122 rb_erase_augmented(&node->rb, root, &augment_callbacks);
91 rb_erase(&node->rb, root);
92 rb_augment_erase_end(deepest, augment_callback, NULL);
93} 123}
94 124
95static void init(void) 125static void init(void)