aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichel Lespinasse <walken@google.com>2012-10-08 19:30:47 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2012-10-09 03:22:34 -0400
commit5bc9188aa207dafd47eab57df7c4fe5b3d3f636a (patch)
tree09bce40b0253f38250dd180315d7b3fa22999988
parent6d58452dc066db61acdff7b84671db1b11a3de1c (diff)
rbtree: low level optimizations in rb_insert_color()
- Use the newly introduced rb_set_parent_color() function to flip the color of nodes whose parent is already known. - Optimize rb_parent() when the node is known to be red - there is no need to mask out the color in that case. - Flipping gparent's color to red requires us to fetch its rb_parent_color field, so we can reuse it as the parent value for the next loop iteration. - Do not use __rb_rotate_left() and __rb_rotate_right() to handle tree rotations: we already have pointers to all relevant nodes, and know their colors (either because we want to adjust it, or because we've tested it, or we can deduce it as black due to the node proximity to a known red node). So we can generate more efficient code by making use of the node pointers we already have, and setting both the parent and color attributes for nodes all at once. Also in Case 2, some node attributes don't have to be set because we know another tree rotation (Case 3) will always follow and override them. Signed-off-by: Michel Lespinasse <walken@google.com> Cc: Andrea Arcangeli <aarcange@redhat.com> Acked-by: David Woodhouse <David.Woodhouse@intel.com> Cc: Rik van Riel <riel@redhat.com> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Daniel Santos <daniel.santos@pobox.com> Cc: Jens Axboe <axboe@kernel.dk> Cc: "Eric W. Biederman" <ebiederm@xmission.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--lib/rbtree.c166
1 files changed, 131 insertions, 35 deletions
diff --git a/lib/rbtree.c b/lib/rbtree.c
index d0be5fcaafe..41cf19b2fe5 100644
--- a/lib/rbtree.c
+++ b/lib/rbtree.c
@@ -23,6 +23,25 @@
23#include <linux/rbtree.h> 23#include <linux/rbtree.h>
24#include <linux/export.h> 24#include <linux/export.h>
25 25
26/*
27 * red-black trees properties: http://en.wikipedia.org/wiki/Rbtree
28 *
29 * 1) A node is either red or black
30 * 2) The root is black
31 * 3) All leaves (NULL) are black
32 * 4) Both children of every red node are black
33 * 5) Every simple path from root to leaves contains the same number
34 * of black nodes.
35 *
36 * 4 and 5 give the O(log n) guarantee, since 4 implies you cannot have two
37 * consecutive red nodes in a path and every red node is therefore followed by
38 * a black. So if B is the number of black nodes on every simple path (as per
39 * 5), then the longest possible path due to 4 is 2B.
40 *
41 * We shall indicate color with case, where black nodes are uppercase and red
42 * nodes will be lowercase.
43 */
44
26#define RB_RED 0 45#define RB_RED 0
27#define RB_BLACK 1 46#define RB_BLACK 1
28 47
@@ -41,6 +60,17 @@ static inline void rb_set_color(struct rb_node *rb, int color)
41 rb->__rb_parent_color = (rb->__rb_parent_color & ~1) | color; 60 rb->__rb_parent_color = (rb->__rb_parent_color & ~1) | color;
42} 61}
43 62
63static inline void rb_set_parent_color(struct rb_node *rb,
64 struct rb_node *p, int color)
65{
66 rb->__rb_parent_color = (unsigned long)p | color;
67}
68
69static inline struct rb_node *rb_red_parent(struct rb_node *red)
70{
71 return (struct rb_node *)red->__rb_parent_color;
72}
73
44static void __rb_rotate_left(struct rb_node *node, struct rb_root *root) 74static void __rb_rotate_left(struct rb_node *node, struct rb_root *root)
45{ 75{
46 struct rb_node *right = node->rb_right; 76 struct rb_node *right = node->rb_right;
@@ -87,9 +117,30 @@ static void __rb_rotate_right(struct rb_node *node, struct rb_root *root)
87 rb_set_parent(node, left); 117 rb_set_parent(node, left);
88} 118}
89 119
120/*
121 * Helper function for rotations:
122 * - old's parent and color get assigned to new
123 * - old gets assigned new as a parent and 'color' as a color.
124 */
125static inline void
126__rb_rotate_set_parents(struct rb_node *old, struct rb_node *new,
127 struct rb_root *root, int color)
128{
129 struct rb_node *parent = rb_parent(old);
130 new->__rb_parent_color = old->__rb_parent_color;
131 rb_set_parent_color(old, new, color);
132 if (parent) {
133 if (parent->rb_left == old)
134 parent->rb_left = new;
135 else
136 parent->rb_right = new;
137 } else
138 root->rb_node = new;
139}
140
90void rb_insert_color(struct rb_node *node, struct rb_root *root) 141void rb_insert_color(struct rb_node *node, struct rb_root *root)
91{ 142{
92 struct rb_node *parent, *gparent; 143 struct rb_node *parent = rb_red_parent(node), *gparent, *tmp;
93 144
94 while (true) { 145 while (true) {
95 /* 146 /*
@@ -99,59 +150,104 @@ void rb_insert_color(struct rb_node *node, struct rb_root *root)
99 * Otherwise, take some corrective action as we don't 150 * Otherwise, take some corrective action as we don't
100 * want a red root or two consecutive red nodes. 151 * want a red root or two consecutive red nodes.
101 */ 152 */
102 parent = rb_parent(node);
103 if (!parent) { 153 if (!parent) {
104 rb_set_black(node); 154 rb_set_parent_color(node, NULL, RB_BLACK);
105 break; 155 break;
106 } else if (rb_is_black(parent)) 156 } else if (rb_is_black(parent))
107 break; 157 break;
108 158
109 gparent = rb_parent(parent); 159 gparent = rb_red_parent(parent);
110 160
111 if (parent == gparent->rb_left) 161 if (parent == gparent->rb_left) {
112 { 162 tmp = gparent->rb_right;
113 { 163 if (tmp && rb_is_red(tmp)) {
114 register struct rb_node *uncle = gparent->rb_right; 164 /*
115 if (uncle && rb_is_red(uncle)) 165 * Case 1 - color flips
116 { 166 *
117 rb_set_black(uncle); 167 * G g
118 rb_set_black(parent); 168 * / \ / \
119 rb_set_red(gparent); 169 * p u --> P U
120 node = gparent; 170 * / /
121 continue; 171 * n N
122 } 172 *
173 * However, since g's parent might be red, and
174 * 4) does not allow this, we need to recurse
175 * at g.
176 */
177 rb_set_parent_color(tmp, gparent, RB_BLACK);
178 rb_set_parent_color(parent, gparent, RB_BLACK);
179 node = gparent;
180 parent = rb_parent(node);
181 rb_set_parent_color(node, parent, RB_RED);
182 continue;
123 } 183 }
124 184
125 if (parent->rb_right == node) { 185 if (parent->rb_right == node) {
126 __rb_rotate_left(parent, root); 186 /*
187 * Case 2 - left rotate at parent
188 *
189 * G G
190 * / \ / \
191 * p U --> n U
192 * \ /
193 * n p
194 *
195 * This still leaves us in violation of 4), the
196 * continuation into Case 3 will fix that.
197 */
198 parent->rb_right = tmp = node->rb_left;
199 node->rb_left = parent;
200 if (tmp)
201 rb_set_parent_color(tmp, parent,
202 RB_BLACK);
203 rb_set_parent_color(parent, node, RB_RED);
127 parent = node; 204 parent = node;
128 } 205 }
129 206
130 rb_set_black(parent); 207 /*
131 rb_set_red(gparent); 208 * Case 3 - right rotate at gparent
132 __rb_rotate_right(gparent, root); 209 *
210 * G P
211 * / \ / \
212 * p U --> n g
213 * / \
214 * n U
215 */
216 gparent->rb_left = tmp = parent->rb_right;
217 parent->rb_right = gparent;
218 if (tmp)
219 rb_set_parent_color(tmp, gparent, RB_BLACK);
220 __rb_rotate_set_parents(gparent, parent, root, RB_RED);
133 break; 221 break;
134 } else { 222 } else {
135 { 223 tmp = gparent->rb_left;
136 register struct rb_node *uncle = gparent->rb_left; 224 if (tmp && rb_is_red(tmp)) {
137 if (uncle && rb_is_red(uncle)) 225 /* Case 1 - color flips */
138 { 226 rb_set_parent_color(tmp, gparent, RB_BLACK);
139 rb_set_black(uncle); 227 rb_set_parent_color(parent, gparent, RB_BLACK);
140 rb_set_black(parent); 228 node = gparent;
141 rb_set_red(gparent); 229 parent = rb_parent(node);
142 node = gparent; 230 rb_set_parent_color(node, parent, RB_RED);
143 continue; 231 continue;
144 }
145 } 232 }
146 233
147 if (parent->rb_left == node) { 234 if (parent->rb_left == node) {
148 __rb_rotate_right(parent, root); 235 /* Case 2 - right rotate at parent */
236 parent->rb_left = tmp = node->rb_right;
237 node->rb_right = parent;
238 if (tmp)
239 rb_set_parent_color(tmp, parent,
240 RB_BLACK);
241 rb_set_parent_color(parent, node, RB_RED);
149 parent = node; 242 parent = node;
150 } 243 }
151 244
152 rb_set_black(parent); 245 /* Case 3 - left rotate at gparent */
153 rb_set_red(gparent); 246 gparent->rb_right = tmp = parent->rb_left;
154 __rb_rotate_left(gparent, root); 247 parent->rb_left = gparent;
248 if (tmp)
249 rb_set_parent_color(tmp, gparent, RB_BLACK);
250 __rb_rotate_set_parents(gparent, parent, root, RB_RED);
155 break; 251 break;
156 } 252 }
157 } 253 }