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