X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=tools%2Fperf%2Futil%2Fthread.c;h=9e8995eaf2b61332e650fb2c4dfde6d615c6ae3e;hb=faa5c5c36ec50bf43e39c7798ce9701e6b002db3;hp=f53fad7c0a8d4a1fde9cceff0a8ac750b8d849b2;hpb=d5b889f2ecec7849e851ddd31c34bdfb3482b5de;p=safe%2Fjmp%2Flinux-2.6 diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index f53fad7..9e8995e 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c @@ -2,24 +2,30 @@ #include #include #include +#include "session.h" #include "thread.h" #include "util.h" #include "debug.h" -static struct rb_root threads; -static struct thread *last_match; +void map_groups__init(struct map_groups *self) +{ + int i; + for (i = 0; i < MAP__NR_TYPES; ++i) { + self->maps[i] = RB_ROOT; + INIT_LIST_HEAD(&self->removed_maps[i]); + } +} static struct thread *thread__new(pid_t pid) { - struct thread *self = calloc(1, sizeof(*self)); + struct thread *self = zalloc(sizeof(*self)); if (self != NULL) { + map_groups__init(&self->mg); self->pid = pid; self->comm = malloc(32); if (self->comm) snprintf(self->comm, 32, ":%d", self->pid); - self->maps = RB_ROOT; - INIT_LIST_HEAD(&self->removed_maps); } return self; @@ -30,32 +36,96 @@ int thread__set_comm(struct thread *self, const char *comm) if (self->comm) free(self->comm); self->comm = strdup(comm); - return self->comm ? 0 : -ENOMEM; + if (self->comm == NULL) + return -ENOMEM; + self->comm_set = true; + return 0; } -static size_t thread__fprintf(struct thread *self, FILE *fp) +int thread__comm_len(struct thread *self) { + if (!self->comm_len) { + if (!self->comm) + return 0; + self->comm_len = strlen(self->comm); + } + + return self->comm_len; +} + +static const char *map_type__name[MAP__NR_TYPES] = { + [MAP__FUNCTION] = "Functions", + [MAP__VARIABLE] = "Variables", +}; + +static size_t __map_groups__fprintf_maps(struct map_groups *self, + enum map_type type, FILE *fp) +{ + size_t printed = fprintf(fp, "%s:\n", map_type__name[type]); struct rb_node *nd; - struct map *pos; - size_t ret = fprintf(fp, "Thread %d %s\nCurrent maps:\n", - self->pid, self->comm); - for (nd = rb_first(&self->maps); nd; nd = rb_next(nd)) { - pos = rb_entry(nd, struct map, rb_node); - ret += map__fprintf(pos, fp); + for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) { + struct map *pos = rb_entry(nd, struct map, rb_node); + printed += fprintf(fp, "Map:"); + printed += map__fprintf(pos, fp); + if (verbose > 1) { + printed += dso__fprintf(pos->dso, type, fp); + printed += fprintf(fp, "--\n"); + } + } + + return printed; +} + +size_t map_groups__fprintf_maps(struct map_groups *self, FILE *fp) +{ + size_t printed = 0, i; + for (i = 0; i < MAP__NR_TYPES; ++i) + printed += __map_groups__fprintf_maps(self, i, fp); + return printed; +} + +static size_t __map_groups__fprintf_removed_maps(struct map_groups *self, + enum map_type type, FILE *fp) +{ + struct map *pos; + size_t printed = 0; + + list_for_each_entry(pos, &self->removed_maps[type], node) { + printed += fprintf(fp, "Map:"); + printed += map__fprintf(pos, fp); + if (verbose > 1) { + printed += dso__fprintf(pos->dso, type, fp); + printed += fprintf(fp, "--\n"); + } } + return printed; +} - ret = fprintf(fp, "Removed maps:\n"); +static size_t map_groups__fprintf_removed_maps(struct map_groups *self, FILE *fp) +{ + size_t printed = 0, i; + for (i = 0; i < MAP__NR_TYPES; ++i) + printed += __map_groups__fprintf_removed_maps(self, i, fp); + return printed; +} - list_for_each_entry(pos, &self->removed_maps, node) - ret += map__fprintf(pos, fp); +static size_t map_groups__fprintf(struct map_groups *self, FILE *fp) +{ + size_t printed = map_groups__fprintf_maps(self, fp); + printed += fprintf(fp, "Removed maps:\n"); + return printed + map_groups__fprintf_removed_maps(self, fp); +} - return ret; +static size_t thread__fprintf(struct thread *self, FILE *fp) +{ + return fprintf(fp, "Thread %d %s\n", self->pid, self->comm) + + map_groups__fprintf(&self->mg, fp); } -struct thread *threads__findnew(pid_t pid) +struct thread *perf_session__findnew(struct perf_session *self, pid_t pid) { - struct rb_node **p = &threads.rb_node; + struct rb_node **p = &self->threads.rb_node; struct rb_node *parent = NULL; struct thread *th; @@ -64,15 +134,15 @@ struct thread *threads__findnew(pid_t pid) * so most of the time we dont have to look up * the full rbtree: */ - if (last_match && last_match->pid == pid) - return last_match; + if (self->last_match && self->last_match->pid == pid) + return self->last_match; while (*p != NULL) { parent = *p; th = rb_entry(parent, struct thread, rb_node); if (th->pid == pid) { - last_match = th; + self->last_match = th; return th; } @@ -85,28 +155,18 @@ struct thread *threads__findnew(pid_t pid) th = thread__new(pid); if (th != NULL) { rb_link_node(&th->rb_node, parent, p); - rb_insert_color(&th->rb_node, &threads); - last_match = th; + rb_insert_color(&th->rb_node, &self->threads); + self->last_match = th; } return th; } -struct thread *register_idle_thread(void) -{ - struct thread *thread = threads__findnew(0); - - if (!thread || thread__set_comm(thread, "swapper")) { - fprintf(stderr, "problem inserting idle task.\n"); - exit(-1); - } - - return thread; -} - -static void thread__remove_overlappings(struct thread *self, struct map *map) +static void map_groups__remove_overlappings(struct map_groups *self, + struct map *map) { - struct rb_node *next = rb_first(&self->maps); + struct rb_root *root = &self->maps[map->type]; + struct rb_node *next = rb_first(root); while (next) { struct map *pos = rb_entry(next, struct map, rb_node); @@ -116,18 +176,18 @@ static void thread__remove_overlappings(struct thread *self, struct map *map) continue; if (verbose >= 2) { - printf("overlapping maps:\n"); - map__fprintf(map, stdout); - map__fprintf(pos, stdout); + fputs("overlapping maps:\n", stderr); + map__fprintf(map, stderr); + map__fprintf(pos, stderr); } - rb_erase(&pos->rb_node, &self->maps); + rb_erase(&pos->rb_node, root); /* * We may have references to this map, for instance in some * hist_entry instances, so just move them to a separate * list. */ - list_add_tail(&pos->node, &self->removed_maps); + list_add_tail(&pos->node, &self->removed_maps[map->type]); } } @@ -173,37 +233,52 @@ struct map *maps__find(struct rb_root *maps, u64 ip) void thread__insert_map(struct thread *self, struct map *map) { - thread__remove_overlappings(self, map); - maps__insert(&self->maps, map); + map_groups__remove_overlappings(&self->mg, map); + map_groups__insert(&self->mg, map); } -int thread__fork(struct thread *self, struct thread *parent) +/* + * XXX This should not really _copy_ te maps, but refcount them. + */ +static int map_groups__clone(struct map_groups *self, + struct map_groups *parent, enum map_type type) { struct rb_node *nd; - - if (self->comm) - free(self->comm); - self->comm = strdup(parent->comm); - if (!self->comm) - return -ENOMEM; - - for (nd = rb_first(&parent->maps); nd; nd = rb_next(nd)) { + for (nd = rb_first(&parent->maps[type]); nd; nd = rb_next(nd)) { struct map *map = rb_entry(nd, struct map, rb_node); struct map *new = map__clone(map); - if (!new) + if (new == NULL) + return -ENOMEM; + map_groups__insert(self, new); + } + return 0; +} + +int thread__fork(struct thread *self, struct thread *parent) +{ + int i; + + if (parent->comm_set) { + if (self->comm) + free(self->comm); + self->comm = strdup(parent->comm); + if (!self->comm) return -ENOMEM; - thread__insert_map(self, new); + self->comm_set = true; } + for (i = 0; i < MAP__NR_TYPES; ++i) + if (map_groups__clone(&self->mg, &parent->mg, i) < 0) + return -ENOMEM; return 0; } -size_t threads__fprintf(FILE *fp) +size_t perf_session__fprintf(struct perf_session *self, FILE *fp) { size_t ret = 0; struct rb_node *nd; - for (nd = rb_first(&threads); nd; nd = rb_next(nd)) { + for (nd = rb_first(&self->threads); nd; nd = rb_next(nd)) { struct thread *pos = rb_entry(nd, struct thread, rb_node); ret += thread__fprintf(pos, fp); @@ -211,3 +286,15 @@ size_t threads__fprintf(FILE *fp) return ret; } + +struct symbol *map_groups__find_symbol(struct map_groups *self, + enum map_type type, u64 addr, + symbol_filter_t filter) +{ + struct map *map = map_groups__find(self, type, addr); + + if (map != NULL) + return map__find_symbol(map, map->map_ip(map, addr), filter); + + return NULL; +}