diff options
author | Arnaldo Carvalho de Melo <acme@redhat.com> | 2009-05-18 15:24:49 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-05-26 07:52:55 -0400 |
commit | 35a50c8a20eea22c141e05c5667ac21c48b8b65d (patch) | |
tree | 6b48bf9647023a207fd3ab1d7bfdcda5a1d38746 /Documentation | |
parent | 62eb93905b3b43cea407cfbc061cc7b40ae1c6e9 (diff) |
perf_counter: Use rb_trees in perf report
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Acked-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Corey Ashford <cjashfor@linux.vnet.ibm.com>
Cc: Marcelo Tosatti <mtosatti@redhat.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
LKML-Reference: <new-submission>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'Documentation')
-rw-r--r-- | Documentation/perf_counter/Makefile | 3 | ||||
-rw-r--r-- | Documentation/perf_counter/builtin-report.c | 60 | ||||
-rw-r--r-- | Documentation/perf_counter/util/rbtree.c | 383 | ||||
-rw-r--r-- | Documentation/perf_counter/util/rbtree.h | 171 |
4 files changed, 601 insertions, 16 deletions
diff --git a/Documentation/perf_counter/Makefile b/Documentation/perf_counter/Makefile index 6bffa86af6be..412dea15d0b7 100644 --- a/Documentation/perf_counter/Makefile +++ b/Documentation/perf_counter/Makefile | |||
@@ -287,6 +287,8 @@ LIB_FILE=libperf.a | |||
287 | 287 | ||
288 | LIB_H += ../../include/linux/perf_counter.h | 288 | LIB_H += ../../include/linux/perf_counter.h |
289 | LIB_H += perf.h | 289 | LIB_H += perf.h |
290 | LIB_H += util/list.h | ||
291 | LIB_H += util/rbtree.h | ||
290 | LIB_H += util/levenshtein.h | 292 | LIB_H += util/levenshtein.h |
291 | LIB_H += util/parse-options.h | 293 | LIB_H += util/parse-options.h |
292 | LIB_H += util/parse-events.h | 294 | LIB_H += util/parse-events.h |
@@ -306,6 +308,7 @@ LIB_OBJS += util/levenshtein.o | |||
306 | LIB_OBJS += util/parse-options.o | 308 | LIB_OBJS += util/parse-options.o |
307 | LIB_OBJS += util/parse-events.o | 309 | LIB_OBJS += util/parse-events.o |
308 | LIB_OBJS += util/path.o | 310 | LIB_OBJS += util/path.o |
311 | LIB_OBJS += util/rbtree.o | ||
309 | LIB_OBJS += util/run-command.o | 312 | LIB_OBJS += util/run-command.o |
310 | LIB_OBJS += util/quote.o | 313 | LIB_OBJS += util/quote.o |
311 | LIB_OBJS += util/strbuf.o | 314 | LIB_OBJS += util/strbuf.o |
diff --git a/Documentation/perf_counter/builtin-report.c b/Documentation/perf_counter/builtin-report.c index ad2f327a6576..f63057fe2cd2 100644 --- a/Documentation/perf_counter/builtin-report.c +++ b/Documentation/perf_counter/builtin-report.c | |||
@@ -32,7 +32,8 @@ | |||
32 | #include <linux/types.h> | 32 | #include <linux/types.h> |
33 | 33 | ||
34 | #include "../../include/linux/perf_counter.h" | 34 | #include "../../include/linux/perf_counter.h" |
35 | #include "list.h" | 35 | #include "util/list.h" |
36 | #include "util/rbtree.h" | ||
36 | 37 | ||
37 | #define SHOW_KERNEL 1 | 38 | #define SHOW_KERNEL 1 |
38 | #define SHOW_USER 2 | 39 | #define SHOW_USER 2 |
@@ -106,10 +107,10 @@ static void section__delete(struct section *self) | |||
106 | } | 107 | } |
107 | 108 | ||
108 | struct symbol { | 109 | struct symbol { |
109 | struct list_head node; | 110 | struct rb_node rb_node; |
110 | uint64_t start; | 111 | uint64_t start; |
111 | uint64_t end; | 112 | uint64_t end; |
112 | char name[0]; | 113 | char name[0]; |
113 | }; | 114 | }; |
114 | 115 | ||
115 | static struct symbol *symbol__new(uint64_t start, uint64_t len, const char *name) | 116 | static struct symbol *symbol__new(uint64_t start, uint64_t len, const char *name) |
@@ -139,7 +140,7 @@ static size_t symbol__fprintf(struct symbol *self, FILE *fp) | |||
139 | struct dso { | 140 | struct dso { |
140 | struct list_head node; | 141 | struct list_head node; |
141 | struct list_head sections; | 142 | struct list_head sections; |
142 | struct list_head syms; | 143 | struct rb_root syms; |
143 | char name[0]; | 144 | char name[0]; |
144 | }; | 145 | }; |
145 | 146 | ||
@@ -150,7 +151,7 @@ static struct dso *dso__new(const char *name) | |||
150 | if (self != NULL) { | 151 | if (self != NULL) { |
151 | strcpy(self->name, name); | 152 | strcpy(self->name, name); |
152 | INIT_LIST_HEAD(&self->sections); | 153 | INIT_LIST_HEAD(&self->sections); |
153 | INIT_LIST_HEAD(&self->syms); | 154 | self->syms = RB_ROOT; |
154 | } | 155 | } |
155 | 156 | ||
156 | return self; | 157 | return self; |
@@ -166,10 +167,14 @@ static void dso__delete_sections(struct dso *self) | |||
166 | 167 | ||
167 | static void dso__delete_symbols(struct dso *self) | 168 | static void dso__delete_symbols(struct dso *self) |
168 | { | 169 | { |
169 | struct symbol *pos, *n; | 170 | struct symbol *pos; |
171 | struct rb_node *next = rb_first(&self->syms); | ||
170 | 172 | ||
171 | list_for_each_entry_safe(pos, n, &self->syms, node) | 173 | while (next) { |
174 | pos = rb_entry(next, struct symbol, rb_node); | ||
175 | next = rb_next(&pos->rb_node); | ||
172 | symbol__delete(pos); | 176 | symbol__delete(pos); |
177 | } | ||
173 | } | 178 | } |
174 | 179 | ||
175 | static void dso__delete(struct dso *self) | 180 | static void dso__delete(struct dso *self) |
@@ -181,7 +186,21 @@ static void dso__delete(struct dso *self) | |||
181 | 186 | ||
182 | static void dso__insert_symbol(struct dso *self, struct symbol *sym) | 187 | static void dso__insert_symbol(struct dso *self, struct symbol *sym) |
183 | { | 188 | { |
184 | list_add_tail(&sym->node, &self->syms); | 189 | struct rb_node **p = &self->syms.rb_node; |
190 | struct rb_node *parent = NULL; | ||
191 | const uint64_t ip = sym->start; | ||
192 | struct symbol *s; | ||
193 | |||
194 | while (*p != NULL) { | ||
195 | parent = *p; | ||
196 | s = rb_entry(parent, struct symbol, rb_node); | ||
197 | if (ip < s->start) | ||
198 | p = &(*p)->rb_left; | ||
199 | else | ||
200 | p = &(*p)->rb_right; | ||
201 | } | ||
202 | rb_link_node(&sym->rb_node, parent, p); | ||
203 | rb_insert_color(&sym->rb_node, &self->syms); | ||
185 | } | 204 | } |
186 | 205 | ||
187 | static struct symbol *dso__find_symbol(struct dso *self, uint64_t ip) | 206 | static struct symbol *dso__find_symbol(struct dso *self, uint64_t ip) |
@@ -189,11 +208,18 @@ static struct symbol *dso__find_symbol(struct dso *self, uint64_t ip) | |||
189 | if (self == NULL) | 208 | if (self == NULL) |
190 | return NULL; | 209 | return NULL; |
191 | 210 | ||
192 | struct symbol *pos; | 211 | struct rb_node *n = self->syms.rb_node; |
193 | 212 | ||
194 | list_for_each_entry(pos, &self->syms, node) | 213 | while (n) { |
195 | if (ip >= pos->start && ip <= pos->end) | 214 | struct symbol *s = rb_entry(n, struct symbol, rb_node); |
196 | return pos; | 215 | |
216 | if (ip < s->start) | ||
217 | n = n->rb_left; | ||
218 | else if (ip > s->end) | ||
219 | n = n->rb_right; | ||
220 | else | ||
221 | return s; | ||
222 | } | ||
197 | 223 | ||
198 | return NULL; | 224 | return NULL; |
199 | } | 225 | } |
@@ -319,11 +345,13 @@ out_close: | |||
319 | 345 | ||
320 | static size_t dso__fprintf(struct dso *self, FILE *fp) | 346 | static size_t dso__fprintf(struct dso *self, FILE *fp) |
321 | { | 347 | { |
322 | struct symbol *pos; | ||
323 | size_t ret = fprintf(fp, "dso: %s\n", self->name); | 348 | size_t ret = fprintf(fp, "dso: %s\n", self->name); |
324 | 349 | ||
325 | list_for_each_entry(pos, &self->syms, node) | 350 | struct rb_node *nd; |
351 | for (nd = rb_first(&self->syms); nd; nd = rb_next(nd)) { | ||
352 | struct symbol *pos = rb_entry(nd, struct symbol, rb_node); | ||
326 | ret += symbol__fprintf(pos, fp); | 353 | ret += symbol__fprintf(pos, fp); |
354 | } | ||
327 | 355 | ||
328 | return ret; | 356 | return ret; |
329 | } | 357 | } |
diff --git a/Documentation/perf_counter/util/rbtree.c b/Documentation/perf_counter/util/rbtree.c new file mode 100644 index 000000000000..b15ba9c7cb3f --- /dev/null +++ b/Documentation/perf_counter/util/rbtree.c | |||
@@ -0,0 +1,383 @@ | |||
1 | /* | ||
2 | Red Black Trees | ||
3 | (C) 1999 Andrea Arcangeli <andrea@suse.de> | ||
4 | (C) 2002 David Woodhouse <dwmw2@infradead.org> | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation; either version 2 of the License, or | ||
9 | (at your option) any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with this program; if not, write to the Free Software | ||
18 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | |||
20 | linux/lib/rbtree.c | ||
21 | */ | ||
22 | |||
23 | #include "rbtree.h" | ||
24 | |||
25 | static void __rb_rotate_left(struct rb_node *node, struct rb_root *root) | ||
26 | { | ||
27 | struct rb_node *right = node->rb_right; | ||
28 | struct rb_node *parent = rb_parent(node); | ||
29 | |||
30 | if ((node->rb_right = right->rb_left)) | ||
31 | rb_set_parent(right->rb_left, node); | ||
32 | right->rb_left = node; | ||
33 | |||
34 | rb_set_parent(right, parent); | ||
35 | |||
36 | if (parent) | ||
37 | { | ||
38 | if (node == parent->rb_left) | ||
39 | parent->rb_left = right; | ||
40 | else | ||
41 | parent->rb_right = right; | ||
42 | } | ||
43 | else | ||
44 | root->rb_node = right; | ||
45 | rb_set_parent(node, right); | ||
46 | } | ||
47 | |||
48 | static void __rb_rotate_right(struct rb_node *node, struct rb_root *root) | ||
49 | { | ||
50 | struct rb_node *left = node->rb_left; | ||
51 | struct rb_node *parent = rb_parent(node); | ||
52 | |||
53 | if ((node->rb_left = left->rb_right)) | ||
54 | rb_set_parent(left->rb_right, node); | ||
55 | left->rb_right = node; | ||
56 | |||
57 | rb_set_parent(left, parent); | ||
58 | |||
59 | if (parent) | ||
60 | { | ||
61 | if (node == parent->rb_right) | ||
62 | parent->rb_right = left; | ||
63 | else | ||
64 | parent->rb_left = left; | ||
65 | } | ||
66 | else | ||
67 | root->rb_node = left; | ||
68 | rb_set_parent(node, left); | ||
69 | } | ||
70 | |||
71 | void rb_insert_color(struct rb_node *node, struct rb_root *root) | ||
72 | { | ||
73 | struct rb_node *parent, *gparent; | ||
74 | |||
75 | while ((parent = rb_parent(node)) && rb_is_red(parent)) | ||
76 | { | ||
77 | gparent = rb_parent(parent); | ||
78 | |||
79 | if (parent == gparent->rb_left) | ||
80 | { | ||
81 | { | ||
82 | register struct rb_node *uncle = gparent->rb_right; | ||
83 | if (uncle && rb_is_red(uncle)) | ||
84 | { | ||
85 | rb_set_black(uncle); | ||
86 | rb_set_black(parent); | ||
87 | rb_set_red(gparent); | ||
88 | node = gparent; | ||
89 | continue; | ||
90 | } | ||
91 | } | ||
92 | |||
93 | if (parent->rb_right == node) | ||
94 | { | ||
95 | register struct rb_node *tmp; | ||
96 | __rb_rotate_left(parent, root); | ||
97 | tmp = parent; | ||
98 | parent = node; | ||
99 | node = tmp; | ||
100 | } | ||
101 | |||
102 | rb_set_black(parent); | ||
103 | rb_set_red(gparent); | ||
104 | __rb_rotate_right(gparent, root); | ||
105 | } else { | ||
106 | { | ||
107 | register struct rb_node *uncle = gparent->rb_left; | ||
108 | if (uncle && rb_is_red(uncle)) | ||
109 | { | ||
110 | rb_set_black(uncle); | ||
111 | rb_set_black(parent); | ||
112 | rb_set_red(gparent); | ||
113 | node = gparent; | ||
114 | continue; | ||
115 | } | ||
116 | } | ||
117 | |||
118 | if (parent->rb_left == node) | ||
119 | { | ||
120 | register struct rb_node *tmp; | ||
121 | __rb_rotate_right(parent, root); | ||
122 | tmp = parent; | ||
123 | parent = node; | ||
124 | node = tmp; | ||
125 | } | ||
126 | |||
127 | rb_set_black(parent); | ||
128 | rb_set_red(gparent); | ||
129 | __rb_rotate_left(gparent, root); | ||
130 | } | ||
131 | } | ||
132 | |||
133 | rb_set_black(root->rb_node); | ||
134 | } | ||
135 | |||
136 | static void __rb_erase_color(struct rb_node *node, struct rb_node *parent, | ||
137 | struct rb_root *root) | ||
138 | { | ||
139 | struct rb_node *other; | ||
140 | |||
141 | while ((!node || rb_is_black(node)) && node != root->rb_node) | ||
142 | { | ||
143 | if (parent->rb_left == node) | ||
144 | { | ||
145 | other = parent->rb_right; | ||
146 | if (rb_is_red(other)) | ||
147 | { | ||
148 | rb_set_black(other); | ||
149 | rb_set_red(parent); | ||
150 | __rb_rotate_left(parent, root); | ||
151 | other = parent->rb_right; | ||
152 | } | ||
153 | if ((!other->rb_left || rb_is_black(other->rb_left)) && | ||
154 | (!other->rb_right || rb_is_black(other->rb_right))) | ||
155 | { | ||
156 | rb_set_red(other); | ||
157 | node = parent; | ||
158 | parent = rb_parent(node); | ||
159 | } | ||
160 | else | ||
161 | { | ||
162 | if (!other->rb_right || rb_is_black(other->rb_right)) | ||
163 | { | ||
164 | rb_set_black(other->rb_left); | ||
165 | rb_set_red(other); | ||
166 | __rb_rotate_right(other, root); | ||
167 | other = parent->rb_right; | ||
168 | } | ||
169 | rb_set_color(other, rb_color(parent)); | ||
170 | rb_set_black(parent); | ||
171 | rb_set_black(other->rb_right); | ||
172 | __rb_rotate_left(parent, root); | ||
173 | node = root->rb_node; | ||
174 | break; | ||
175 | } | ||
176 | } | ||
177 | else | ||
178 | { | ||
179 | other = parent->rb_left; | ||
180 | if (rb_is_red(other)) | ||
181 | { | ||
182 | rb_set_black(other); | ||
183 | rb_set_red(parent); | ||
184 | __rb_rotate_right(parent, root); | ||
185 | other = parent->rb_left; | ||
186 | } | ||
187 | if ((!other->rb_left || rb_is_black(other->rb_left)) && | ||
188 | (!other->rb_right || rb_is_black(other->rb_right))) | ||
189 | { | ||
190 | rb_set_red(other); | ||
191 | node = parent; | ||
192 | parent = rb_parent(node); | ||
193 | } | ||
194 | else | ||
195 | { | ||
196 | if (!other->rb_left || rb_is_black(other->rb_left)) | ||
197 | { | ||
198 | rb_set_black(other->rb_right); | ||
199 | rb_set_red(other); | ||
200 | __rb_rotate_left(other, root); | ||
201 | other = parent->rb_left; | ||
202 | } | ||
203 | rb_set_color(other, rb_color(parent)); | ||
204 | rb_set_black(parent); | ||
205 | rb_set_black(other->rb_left); | ||
206 | __rb_rotate_right(parent, root); | ||
207 | node = root->rb_node; | ||
208 | break; | ||
209 | } | ||
210 | } | ||
211 | } | ||
212 | if (node) | ||
213 | rb_set_black(node); | ||
214 | } | ||
215 | |||
216 | void rb_erase(struct rb_node *node, struct rb_root *root) | ||
217 | { | ||
218 | struct rb_node *child, *parent; | ||
219 | int color; | ||
220 | |||
221 | if (!node->rb_left) | ||
222 | child = node->rb_right; | ||
223 | else if (!node->rb_right) | ||
224 | child = node->rb_left; | ||
225 | else | ||
226 | { | ||
227 | struct rb_node *old = node, *left; | ||
228 | |||
229 | node = node->rb_right; | ||
230 | while ((left = node->rb_left) != NULL) | ||
231 | node = left; | ||
232 | child = node->rb_right; | ||
233 | parent = rb_parent(node); | ||
234 | color = rb_color(node); | ||
235 | |||
236 | if (child) | ||
237 | rb_set_parent(child, parent); | ||
238 | if (parent == old) { | ||
239 | parent->rb_right = child; | ||
240 | parent = node; | ||
241 | } else | ||
242 | parent->rb_left = child; | ||
243 | |||
244 | node->rb_parent_color = old->rb_parent_color; | ||
245 | node->rb_right = old->rb_right; | ||
246 | node->rb_left = old->rb_left; | ||
247 | |||
248 | if (rb_parent(old)) | ||
249 | { | ||
250 | if (rb_parent(old)->rb_left == old) | ||
251 | rb_parent(old)->rb_left = node; | ||
252 | else | ||
253 | rb_parent(old)->rb_right = node; | ||
254 | } else | ||
255 | root->rb_node = node; | ||
256 | |||
257 | rb_set_parent(old->rb_left, node); | ||
258 | if (old->rb_right) | ||
259 | rb_set_parent(old->rb_right, node); | ||
260 | goto color; | ||
261 | } | ||
262 | |||
263 | parent = rb_parent(node); | ||
264 | color = rb_color(node); | ||
265 | |||
266 | if (child) | ||
267 | rb_set_parent(child, parent); | ||
268 | if (parent) | ||
269 | { | ||
270 | if (parent->rb_left == node) | ||
271 | parent->rb_left = child; | ||
272 | else | ||
273 | parent->rb_right = child; | ||
274 | } | ||
275 | else | ||
276 | root->rb_node = child; | ||
277 | |||
278 | color: | ||
279 | if (color == RB_BLACK) | ||
280 | __rb_erase_color(child, parent, root); | ||
281 | } | ||
282 | |||
283 | /* | ||
284 | * This function returns the first node (in sort order) of the tree. | ||
285 | */ | ||
286 | struct rb_node *rb_first(const struct rb_root *root) | ||
287 | { | ||
288 | struct rb_node *n; | ||
289 | |||
290 | n = root->rb_node; | ||
291 | if (!n) | ||
292 | return NULL; | ||
293 | while (n->rb_left) | ||
294 | n = n->rb_left; | ||
295 | return n; | ||
296 | } | ||
297 | |||
298 | struct rb_node *rb_last(const struct rb_root *root) | ||
299 | { | ||
300 | struct rb_node *n; | ||
301 | |||
302 | n = root->rb_node; | ||
303 | if (!n) | ||
304 | return NULL; | ||
305 | while (n->rb_right) | ||
306 | n = n->rb_right; | ||
307 | return n; | ||
308 | } | ||
309 | |||
310 | struct rb_node *rb_next(const struct rb_node *node) | ||
311 | { | ||
312 | struct rb_node *parent; | ||
313 | |||
314 | if (rb_parent(node) == node) | ||
315 | return NULL; | ||
316 | |||
317 | /* If we have a right-hand child, go down and then left as far | ||
318 | as we can. */ | ||
319 | if (node->rb_right) { | ||
320 | node = node->rb_right; | ||
321 | while (node->rb_left) | ||
322 | node=node->rb_left; | ||
323 | return (struct rb_node *)node; | ||
324 | } | ||
325 | |||
326 | /* No right-hand children. Everything down and left is | ||
327 | smaller than us, so any 'next' node must be in the general | ||
328 | direction of our parent. Go up the tree; any time the | ||
329 | ancestor is a right-hand child of its parent, keep going | ||
330 | up. First time it's a left-hand child of its parent, said | ||
331 | parent is our 'next' node. */ | ||
332 | while ((parent = rb_parent(node)) && node == parent->rb_right) | ||
333 | node = parent; | ||
334 | |||
335 | return parent; | ||
336 | } | ||
337 | |||
338 | struct rb_node *rb_prev(const struct rb_node *node) | ||
339 | { | ||
340 | struct rb_node *parent; | ||
341 | |||
342 | if (rb_parent(node) == node) | ||
343 | return NULL; | ||
344 | |||
345 | /* If we have a left-hand child, go down and then right as far | ||
346 | as we can. */ | ||
347 | if (node->rb_left) { | ||
348 | node = node->rb_left; | ||
349 | while (node->rb_right) | ||
350 | node=node->rb_right; | ||
351 | return (struct rb_node *)node; | ||
352 | } | ||
353 | |||
354 | /* No left-hand children. Go up till we find an ancestor which | ||
355 | is a right-hand child of its parent */ | ||
356 | while ((parent = rb_parent(node)) && node == parent->rb_left) | ||
357 | node = parent; | ||
358 | |||
359 | return parent; | ||
360 | } | ||
361 | |||
362 | void rb_replace_node(struct rb_node *victim, struct rb_node *new, | ||
363 | struct rb_root *root) | ||
364 | { | ||
365 | struct rb_node *parent = rb_parent(victim); | ||
366 | |||
367 | /* Set the surrounding nodes to point to the replacement */ | ||
368 | if (parent) { | ||
369 | if (victim == parent->rb_left) | ||
370 | parent->rb_left = new; | ||
371 | else | ||
372 | parent->rb_right = new; | ||
373 | } else { | ||
374 | root->rb_node = new; | ||
375 | } | ||
376 | if (victim->rb_left) | ||
377 | rb_set_parent(victim->rb_left, new); | ||
378 | if (victim->rb_right) | ||
379 | rb_set_parent(victim->rb_right, new); | ||
380 | |||
381 | /* Copy the pointers/colour from the victim to the replacement */ | ||
382 | *new = *victim; | ||
383 | } | ||
diff --git a/Documentation/perf_counter/util/rbtree.h b/Documentation/perf_counter/util/rbtree.h new file mode 100644 index 000000000000..6bdc488a47fb --- /dev/null +++ b/Documentation/perf_counter/util/rbtree.h | |||
@@ -0,0 +1,171 @@ | |||
1 | /* | ||
2 | Red Black Trees | ||
3 | (C) 1999 Andrea Arcangeli <andrea@suse.de> | ||
4 | |||
5 | This program is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published by | ||
7 | the Free Software Foundation; either version 2 of the License, or | ||
8 | (at your option) any later version. | ||
9 | |||
10 | This program is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | GNU General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with this program; if not, write to the Free Software | ||
17 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | |||
19 | linux/include/linux/rbtree.h | ||
20 | |||
21 | To use rbtrees you'll have to implement your own insert and search cores. | ||
22 | This will avoid us to use callbacks and to drop drammatically performances. | ||
23 | I know it's not the cleaner way, but in C (not in C++) to get | ||
24 | performances and genericity... | ||
25 | |||
26 | Some example of insert and search follows here. The search is a plain | ||
27 | normal search over an ordered tree. The insert instead must be implemented | ||
28 | int two steps: as first thing the code must insert the element in | ||
29 | order as a red leaf in the tree, then the support library function | ||
30 | rb_insert_color() must be called. Such function will do the | ||
31 | not trivial work to rebalance the rbtree if necessary. | ||
32 | |||
33 | ----------------------------------------------------------------------- | ||
34 | static inline struct page * rb_search_page_cache(struct inode * inode, | ||
35 | unsigned long offset) | ||
36 | { | ||
37 | struct rb_node * n = inode->i_rb_page_cache.rb_node; | ||
38 | struct page * page; | ||
39 | |||
40 | while (n) | ||
41 | { | ||
42 | page = rb_entry(n, struct page, rb_page_cache); | ||
43 | |||
44 | if (offset < page->offset) | ||
45 | n = n->rb_left; | ||
46 | else if (offset > page->offset) | ||
47 | n = n->rb_right; | ||
48 | else | ||
49 | return page; | ||
50 | } | ||
51 | return NULL; | ||
52 | } | ||
53 | |||
54 | static inline struct page * __rb_insert_page_cache(struct inode * inode, | ||
55 | unsigned long offset, | ||
56 | struct rb_node * node) | ||
57 | { | ||
58 | struct rb_node ** p = &inode->i_rb_page_cache.rb_node; | ||
59 | struct rb_node * parent = NULL; | ||
60 | struct page * page; | ||
61 | |||
62 | while (*p) | ||
63 | { | ||
64 | parent = *p; | ||
65 | page = rb_entry(parent, struct page, rb_page_cache); | ||
66 | |||
67 | if (offset < page->offset) | ||
68 | p = &(*p)->rb_left; | ||
69 | else if (offset > page->offset) | ||
70 | p = &(*p)->rb_right; | ||
71 | else | ||
72 | return page; | ||
73 | } | ||
74 | |||
75 | rb_link_node(node, parent, p); | ||
76 | |||
77 | return NULL; | ||
78 | } | ||
79 | |||
80 | static inline struct page * rb_insert_page_cache(struct inode * inode, | ||
81 | unsigned long offset, | ||
82 | struct rb_node * node) | ||
83 | { | ||
84 | struct page * ret; | ||
85 | if ((ret = __rb_insert_page_cache(inode, offset, node))) | ||
86 | goto out; | ||
87 | rb_insert_color(node, &inode->i_rb_page_cache); | ||
88 | out: | ||
89 | return ret; | ||
90 | } | ||
91 | ----------------------------------------------------------------------- | ||
92 | */ | ||
93 | |||
94 | #ifndef _LINUX_RBTREE_H | ||
95 | #define _LINUX_RBTREE_H | ||
96 | |||
97 | #include <stddef.h> | ||
98 | |||
99 | /** | ||
100 | * container_of - cast a member of a structure out to the containing structure | ||
101 | * @ptr: the pointer to the member. | ||
102 | * @type: the type of the container struct this is embedded in. | ||
103 | * @member: the name of the member within the struct. | ||
104 | * | ||
105 | */ | ||
106 | #define container_of(ptr, type, member) ({ \ | ||
107 | const typeof( ((type *)0)->member ) *__mptr = (ptr); \ | ||
108 | (type *)( (char *)__mptr - offsetof(type,member) );}) | ||
109 | |||
110 | struct rb_node | ||
111 | { | ||
112 | unsigned long rb_parent_color; | ||
113 | #define RB_RED 0 | ||
114 | #define RB_BLACK 1 | ||
115 | struct rb_node *rb_right; | ||
116 | struct rb_node *rb_left; | ||
117 | } __attribute__((aligned(sizeof(long)))); | ||
118 | /* The alignment might seem pointless, but allegedly CRIS needs it */ | ||
119 | |||
120 | struct rb_root | ||
121 | { | ||
122 | struct rb_node *rb_node; | ||
123 | }; | ||
124 | |||
125 | |||
126 | #define rb_parent(r) ((struct rb_node *)((r)->rb_parent_color & ~3)) | ||
127 | #define rb_color(r) ((r)->rb_parent_color & 1) | ||
128 | #define rb_is_red(r) (!rb_color(r)) | ||
129 | #define rb_is_black(r) rb_color(r) | ||
130 | #define rb_set_red(r) do { (r)->rb_parent_color &= ~1; } while (0) | ||
131 | #define rb_set_black(r) do { (r)->rb_parent_color |= 1; } while (0) | ||
132 | |||
133 | static inline void rb_set_parent(struct rb_node *rb, struct rb_node *p) | ||
134 | { | ||
135 | rb->rb_parent_color = (rb->rb_parent_color & 3) | (unsigned long)p; | ||
136 | } | ||
137 | static inline void rb_set_color(struct rb_node *rb, int color) | ||
138 | { | ||
139 | rb->rb_parent_color = (rb->rb_parent_color & ~1) | color; | ||
140 | } | ||
141 | |||
142 | #define RB_ROOT (struct rb_root) { NULL, } | ||
143 | #define rb_entry(ptr, type, member) container_of(ptr, type, member) | ||
144 | |||
145 | #define RB_EMPTY_ROOT(root) ((root)->rb_node == NULL) | ||
146 | #define RB_EMPTY_NODE(node) (rb_parent(node) == node) | ||
147 | #define RB_CLEAR_NODE(node) (rb_set_parent(node, node)) | ||
148 | |||
149 | extern void rb_insert_color(struct rb_node *, struct rb_root *); | ||
150 | extern void rb_erase(struct rb_node *, struct rb_root *); | ||
151 | |||
152 | /* Find logical next and previous nodes in a tree */ | ||
153 | extern struct rb_node *rb_next(const struct rb_node *); | ||
154 | extern struct rb_node *rb_prev(const struct rb_node *); | ||
155 | extern struct rb_node *rb_first(const struct rb_root *); | ||
156 | extern struct rb_node *rb_last(const struct rb_root *); | ||
157 | |||
158 | /* Fast replacement of a single node without remove/rebalance/add/rebalance */ | ||
159 | extern void rb_replace_node(struct rb_node *victim, struct rb_node *new, | ||
160 | struct rb_root *root); | ||
161 | |||
162 | static inline void rb_link_node(struct rb_node * node, struct rb_node * parent, | ||
163 | struct rb_node ** rb_link) | ||
164 | { | ||
165 | node->rb_parent_color = (unsigned long )parent; | ||
166 | node->rb_left = node->rb_right = NULL; | ||
167 | |||
168 | *rb_link = node; | ||
169 | } | ||
170 | |||
171 | #endif /* _LINUX_RBTREE_H */ | ||