diff options
Diffstat (limited to 'tools/perf/util/thread.c')
-rw-r--r-- | tools/perf/util/thread.c | 115 |
1 files changed, 89 insertions, 26 deletions
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index 1796625f7784..2229f82cd630 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c | |||
@@ -9,17 +9,26 @@ | |||
9 | static struct rb_root threads; | 9 | static struct rb_root threads; |
10 | static struct thread *last_match; | 10 | static struct thread *last_match; |
11 | 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 | |||
12 | static struct thread *thread__new(pid_t pid) | 23 | static struct thread *thread__new(pid_t pid) |
13 | { | 24 | { |
14 | struct thread *self = zalloc(sizeof(*self)); | 25 | struct thread *self = zalloc(sizeof(*self)); |
15 | 26 | ||
16 | if (self != NULL) { | 27 | if (self != NULL) { |
17 | self->pid = pid; | 28 | thread__init(self, pid); |
18 | self->comm = malloc(32); | 29 | self->comm = malloc(32); |
19 | if (self->comm) | 30 | if (self->comm) |
20 | snprintf(self->comm, 32, ":%d", self->pid); | 31 | snprintf(self->comm, 32, ":%d", self->pid); |
21 | self->maps = RB_ROOT; | ||
22 | INIT_LIST_HEAD(&self->removed_maps); | ||
23 | } | 32 | } |
24 | 33 | ||
25 | return self; | 34 | return self; |
@@ -44,24 +53,68 @@ int thread__comm_len(struct thread *self) | |||
44 | return self->comm_len; | 53 | return self->comm_len; |
45 | } | 54 | } |
46 | 55 | ||
47 | static size_t thread__fprintf(struct thread *self, FILE *fp) | 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) | ||
48 | { | 62 | { |
63 | size_t printed = fprintf(fp, "%s:\n", map_type__name[type]); | ||
49 | struct rb_node *nd; | 64 | struct rb_node *nd; |
50 | struct map *pos; | ||
51 | size_t ret = fprintf(fp, "Thread %d %s\nCurrent maps:\n", | ||
52 | self->pid, self->comm); | ||
53 | 65 | ||
54 | for (nd = rb_first(&self->maps); nd; nd = rb_next(nd)) { | 66 | for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) { |
55 | pos = rb_entry(nd, struct map, rb_node); | 67 | struct map *pos = rb_entry(nd, struct map, rb_node); |
56 | ret += map__fprintf(pos, fp); | 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 | } | ||
57 | } | 74 | } |
58 | 75 | ||
59 | ret = fprintf(fp, "Removed maps:\n"); | 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 | } | ||
60 | 86 | ||
61 | list_for_each_entry(pos, &self->removed_maps, node) | 87 | static size_t __thread__fprintf_removed_maps(struct thread *self, |
62 | ret += map__fprintf(pos, fp); | 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 | } | ||
63 | 103 | ||
64 | return ret; | 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); | ||
65 | } | 118 | } |
66 | 119 | ||
67 | struct thread *threads__findnew(pid_t pid) | 120 | struct thread *threads__findnew(pid_t pid) |
@@ -117,7 +170,8 @@ struct thread *register_idle_thread(void) | |||
117 | 170 | ||
118 | static void thread__remove_overlappings(struct thread *self, struct map *map) | 171 | static void thread__remove_overlappings(struct thread *self, struct map *map) |
119 | { | 172 | { |
120 | struct rb_node *next = rb_first(&self->maps); | 173 | struct rb_root *root = &self->maps[map->type]; |
174 | struct rb_node *next = rb_first(root); | ||
121 | 175 | ||
122 | while (next) { | 176 | while (next) { |
123 | struct map *pos = rb_entry(next, struct map, rb_node); | 177 | struct map *pos = rb_entry(next, struct map, rb_node); |
@@ -132,13 +186,13 @@ static void thread__remove_overlappings(struct thread *self, struct map *map) | |||
132 | map__fprintf(pos, stderr); | 186 | map__fprintf(pos, stderr); |
133 | } | 187 | } |
134 | 188 | ||
135 | rb_erase(&pos->rb_node, &self->maps); | 189 | rb_erase(&pos->rb_node, root); |
136 | /* | 190 | /* |
137 | * We may have references to this map, for instance in some | 191 | * We may have references to this map, for instance in some |
138 | * hist_entry instances, so just move them to a separate | 192 | * hist_entry instances, so just move them to a separate |
139 | * list. | 193 | * list. |
140 | */ | 194 | */ |
141 | list_add_tail(&pos->node, &self->removed_maps); | 195 | list_add_tail(&pos->node, &self->removed_maps[map->type]); |
142 | } | 196 | } |
143 | } | 197 | } |
144 | 198 | ||
@@ -185,12 +239,26 @@ struct map *maps__find(struct rb_root *maps, u64 ip) | |||
185 | void thread__insert_map(struct thread *self, struct map *map) | 239 | void thread__insert_map(struct thread *self, struct map *map) |
186 | { | 240 | { |
187 | thread__remove_overlappings(self, map); | 241 | thread__remove_overlappings(self, map); |
188 | maps__insert(&self->maps, map); | 242 | maps__insert(&self->maps[map->type], map); |
189 | } | 243 | } |
190 | 244 | ||
191 | int thread__fork(struct thread *self, struct thread *parent) | 245 | static int thread__clone_maps(struct thread *self, struct thread *parent, |
246 | enum map_type type) | ||
192 | { | 247 | { |
193 | struct rb_node *nd; | 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; | ||
194 | 262 | ||
195 | if (self->comm) | 263 | if (self->comm) |
196 | free(self->comm); | 264 | free(self->comm); |
@@ -198,14 +266,9 @@ int thread__fork(struct thread *self, struct thread *parent) | |||
198 | if (!self->comm) | 266 | if (!self->comm) |
199 | return -ENOMEM; | 267 | return -ENOMEM; |
200 | 268 | ||
201 | for (nd = rb_first(&parent->maps); nd; nd = rb_next(nd)) { | 269 | for (i = 0; i < MAP__NR_TYPES; ++i) |
202 | struct map *map = rb_entry(nd, struct map, rb_node); | 270 | if (thread__clone_maps(self, parent, i) < 0) |
203 | struct map *new = map__clone(map); | ||
204 | if (!new) | ||
205 | return -ENOMEM; | 271 | return -ENOMEM; |
206 | thread__insert_map(self, new); | ||
207 | } | ||
208 | |||
209 | return 0; | 272 | return 0; |
210 | } | 273 | } |
211 | 274 | ||