diff options
Diffstat (limited to 'tools')
-rw-r--r-- | tools/perf/builtin-annotate.c | 135 | ||||
-rw-r--r-- | tools/perf/builtin-top.c | 2 | ||||
-rw-r--r-- | tools/perf/util/event.c | 4 | ||||
-rw-r--r-- | tools/perf/util/probe-event.c | 3 | ||||
-rw-r--r-- | tools/perf/util/thread.c | 34 |
5 files changed, 148 insertions, 30 deletions
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index e47dd1587e39..5ec5de995872 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c | |||
@@ -145,21 +145,58 @@ static int process_sample_event(event_t *event, struct perf_session *session) | |||
145 | return 0; | 145 | return 0; |
146 | } | 146 | } |
147 | 147 | ||
148 | static int parse_line(FILE *file, struct hist_entry *he, u64 len) | 148 | struct objdump_line { |
149 | struct list_head node; | ||
150 | s64 offset; | ||
151 | char *line; | ||
152 | }; | ||
153 | |||
154 | static struct objdump_line *objdump_line__new(s64 offset, char *line) | ||
155 | { | ||
156 | struct objdump_line *self = malloc(sizeof(*self)); | ||
157 | |||
158 | if (self != NULL) { | ||
159 | self->offset = offset; | ||
160 | self->line = line; | ||
161 | } | ||
162 | |||
163 | return self; | ||
164 | } | ||
165 | |||
166 | static void objdump_line__free(struct objdump_line *self) | ||
167 | { | ||
168 | free(self->line); | ||
169 | free(self); | ||
170 | } | ||
171 | |||
172 | static void objdump__add_line(struct list_head *head, struct objdump_line *line) | ||
173 | { | ||
174 | list_add_tail(&line->node, head); | ||
175 | } | ||
176 | |||
177 | static struct objdump_line *objdump__get_next_ip_line(struct list_head *head, | ||
178 | struct objdump_line *pos) | ||
179 | { | ||
180 | list_for_each_entry_continue(pos, head, node) | ||
181 | if (pos->offset >= 0) | ||
182 | return pos; | ||
183 | |||
184 | return NULL; | ||
185 | } | ||
186 | |||
187 | static int parse_line(FILE *file, struct hist_entry *he, | ||
188 | struct list_head *head) | ||
149 | { | 189 | { |
150 | struct symbol *sym = he->sym; | 190 | struct symbol *sym = he->sym; |
191 | struct objdump_line *objdump_line; | ||
151 | char *line = NULL, *tmp, *tmp2; | 192 | char *line = NULL, *tmp, *tmp2; |
152 | static const char *prev_line; | ||
153 | static const char *prev_color; | ||
154 | unsigned int offset; | ||
155 | size_t line_len; | 193 | size_t line_len; |
156 | u64 start; | 194 | s64 line_ip, offset = -1; |
157 | s64 line_ip; | ||
158 | int ret; | ||
159 | char *c; | 195 | char *c; |
160 | 196 | ||
161 | if (getline(&line, &line_len, file) < 0) | 197 | if (getline(&line, &line_len, file) < 0) |
162 | return -1; | 198 | return -1; |
199 | |||
163 | if (!line) | 200 | if (!line) |
164 | return -1; | 201 | return -1; |
165 | 202 | ||
@@ -168,8 +205,6 @@ static int parse_line(FILE *file, struct hist_entry *he, u64 len) | |||
168 | *c = 0; | 205 | *c = 0; |
169 | 206 | ||
170 | line_ip = -1; | 207 | line_ip = -1; |
171 | offset = 0; | ||
172 | ret = -2; | ||
173 | 208 | ||
174 | /* | 209 | /* |
175 | * Strip leading spaces: | 210 | * Strip leading spaces: |
@@ -190,9 +225,30 @@ static int parse_line(FILE *file, struct hist_entry *he, u64 len) | |||
190 | line_ip = -1; | 225 | line_ip = -1; |
191 | } | 226 | } |
192 | 227 | ||
193 | start = map__rip_2objdump(he->map, sym->start); | ||
194 | |||
195 | if (line_ip != -1) { | 228 | if (line_ip != -1) { |
229 | u64 start = map__rip_2objdump(he->map, sym->start); | ||
230 | offset = line_ip - start; | ||
231 | } | ||
232 | |||
233 | objdump_line = objdump_line__new(offset, line); | ||
234 | if (objdump_line == NULL) { | ||
235 | free(line); | ||
236 | return -1; | ||
237 | } | ||
238 | objdump__add_line(head, objdump_line); | ||
239 | |||
240 | return 0; | ||
241 | } | ||
242 | |||
243 | static int objdump_line__print(struct objdump_line *self, | ||
244 | struct list_head *head, | ||
245 | struct hist_entry *he, u64 len) | ||
246 | { | ||
247 | struct symbol *sym = he->sym; | ||
248 | static const char *prev_line; | ||
249 | static const char *prev_color; | ||
250 | |||
251 | if (self->offset != -1) { | ||
196 | const char *path = NULL; | 252 | const char *path = NULL; |
197 | unsigned int hits = 0; | 253 | unsigned int hits = 0; |
198 | double percent = 0.0; | 254 | double percent = 0.0; |
@@ -200,15 +256,22 @@ static int parse_line(FILE *file, struct hist_entry *he, u64 len) | |||
200 | struct sym_priv *priv = symbol__priv(sym); | 256 | struct sym_priv *priv = symbol__priv(sym); |
201 | struct sym_ext *sym_ext = priv->ext; | 257 | struct sym_ext *sym_ext = priv->ext; |
202 | struct sym_hist *h = priv->hist; | 258 | struct sym_hist *h = priv->hist; |
259 | s64 offset = self->offset; | ||
260 | struct objdump_line *next = objdump__get_next_ip_line(head, self); | ||
261 | |||
262 | while (offset < (s64)len && | ||
263 | (next == NULL || offset < next->offset)) { | ||
264 | if (sym_ext) { | ||
265 | if (path == NULL) | ||
266 | path = sym_ext[offset].path; | ||
267 | percent += sym_ext[offset].percent; | ||
268 | } else | ||
269 | hits += h->ip[offset]; | ||
270 | |||
271 | ++offset; | ||
272 | } | ||
203 | 273 | ||
204 | offset = line_ip - start; | 274 | if (sym_ext == NULL && h->sum) |
205 | if (offset < len) | ||
206 | hits = h->ip[offset]; | ||
207 | |||
208 | if (offset < len && sym_ext) { | ||
209 | path = sym_ext[offset].path; | ||
210 | percent = sym_ext[offset].percent; | ||
211 | } else if (h->sum) | ||
212 | percent = 100.0 * hits / h->sum; | 275 | percent = 100.0 * hits / h->sum; |
213 | 276 | ||
214 | color = get_percent_color(percent); | 277 | color = get_percent_color(percent); |
@@ -229,12 +292,12 @@ static int parse_line(FILE *file, struct hist_entry *he, u64 len) | |||
229 | 292 | ||
230 | color_fprintf(stdout, color, " %7.2f", percent); | 293 | color_fprintf(stdout, color, " %7.2f", percent); |
231 | printf(" : "); | 294 | printf(" : "); |
232 | color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", line); | 295 | color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", self->line); |
233 | } else { | 296 | } else { |
234 | if (!*line) | 297 | if (!*self->line) |
235 | printf(" :\n"); | 298 | printf(" :\n"); |
236 | else | 299 | else |
237 | printf(" : %s\n", line); | 300 | printf(" : %s\n", self->line); |
238 | } | 301 | } |
239 | 302 | ||
240 | return 0; | 303 | return 0; |
@@ -360,6 +423,20 @@ static void print_summary(const char *filename) | |||
360 | } | 423 | } |
361 | } | 424 | } |
362 | 425 | ||
426 | static void hist_entry__print_hits(struct hist_entry *self) | ||
427 | { | ||
428 | struct symbol *sym = self->sym; | ||
429 | struct sym_priv *priv = symbol__priv(sym); | ||
430 | struct sym_hist *h = priv->hist; | ||
431 | u64 len = sym->end - sym->start, offset; | ||
432 | |||
433 | for (offset = 0; offset < len; ++offset) | ||
434 | if (h->ip[offset] != 0) | ||
435 | printf("%*Lx: %Lu\n", BITS_PER_LONG / 2, | ||
436 | sym->start + offset, h->ip[offset]); | ||
437 | printf("%*s: %Lu\n", BITS_PER_LONG / 2, "h->sum", h->sum); | ||
438 | } | ||
439 | |||
363 | static void annotate_sym(struct hist_entry *he) | 440 | static void annotate_sym(struct hist_entry *he) |
364 | { | 441 | { |
365 | struct map *map = he->map; | 442 | struct map *map = he->map; |
@@ -369,6 +446,8 @@ static void annotate_sym(struct hist_entry *he) | |||
369 | u64 len; | 446 | u64 len; |
370 | char command[PATH_MAX*2]; | 447 | char command[PATH_MAX*2]; |
371 | FILE *file; | 448 | FILE *file; |
449 | LIST_HEAD(head); | ||
450 | struct objdump_line *pos, *n; | ||
372 | 451 | ||
373 | if (!filename) | 452 | if (!filename) |
374 | return; | 453 | return; |
@@ -410,11 +489,21 @@ static void annotate_sym(struct hist_entry *he) | |||
410 | return; | 489 | return; |
411 | 490 | ||
412 | while (!feof(file)) { | 491 | while (!feof(file)) { |
413 | if (parse_line(file, he, len) < 0) | 492 | if (parse_line(file, he, &head) < 0) |
414 | break; | 493 | break; |
415 | } | 494 | } |
416 | 495 | ||
417 | pclose(file); | 496 | pclose(file); |
497 | |||
498 | if (verbose) | ||
499 | hist_entry__print_hits(he); | ||
500 | |||
501 | list_for_each_entry_safe(pos, n, &head, node) { | ||
502 | objdump_line__print(pos, &head, he, len); | ||
503 | list_del(&pos->node); | ||
504 | objdump_line__free(pos); | ||
505 | } | ||
506 | |||
418 | if (print_line) | 507 | if (print_line) |
419 | free_source_line(he, len); | 508 | free_source_line(he, len); |
420 | } | 509 | } |
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index c6706984b7b3..31f2e597800c 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c | |||
@@ -706,7 +706,7 @@ static void print_mapped_keys(void) | |||
706 | fprintf(stdout, "\t[w] toggle display weighted/count[E]r. \t(%d)\n", display_weighted ? 1 : 0); | 706 | fprintf(stdout, "\t[w] toggle display weighted/count[E]r. \t(%d)\n", display_weighted ? 1 : 0); |
707 | 707 | ||
708 | fprintf(stdout, | 708 | fprintf(stdout, |
709 | "\t[K] hide kernel_symbols symbols. \t(%s)\n", | 709 | "\t[K] hide kernel_symbols symbols. \t(%s)\n", |
710 | hide_kernel_symbols ? "yes" : "no"); | 710 | hide_kernel_symbols ? "yes" : "no"); |
711 | fprintf(stdout, | 711 | fprintf(stdout, |
712 | "\t[U] hide user symbols. \t(%s)\n", | 712 | "\t[U] hide user symbols. \t(%s)\n", |
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 9eb7005bc6d6..705ec63548b4 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c | |||
@@ -442,10 +442,10 @@ void thread__find_addr_map(struct thread *self, | |||
442 | al->thread = self; | 442 | al->thread = self; |
443 | al->addr = addr; | 443 | al->addr = addr; |
444 | 444 | ||
445 | if (cpumode & PERF_RECORD_MISC_KERNEL) { | 445 | if (cpumode == PERF_RECORD_MISC_KERNEL) { |
446 | al->level = 'k'; | 446 | al->level = 'k'; |
447 | mg = &session->kmaps; | 447 | mg = &session->kmaps; |
448 | } else if (cpumode & PERF_RECORD_MISC_USER) | 448 | } else if (cpumode == PERF_RECORD_MISC_USER) |
449 | al->level = '.'; | 449 | al->level = '.'; |
450 | else { | 450 | else { |
451 | al->level = 'H'; | 451 | al->level = 'H'; |
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index fa156f008e0b..c971e81e9cbf 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c | |||
@@ -320,6 +320,7 @@ int synthesize_perf_probe_point(struct probe_point *pp) | |||
320 | int ret; | 320 | int ret; |
321 | 321 | ||
322 | pp->probes[0] = buf = zalloc(MAX_CMDLEN); | 322 | pp->probes[0] = buf = zalloc(MAX_CMDLEN); |
323 | pp->found = 1; | ||
323 | if (!buf) | 324 | if (!buf) |
324 | die("Failed to allocate memory by zalloc."); | 325 | die("Failed to allocate memory by zalloc."); |
325 | if (pp->offset) { | 326 | if (pp->offset) { |
@@ -342,6 +343,7 @@ int synthesize_perf_probe_point(struct probe_point *pp) | |||
342 | error: | 343 | error: |
343 | free(pp->probes[0]); | 344 | free(pp->probes[0]); |
344 | pp->probes[0] = NULL; | 345 | pp->probes[0] = NULL; |
346 | pp->found = 0; | ||
345 | } | 347 | } |
346 | return ret; | 348 | return ret; |
347 | } | 349 | } |
@@ -507,6 +509,7 @@ void show_perf_probe_events(void) | |||
507 | 509 | ||
508 | setup_pager(); | 510 | setup_pager(); |
509 | 511 | ||
512 | memset(&pp, 0, sizeof(pp)); | ||
510 | fd = open_kprobe_events(O_RDONLY, 0); | 513 | fd = open_kprobe_events(O_RDONLY, 0); |
511 | rawlist = get_trace_kprobe_event_rawlist(fd); | 514 | rawlist = get_trace_kprobe_event_rawlist(fd); |
512 | close(fd); | 515 | close(fd); |
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index c090654cb6c0..21b92162282b 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c | |||
@@ -31,15 +31,41 @@ static struct thread *thread__new(pid_t pid) | |||
31 | return self; | 31 | return self; |
32 | } | 32 | } |
33 | 33 | ||
34 | static void map_groups__flush(struct map_groups *self) | ||
35 | { | ||
36 | int type; | ||
37 | |||
38 | for (type = 0; type < MAP__NR_TYPES; type++) { | ||
39 | struct rb_root *root = &self->maps[type]; | ||
40 | struct rb_node *next = rb_first(root); | ||
41 | |||
42 | while (next) { | ||
43 | struct map *pos = rb_entry(next, struct map, rb_node); | ||
44 | next = rb_next(&pos->rb_node); | ||
45 | rb_erase(&pos->rb_node, root); | ||
46 | /* | ||
47 | * We may have references to this map, for | ||
48 | * instance in some hist_entry instances, so | ||
49 | * just move them to a separate list. | ||
50 | */ | ||
51 | list_add_tail(&pos->node, &self->removed_maps[pos->type]); | ||
52 | } | ||
53 | } | ||
54 | } | ||
55 | |||
34 | int thread__set_comm(struct thread *self, const char *comm) | 56 | int thread__set_comm(struct thread *self, const char *comm) |
35 | { | 57 | { |
58 | int err; | ||
59 | |||
36 | if (self->comm) | 60 | if (self->comm) |
37 | free(self->comm); | 61 | free(self->comm); |
38 | self->comm = strdup(comm); | 62 | self->comm = strdup(comm); |
39 | if (self->comm == NULL) | 63 | err = self->comm == NULL ? -ENOMEM : 0; |
40 | return -ENOMEM; | 64 | if (!err) { |
41 | self->comm_set = true; | 65 | self->comm_set = true; |
42 | return 0; | 66 | map_groups__flush(&self->mg); |
67 | } | ||
68 | return err; | ||
43 | } | 69 | } |
44 | 70 | ||
45 | int thread__comm_len(struct thread *self) | 71 | int thread__comm_len(struct thread *self) |