aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf')
-rw-r--r--tools/perf/builtin-top.c496
1 files changed, 456 insertions, 40 deletions
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index f139f1ab9333..d58701346b1e 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -31,6 +31,8 @@
31#include <fcntl.h> 31#include <fcntl.h>
32 32
33#include <stdio.h> 33#include <stdio.h>
34#include <termios.h>
35#include <unistd.h>
34 36
35#include <errno.h> 37#include <errno.h>
36#include <time.h> 38#include <time.h>
@@ -54,7 +56,7 @@ static int system_wide = 0;
54 56
55static int default_interval = 100000; 57static int default_interval = 100000;
56 58
57static u64 count_filter = 5; 59static int count_filter = 5;
58static int print_entries = 15; 60static int print_entries = 15;
59 61
60static int target_pid = -1; 62static int target_pid = -1;
@@ -69,15 +71,27 @@ static int freq = 0;
69static int verbose = 0; 71static int verbose = 0;
70static char *vmlinux = NULL; 72static char *vmlinux = NULL;
71 73
72static char *sym_filter;
73static unsigned long filter_start;
74static unsigned long filter_end;
75
76static int delay_secs = 2; 74static int delay_secs = 2;
77static int zero; 75static int zero;
78static int dump_symtab; 76static int dump_symtab;
79 77
80/* 78/*
79 * Source
80 */
81
82struct source_line {
83 u64 eip;
84 unsigned long count[MAX_COUNTERS];
85 char *line;
86 struct source_line *next;
87};
88
89static char *sym_filter = NULL;
90struct sym_entry *sym_filter_entry = NULL;
91static int sym_pcnt_filter = 5;
92static int sym_counter = 0;
93
94/*
81 * Symbols 95 * Symbols
82 */ 96 */
83 97
@@ -91,9 +105,237 @@ struct sym_entry {
91 unsigned long snap_count; 105 unsigned long snap_count;
92 double weight; 106 double weight;
93 int skip; 107 int skip;
108 struct source_line *source;
109 struct source_line *lines;
110 struct source_line **lines_tail;
111 pthread_mutex_t source_lock;
94}; 112};
95 113
96struct sym_entry *sym_filter_entry; 114/*
115 * Source functions
116 */
117
118static void parse_source(struct sym_entry *syme)
119{
120 struct symbol *sym;
121 struct module *module;
122 struct section *section = NULL;
123 FILE *file;
124 char command[PATH_MAX*2], *path = vmlinux;
125 u64 start, end, len;
126
127 if (!syme)
128 return;
129
130 if (syme->lines) {
131 pthread_mutex_lock(&syme->source_lock);
132 goto out_assign;
133 }
134
135 sym = (struct symbol *)(syme + 1);
136 module = sym->module;
137
138 if (module)
139 path = module->path;
140 if (!path)
141 return;
142
143 start = sym->obj_start;
144 if (!start)
145 start = sym->start;
146
147 if (module) {
148 section = module->sections->find_section(module->sections, ".text");
149 if (section)
150 start -= section->vma;
151 }
152
153 end = start + sym->end - sym->start + 1;
154 len = sym->end - sym->start;
155
156 sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s", start, end, path);
157
158 file = popen(command, "r");
159 if (!file)
160 return;
161
162 pthread_mutex_lock(&syme->source_lock);
163 syme->lines_tail = &syme->lines;
164 while (!feof(file)) {
165 struct source_line *src;
166 size_t dummy = 0;
167 char *c;
168
169 src = malloc(sizeof(struct source_line));
170 assert(src != NULL);
171 memset(src, 0, sizeof(struct source_line));
172
173 if (getline(&src->line, &dummy, file) < 0)
174 break;
175 if (!src->line)
176 break;
177
178 c = strchr(src->line, '\n');
179 if (c)
180 *c = 0;
181
182 src->next = NULL;
183 *syme->lines_tail = src;
184 syme->lines_tail = &src->next;
185
186 if (strlen(src->line)>8 && src->line[8] == ':') {
187 src->eip = strtoull(src->line, NULL, 16);
188 if (section)
189 src->eip += section->vma;
190 }
191 if (strlen(src->line)>8 && src->line[16] == ':') {
192 src->eip = strtoull(src->line, NULL, 16);
193 if (section)
194 src->eip += section->vma;
195 }
196 }
197 pclose(file);
198out_assign:
199 sym_filter_entry = syme;
200 pthread_mutex_unlock(&syme->source_lock);
201}
202
203static void __zero_source_counters(struct sym_entry *syme)
204{
205 int i;
206 struct source_line *line;
207
208 line = syme->lines;
209 while (line) {
210 for (i = 0; i < nr_counters; i++)
211 line->count[i] = 0;
212 line = line->next;
213 }
214}
215
216static void record_precise_ip(struct sym_entry *syme, int counter, u64 ip)
217{
218 struct source_line *line;
219
220 if (syme != sym_filter_entry)
221 return;
222
223 if (pthread_mutex_trylock(&syme->source_lock))
224 return;
225
226 if (!syme->source)
227 goto out_unlock;
228
229 for (line = syme->lines; line; line = line->next) {
230 if (line->eip == ip) {
231 line->count[counter]++;
232 break;
233 }
234 if (line->eip > ip)
235 break;
236 }
237out_unlock:
238 pthread_mutex_unlock(&syme->source_lock);
239}
240
241static void lookup_sym_source(struct sym_entry *syme)
242{
243 struct symbol *symbol = (struct symbol *)(syme + 1);
244 struct source_line *line;
245 char pattern[PATH_MAX];
246 char *idx;
247
248 sprintf(pattern, "<%s>:", symbol->name);
249
250 if (symbol->module) {
251 idx = strstr(pattern, "\t");
252 if (idx)
253 *idx = 0;
254 }
255
256 pthread_mutex_lock(&syme->source_lock);
257 for (line = syme->lines; line; line = line->next) {
258 if (strstr(line->line, pattern)) {
259 syme->source = line;
260 break;
261 }
262 }
263 pthread_mutex_unlock(&syme->source_lock);
264}
265
266static void show_lines(struct source_line *queue, int count, int total)
267{
268 int i;
269 struct source_line *line;
270
271 line = queue;
272 for (i = 0; i < count; i++) {
273 float pcnt = 100.0*(float)line->count[sym_counter]/(float)total;
274
275 printf("%8li %4.1f%%\t%s\n", line->count[sym_counter], pcnt, line->line);
276 line = line->next;
277 }
278}
279
280#define TRACE_COUNT 3
281
282static void show_details(struct sym_entry *syme)
283{
284 struct symbol *symbol;
285 struct source_line *line;
286 struct source_line *line_queue = NULL;
287 int displayed = 0;
288 int line_queue_count = 0, total = 0, more = 0;
289
290 if (!syme)
291 return;
292
293 if (!syme->source)
294 lookup_sym_source(syme);
295
296 if (!syme->source)
297 return;
298
299 symbol = (struct symbol *)(syme + 1);
300 printf("Showing %s for %s\n", event_name(sym_counter), symbol->name);
301 printf(" Events Pcnt (>=%d%%)\n", sym_pcnt_filter);
302
303 pthread_mutex_lock(&syme->source_lock);
304 line = syme->source;
305 while (line) {
306 total += line->count[sym_counter];
307 line = line->next;
308 }
309
310 line = syme->source;
311 while (line) {
312 float pcnt = 0.0;
313
314 if (!line_queue_count)
315 line_queue = line;
316 line_queue_count++;
317
318 if (line->count[sym_counter])
319 pcnt = 100.0 * line->count[sym_counter] / (float)total;
320 if (pcnt >= (float)sym_pcnt_filter) {
321 if (displayed <= print_entries)
322 show_lines(line_queue, line_queue_count, total);
323 else more++;
324 displayed += line_queue_count;
325 line_queue_count = 0;
326 line_queue = NULL;
327 } else if (line_queue_count > TRACE_COUNT) {
328 line_queue = line_queue->next;
329 line_queue_count--;
330 }
331
332 line->count[sym_counter] = zero ? 0 : line->count[sym_counter] * 7 / 8;
333 line = line->next;
334 }
335 pthread_mutex_unlock(&syme->source_lock);
336 if (more)
337 printf("%d lines not displayed, maybe increase display entries [e]\n", more);
338}
97 339
98struct dso *kernel_dso; 340struct dso *kernel_dso;
99 341
@@ -228,6 +470,11 @@ static void print_sym_table(void)
228 470
229 printf("------------------------------------------------------------------------------\n\n"); 471 printf("------------------------------------------------------------------------------\n\n");
230 472
473 if (sym_filter_entry) {
474 show_details(sym_filter_entry);
475 return;
476 }
477
231 if (nr_counters == 1) 478 if (nr_counters == 1)
232 printf(" samples pcnt"); 479 printf(" samples pcnt");
233 else 480 else
@@ -242,7 +489,7 @@ static void print_sym_table(void)
242 struct symbol *sym = (struct symbol *)(syme + 1); 489 struct symbol *sym = (struct symbol *)(syme + 1);
243 double pcnt; 490 double pcnt;
244 491
245 if (++printed > print_entries || syme->snap_count < count_filter) 492 if (++printed > print_entries || (int)syme->snap_count < count_filter)
246 continue; 493 continue;
247 494
248 pcnt = 100.0 - (100.0 * ((sum_ksamples - syme->snap_count) / 495 pcnt = 100.0 - (100.0 * ((sum_ksamples - syme->snap_count) /
@@ -261,19 +508,208 @@ static void print_sym_table(void)
261 } 508 }
262} 509}
263 510
511static void prompt_integer(int *target, const char *msg)
512{
513 char *buf = malloc(0), *p;
514 size_t dummy = 0;
515 int tmp;
516
517 fprintf(stdout, "\n%s: ", msg);
518 if (getline(&buf, &dummy, stdin) < 0)
519 return;
520
521 p = strchr(buf, '\n');
522 if (p)
523 *p = 0;
524
525 p = buf;
526 while(*p) {
527 if (!isdigit(*p))
528 goto out_free;
529 p++;
530 }
531 tmp = strtoul(buf, NULL, 10);
532 *target = tmp;
533out_free:
534 free(buf);
535}
536
537static void prompt_percent(int *target, const char *msg)
538{
539 int tmp = 0;
540
541 prompt_integer(&tmp, msg);
542 if (tmp >= 0 && tmp <= 100)
543 *target = tmp;
544}
545
546static void prompt_symbol(struct sym_entry **target, const char *msg)
547{
548 char *buf = malloc(0), *p;
549 struct sym_entry *syme = *target, *n, *found = NULL;
550 size_t dummy = 0;
551
552 /* zero counters of active symbol */
553 if (syme) {
554 pthread_mutex_lock(&syme->source_lock);
555 __zero_source_counters(syme);
556 *target = NULL;
557 pthread_mutex_unlock(&syme->source_lock);
558 }
559
560 fprintf(stdout, "\n%s: ", msg);
561 if (getline(&buf, &dummy, stdin) < 0)
562 goto out_free;
563
564 p = strchr(buf, '\n');
565 if (p)
566 *p = 0;
567
568 pthread_mutex_lock(&active_symbols_lock);
569 syme = list_entry(active_symbols.next, struct sym_entry, node);
570 pthread_mutex_unlock(&active_symbols_lock);
571
572 list_for_each_entry_safe_from(syme, n, &active_symbols, node) {
573 struct symbol *sym = (struct symbol *)(syme + 1);
574
575 if (!strcmp(buf, sym->name)) {
576 found = syme;
577 break;
578 }
579 }
580
581 if (!found) {
582 fprintf(stderr, "Sorry, %s is not active.\n", sym_filter);
583 sleep(1);
584 return;
585 } else
586 parse_source(found);
587
588out_free:
589 free(buf);
590}
591
592static void print_known_keys(void)
593{
594 fprintf(stdout, "\nknown keys:\n");
595 fprintf(stdout, "\t[d] select display delay.\n");
596 fprintf(stdout, "\t[e] select display entries (lines).\n");
597 fprintf(stdout, "\t[E] select annotation event counter.\n");
598 fprintf(stdout, "\t[f] select normal display count filter.\n");
599 fprintf(stdout, "\t[F] select annotation display count filter (percentage).\n");
600 fprintf(stdout, "\t[qQ] quit.\n");
601 fprintf(stdout, "\t[s] select annotation symbol and start annotation.\n");
602 fprintf(stdout, "\t[S] stop annotation, revert to normal display.\n");
603 fprintf(stdout, "\t[z] toggle event count zeroing.\n");
604}
605
606static void handle_keypress(int c)
607{
608 int once = 0;
609repeat:
610 switch (c) {
611 case 'd':
612 prompt_integer(&delay_secs, "Enter display delay");
613 break;
614 case 'e':
615 prompt_integer(&print_entries, "Enter display entries (lines)");
616 break;
617 case 'E':
618 if (nr_counters > 1) {
619 int i;
620
621 fprintf(stderr, "\nAvailable events:");
622 for (i = 0; i < nr_counters; i++)
623 fprintf(stderr, "\n\t%d %s", i, event_name(i));
624
625 prompt_integer(&sym_counter, "Enter details event counter");
626
627 if (sym_counter >= nr_counters) {
628 fprintf(stderr, "Sorry, no such event, using %s.\n", event_name(0));
629 sym_counter = 0;
630 sleep(1);
631 }
632 } else sym_counter = 0;
633 break;
634 case 'f':
635 prompt_integer(&count_filter, "Enter display event count filter");
636 break;
637 case 'F':
638 prompt_percent(&sym_pcnt_filter, "Enter details display event filter (percent)");
639 break;
640 case 'q':
641 case 'Q':
642 printf("exiting.\n");
643 exit(0);
644 case 's':
645 prompt_symbol(&sym_filter_entry, "Enter details symbol");
646 break;
647 case 'S':
648 if (!sym_filter_entry)
649 break;
650 else {
651 struct sym_entry *syme = sym_filter_entry;
652
653 pthread_mutex_lock(&syme->source_lock);
654 sym_filter_entry = NULL;
655 __zero_source_counters(syme);
656 pthread_mutex_unlock(&syme->source_lock);
657 }
658 break;
659 case 'z':
660 zero = ~zero;
661 break;
662 default: {
663 struct pollfd stdin_poll = { .fd = 0, .events = POLLIN };
664 struct termios tc, save;
665
666 if (!once) {
667 print_known_keys();
668 once++;
669 }
670
671 tcgetattr(0, &save);
672 tc = save;
673 tc.c_lflag &= ~(ICANON | ECHO);
674 tc.c_cc[VMIN] = 0;
675 tc.c_cc[VTIME] = 0;
676 tcsetattr(0, TCSANOW, &tc);
677
678 poll(&stdin_poll, 1, -1);
679 c = getc(stdin);
680
681 tcsetattr(0, TCSAFLUSH, &save);
682 goto repeat;
683 }
684 }
685}
686
264static void *display_thread(void *arg __used) 687static void *display_thread(void *arg __used)
265{ 688{
266 struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; 689 struct pollfd stdin_poll = { .fd = 0, .events = POLLIN };
267 int delay_msecs = delay_secs * 1000; 690 struct termios tc, save;
268 691 int delay_msecs, c;
269 printf("PerfTop refresh period: %d seconds\n", delay_secs); 692
693 tcgetattr(0, &save);
694 tc = save;
695 tc.c_lflag &= ~(ICANON | ECHO);
696 tc.c_cc[VMIN] = 0;
697 tc.c_cc[VTIME] = 0;
698repeat:
699 delay_msecs = delay_secs * 1000;
700 tcsetattr(0, TCSANOW, &tc);
701 /* trash return*/
702 getc(stdin);
270 703
271 do { 704 do {
272 print_sym_table(); 705 print_sym_table();
273 } while (!poll(&stdin_poll, 1, delay_msecs) == 1); 706 } while (!poll(&stdin_poll, 1, delay_msecs) == 1);
274 707
275 printf("key pressed - exiting.\n"); 708 c = getc(stdin);
276 exit(0); 709 tcsetattr(0, TCSAFLUSH, &save);
710
711 handle_keypress(c);
712 goto repeat;
277 713
278 return NULL; 714 return NULL;
279} 715}
@@ -293,7 +729,6 @@ static const char *skip_symbols[] = {
293 729
294static int symbol_filter(struct dso *self, struct symbol *sym) 730static int symbol_filter(struct dso *self, struct symbol *sym)
295{ 731{
296 static int filter_match;
297 struct sym_entry *syme; 732 struct sym_entry *syme;
298 const char *name = sym->name; 733 const char *name = sym->name;
299 int i; 734 int i;
@@ -315,6 +750,10 @@ static int symbol_filter(struct dso *self, struct symbol *sym)
315 return 1; 750 return 1;
316 751
317 syme = dso__sym_priv(self, sym); 752 syme = dso__sym_priv(self, sym);
753 pthread_mutex_init(&syme->source_lock, NULL);
754 if (!sym_filter_entry && sym_filter && !strcmp(name, sym_filter))
755 sym_filter_entry = syme;
756
318 for (i = 0; skip_symbols[i]; i++) { 757 for (i = 0; skip_symbols[i]; i++) {
319 if (!strcmp(skip_symbols[i], name)) { 758 if (!strcmp(skip_symbols[i], name)) {
320 syme->skip = 1; 759 syme->skip = 1;
@@ -322,29 +761,6 @@ static int symbol_filter(struct dso *self, struct symbol *sym)
322 } 761 }
323 } 762 }
324 763
325 if (filter_match == 1) {
326 filter_end = sym->start;
327 filter_match = -1;
328 if (filter_end - filter_start > 10000) {
329 fprintf(stderr,
330 "hm, too large filter symbol <%s> - skipping.\n",
331 sym_filter);
332 fprintf(stderr, "symbol filter start: %016lx\n",
333 filter_start);
334 fprintf(stderr, " end: %016lx\n",
335 filter_end);
336 filter_end = filter_start = 0;
337 sym_filter = NULL;
338 sleep(1);
339 }
340 }
341
342 if (filter_match == 0 && sym_filter && !strcmp(name, sym_filter)) {
343 filter_match = 1;
344 filter_start = sym->start;
345 }
346
347
348 return 0; 764 return 0;
349} 765}
350 766
@@ -380,8 +796,6 @@ out_delete_dso:
380 return -1; 796 return -1;
381} 797}
382 798
383#define TRACE_COUNT 3
384
385/* 799/*
386 * Binary search in the histogram table and record the hit: 800 * Binary search in the histogram table and record the hit:
387 */ 801 */
@@ -394,6 +808,7 @@ static void record_ip(u64 ip, int counter)
394 808
395 if (!syme->skip) { 809 if (!syme->skip) {
396 syme->count[counter]++; 810 syme->count[counter]++;
811 record_precise_ip(syme, counter, ip);
397 pthread_mutex_lock(&active_symbols_lock); 812 pthread_mutex_lock(&active_symbols_lock);
398 if (list_empty(&syme->node) || !syme->node.next) 813 if (list_empty(&syme->node) || !syme->node.next)
399 __list_insert_active_sym(syme); 814 __list_insert_active_sym(syme);
@@ -690,8 +1105,8 @@ static const struct option options[] = {
690 "put the counters into a counter group"), 1105 "put the counters into a counter group"),
691 OPT_BOOLEAN('i', "inherit", &inherit, 1106 OPT_BOOLEAN('i', "inherit", &inherit,
692 "child tasks inherit counters"), 1107 "child tasks inherit counters"),
693 OPT_STRING('s', "sym-filter", &sym_filter, "pattern", 1108 OPT_STRING('s', "sym-annotate", &sym_filter, "symbol name",
694 "only display symbols matchig this pattern"), 1109 "symbol to annotate - requires -k option"),
695 OPT_BOOLEAN('z', "zero", &zero, 1110 OPT_BOOLEAN('z', "zero", &zero,
696 "zero history across updates"), 1111 "zero history across updates"),
697 OPT_INTEGER('F', "freq", &freq, 1112 OPT_INTEGER('F', "freq", &freq,
@@ -734,6 +1149,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
734 delay_secs = 1; 1149 delay_secs = 1;
735 1150
736 parse_symbols(); 1151 parse_symbols();
1152 parse_source(sym_filter_entry);
737 1153
738 /* 1154 /*
739 * Fill in the ones not specifically initialized via -c: 1155 * Fill in the ones not specifically initialized via -c: