diff options
author | Arnaldo Carvalho de Melo <acme@redhat.com> | 2011-02-08 10:27:39 -0500 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2011-02-08 12:03:36 -0500 |
commit | ce6f4fab4059cd72638a0cfa596a8ee2c79c1c8e (patch) | |
tree | 00416d7a54d9ef265b9358022e804217dcb5d870 /tools/perf | |
parent | e3087b80aa0bceda9863f33307460f3ba79f2b15 (diff) |
perf annotate: Move locking to struct annotation
Since we'll need it when implementing the live annotate TUI browser.
This also simplifies things a bit by having the list head for the source
code to be in the dynamicly allocated part of struct annotation, that
way we don't have to pass it around, it can be found from the struct
symbol that is passed everywhere.
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Cc: Tom Zanussi <tzanussi@gmail.com>
LKML-Reference: <new-submission>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools/perf')
-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 | } |