f53fad7c0a8d4a1fde9cceff0a8ac750b8d849b2
[pandora-kernel.git] / 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 static struct thread *thread__new(pid_t pid)
13 {
14         struct thread *self = calloc(1, sizeof(*self));
15
16         if (self != NULL) {
17                 self->pid = pid;
18                 self->comm = malloc(32);
19                 if (self->comm)
20                         snprintf(self->comm, 32, ":%d", self->pid);
21                 self->maps = RB_ROOT;
22                 INIT_LIST_HEAD(&self->removed_maps);
23         }
24
25         return self;
26 }
27
28 int thread__set_comm(struct thread *self, const char *comm)
29 {
30         if (self->comm)
31                 free(self->comm);
32         self->comm = strdup(comm);
33         return self->comm ? 0 : -ENOMEM;
34 }
35
36 static size_t thread__fprintf(struct thread *self, FILE *fp)
37 {
38         struct rb_node *nd;
39         struct map *pos;
40         size_t ret = fprintf(fp, "Thread %d %s\nCurrent maps:\n",
41                              self->pid, self->comm);
42
43         for (nd = rb_first(&self->maps); nd; nd = rb_next(nd)) {
44                 pos = rb_entry(nd, struct map, rb_node);
45                 ret += map__fprintf(pos, fp);
46         }
47
48         ret = fprintf(fp, "Removed maps:\n");
49
50         list_for_each_entry(pos, &self->removed_maps, node)
51                 ret += map__fprintf(pos, fp);
52
53         return ret;
54 }
55
56 struct thread *threads__findnew(pid_t pid)
57 {
58         struct rb_node **p = &threads.rb_node;
59         struct rb_node *parent = NULL;
60         struct thread *th;
61
62         /*
63          * Font-end cache - PID lookups come in blocks,
64          * so most of the time we dont have to look up
65          * the full rbtree:
66          */
67         if (last_match && last_match->pid == pid)
68                 return last_match;
69
70         while (*p != NULL) {
71                 parent = *p;
72                 th = rb_entry(parent, struct thread, rb_node);
73
74                 if (th->pid == pid) {
75                         last_match = th;
76                         return th;
77                 }
78
79                 if (pid < th->pid)
80                         p = &(*p)->rb_left;
81                 else
82                         p = &(*p)->rb_right;
83         }
84
85         th = thread__new(pid);
86         if (th != NULL) {
87                 rb_link_node(&th->rb_node, parent, p);
88                 rb_insert_color(&th->rb_node, &threads);
89                 last_match = th;
90         }
91
92         return th;
93 }
94
95 struct thread *register_idle_thread(void)
96 {
97         struct thread *thread = threads__findnew(0);
98
99         if (!thread || thread__set_comm(thread, "swapper")) {
100                 fprintf(stderr, "problem inserting idle task.\n");
101                 exit(-1);
102         }
103
104         return thread;
105 }
106
107 static void thread__remove_overlappings(struct thread *self, struct map *map)
108 {
109         struct rb_node *next = rb_first(&self->maps);
110
111         while (next) {
112                 struct map *pos = rb_entry(next, struct map, rb_node);
113                 next = rb_next(&pos->rb_node);
114
115                 if (!map__overlap(pos, map))
116                         continue;
117
118                 if (verbose >= 2) {
119                         printf("overlapping maps:\n");
120                         map__fprintf(map, stdout);
121                         map__fprintf(pos, stdout);
122                 }
123
124                 rb_erase(&pos->rb_node, &self->maps);
125                 /*
126                  * We may have references to this map, for instance in some
127                  * hist_entry instances, so just move them to a separate
128                  * list.
129                  */
130                 list_add_tail(&pos->node, &self->removed_maps);
131         }
132 }
133
134 void maps__insert(struct rb_root *maps, struct map *map)
135 {
136         struct rb_node **p = &maps->rb_node;
137         struct rb_node *parent = NULL;
138         const u64 ip = map->start;
139         struct map *m;
140
141         while (*p != NULL) {
142                 parent = *p;
143                 m = rb_entry(parent, struct map, rb_node);
144                 if (ip < m->start)
145                         p = &(*p)->rb_left;
146                 else
147                         p = &(*p)->rb_right;
148         }
149
150         rb_link_node(&map->rb_node, parent, p);
151         rb_insert_color(&map->rb_node, maps);
152 }
153
154 struct map *maps__find(struct rb_root *maps, u64 ip)
155 {
156         struct rb_node **p = &maps->rb_node;
157         struct rb_node *parent = NULL;
158         struct map *m;
159
160         while (*p != NULL) {
161                 parent = *p;
162                 m = rb_entry(parent, struct map, rb_node);
163                 if (ip < m->start)
164                         p = &(*p)->rb_left;
165                 else if (ip > m->end)
166                         p = &(*p)->rb_right;
167                 else
168                         return m;
169         }
170
171         return NULL;
172 }
173
174 void thread__insert_map(struct thread *self, struct map *map)
175 {
176         thread__remove_overlappings(self, map);
177         maps__insert(&self->maps, map);
178 }
179
180 int thread__fork(struct thread *self, struct thread *parent)
181 {
182         struct rb_node *nd;
183
184         if (self->comm)
185                 free(self->comm);
186         self->comm = strdup(parent->comm);
187         if (!self->comm)
188                 return -ENOMEM;
189
190         for (nd = rb_first(&parent->maps); nd; nd = rb_next(nd)) {
191                 struct map *map = rb_entry(nd, struct map, rb_node);
192                 struct map *new = map__clone(map);
193                 if (!new)
194                         return -ENOMEM;
195                 thread__insert_map(self, new);
196         }
197
198         return 0;
199 }
200
201 size_t threads__fprintf(FILE *fp)
202 {
203         size_t ret = 0;
204         struct rb_node *nd;
205
206         for (nd = rb_first(&threads); nd; nd = rb_next(nd)) {
207                 struct thread *pos = rb_entry(nd, struct thread, rb_node);
208
209                 ret += thread__fprintf(pos, fp);
210         }
211
212         return ret;
213 }