diff options
Diffstat (limited to 'tools/perf/util/maps.c')
-rw-r--r-- | tools/perf/util/maps.c | 317 |
1 files changed, 195 insertions, 122 deletions
diff --git a/tools/perf/util/maps.c b/tools/perf/util/maps.c index 37bd5b40000d..1aeb1db58fe5 100644 --- a/tools/perf/util/maps.c +++ b/tools/perf/util/maps.c @@ -10,17 +10,15 @@ #include "ui/ui.h" #include "unwind.h" -static void __maps__insert(struct maps *maps, struct map *map); - static void maps__init(struct maps *maps, struct machine *machine) { - maps->entries = RB_ROOT; - init_rwsem(&maps->lock); - maps->machine = machine; - maps->last_search_by_name = NULL; - maps->nr_maps = 0; - maps->maps_by_name = NULL; - refcount_set(&maps->refcnt, 1); + refcount_set(maps__refcnt(maps), 1); + init_rwsem(maps__lock(maps)); + RC_CHK_ACCESS(maps)->entries = RB_ROOT; + RC_CHK_ACCESS(maps)->machine = machine; + RC_CHK_ACCESS(maps)->last_search_by_name = NULL; + RC_CHK_ACCESS(maps)->nr_maps = 0; + RC_CHK_ACCESS(maps)->maps_by_name = NULL; } static void __maps__free_maps_by_name(struct maps *maps) @@ -28,17 +26,54 @@ static void __maps__free_maps_by_name(struct maps *maps) /* * Free everything to try to do it from the rbtree in the next search */ - zfree(&maps->maps_by_name); - maps->nr_maps_allocated = 0; + for (unsigned int i = 0; i < maps__nr_maps(maps); i++) + map__put(maps__maps_by_name(maps)[i]); + + zfree(&RC_CHK_ACCESS(maps)->maps_by_name); + RC_CHK_ACCESS(maps)->nr_maps_allocated = 0; } -void maps__insert(struct maps *maps, struct map *map) +static int __maps__insert(struct maps *maps, struct map *map) { - down_write(&maps->lock); - __maps__insert(maps, map); - ++maps->nr_maps; + struct rb_node **p = &maps__entries(maps)->rb_node; + struct rb_node *parent = NULL; + const u64 ip = map__start(map); + struct map_rb_node *m, *new_rb_node; + + new_rb_node = malloc(sizeof(*new_rb_node)); + if (!new_rb_node) + return -ENOMEM; + + RB_CLEAR_NODE(&new_rb_node->rb_node); + new_rb_node->map = map__get(map); + + while (*p != NULL) { + parent = *p; + m = rb_entry(parent, struct map_rb_node, rb_node); + if (ip < map__start(m->map)) + p = &(*p)->rb_left; + else + p = &(*p)->rb_right; + } - if (map->dso && map->dso->kernel) { + rb_link_node(&new_rb_node->rb_node, parent, p); + rb_insert_color(&new_rb_node->rb_node, maps__entries(maps)); + return 0; +} + +int maps__insert(struct maps *maps, struct map *map) +{ + int err; + const struct dso *dso = map__dso(map); + + down_write(maps__lock(maps)); + err = __maps__insert(maps, map); + if (err) + goto out; + + ++RC_CHK_ACCESS(maps)->nr_maps; + + if (dso && dso->kernel) { struct kmap *kmap = map__kmap(map); if (kmap) @@ -52,60 +87,72 @@ void maps__insert(struct maps *maps, struct map *map) * If we already performed some search by name, then we need to add the just * inserted map and resort. */ - if (maps->maps_by_name) { - if (maps->nr_maps > maps->nr_maps_allocated) { - int nr_allocate = maps->nr_maps * 2; - struct map **maps_by_name = realloc(maps->maps_by_name, nr_allocate * sizeof(map)); + if (maps__maps_by_name(maps)) { + if (maps__nr_maps(maps) > RC_CHK_ACCESS(maps)->nr_maps_allocated) { + int nr_allocate = maps__nr_maps(maps) * 2; + struct map **maps_by_name = realloc(maps__maps_by_name(maps), + nr_allocate * sizeof(map)); if (maps_by_name == NULL) { __maps__free_maps_by_name(maps); - up_write(&maps->lock); - return; + err = -ENOMEM; + goto out; } - maps->maps_by_name = maps_by_name; - maps->nr_maps_allocated = nr_allocate; + RC_CHK_ACCESS(maps)->maps_by_name = maps_by_name; + RC_CHK_ACCESS(maps)->nr_maps_allocated = nr_allocate; } - maps->maps_by_name[maps->nr_maps - 1] = map; + maps__maps_by_name(maps)[maps__nr_maps(maps) - 1] = map__get(map); __maps__sort_by_name(maps); } - up_write(&maps->lock); + out: + up_write(maps__lock(maps)); + return err; } -static void __maps__remove(struct maps *maps, struct map *map) +static void __maps__remove(struct maps *maps, struct map_rb_node *rb_node) { - rb_erase_init(&map->rb_node, &maps->entries); - map__put(map); + rb_erase_init(&rb_node->rb_node, maps__entries(maps)); + map__put(rb_node->map); + free(rb_node); } void maps__remove(struct maps *maps, struct map *map) { - down_write(&maps->lock); - if (maps->last_search_by_name == map) - maps->last_search_by_name = NULL; + struct map_rb_node *rb_node; - __maps__remove(maps, map); - --maps->nr_maps; - if (maps->maps_by_name) + down_write(maps__lock(maps)); + if (RC_CHK_ACCESS(maps)->last_search_by_name == map) + RC_CHK_ACCESS(maps)->last_search_by_name = NULL; + + rb_node = maps__find_node(maps, map); + assert(rb_node->RC_CHK_ACCESS(map) == RC_CHK_ACCESS(map)); + __maps__remove(maps, rb_node); + if (maps__maps_by_name(maps)) __maps__free_maps_by_name(maps); - up_write(&maps->lock); + --RC_CHK_ACCESS(maps)->nr_maps; + up_write(maps__lock(maps)); } static void __maps__purge(struct maps *maps) { - struct map *pos, *next; + struct map_rb_node *pos, *next; + + if (maps__maps_by_name(maps)) + __maps__free_maps_by_name(maps); maps__for_each_entry_safe(maps, pos, next) { - rb_erase_init(&pos->rb_node, &maps->entries); - map__put(pos); + rb_erase_init(&pos->rb_node, maps__entries(maps)); + map__put(pos->map); + free(pos); } } static void maps__exit(struct maps *maps) { - down_write(&maps->lock); + down_write(maps__lock(maps)); __maps__purge(maps); - up_write(&maps->lock); + up_write(maps__lock(maps)); } bool maps__empty(struct maps *maps) @@ -115,25 +162,38 @@ bool maps__empty(struct maps *maps) struct maps *maps__new(struct machine *machine) { - struct maps *maps = zalloc(sizeof(*maps)); + struct maps *result; + RC_STRUCT(maps) *maps = zalloc(sizeof(*maps)); - if (maps != NULL) - maps__init(maps, machine); + if (ADD_RC_CHK(result, maps)) + maps__init(result, machine); - return maps; + return result; } void maps__delete(struct maps *maps) { maps__exit(maps); unwind__finish_access(maps); - free(maps); + RC_CHK_FREE(maps); +} + +struct maps *maps__get(struct maps *maps) +{ + struct maps *result; + + if (RC_CHK_GET(result, maps)) + refcount_inc(maps__refcnt(maps)); + + return result; } void maps__put(struct maps *maps) { - if (maps && refcount_dec_and_test(&maps->refcnt)) + if (maps && refcount_dec_and_test(maps__refcnt(maps))) maps__delete(maps); + else + RC_CHK_PUT(maps); } struct symbol *maps__find_symbol(struct maps *maps, u64 addr, struct map **mapp) @@ -144,7 +204,7 @@ struct symbol *maps__find_symbol(struct maps *maps, u64 addr, struct map **mapp) if (map != NULL && map__load(map) >= 0) { if (mapp != NULL) *mapp = map; - return map__find_symbol(map, map->map_ip(map, addr)); + return map__find_symbol(map, map__map_ip(map, addr)); } return NULL; @@ -153,33 +213,33 @@ struct symbol *maps__find_symbol(struct maps *maps, u64 addr, struct map **mapp) struct symbol *maps__find_symbol_by_name(struct maps *maps, const char *name, struct map **mapp) { struct symbol *sym; - struct map *pos; + struct map_rb_node *pos; - down_read(&maps->lock); + down_read(maps__lock(maps)); maps__for_each_entry(maps, pos) { - sym = map__find_symbol_by_name(pos, name); + sym = map__find_symbol_by_name(pos->map, name); if (sym == NULL) continue; - if (!map__contains_symbol(pos, sym)) { + if (!map__contains_symbol(pos->map, sym)) { sym = NULL; continue; } if (mapp != NULL) - *mapp = pos; + *mapp = pos->map; goto out; } sym = NULL; out: - up_read(&maps->lock); + up_read(maps__lock(maps)); return sym; } int maps__find_ams(struct maps *maps, struct addr_map_symbol *ams) { - if (ams->addr < ams->ms.map->start || ams->addr >= ams->ms.map->end) { + if (ams->addr < map__start(ams->ms.map) || ams->addr >= map__end(ams->ms.map)) { if (maps == NULL) return -1; ams->ms.map = maps__find(maps, ams->addr); @@ -187,7 +247,7 @@ int maps__find_ams(struct maps *maps, struct addr_map_symbol *ams) return -1; } - ams->al_addr = ams->ms.map->map_ip(ams->ms.map, ams->addr); + ams->al_addr = map__map_ip(ams->ms.map, ams->addr); ams->ms.sym = map__find_symbol(ams->ms.map, ams->al_addr); return ams->ms.sym ? 0 : -1; @@ -196,20 +256,20 @@ int maps__find_ams(struct maps *maps, struct addr_map_symbol *ams) size_t maps__fprintf(struct maps *maps, FILE *fp) { size_t printed = 0; - struct map *pos; + struct map_rb_node *pos; - down_read(&maps->lock); + down_read(maps__lock(maps)); maps__for_each_entry(maps, pos) { printed += fprintf(fp, "Map:"); - printed += map__fprintf(pos, fp); + printed += map__fprintf(pos->map, fp); if (verbose > 2) { - printed += dso__fprintf(pos->dso, fp); + printed += dso__fprintf(map__dso(pos->map), fp); printed += fprintf(fp, "--\n"); } } - up_read(&maps->lock); + up_read(maps__lock(maps)); return printed; } @@ -220,9 +280,9 @@ int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp) struct rb_node *next, *first; int err = 0; - down_write(&maps->lock); + down_write(maps__lock(maps)); - root = &maps->entries; + root = maps__entries(maps); /* * Find first map where end > map->start. @@ -231,11 +291,11 @@ int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp) next = root->rb_node; first = NULL; while (next) { - struct map *pos = rb_entry(next, struct map, rb_node); + struct map_rb_node *pos = rb_entry(next, struct map_rb_node, rb_node); - if (pos->end > map->start) { + if (map__end(pos->map) > map__start(map)) { first = next; - if (pos->start <= map->start) + if (map__start(pos->map) <= map__start(map)) break; next = next->rb_left; } else @@ -243,26 +303,26 @@ int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp) } next = first; - while (next) { - struct map *pos = rb_entry(next, struct map, rb_node); + while (next && !err) { + struct map_rb_node *pos = rb_entry(next, struct map_rb_node, rb_node); next = rb_next(&pos->rb_node); /* * Stop if current map starts after map->end. * Maps are ordered by start: next will not overlap for sure. */ - if (pos->start >= map->end) + if (map__start(pos->map) >= map__end(map)) break; if (verbose >= 2) { if (use_browser) { pr_debug("overlapping maps in %s (disable tui for more info)\n", - map->dso->name); + map__dso(map)->name); } else { fputs("overlapping maps:\n", fp); map__fprintf(map, fp); - map__fprintf(pos, fp); + map__fprintf(pos->map, fp); } } @@ -271,47 +331,51 @@ int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp) * Now check if we need to create new maps for areas not * overlapped by the new map: */ - if (map->start > pos->start) { - struct map *before = map__clone(pos); + if (map__start(map) > map__start(pos->map)) { + struct map *before = map__clone(pos->map); if (before == NULL) { err = -ENOMEM; goto put_map; } - before->end = map->start; - __maps__insert(maps, before); + map__set_end(before, map__start(map)); + err = __maps__insert(maps, before); + if (err) { + map__put(before); + goto put_map; + } + if (verbose >= 2 && !use_browser) map__fprintf(before, fp); map__put(before); } - if (map->end < pos->end) { - struct map *after = map__clone(pos); + if (map__end(map) < map__end(pos->map)) { + struct map *after = map__clone(pos->map); if (after == NULL) { err = -ENOMEM; goto put_map; } - after->start = map->end; - after->pgoff += map->end - pos->start; - assert(pos->map_ip(pos, map->end) == after->map_ip(after, map->end)); - __maps__insert(maps, after); + map__set_start(after, map__end(map)); + map__add_pgoff(after, map__end(map) - map__start(pos->map)); + assert(map__map_ip(pos->map, map__end(map)) == + map__map_ip(after, map__end(map))); + err = __maps__insert(maps, after); + if (err) { + map__put(after); + goto put_map; + } if (verbose >= 2 && !use_browser) map__fprintf(after, fp); map__put(after); } put_map: - map__put(pos); - - if (err) - goto out; + map__put(pos->map); } - - err = 0; -out: - up_write(&maps->lock); + up_write(maps__lock(maps)); return err; } @@ -322,12 +386,12 @@ int maps__clone(struct thread *thread, struct maps *parent) { struct maps *maps = thread->maps; int err; - struct map *map; + struct map_rb_node *rb_node; - down_read(&parent->lock); + down_read(maps__lock(parent)); - maps__for_each_entry(parent, map) { - struct map *new = map__clone(map); + maps__for_each_entry(parent, rb_node) { + struct map *new = map__clone(rb_node->map); if (new == NULL) { err = -ENOMEM; @@ -338,50 +402,44 @@ int maps__clone(struct thread *thread, struct maps *parent) if (err) goto out_unlock; - maps__insert(maps, new); + err = maps__insert(maps, new); + if (err) + goto out_unlock; + map__put(new); } err = 0; out_unlock: - up_read(&parent->lock); + up_read(maps__lock(parent)); return err; } -static void __maps__insert(struct maps *maps, struct map *map) +struct map_rb_node *maps__find_node(struct maps *maps, struct map *map) { - struct rb_node **p = &maps->entries.rb_node; - struct rb_node *parent = NULL; - const u64 ip = map->start; - struct map *m; + struct map_rb_node *rb_node; - while (*p != NULL) { - parent = *p; - m = rb_entry(parent, struct map, rb_node); - if (ip < m->start) - p = &(*p)->rb_left; - else - p = &(*p)->rb_right; + maps__for_each_entry(maps, rb_node) { + if (rb_node->RC_CHK_ACCESS(map) == RC_CHK_ACCESS(map)) + return rb_node; } - - rb_link_node(&map->rb_node, parent, p); - rb_insert_color(&map->rb_node, &maps->entries); - map__get(map); + return NULL; } struct map *maps__find(struct maps *maps, u64 ip) { struct rb_node *p; - struct map *m; + struct map_rb_node *m; + - down_read(&maps->lock); + down_read(maps__lock(maps)); - p = maps->entries.rb_node; + p = maps__entries(maps)->rb_node; while (p != NULL) { - m = rb_entry(p, struct map, rb_node); - if (ip < m->start) + m = rb_entry(p, struct map_rb_node, rb_node); + if (ip < map__start(m->map)) p = p->rb_left; - else if (ip >= m->end) + else if (ip >= map__end(m->map)) p = p->rb_right; else goto out; @@ -389,15 +447,30 @@ struct map *maps__find(struct maps *maps, u64 ip) m = NULL; out: - up_read(&maps->lock); - return m; + up_read(maps__lock(maps)); + return m ? m->map : NULL; } -struct map *maps__first(struct maps *maps) +struct map_rb_node *maps__first(struct maps *maps) { - struct rb_node *first = rb_first(&maps->entries); + struct rb_node *first = rb_first(maps__entries(maps)); if (first) - return rb_entry(first, struct map, rb_node); + return rb_entry(first, struct map_rb_node, rb_node); return NULL; } + +struct map_rb_node *map_rb_node__next(struct map_rb_node *node) +{ + struct rb_node *next; + + if (!node) + return NULL; + + next = rb_next(&node->rb_node); + + if (!next) + return NULL; + + return rb_entry(next, struct map_rb_node, rb_node); +} |