diff options
| -rw-r--r-- | tools/perf/Makefile | 1 | ||||
| -rw-r--r-- | tools/perf/util/event.h | 4 | ||||
| -rw-r--r-- | tools/perf/util/thread.c | 129 | ||||
| -rw-r--r-- | tools/perf/util/thread.h | 12 |
4 files changed, 95 insertions, 51 deletions
diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 3a99a9fda645..055290a5b835 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile | |||
| @@ -341,6 +341,7 @@ LIB_H += util/color.h | |||
| 341 | LIB_H += util/values.h | 341 | LIB_H += util/values.h |
| 342 | LIB_H += util/sort.h | 342 | LIB_H += util/sort.h |
| 343 | LIB_H += util/hist.h | 343 | LIB_H += util/hist.h |
| 344 | LIB_H += util/thread.h | ||
| 344 | 345 | ||
| 345 | LIB_OBJS += util/abspath.o | 346 | LIB_OBJS += util/abspath.o |
| 346 | LIB_OBJS += util/alias.o | 347 | LIB_OBJS += util/alias.o |
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index c31a5da6458b..4c69eb553807 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h | |||
| @@ -3,7 +3,7 @@ | |||
| 3 | 3 | ||
| 4 | #include "../perf.h" | 4 | #include "../perf.h" |
| 5 | #include "util.h" | 5 | #include "util.h" |
| 6 | #include <linux/list.h> | 6 | #include <linux/rbtree.h> |
| 7 | 7 | ||
| 8 | enum { | 8 | enum { |
| 9 | SHOW_KERNEL = 1, | 9 | SHOW_KERNEL = 1, |
| @@ -79,7 +79,7 @@ typedef union event_union { | |||
| 79 | } event_t; | 79 | } event_t; |
| 80 | 80 | ||
| 81 | struct map { | 81 | struct map { |
| 82 | struct list_head node; | 82 | struct rb_node rb_node; |
| 83 | u64 start; | 83 | u64 start; |
| 84 | u64 end; | 84 | u64 end; |
| 85 | u64 pgoff; | 85 | u64 pgoff; |
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index 45efb5db0d19..9d0945cc66d1 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c | |||
| @@ -15,7 +15,7 @@ static struct thread *thread__new(pid_t pid) | |||
| 15 | self->comm = malloc(32); | 15 | self->comm = malloc(32); |
| 16 | if (self->comm) | 16 | if (self->comm) |
| 17 | snprintf(self->comm, 32, ":%d", self->pid); | 17 | snprintf(self->comm, 32, ":%d", self->pid); |
| 18 | INIT_LIST_HEAD(&self->maps); | 18 | self->maps = RB_ROOT; |
| 19 | } | 19 | } |
| 20 | 20 | ||
| 21 | return self; | 21 | return self; |
| @@ -31,11 +31,13 @@ int thread__set_comm(struct thread *self, const char *comm) | |||
| 31 | 31 | ||
| 32 | static size_t thread__fprintf(struct thread *self, FILE *fp) | 32 | static size_t thread__fprintf(struct thread *self, FILE *fp) |
| 33 | { | 33 | { |
| 34 | struct map *pos; | 34 | struct rb_node *nd; |
| 35 | size_t ret = fprintf(fp, "Thread %d %s\n", self->pid, self->comm); | 35 | size_t ret = fprintf(fp, "Thread %d %s\n", self->pid, self->comm); |
| 36 | 36 | ||
| 37 | list_for_each_entry(pos, &self->maps, node) | 37 | for (nd = rb_first(&self->maps); nd; nd = rb_next(nd)) { |
| 38 | struct map *pos = rb_entry(nd, struct map, rb_node); | ||
| 38 | ret += map__fprintf(pos, fp); | 39 | ret += map__fprintf(pos, fp); |
| 40 | } | ||
| 39 | 41 | ||
| 40 | return ret; | 42 | return ret; |
| 41 | } | 43 | } |
| @@ -93,42 +95,90 @@ register_idle_thread(struct rb_root *threads, struct thread **last_match) | |||
| 93 | return thread; | 95 | return thread; |
| 94 | } | 96 | } |
| 95 | 97 | ||
| 96 | void thread__insert_map(struct thread *self, struct map *map) | 98 | static void thread__remove_overlappings(struct thread *self, struct map *map) |
| 97 | { | 99 | { |
| 98 | struct map *pos, *tmp; | 100 | struct rb_node *next = rb_first(&self->maps); |
| 99 | 101 | ||
| 100 | list_for_each_entry_safe(pos, tmp, &self->maps, node) { | 102 | while (next) { |
| 101 | if (map__overlap(pos, map)) { | 103 | struct map *pos = rb_entry(next, struct map, rb_node); |
| 102 | if (verbose >= 2) { | 104 | next = rb_next(&pos->rb_node); |
| 103 | printf("overlapping maps:\n"); | 105 | |
| 104 | map__fprintf(map, stdout); | 106 | if (!map__overlap(pos, map)) |
| 105 | map__fprintf(pos, stdout); | 107 | continue; |
| 106 | } | 108 | |
| 107 | 109 | if (verbose >= 2) { | |
| 108 | if (map->start <= pos->start && map->end > pos->start) | 110 | printf("overlapping maps:\n"); |
| 109 | pos->start = map->end; | 111 | map__fprintf(map, stdout); |
| 110 | 112 | map__fprintf(pos, stdout); | |
| 111 | if (map->end >= pos->end && map->start < pos->end) | 113 | } |
| 112 | pos->end = map->start; | 114 | |
| 113 | 115 | if (map->start <= pos->start && map->end > pos->start) | |
| 114 | if (verbose >= 2) { | 116 | pos->start = map->end; |
| 115 | printf("after collision:\n"); | 117 | |
| 116 | map__fprintf(pos, stdout); | 118 | if (map->end >= pos->end && map->start < pos->end) |
| 117 | } | 119 | pos->end = map->start; |
| 118 | 120 | ||
| 119 | if (pos->start >= pos->end) { | 121 | if (verbose >= 2) { |
| 120 | list_del_init(&pos->node); | 122 | printf("after collision:\n"); |
| 121 | free(pos); | 123 | map__fprintf(pos, stdout); |
| 122 | } | 124 | } |
| 125 | |||
| 126 | if (pos->start >= pos->end) { | ||
| 127 | rb_erase(&pos->rb_node, &self->maps); | ||
| 128 | free(pos); | ||
| 123 | } | 129 | } |
| 124 | } | 130 | } |
| 131 | } | ||
| 132 | |||
| 133 | void maps__insert(struct rb_root *maps, struct map *map) | ||
| 134 | { | ||
| 135 | struct rb_node **p = &maps->rb_node; | ||
| 136 | struct rb_node *parent = NULL; | ||
| 137 | const u64 ip = map->start; | ||
| 138 | struct map *m; | ||
| 139 | |||
| 140 | while (*p != NULL) { | ||
| 141 | parent = *p; | ||
| 142 | m = rb_entry(parent, struct map, rb_node); | ||
| 143 | if (ip < m->start) | ||
| 144 | p = &(*p)->rb_left; | ||
| 145 | else | ||
| 146 | p = &(*p)->rb_right; | ||
| 147 | } | ||
| 148 | |||
| 149 | rb_link_node(&map->rb_node, parent, p); | ||
| 150 | rb_insert_color(&map->rb_node, maps); | ||
| 151 | } | ||
| 152 | |||
| 153 | struct map *maps__find(struct rb_root *maps, u64 ip) | ||
| 154 | { | ||
| 155 | struct rb_node **p = &maps->rb_node; | ||
| 156 | struct rb_node *parent = NULL; | ||
| 157 | struct map *m; | ||
| 158 | |||
| 159 | while (*p != NULL) { | ||
| 160 | parent = *p; | ||
| 161 | m = rb_entry(parent, struct map, rb_node); | ||
| 162 | if (ip < m->start) | ||
| 163 | p = &(*p)->rb_left; | ||
| 164 | else if (ip > m->end) | ||
| 165 | p = &(*p)->rb_right; | ||
| 166 | else | ||
| 167 | return m; | ||
| 168 | } | ||
| 169 | |||
| 170 | return NULL; | ||
| 171 | } | ||
| 125 | 172 | ||
| 126 | list_add_tail(&map->node, &self->maps); | 173 | void thread__insert_map(struct thread *self, struct map *map) |
| 174 | { | ||
| 175 | thread__remove_overlappings(self, map); | ||
| 176 | maps__insert(&self->maps, map); | ||
| 127 | } | 177 | } |
| 128 | 178 | ||
| 129 | int thread__fork(struct thread *self, struct thread *parent) | 179 | int thread__fork(struct thread *self, struct thread *parent) |
| 130 | { | 180 | { |
| 131 | struct map *map; | 181 | struct rb_node *nd; |
| 132 | 182 | ||
| 133 | if (self->comm) | 183 | if (self->comm) |
| 134 | free(self->comm); | 184 | free(self->comm); |
| @@ -136,7 +186,8 @@ int thread__fork(struct thread *self, struct thread *parent) | |||
| 136 | if (!self->comm) | 186 | if (!self->comm) |
| 137 | return -ENOMEM; | 187 | return -ENOMEM; |
| 138 | 188 | ||
| 139 | list_for_each_entry(map, &parent->maps, node) { | 189 | for (nd = rb_first(&parent->maps); nd; nd = rb_next(nd)) { |
| 190 | struct map *map = rb_entry(nd, struct map, rb_node); | ||
| 140 | struct map *new = map__clone(map); | 191 | struct map *new = map__clone(map); |
| 141 | if (!new) | 192 | if (!new) |
| 142 | return -ENOMEM; | 193 | return -ENOMEM; |
| @@ -146,20 +197,6 @@ int thread__fork(struct thread *self, struct thread *parent) | |||
| 146 | return 0; | 197 | return 0; |
| 147 | } | 198 | } |
| 148 | 199 | ||
| 149 | struct map *thread__find_map(struct thread *self, u64 ip) | ||
| 150 | { | ||
| 151 | struct map *pos; | ||
| 152 | |||
| 153 | if (self == NULL) | ||
| 154 | return NULL; | ||
| 155 | |||
| 156 | list_for_each_entry(pos, &self->maps, node) | ||
| 157 | if (ip >= pos->start && ip <= pos->end) | ||
| 158 | return pos; | ||
| 159 | |||
| 160 | return NULL; | ||
| 161 | } | ||
| 162 | |||
| 163 | size_t threads__fprintf(FILE *fp, struct rb_root *threads) | 200 | size_t threads__fprintf(FILE *fp, struct rb_root *threads) |
| 164 | { | 201 | { |
| 165 | size_t ret = 0; | 202 | size_t ret = 0; |
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h index 693ed1ea10b4..bbb37c1a52ee 100644 --- a/tools/perf/util/thread.h +++ b/tools/perf/util/thread.h | |||
| @@ -2,13 +2,12 @@ | |||
| 2 | #define __PERF_THREAD_H | 2 | #define __PERF_THREAD_H |
| 3 | 3 | ||
| 4 | #include <linux/rbtree.h> | 4 | #include <linux/rbtree.h> |
| 5 | #include <linux/list.h> | ||
| 6 | #include <unistd.h> | 5 | #include <unistd.h> |
| 7 | #include "symbol.h" | 6 | #include "symbol.h" |
| 8 | 7 | ||
| 9 | struct thread { | 8 | struct thread { |
| 10 | struct rb_node rb_node; | 9 | struct rb_node rb_node; |
| 11 | struct list_head maps; | 10 | struct rb_root maps; |
| 12 | pid_t pid; | 11 | pid_t pid; |
| 13 | char shortname[3]; | 12 | char shortname[3]; |
| 14 | char *comm; | 13 | char *comm; |
| @@ -21,7 +20,14 @@ struct thread * | |||
| 21 | register_idle_thread(struct rb_root *threads, struct thread **last_match); | 20 | register_idle_thread(struct rb_root *threads, struct thread **last_match); |
| 22 | void thread__insert_map(struct thread *self, struct map *map); | 21 | void thread__insert_map(struct thread *self, struct map *map); |
| 23 | int thread__fork(struct thread *self, struct thread *parent); | 22 | int thread__fork(struct thread *self, struct thread *parent); |
| 24 | struct map *thread__find_map(struct thread *self, u64 ip); | ||
| 25 | size_t threads__fprintf(FILE *fp, struct rb_root *threads); | 23 | size_t threads__fprintf(FILE *fp, struct rb_root *threads); |
| 26 | 24 | ||
| 25 | void maps__insert(struct rb_root *maps, struct map *map); | ||
| 26 | struct map *maps__find(struct rb_root *maps, u64 ip); | ||
| 27 | |||
| 28 | static inline struct map *thread__find_map(struct thread *self, u64 ip) | ||
| 29 | { | ||
| 30 | return self ? maps__find(&self->maps, ip) : NULL; | ||
| 31 | } | ||
| 32 | |||
| 27 | #endif /* __PERF_THREAD_H */ | 33 | #endif /* __PERF_THREAD_H */ |
