diff options
-rw-r--r-- | tools/perf/builtin-annotate.c | 14 | ||||
-rw-r--r-- | tools/perf/builtin-report.c | 5 | ||||
-rw-r--r-- | tools/perf/builtin-top.c | 67 | ||||
-rw-r--r-- | tools/perf/util/annotate.c | 85 | ||||
-rw-r--r-- | tools/perf/util/annotate.h | 34 | ||||
-rw-r--r-- | tools/perf/util/hist.c | 5 | ||||
-rw-r--r-- | tools/perf/util/hist.h | 3 | ||||
-rw-r--r-- | tools/perf/util/top.h | 6 | ||||
-rw-r--r-- | tools/perf/util/ui/browsers/annotate.c | 18 |
9 files changed, 126 insertions, 111 deletions
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index ea6a1165956f..427182953fd7 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c | |||
@@ -62,7 +62,8 @@ static int hists__add_entry(struct hists *self, struct addr_location *al) | |||
62 | * All aggregated on the first sym_hist. | 62 | * All aggregated on the first sym_hist. |
63 | */ | 63 | */ |
64 | struct annotation *notes = symbol__annotation(he->ms.sym); | 64 | struct annotation *notes = symbol__annotation(he->ms.sym); |
65 | if (notes->histograms == NULL && symbol__alloc_hist(he->ms.sym, 1) < 0) | 65 | if (notes->src == NULL && |
66 | symbol__alloc_hist(he->ms.sym, 1) < 0) | ||
66 | return -ENOMEM; | 67 | return -ENOMEM; |
67 | 68 | ||
68 | return hist_entry__inc_addr_samples(he, 0, al->addr); | 69 | return hist_entry__inc_addr_samples(he, 0, al->addr); |
@@ -77,7 +78,8 @@ static int process_sample_event(union perf_event *event, | |||
77 | { | 78 | { |
78 | struct addr_location al; | 79 | struct addr_location al; |
79 | 80 | ||
80 | if (perf_event__preprocess_sample(event, session, &al, sample, NULL) < 0) { | 81 | if (perf_event__preprocess_sample(event, session, &al, sample, |
82 | symbol__annotate_init) < 0) { | ||
81 | pr_warning("problem processing %d event, skipping it.\n", | 83 | pr_warning("problem processing %d event, skipping it.\n", |
82 | event->header.type); | 84 | event->header.type); |
83 | return -1; | 85 | return -1; |
@@ -111,7 +113,7 @@ static void hists__find_annotations(struct hists *self) | |||
111 | goto find_next; | 113 | goto find_next; |
112 | 114 | ||
113 | notes = symbol__annotation(he->ms.sym); | 115 | notes = symbol__annotation(he->ms.sym); |
114 | if (notes->histograms == NULL) { | 116 | if (notes->src == NULL) { |
115 | find_next: | 117 | find_next: |
116 | if (key == KEY_LEFT) | 118 | if (key == KEY_LEFT) |
117 | nd = rb_prev(nd); | 119 | nd = rb_prev(nd); |
@@ -142,11 +144,11 @@ find_next: | |||
142 | nd = rb_next(nd); | 144 | nd = rb_next(nd); |
143 | /* | 145 | /* |
144 | * Since we have a hist_entry per IP for the same | 146 | * Since we have a hist_entry per IP for the same |
145 | * symbol, free he->ms.sym->histogram to signal we already | 147 | * symbol, free he->ms.sym->src to signal we already |
146 | * processed this symbol. | 148 | * processed this symbol. |
147 | */ | 149 | */ |
148 | free(notes->histograms); | 150 | free(notes->src); |
149 | notes->histograms = NULL; | 151 | notes->src = NULL; |
150 | } | 152 | } |
151 | } | 153 | } |
152 | } | 154 | } |
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index de06bf55efff..f403aced4cba 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c | |||
@@ -123,7 +123,7 @@ static int perf_session__add_hist_entry(struct perf_session *session, | |||
123 | * All aggregated on the first sym_hist. | 123 | * All aggregated on the first sym_hist. |
124 | */ | 124 | */ |
125 | struct annotation *notes = symbol__annotation(he->ms.sym); | 125 | struct annotation *notes = symbol__annotation(he->ms.sym); |
126 | if (notes->histograms == NULL && | 126 | if (notes->src == NULL && |
127 | symbol__alloc_hist(he->ms.sym, 1) < 0) | 127 | symbol__alloc_hist(he->ms.sym, 1) < 0) |
128 | err = -ENOMEM; | 128 | err = -ENOMEM; |
129 | else | 129 | else |
@@ -166,7 +166,8 @@ static int process_sample_event(union perf_event *event, | |||
166 | struct addr_location al; | 166 | struct addr_location al; |
167 | struct perf_event_attr *attr; | 167 | struct perf_event_attr *attr; |
168 | 168 | ||
169 | if (perf_event__preprocess_sample(event, session, &al, sample, NULL) < 0) { | 169 | if (perf_event__preprocess_sample(event, session, &al, sample, |
170 | symbol__annotate_init) < 0) { | ||
170 | fprintf(stderr, "problem processing %d event, skipping it.\n", | 171 | fprintf(stderr, "problem processing %d event, skipping it.\n", |
171 | event->header.type); | 172 | event->header.type); |
172 | return -1; | 173 | return -1; |
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index b790673cb0aa..7dbf22d096b8 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c | |||
@@ -139,7 +139,7 @@ static void sig_winch_handler(int sig __used) | |||
139 | static int parse_source(struct sym_entry *syme) | 139 | static int parse_source(struct sym_entry *syme) |
140 | { | 140 | { |
141 | struct symbol *sym; | 141 | struct symbol *sym; |
142 | struct sym_entry_source *source; | 142 | struct annotation *notes; |
143 | struct map *map; | 143 | struct map *map; |
144 | int err = -1; | 144 | int err = -1; |
145 | 145 | ||
@@ -152,39 +152,35 @@ static int parse_source(struct sym_entry *syme) | |||
152 | /* | 152 | /* |
153 | * We can't annotate with just /proc/kallsyms | 153 | * We can't annotate with just /proc/kallsyms |
154 | */ | 154 | */ |
155 | if (map->dso->origin == DSO__ORIG_KERNEL) | 155 | if (map->dso->origin == DSO__ORIG_KERNEL) { |
156 | pr_err("Can't annotate %s: No vmlinux file was found in the " | ||
157 | "path\n", sym->name); | ||
158 | sleep(1); | ||
156 | return -1; | 159 | return -1; |
157 | |||
158 | if (syme->src == NULL) { | ||
159 | syme->src = zalloc(sizeof(*source)); | ||
160 | if (syme->src == NULL) | ||
161 | return -1; | ||
162 | pthread_mutex_init(&syme->src->lock, NULL); | ||
163 | INIT_LIST_HEAD(&syme->src->head); | ||
164 | } | 160 | } |
165 | 161 | ||
166 | source = syme->src; | 162 | notes = symbol__annotation(sym); |
167 | 163 | if (notes->src != NULL) { | |
168 | if (symbol__annotation(sym)->histograms != NULL) { | 164 | pthread_mutex_lock(¬es->lock); |
169 | pthread_mutex_lock(&source->lock); | ||
170 | goto out_assign; | 165 | goto out_assign; |
171 | } | 166 | } |
172 | 167 | ||
173 | pthread_mutex_lock(&source->lock); | 168 | pthread_mutex_lock(¬es->lock); |
174 | 169 | ||
175 | if (symbol__alloc_hist(sym, top.evlist->nr_entries) < 0) { | 170 | if (symbol__alloc_hist(sym, top.evlist->nr_entries) < 0) { |
176 | pr_err("Not enough memory for annotating '%s' symbol!\n", | 171 | pr_err("Not enough memory for annotating '%s' symbol!\n", |
177 | sym->name); | 172 | sym->name); |
173 | sleep(1); | ||
178 | goto out_unlock; | 174 | goto out_unlock; |
179 | } | 175 | } |
180 | 176 | ||
181 | err = symbol__annotate(sym, syme->map, &source->head, 0); | 177 | err = symbol__annotate(sym, syme->map, 0); |
182 | if (err == 0) { | 178 | if (err == 0) { |
183 | out_assign: | 179 | out_assign: |
184 | sym_filter_entry = syme; | 180 | sym_filter_entry = syme; |
185 | } | 181 | } |
186 | out_unlock: | 182 | out_unlock: |
187 | pthread_mutex_unlock(&source->lock); | 183 | pthread_mutex_unlock(¬es->lock); |
188 | return err; | 184 | return err; |
189 | } | 185 | } |
190 | 186 | ||
@@ -196,20 +192,27 @@ static void __zero_source_counters(struct sym_entry *syme) | |||
196 | 192 | ||
197 | static void record_precise_ip(struct sym_entry *syme, int counter, u64 ip) | 193 | static void record_precise_ip(struct sym_entry *syme, int counter, u64 ip) |
198 | { | 194 | { |
195 | struct annotation *notes; | ||
196 | struct symbol *sym; | ||
197 | |||
199 | if (syme != sym_filter_entry) | 198 | if (syme != sym_filter_entry) |
200 | return; | 199 | return; |
201 | 200 | ||
202 | if (pthread_mutex_trylock(&syme->src->lock)) | 201 | sym = sym_entry__symbol(syme); |
202 | notes = symbol__annotation(sym); | ||
203 | |||
204 | if (pthread_mutex_trylock(¬es->lock)) | ||
203 | return; | 205 | return; |
204 | 206 | ||
205 | ip = syme->map->map_ip(syme->map, ip); | 207 | ip = syme->map->map_ip(syme->map, ip); |
206 | symbol__inc_addr_samples(sym_entry__symbol(syme), syme->map, counter, ip); | 208 | symbol__inc_addr_samples(sym, syme->map, counter, ip); |
207 | 209 | ||
208 | pthread_mutex_unlock(&syme->src->lock); | 210 | pthread_mutex_unlock(¬es->lock); |
209 | } | 211 | } |
210 | 212 | ||
211 | static void show_details(struct sym_entry *syme) | 213 | static void show_details(struct sym_entry *syme) |
212 | { | 214 | { |
215 | struct annotation *notes; | ||
213 | struct symbol *symbol; | 216 | struct symbol *symbol; |
214 | int more; | 217 | int more; |
215 | 218 | ||
@@ -217,24 +220,26 @@ static void show_details(struct sym_entry *syme) | |||
217 | return; | 220 | return; |
218 | 221 | ||
219 | symbol = sym_entry__symbol(syme); | 222 | symbol = sym_entry__symbol(syme); |
220 | if (!syme->src || symbol__annotation(symbol)->histograms == NULL) | 223 | notes = symbol__annotation(symbol); |
221 | return; | 224 | |
225 | pthread_mutex_lock(¬es->lock); | ||
226 | |||
227 | if (notes->src == NULL) | ||
228 | goto out_unlock; | ||
222 | 229 | ||
223 | printf("Showing %s for %s\n", event_name(top.sym_evsel), symbol->name); | 230 | printf("Showing %s for %s\n", event_name(top.sym_evsel), symbol->name); |
224 | printf(" Events Pcnt (>=%d%%)\n", sym_pcnt_filter); | 231 | printf(" Events Pcnt (>=%d%%)\n", sym_pcnt_filter); |
225 | 232 | ||
226 | pthread_mutex_lock(&syme->src->lock); | 233 | more = symbol__annotate_printf(symbol, syme->map, top.sym_evsel->idx, |
227 | more = symbol__annotate_printf(symbol, syme->map, &syme->src->head, | 234 | 0, sym_pcnt_filter, top.print_entries); |
228 | top.sym_evsel->idx, 0, sym_pcnt_filter, | ||
229 | top.print_entries); | ||
230 | if (top.zero) | 235 | if (top.zero) |
231 | symbol__annotate_zero_histogram(symbol, top.sym_evsel->idx); | 236 | symbol__annotate_zero_histogram(symbol, top.sym_evsel->idx); |
232 | else | 237 | else |
233 | symbol__annotate_decay_histogram(symbol, &syme->src->head, | 238 | symbol__annotate_decay_histogram(symbol, top.sym_evsel->idx); |
234 | top.sym_evsel->idx); | ||
235 | pthread_mutex_unlock(&syme->src->lock); | ||
236 | if (more != 0) | 239 | if (more != 0) |
237 | printf("%d lines not displayed, maybe increase display entries [e]\n", more); | 240 | printf("%d lines not displayed, maybe increase display entries [e]\n", more); |
241 | out_unlock: | ||
242 | pthread_mutex_unlock(¬es->lock); | ||
238 | } | 243 | } |
239 | 244 | ||
240 | static const char CONSOLE_CLEAR[] = "[H[2J"; | 245 | static const char CONSOLE_CLEAR[] = "[H[2J"; |
@@ -372,10 +377,8 @@ static void prompt_symbol(struct sym_entry **target, const char *msg) | |||
372 | 377 | ||
373 | /* zero counters of active symbol */ | 378 | /* zero counters of active symbol */ |
374 | if (syme) { | 379 | if (syme) { |
375 | pthread_mutex_lock(&syme->src->lock); | ||
376 | __zero_source_counters(syme); | 380 | __zero_source_counters(syme); |
377 | *target = NULL; | 381 | *target = NULL; |
378 | pthread_mutex_unlock(&syme->src->lock); | ||
379 | } | 382 | } |
380 | 383 | ||
381 | fprintf(stdout, "\n%s: ", msg); | 384 | fprintf(stdout, "\n%s: ", msg); |
@@ -554,10 +557,8 @@ static void handle_keypress(struct perf_session *session, int c) | |||
554 | else { | 557 | else { |
555 | struct sym_entry *syme = sym_filter_entry; | 558 | struct sym_entry *syme = sym_filter_entry; |
556 | 559 | ||
557 | pthread_mutex_lock(&syme->src->lock); | ||
558 | sym_filter_entry = NULL; | 560 | sym_filter_entry = NULL; |
559 | __zero_source_counters(syme); | 561 | __zero_source_counters(syme); |
560 | pthread_mutex_unlock(&syme->src->lock); | ||
561 | } | 562 | } |
562 | break; | 563 | break; |
563 | case 'U': | 564 | case 'U': |
@@ -653,7 +654,7 @@ static int symbol_filter(struct map *map, struct symbol *sym) | |||
653 | 654 | ||
654 | syme = symbol__priv(sym); | 655 | syme = symbol__priv(sym); |
655 | syme->map = map; | 656 | syme->map = map; |
656 | syme->src = NULL; | 657 | symbol__annotate_init(map, sym); |
657 | 658 | ||
658 | if (!sym_filter_entry && sym_filter && !strcmp(name, sym_filter)) { | 659 | if (!sym_filter_entry && sym_filter && !strcmp(name, sym_filter)) { |
659 | /* schedule initial sym_filter_entry setup */ | 660 | /* schedule initial sym_filter_entry setup */ |
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 6db435167d74..c777bdaf91da 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c | |||
@@ -14,25 +14,39 @@ | |||
14 | #include "symbol.h" | 14 | #include "symbol.h" |
15 | #include "debug.h" | 15 | #include "debug.h" |
16 | #include "annotate.h" | 16 | #include "annotate.h" |
17 | #include <pthread.h> | ||
17 | 18 | ||
18 | int symbol__alloc_hist(struct symbol *sym, int nevents) | 19 | int symbol__annotate_init(struct map *map __used, struct symbol *sym) |
19 | { | 20 | { |
20 | struct annotation *notes = symbol__annotation(sym); | 21 | struct annotation *notes = symbol__annotation(sym); |
22 | pthread_mutex_init(¬es->lock, NULL); | ||
23 | return 0; | ||
24 | } | ||
21 | 25 | ||
22 | notes->sizeof_sym_hist = (sizeof(*notes->histograms) + | 26 | int symbol__alloc_hist(struct symbol *sym, int nevents) |
27 | { | ||
28 | struct annotation *notes = symbol__annotation(sym); | ||
29 | size_t sizeof_sym_hist = (sizeof(struct sym_hist) + | ||
23 | (sym->end - sym->start) * sizeof(u64)); | 30 | (sym->end - sym->start) * sizeof(u64)); |
24 | notes->histograms = calloc(nevents, notes->sizeof_sym_hist); | 31 | |
25 | notes->nr_histograms = nevents; | 32 | notes->src = zalloc(sizeof(*notes->src) + nevents * sizeof_sym_hist); |
26 | return notes->histograms == NULL ? -1 : 0; | 33 | if (notes->src == NULL) |
34 | return -1; | ||
35 | notes->src->sizeof_sym_hist = sizeof_sym_hist; | ||
36 | notes->src->nr_histograms = nevents; | ||
37 | INIT_LIST_HEAD(¬es->src->source); | ||
38 | return 0; | ||
27 | } | 39 | } |
28 | 40 | ||
29 | void symbol__annotate_zero_histograms(struct symbol *sym) | 41 | void symbol__annotate_zero_histograms(struct symbol *sym) |
30 | { | 42 | { |
31 | struct annotation *notes = symbol__annotation(sym); | 43 | struct annotation *notes = symbol__annotation(sym); |
32 | 44 | ||
33 | if (notes->histograms != NULL) | 45 | pthread_mutex_lock(¬es->lock); |
34 | memset(notes->histograms, 0, | 46 | if (notes->src != NULL) |
35 | notes->nr_histograms * notes->sizeof_sym_hist); | 47 | memset(notes->src->histograms, 0, |
48 | notes->src->nr_histograms * notes->src->sizeof_sym_hist); | ||
49 | pthread_mutex_unlock(¬es->lock); | ||
36 | } | 50 | } |
37 | 51 | ||
38 | int symbol__inc_addr_samples(struct symbol *sym, struct map *map, | 52 | int symbol__inc_addr_samples(struct symbol *sym, struct map *map, |
@@ -43,7 +57,7 @@ int symbol__inc_addr_samples(struct symbol *sym, struct map *map, | |||
43 | struct sym_hist *h; | 57 | struct sym_hist *h; |
44 | 58 | ||
45 | notes = symbol__annotation(sym); | 59 | notes = symbol__annotation(sym); |
46 | if (notes->histograms == NULL) | 60 | if (notes->src == NULL) |
47 | return -ENOMEM; | 61 | return -ENOMEM; |
48 | 62 | ||
49 | pr_debug3("%s: addr=%#" PRIx64 "\n", __func__, map->unmap_ip(map, addr)); | 63 | pr_debug3("%s: addr=%#" PRIx64 "\n", __func__, map->unmap_ip(map, addr)); |
@@ -95,8 +109,7 @@ struct objdump_line *objdump__get_next_ip_line(struct list_head *head, | |||
95 | return NULL; | 109 | return NULL; |
96 | } | 110 | } |
97 | 111 | ||
98 | static int objdump_line__print(struct objdump_line *oline, | 112 | static int objdump_line__print(struct objdump_line *oline, struct symbol *sym, |
99 | struct list_head *head, struct symbol *sym, | ||
100 | int evidx, u64 len, int min_pcnt, | 113 | int evidx, u64 len, int min_pcnt, |
101 | int printed, int max_lines) | 114 | int printed, int max_lines) |
102 | { | 115 | { |
@@ -109,10 +122,12 @@ static int objdump_line__print(struct objdump_line *oline, | |||
109 | double percent = 0.0; | 122 | double percent = 0.0; |
110 | const char *color; | 123 | const char *color; |
111 | struct annotation *notes = symbol__annotation(sym); | 124 | struct annotation *notes = symbol__annotation(sym); |
112 | struct source_line *src_line = notes->src_line; | 125 | struct source_line *src_line = notes->src->lines; |
113 | struct sym_hist *h = annotation__histogram(notes, evidx); | 126 | struct sym_hist *h = annotation__histogram(notes, evidx); |
114 | s64 offset = oline->offset; | 127 | s64 offset = oline->offset; |
115 | struct objdump_line *next = objdump__get_next_ip_line(head, oline); | 128 | struct objdump_line *next; |
129 | |||
130 | next = objdump__get_next_ip_line(¬es->src->source, oline); | ||
116 | 131 | ||
117 | while (offset < (s64)len && | 132 | while (offset < (s64)len && |
118 | (next == NULL || offset < next->offset)) { | 133 | (next == NULL || offset < next->offset)) { |
@@ -166,9 +181,10 @@ static int objdump_line__print(struct objdump_line *oline, | |||
166 | return 0; | 181 | return 0; |
167 | } | 182 | } |
168 | 183 | ||
169 | static int symbol__parse_objdump_line(struct symbol *sym, struct map *map, FILE *file, | 184 | static int symbol__parse_objdump_line(struct symbol *sym, struct map *map, |
170 | struct list_head *head, size_t privsize) | 185 | FILE *file, size_t privsize) |
171 | { | 186 | { |
187 | struct annotation *notes = symbol__annotation(sym); | ||
172 | struct objdump_line *objdump_line; | 188 | struct objdump_line *objdump_line; |
173 | char *line = NULL, *tmp, *tmp2, *c; | 189 | char *line = NULL, *tmp, *tmp2, *c; |
174 | size_t line_len; | 190 | size_t line_len; |
@@ -222,13 +238,12 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map, FILE | |||
222 | free(line); | 238 | free(line); |
223 | return -1; | 239 | return -1; |
224 | } | 240 | } |
225 | objdump__add_line(head, objdump_line); | 241 | objdump__add_line(¬es->src->source, objdump_line); |
226 | 242 | ||
227 | return 0; | 243 | return 0; |
228 | } | 244 | } |
229 | 245 | ||
230 | int symbol__annotate(struct symbol *sym, struct map *map, | 246 | int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize) |
231 | struct list_head *head, size_t privsize) | ||
232 | { | 247 | { |
233 | struct dso *dso = map->dso; | 248 | struct dso *dso = map->dso; |
234 | char *filename = dso__build_id_filename(dso, NULL, 0); | 249 | char *filename = dso__build_id_filename(dso, NULL, 0); |
@@ -297,7 +312,7 @@ fallback: | |||
297 | goto out_free_filename; | 312 | goto out_free_filename; |
298 | 313 | ||
299 | while (!feof(file)) | 314 | while (!feof(file)) |
300 | if (symbol__parse_objdump_line(sym, map, file, head, privsize) < 0) | 315 | if (symbol__parse_objdump_line(sym, map, file, privsize) < 0) |
301 | break; | 316 | break; |
302 | 317 | ||
303 | pclose(file); | 318 | pclose(file); |
@@ -330,14 +345,14 @@ static void insert_source_line(struct rb_root *root, struct source_line *src_lin | |||
330 | static void symbol__free_source_line(struct symbol *sym, int len) | 345 | static void symbol__free_source_line(struct symbol *sym, int len) |
331 | { | 346 | { |
332 | struct annotation *notes = symbol__annotation(sym); | 347 | struct annotation *notes = symbol__annotation(sym); |
333 | struct source_line *src_line = notes->src_line; | 348 | struct source_line *src_line = notes->src->lines; |
334 | int i; | 349 | int i; |
335 | 350 | ||
336 | for (i = 0; i < len; i++) | 351 | for (i = 0; i < len; i++) |
337 | free(src_line[i].path); | 352 | free(src_line[i].path); |
338 | 353 | ||
339 | free(src_line); | 354 | free(src_line); |
340 | notes->src_line = NULL; | 355 | notes->src->lines = NULL; |
341 | } | 356 | } |
342 | 357 | ||
343 | /* Get the filename:line for the colored entries */ | 358 | /* Get the filename:line for the colored entries */ |
@@ -355,8 +370,8 @@ static int symbol__get_source_line(struct symbol *sym, struct map *map, | |||
355 | if (!h->sum) | 370 | if (!h->sum) |
356 | return 0; | 371 | return 0; |
357 | 372 | ||
358 | src_line = notes->src_line = calloc(len, sizeof(struct source_line)); | 373 | src_line = notes->src->lines = calloc(len, sizeof(struct source_line)); |
359 | if (!notes->src_line) | 374 | if (!notes->src->lines) |
360 | return -1; | 375 | return -1; |
361 | 376 | ||
362 | start = map->unmap_ip(map, sym->start); | 377 | start = map->unmap_ip(map, sym->start); |
@@ -436,12 +451,12 @@ static void symbol__annotate_hits(struct symbol *sym, int evidx) | |||
436 | printf("%*s: %" PRIu64 "\n", BITS_PER_LONG / 2, "h->sum", h->sum); | 451 | printf("%*s: %" PRIu64 "\n", BITS_PER_LONG / 2, "h->sum", h->sum); |
437 | } | 452 | } |
438 | 453 | ||
439 | int symbol__annotate_printf(struct symbol *sym, struct map *map, | 454 | int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx, |
440 | struct list_head *head, int evidx, bool full_paths, | 455 | bool full_paths, int min_pcnt, int max_lines) |
441 | int min_pcnt, int max_lines) | ||
442 | { | 456 | { |
443 | struct dso *dso = map->dso; | 457 | struct dso *dso = map->dso; |
444 | const char *filename = dso->long_name, *d_filename; | 458 | const char *filename = dso->long_name, *d_filename; |
459 | struct annotation *notes = symbol__annotation(sym); | ||
445 | struct objdump_line *pos; | 460 | struct objdump_line *pos; |
446 | int printed = 2; | 461 | int printed = 2; |
447 | int more = 0; | 462 | int more = 0; |
@@ -460,8 +475,8 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, | |||
460 | if (verbose) | 475 | if (verbose) |
461 | symbol__annotate_hits(sym, evidx); | 476 | symbol__annotate_hits(sym, evidx); |
462 | 477 | ||
463 | list_for_each_entry(pos, head, node) { | 478 | list_for_each_entry(pos, ¬es->src->source, node) { |
464 | switch (objdump_line__print(pos, head, sym, evidx, len, min_pcnt, | 479 | switch (objdump_line__print(pos, sym, evidx, len, min_pcnt, |
465 | printed, max_lines)) { | 480 | printed, max_lines)) { |
466 | case 0: | 481 | case 0: |
467 | ++printed; | 482 | ++printed; |
@@ -485,11 +500,10 @@ void symbol__annotate_zero_histogram(struct symbol *sym, int evidx) | |||
485 | struct annotation *notes = symbol__annotation(sym); | 500 | struct annotation *notes = symbol__annotation(sym); |
486 | struct sym_hist *h = annotation__histogram(notes, evidx); | 501 | struct sym_hist *h = annotation__histogram(notes, evidx); |
487 | 502 | ||
488 | memset(h, 0, notes->sizeof_sym_hist); | 503 | memset(h, 0, notes->src->sizeof_sym_hist); |
489 | } | 504 | } |
490 | 505 | ||
491 | void symbol__annotate_decay_histogram(struct symbol *sym, | 506 | void symbol__annotate_decay_histogram(struct symbol *sym, int evidx) |
492 | struct list_head *head, int evidx) | ||
493 | { | 507 | { |
494 | struct annotation *notes = symbol__annotation(sym); | 508 | struct annotation *notes = symbol__annotation(sym); |
495 | struct sym_hist *h = annotation__histogram(notes, evidx); | 509 | struct sym_hist *h = annotation__histogram(notes, evidx); |
@@ -497,7 +511,7 @@ void symbol__annotate_decay_histogram(struct symbol *sym, | |||
497 | 511 | ||
498 | h->sum = 0; | 512 | h->sum = 0; |
499 | 513 | ||
500 | list_for_each_entry(pos, head, node) { | 514 | list_for_each_entry(pos, ¬es->src->source, node) { |
501 | if (pos->offset != -1) { | 515 | if (pos->offset != -1) { |
502 | h->addr[pos->offset] = h->addr[pos->offset] * 7 / 8; | 516 | h->addr[pos->offset] = h->addr[pos->offset] * 7 / 8; |
503 | h->sum += h->addr[pos->offset]; | 517 | h->sum += h->addr[pos->offset]; |
@@ -522,10 +536,9 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx, | |||
522 | struct dso *dso = map->dso; | 536 | struct dso *dso = map->dso; |
523 | const char *filename = dso->long_name; | 537 | const char *filename = dso->long_name; |
524 | struct rb_root source_line = RB_ROOT; | 538 | struct rb_root source_line = RB_ROOT; |
525 | LIST_HEAD(head); | ||
526 | u64 len; | 539 | u64 len; |
527 | 540 | ||
528 | if (symbol__annotate(sym, map, &head, 0) < 0) | 541 | if (symbol__annotate(sym, map, 0) < 0) |
529 | return -1; | 542 | return -1; |
530 | 543 | ||
531 | len = sym->end - sym->start; | 544 | len = sym->end - sym->start; |
@@ -536,12 +549,12 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx, | |||
536 | print_summary(&source_line, filename); | 549 | print_summary(&source_line, filename); |
537 | } | 550 | } |
538 | 551 | ||
539 | symbol__annotate_printf(sym, map, &head, evidx, full_paths, | 552 | symbol__annotate_printf(sym, map, evidx, full_paths, |
540 | min_pcnt, max_lines); | 553 | min_pcnt, max_lines); |
541 | if (print_lines) | 554 | if (print_lines) |
542 | symbol__free_source_line(sym, len); | 555 | symbol__free_source_line(sym, len); |
543 | 556 | ||
544 | objdump_line_list__purge(&head); | 557 | objdump_line_list__purge(&symbol__annotation(sym)->src->source); |
545 | 558 | ||
546 | return 0; | 559 | return 0; |
547 | } | 560 | } |
diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index bc08b36a713a..b237c8678c22 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h | |||
@@ -28,22 +28,29 @@ struct source_line { | |||
28 | char *path; | 28 | char *path; |
29 | }; | 29 | }; |
30 | 30 | ||
31 | /** struct annotation - symbols with hits have this attached as in sannotation | 31 | /** struct annotated_source - symbols with hits have this attached as in sannotation |
32 | * | 32 | * |
33 | * @histogram: Array of addr hit histograms per event being monitored | 33 | * @histogram: Array of addr hit histograms per event being monitored |
34 | * @src_line: If 'print_lines' is specified, per source code line percentages | 34 | * @lines: If 'print_lines' is specified, per source code line percentages |
35 | * @source: source parsed from objdump -dS | ||
35 | * | 36 | * |
36 | * src_line is allocated, percentages calculated and all sorted by percentage | 37 | * lines is allocated, percentages calculated and all sorted by percentage |
37 | * when the annotation is about to be presented, so the percentages are for | 38 | * when the annotation is about to be presented, so the percentages are for |
38 | * one of the entries in the histogram array, i.e. for the event/counter being | 39 | * one of the entries in the histogram array, i.e. for the event/counter being |
39 | * presented. It is deallocated right after symbol__{tui,tty,etc}_annotate | 40 | * presented. It is deallocated right after symbol__{tui,tty,etc}_annotate |
40 | * returns. | 41 | * returns. |
41 | */ | 42 | */ |
42 | struct annotation { | 43 | struct annotated_source { |
43 | struct source_line *src_line; | 44 | struct list_head source; |
44 | struct sym_hist *histograms; | 45 | struct source_line *lines; |
45 | int nr_histograms; | 46 | int nr_histograms; |
46 | int sizeof_sym_hist; | 47 | int sizeof_sym_hist; |
48 | struct sym_hist histograms[0]; | ||
49 | }; | ||
50 | |||
51 | struct annotation { | ||
52 | pthread_mutex_t lock; | ||
53 | struct annotated_source *src; | ||
47 | }; | 54 | }; |
48 | 55 | ||
49 | struct sannotation { | 56 | struct sannotation { |
@@ -53,7 +60,8 @@ struct sannotation { | |||
53 | 60 | ||
54 | static inline struct sym_hist *annotation__histogram(struct annotation *notes, int idx) | 61 | static inline struct sym_hist *annotation__histogram(struct annotation *notes, int idx) |
55 | { | 62 | { |
56 | return ((void *)notes->histograms) + (notes->sizeof_sym_hist * idx); | 63 | return (((void *)¬es->src->histograms) + |
64 | (notes->src->sizeof_sym_hist * idx)); | ||
57 | } | 65 | } |
58 | 66 | ||
59 | static inline struct annotation *symbol__annotation(struct symbol *sym) | 67 | static inline struct annotation *symbol__annotation(struct symbol *sym) |
@@ -67,14 +75,12 @@ int symbol__inc_addr_samples(struct symbol *sym, struct map *map, | |||
67 | int symbol__alloc_hist(struct symbol *sym, int nevents); | 75 | int symbol__alloc_hist(struct symbol *sym, int nevents); |
68 | void symbol__annotate_zero_histograms(struct symbol *sym); | 76 | void symbol__annotate_zero_histograms(struct symbol *sym); |
69 | 77 | ||
70 | int symbol__annotate(struct symbol *sym, struct map *map, | 78 | int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize); |
71 | struct list_head *head, size_t privsize); | 79 | int symbol__annotate_init(struct map *map __used, struct symbol *sym); |
72 | int symbol__annotate_printf(struct symbol *sym, struct map *map, | 80 | int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx, |
73 | struct list_head *head, int evidx, bool full_paths, | 81 | bool full_paths, int min_pcnt, int max_lines); |
74 | int min_pcnt, int max_lines); | ||
75 | void symbol__annotate_zero_histogram(struct symbol *sym, int evidx); | 82 | void symbol__annotate_zero_histogram(struct symbol *sym, int evidx); |
76 | void symbol__annotate_decay_histogram(struct symbol *sym, | 83 | void symbol__annotate_decay_histogram(struct symbol *sym, int evidx); |
77 | struct list_head *head, int evidx); | ||
78 | void objdump_line_list__purge(struct list_head *head); | 84 | void objdump_line_list__purge(struct list_head *head); |
79 | 85 | ||
80 | int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx, | 86 | int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx, |
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index bac5ab684967..3f437236f193 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c | |||
@@ -955,10 +955,9 @@ int hist_entry__inc_addr_samples(struct hist_entry *he, int evidx, u64 ip) | |||
955 | return symbol__inc_addr_samples(he->ms.sym, he->ms.map, evidx, ip); | 955 | return symbol__inc_addr_samples(he->ms.sym, he->ms.map, evidx, ip); |
956 | } | 956 | } |
957 | 957 | ||
958 | int hist_entry__annotate(struct hist_entry *he, struct list_head *head, | 958 | int hist_entry__annotate(struct hist_entry *he, size_t privsize) |
959 | size_t privsize) | ||
960 | { | 959 | { |
961 | return symbol__annotate(he->ms.sym, he->ms.map, head, privsize); | 960 | return symbol__annotate(he->ms.sym, he->ms.map, privsize); |
962 | } | 961 | } |
963 | 962 | ||
964 | void hists__inc_nr_events(struct hists *self, u32 type) | 963 | void hists__inc_nr_events(struct hists *self, u32 type) |
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index 2c6cdae6a764..37c79089de09 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h | |||
@@ -78,8 +78,7 @@ size_t hists__fprintf(struct hists *self, struct hists *pair, | |||
78 | bool show_displacement, FILE *fp); | 78 | bool show_displacement, FILE *fp); |
79 | 79 | ||
80 | int hist_entry__inc_addr_samples(struct hist_entry *self, int evidx, u64 addr); | 80 | int hist_entry__inc_addr_samples(struct hist_entry *self, int evidx, u64 addr); |
81 | int hist_entry__annotate(struct hist_entry *self, struct list_head *head, | 81 | int hist_entry__annotate(struct hist_entry *self, size_t privsize); |
82 | size_t privsize); | ||
83 | 82 | ||
84 | void hists__filter_by_dso(struct hists *self, const struct dso *dso); | 83 | void hists__filter_by_dso(struct hists *self, const struct dso *dso); |
85 | void hists__filter_by_thread(struct hists *self, const struct thread *thread); | 84 | void hists__filter_by_thread(struct hists *self, const struct thread *thread); |
diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h index 62e32939f3d1..4f769f47e19a 100644 --- a/tools/perf/util/top.h +++ b/tools/perf/util/top.h | |||
@@ -11,11 +11,6 @@ | |||
11 | struct perf_evlist; | 11 | struct perf_evlist; |
12 | struct perf_evsel; | 12 | struct perf_evsel; |
13 | 13 | ||
14 | struct sym_entry_source { | ||
15 | struct list_head head; | ||
16 | pthread_mutex_t lock; | ||
17 | }; | ||
18 | |||
19 | struct sym_entry { | 14 | struct sym_entry { |
20 | struct rb_node rb_node; | 15 | struct rb_node rb_node; |
21 | struct list_head node; | 16 | struct list_head node; |
@@ -24,7 +19,6 @@ struct sym_entry { | |||
24 | int skip; | 19 | int skip; |
25 | u8 origin; | 20 | u8 origin; |
26 | struct map *map; | 21 | struct map *map; |
27 | struct sym_entry_source *src; | ||
28 | unsigned long count[0]; | 22 | unsigned long count[0]; |
29 | }; | 23 | }; |
30 | 24 | ||
diff --git a/tools/perf/util/ui/browsers/annotate.c b/tools/perf/util/ui/browsers/annotate.c index 8d8a16895af7..1aa39658539c 100644 --- a/tools/perf/util/ui/browsers/annotate.c +++ b/tools/perf/util/ui/browsers/annotate.c | |||
@@ -60,7 +60,6 @@ static void annotate_browser__write(struct ui_browser *self, void *entry, int ro | |||
60 | } | 60 | } |
61 | 61 | ||
62 | static double objdump_line__calc_percent(struct objdump_line *self, | 62 | static double objdump_line__calc_percent(struct objdump_line *self, |
63 | struct list_head *head, | ||
64 | struct symbol *sym, int evidx) | 63 | struct symbol *sym, int evidx) |
65 | { | 64 | { |
66 | double percent = 0.0; | 65 | double percent = 0.0; |
@@ -69,11 +68,12 @@ static double objdump_line__calc_percent(struct objdump_line *self, | |||
69 | int len = sym->end - sym->start; | 68 | int len = sym->end - sym->start; |
70 | unsigned int hits = 0; | 69 | unsigned int hits = 0; |
71 | struct annotation *notes = symbol__annotation(sym); | 70 | struct annotation *notes = symbol__annotation(sym); |
72 | struct source_line *src_line = notes->src_line; | 71 | struct source_line *src_line = notes->src->lines; |
73 | struct sym_hist *h = annotation__histogram(notes, evidx); | 72 | struct sym_hist *h = annotation__histogram(notes, evidx); |
74 | s64 offset = self->offset; | 73 | s64 offset = self->offset; |
75 | struct objdump_line *next = objdump__get_next_ip_line(head, self); | 74 | struct objdump_line *next; |
76 | 75 | ||
76 | next = objdump__get_next_ip_line(¬es->src->source, self); | ||
77 | while (offset < (s64)len && | 77 | while (offset < (s64)len && |
78 | (next == NULL || offset < next->offset)) { | 78 | (next == NULL || offset < next->offset)) { |
79 | if (src_line) { | 79 | if (src_line) { |
@@ -192,10 +192,10 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx) | |||
192 | { | 192 | { |
193 | struct objdump_line *pos, *n; | 193 | struct objdump_line *pos, *n; |
194 | struct objdump_line_rb_node *rbpos; | 194 | struct objdump_line_rb_node *rbpos; |
195 | LIST_HEAD(head); | 195 | struct annotation *notes = symbol__annotation(sym); |
196 | struct annotate_browser browser = { | 196 | struct annotate_browser browser = { |
197 | .b = { | 197 | .b = { |
198 | .entries = &head, | 198 | .entries = ¬es->src->source, |
199 | .refresh = ui_browser__list_head_refresh, | 199 | .refresh = ui_browser__list_head_refresh, |
200 | .seek = ui_browser__list_head_seek, | 200 | .seek = ui_browser__list_head_seek, |
201 | .write = annotate_browser__write, | 201 | .write = annotate_browser__write, |
@@ -210,20 +210,20 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx) | |||
210 | if (map->dso->annotate_warned) | 210 | if (map->dso->annotate_warned) |
211 | return -1; | 211 | return -1; |
212 | 212 | ||
213 | if (symbol__annotate(sym, map, &head, sizeof(*rbpos)) < 0) { | 213 | if (symbol__annotate(sym, map, sizeof(*rbpos)) < 0) { |
214 | ui__error_window(ui_helpline__last_msg); | 214 | ui__error_window(ui_helpline__last_msg); |
215 | return -1; | 215 | return -1; |
216 | } | 216 | } |
217 | 217 | ||
218 | ui_helpline__push("Press <- or ESC to exit"); | 218 | ui_helpline__push("Press <- or ESC to exit"); |
219 | 219 | ||
220 | list_for_each_entry(pos, &head, node) { | 220 | list_for_each_entry(pos, ¬es->src->source, node) { |
221 | size_t line_len = strlen(pos->line); | 221 | size_t line_len = strlen(pos->line); |
222 | if (browser.b.width < line_len) | 222 | if (browser.b.width < line_len) |
223 | browser.b.width = line_len; | 223 | browser.b.width = line_len; |
224 | rbpos = objdump_line__rb(pos); | 224 | rbpos = objdump_line__rb(pos); |
225 | rbpos->idx = browser.b.nr_entries++; | 225 | rbpos->idx = browser.b.nr_entries++; |
226 | rbpos->percent = objdump_line__calc_percent(pos, &head, sym, evidx); | 226 | rbpos->percent = objdump_line__calc_percent(pos, sym, evidx); |
227 | if (rbpos->percent < 0.01) | 227 | if (rbpos->percent < 0.01) |
228 | continue; | 228 | continue; |
229 | objdump__insert_line(&browser.entries, rbpos); | 229 | objdump__insert_line(&browser.entries, rbpos); |
@@ -238,7 +238,7 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx) | |||
238 | 238 | ||
239 | browser.b.width += 18; /* Percentage */ | 239 | browser.b.width += 18; /* Percentage */ |
240 | ret = annotate_browser__run(&browser); | 240 | ret = annotate_browser__run(&browser); |
241 | list_for_each_entry_safe(pos, n, &head, node) { | 241 | list_for_each_entry_safe(pos, n, ¬es->src->source, node) { |
242 | list_del(&pos->node); | 242 | list_del(&pos->node); |
243 | objdump_line__free(pos); | 243 | objdump_line__free(pos); |
244 | } | 244 | } |