Commit | Line | Data |
---|---|---|
6baa0a5a FW |
1 | #include "../perf.h" |
2 | #include <stdlib.h> | |
3 | #include <stdio.h> | |
4 | #include <string.h> | |
5 | #include "thread.h" | |
6 | #include "util.h" | |
6e086437 | 7 | #include "debug.h" |
6baa0a5a | 8 | |
d5b889f2 ACM |
9 | static struct rb_root threads; |
10 | static struct thread *last_match; | |
11 | ||
97ea1a7f | 12 | static struct thread *thread__new(pid_t pid) |
6baa0a5a | 13 | { |
0ec04e16 | 14 | struct thread *self = calloc(1, sizeof(*self)); |
6baa0a5a FW |
15 | |
16 | if (self != NULL) { | |
17 | self->pid = pid; | |
97ea1a7f FW |
18 | self->comm = malloc(32); |
19 | if (self->comm) | |
20 | snprintf(self->comm, 32, ":%d", self->pid); | |
1b46cddf | 21 | self->maps = RB_ROOT; |
439d473b | 22 | INIT_LIST_HEAD(&self->removed_maps); |
6baa0a5a FW |
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 | { | |
1b46cddf | 38 | struct rb_node *nd; |
439d473b ACM |
39 | struct map *pos; |
40 | size_t ret = fprintf(fp, "Thread %d %s\nCurrent maps:\n", | |
41 | self->pid, self->comm); | |
6baa0a5a | 42 | |
1b46cddf | 43 | for (nd = rb_first(&self->maps); nd; nd = rb_next(nd)) { |
439d473b | 44 | pos = rb_entry(nd, struct map, rb_node); |
6baa0a5a | 45 | ret += map__fprintf(pos, fp); |
1b46cddf | 46 | } |
6baa0a5a | 47 | |
439d473b ACM |
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 | ||
6baa0a5a FW |
53 | return ret; |
54 | } | |
55 | ||
d5b889f2 | 56 | struct thread *threads__findnew(pid_t pid) |
6baa0a5a | 57 | { |
d5b889f2 | 58 | struct rb_node **p = &threads.rb_node; |
6baa0a5a FW |
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 | */ | |
d5b889f2 ACM |
67 | if (last_match && last_match->pid == pid) |
68 | return last_match; | |
6baa0a5a FW |
69 | |
70 | while (*p != NULL) { | |
71 | parent = *p; | |
72 | th = rb_entry(parent, struct thread, rb_node); | |
73 | ||
74 | if (th->pid == pid) { | |
d5b889f2 | 75 | last_match = th; |
6baa0a5a FW |
76 | return th; |
77 | } | |
78 | ||
79 | if (pid < th->pid) | |
80 | p = &(*p)->rb_left; | |
81 | else | |
82 | p = &(*p)->rb_right; | |
83 | } | |
84 | ||
97ea1a7f | 85 | th = thread__new(pid); |
6baa0a5a FW |
86 | if (th != NULL) { |
87 | rb_link_node(&th->rb_node, parent, p); | |
d5b889f2 ACM |
88 | rb_insert_color(&th->rb_node, &threads); |
89 | last_match = th; | |
6baa0a5a FW |
90 | } |
91 | ||
92 | return th; | |
93 | } | |
94 | ||
d5b889f2 | 95 | struct thread *register_idle_thread(void) |
5b447a6a | 96 | { |
d5b889f2 | 97 | struct thread *thread = threads__findnew(0); |
5b447a6a | 98 | |
80ed0987 | 99 | if (!thread || thread__set_comm(thread, "swapper")) { |
5b447a6a FW |
100 | fprintf(stderr, "problem inserting idle task.\n"); |
101 | exit(-1); | |
102 | } | |
103 | ||
104 | return thread; | |
105 | } | |
106 | ||
1b46cddf | 107 | static void thread__remove_overlappings(struct thread *self, struct map *map) |
6baa0a5a | 108 | { |
1b46cddf ACM |
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 | ||
439d473b ACM |
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); | |
6baa0a5a | 131 | } |
1b46cddf ACM |
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 | } | |
6baa0a5a | 173 | |
1b46cddf ACM |
174 | void thread__insert_map(struct thread *self, struct map *map) |
175 | { | |
176 | thread__remove_overlappings(self, map); | |
177 | maps__insert(&self->maps, map); | |
6baa0a5a FW |
178 | } |
179 | ||
180 | int thread__fork(struct thread *self, struct thread *parent) | |
181 | { | |
1b46cddf | 182 | struct rb_node *nd; |
6baa0a5a FW |
183 | |
184 | if (self->comm) | |
185 | free(self->comm); | |
186 | self->comm = strdup(parent->comm); | |
187 | if (!self->comm) | |
188 | return -ENOMEM; | |
189 | ||
1b46cddf ACM |
190 | for (nd = rb_first(&parent->maps); nd; nd = rb_next(nd)) { |
191 | struct map *map = rb_entry(nd, struct map, rb_node); | |
6baa0a5a FW |
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 | ||
d5b889f2 | 201 | size_t threads__fprintf(FILE *fp) |
6baa0a5a FW |
202 | { |
203 | size_t ret = 0; | |
204 | struct rb_node *nd; | |
205 | ||
d5b889f2 | 206 | for (nd = rb_first(&threads); nd; nd = rb_next(nd)) { |
6baa0a5a FW |
207 | struct thread *pos = rb_entry(nd, struct thread, rb_node); |
208 | ||
209 | ret += thread__fprintf(pos, fp); | |
210 | } | |
211 | ||
212 | return ret; | |
213 | } |