a1285129c831b12d6079a6d598e0f3e5de437d62
[safe/jmp/linux-2.6] / tools / perf / util / thread.c
1 #include "../perf.h"
2 #include <stdlib.h>
3 #include <stdio.h>
4 #include <string.h>
5 #include "thread.h"
6 #include "util.h"
7 #include "debug.h"
8
9 static struct rb_root threads;
10 static struct thread *last_match;
11
12 void map_groups__init(struct map_groups *self)
13 {
14         int i;
15         for (i = 0; i < MAP__NR_TYPES; ++i) {
16                 self->maps[i] = RB_ROOT;
17                 INIT_LIST_HEAD(&self->removed_maps[i]);
18         }
19 }
20
21 static struct thread *thread__new(pid_t pid)
22 {
23         struct thread *self = zalloc(sizeof(*self));
24
25         if (self != NULL) {
26                 map_groups__init(&self->mg);
27                 self->pid = pid;
28                 self->comm = malloc(32);
29                 if (self->comm)
30                         snprintf(self->comm, 32, ":%d", self->pid);
31         }
32
33         return self;
34 }
35
36 int thread__set_comm(struct thread *self, const char *comm)
37 {
38         if (self->comm)
39                 free(self->comm);
40         self->comm = strdup(comm);
41         return self->comm ? 0 : -ENOMEM;
42 }
43
44 int thread__comm_len(struct thread *self)
45 {
46         if (!self->comm_len) {
47                 if (!self->comm)
48                         return 0;
49                 self->comm_len = strlen(self->comm);
50         }
51
52         return self->comm_len;
53 }
54
55 static const char *map_type__name[MAP__NR_TYPES] = {
56         [MAP__FUNCTION] = "Functions",
57 };
58
59 static size_t __map_groups__fprintf_maps(struct map_groups *self,
60                                          enum map_type type, FILE *fp)
61 {
62         size_t printed = fprintf(fp, "%s:\n", map_type__name[type]);
63         struct rb_node *nd;
64
65         for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) {
66                 struct map *pos = rb_entry(nd, struct map, rb_node);
67                 printed += fprintf(fp, "Map:");
68                 printed += map__fprintf(pos, fp);
69                 if (verbose > 1) {
70                         printed += dso__fprintf(pos->dso, type, fp);
71                         printed += fprintf(fp, "--\n");
72                 }
73         }
74
75         return printed;
76 }
77
78 size_t map_groups__fprintf_maps(struct map_groups *self, FILE *fp)
79 {
80         size_t printed = 0, i;
81         for (i = 0; i < MAP__NR_TYPES; ++i)
82                 printed += __map_groups__fprintf_maps(self, i, fp);
83         return printed;
84 }
85
86 static size_t __map_groups__fprintf_removed_maps(struct map_groups *self,
87                                                  enum map_type type, FILE *fp)
88 {
89         struct map *pos;
90         size_t printed = 0;
91
92         list_for_each_entry(pos, &self->removed_maps[type], node) {
93                 printed += fprintf(fp, "Map:");
94                 printed += map__fprintf(pos, fp);
95                 if (verbose > 1) {
96                         printed += dso__fprintf(pos->dso, type, fp);
97                         printed += fprintf(fp, "--\n");
98                 }
99         }
100         return printed;
101 }
102
103 static size_t map_groups__fprintf_removed_maps(struct map_groups *self, FILE *fp)
104 {
105         size_t printed = 0, i;
106         for (i = 0; i < MAP__NR_TYPES; ++i)
107                 printed += __map_groups__fprintf_removed_maps(self, i, fp);
108         return printed;
109 }
110
111 static size_t map_groups__fprintf(struct map_groups *self, FILE *fp)
112 {
113         size_t printed = map_groups__fprintf_maps(self, fp);
114         printed += fprintf(fp, "Removed maps:\n");
115         return printed + map_groups__fprintf_removed_maps(self, fp);
116 }
117
118 static size_t thread__fprintf(struct thread *self, FILE *fp)
119 {
120         return fprintf(fp, "Thread %d %s\n", self->pid, self->comm) +
121                map_groups__fprintf(&self->mg, fp);
122 }
123
124 struct thread *threads__findnew(pid_t pid)
125 {
126         struct rb_node **p = &threads.rb_node;
127         struct rb_node *parent = NULL;
128         struct thread *th;
129
130         /*
131          * Font-end cache - PID lookups come in blocks,
132          * so most of the time we dont have to look up
133          * the full rbtree:
134          */
135         if (last_match && last_match->pid == pid)
136                 return last_match;
137
138         while (*p != NULL) {
139                 parent = *p;
140                 th = rb_entry(parent, struct thread, rb_node);
141
142                 if (th->pid == pid) {
143                         last_match = th;
144                         return th;
145                 }
146
147                 if (pid < th->pid)
148                         p = &(*p)->rb_left;
149                 else
150                         p = &(*p)->rb_right;
151         }
152
153         th = thread__new(pid);
154         if (th != NULL) {
155                 rb_link_node(&th->rb_node, parent, p);
156                 rb_insert_color(&th->rb_node, &threads);
157                 last_match = th;
158         }
159
160         return th;
161 }
162
163 struct thread *register_idle_thread(void)
164 {
165         struct thread *thread = threads__findnew(0);
166
167         if (!thread || thread__set_comm(thread, "swapper")) {
168                 fprintf(stderr, "problem inserting idle task.\n");
169                 exit(-1);
170         }
171
172         return thread;
173 }
174
175 static void map_groups__remove_overlappings(struct map_groups *self,
176                                             struct map *map)
177 {
178         struct rb_root *root = &self->maps[map->type];
179         struct rb_node *next = rb_first(root);
180
181         while (next) {
182                 struct map *pos = rb_entry(next, struct map, rb_node);
183                 next = rb_next(&pos->rb_node);
184
185                 if (!map__overlap(pos, map))
186                         continue;
187
188                 if (verbose >= 2) {
189                         fputs("overlapping maps:\n", stderr);
190                         map__fprintf(map, stderr);
191                         map__fprintf(pos, stderr);
192                 }
193
194                 rb_erase(&pos->rb_node, root);
195                 /*
196                  * We may have references to this map, for instance in some
197                  * hist_entry instances, so just move them to a separate
198                  * list.
199                  */
200                 list_add_tail(&pos->node, &self->removed_maps[map->type]);
201         }
202 }
203
204 void maps__insert(struct rb_root *maps, struct map *map)
205 {
206         struct rb_node **p = &maps->rb_node;
207         struct rb_node *parent = NULL;
208         const u64 ip = map->start;
209         struct map *m;
210
211         while (*p != NULL) {
212                 parent = *p;
213                 m = rb_entry(parent, struct map, rb_node);
214                 if (ip < m->start)
215                         p = &(*p)->rb_left;
216                 else
217                         p = &(*p)->rb_right;
218         }
219
220         rb_link_node(&map->rb_node, parent, p);
221         rb_insert_color(&map->rb_node, maps);
222 }
223
224 struct map *maps__find(struct rb_root *maps, u64 ip)
225 {
226         struct rb_node **p = &maps->rb_node;
227         struct rb_node *parent = NULL;
228         struct map *m;
229
230         while (*p != NULL) {
231                 parent = *p;
232                 m = rb_entry(parent, struct map, rb_node);
233                 if (ip < m->start)
234                         p = &(*p)->rb_left;
235                 else if (ip > m->end)
236                         p = &(*p)->rb_right;
237                 else
238                         return m;
239         }
240
241         return NULL;
242 }
243
244 void thread__insert_map(struct thread *self, struct map *map)
245 {
246         map_groups__remove_overlappings(&self->mg, map);
247         map_groups__insert(&self->mg, map);
248 }
249
250 /*
251  * XXX This should not really _copy_ te maps, but refcount them.
252  */
253 static int map_groups__clone(struct map_groups *self,
254                              struct map_groups *parent, enum map_type type)
255 {
256         struct rb_node *nd;
257         for (nd = rb_first(&parent->maps[type]); nd; nd = rb_next(nd)) {
258                 struct map *map = rb_entry(nd, struct map, rb_node);
259                 struct map *new = map__clone(map);
260                 if (new == NULL)
261                         return -ENOMEM;
262                 map_groups__insert(self, new);
263         }
264         return 0;
265 }
266
267 int thread__fork(struct thread *self, struct thread *parent)
268 {
269         int i;
270
271         if (self->comm)
272                 free(self->comm);
273         self->comm = strdup(parent->comm);
274         if (!self->comm)
275                 return -ENOMEM;
276
277         for (i = 0; i < MAP__NR_TYPES; ++i)
278                 if (map_groups__clone(&self->mg, &parent->mg, i) < 0)
279                         return -ENOMEM;
280         return 0;
281 }
282
283 size_t threads__fprintf(FILE *fp)
284 {
285         size_t ret = 0;
286         struct rb_node *nd;
287
288         for (nd = rb_first(&threads); nd; nd = rb_next(nd)) {
289                 struct thread *pos = rb_entry(nd, struct thread, rb_node);
290
291                 ret += thread__fprintf(pos, fp);
292         }
293
294         return ret;
295 }
296
297 struct symbol *map_groups__find_symbol(struct map_groups *self,
298                                        enum map_type type, u64 addr,
299                                        symbol_filter_t filter)
300 {
301         struct map *map = map_groups__find(self, type, addr);
302
303         if (map != NULL)
304                 return map__find_symbol(map, map->map_ip(map, addr), filter);
305
306         return NULL;
307 }