aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/builtin-top.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/builtin-top.c')
-rw-r--r--tools/perf/builtin-top.c553
1 files changed, 509 insertions, 44 deletions
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index c0a423004e15..7de28ce9ca26 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,28 @@ 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;
93static int display_weighted = -1;
94
95/*
81 * Symbols 96 * Symbols
82 */ 97 */
83 98
@@ -91,9 +106,237 @@ struct sym_entry {
91 unsigned long snap_count; 106 unsigned long snap_count;
92 double weight; 107 double weight;
93 int skip; 108 int skip;
109 struct source_line *source;
110 struct source_line *lines;
111 struct source_line **lines_tail;
112 pthread_mutex_t source_lock;
94}; 113};
95 114
96struct sym_entry *sym_filter_entry; 115/*
116 * Source functions
117 */
118
119static void parse_source(struct sym_entry *syme)
120{
121 struct symbol *sym;
122 struct module *module;
123 struct section *section = NULL;
124 FILE *file;
125 char command[PATH_MAX*2], *path = vmlinux;
126 u64 start, end, len;
127
128 if (!syme)
129 return;
130
131 if (syme->lines) {
132 pthread_mutex_lock(&syme->source_lock);
133 goto out_assign;
134 }
135
136 sym = (struct symbol *)(syme + 1);
137 module = sym->module;
138
139 if (module)
140 path = module->path;
141 if (!path)
142 return;
143
144 start = sym->obj_start;
145 if (!start)
146 start = sym->start;
147
148 if (module) {
149 section = module->sections->find_section(module->sections, ".text");
150 if (section)
151 start -= section->vma;
152 }
153
154 end = start + sym->end - sym->start + 1;
155 len = sym->end - sym->start;
156
157 sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s", start, end, path);
158
159 file = popen(command, "r");
160 if (!file)
161 return;
162
163 pthread_mutex_lock(&syme->source_lock);
164 syme->lines_tail = &syme->lines;
165 while (!feof(file)) {
166 struct source_line *src;
167 size_t dummy = 0;
168 char *c;
169
170 src = malloc(sizeof(struct source_line));
171 assert(src != NULL);
172 memset(src, 0, sizeof(struct source_line));
173
174 if (getline(&src->line, &dummy, file) < 0)
175 break;
176 if (!src->line)
177 break;
178
179 c = strchr(src->line, '\n');
180 if (c)
181 *c = 0;
182
183 src->next = NULL;
184 *syme->lines_tail = src;
185 syme->lines_tail = &src->next;
186
187 if (strlen(src->line)>8 && src->line[8] == ':') {
188 src->eip = strtoull(src->line, NULL, 16);
189 if (section)
190 src->eip += section->vma;
191 }
192 if (strlen(src->line)>8 && src->line[16] == ':') {
193 src->eip = strtoull(src->line, NULL, 16);
194 if (section)
195 src->eip += section->vma;
196 }
197 }
198 pclose(file);
199out_assign:
200 sym_filter_entry = syme;
201 pthread_mutex_unlock(&syme->source_lock);
202}
203
204static void __zero_source_counters(struct sym_entry *syme)
205{
206 int i;
207 struct source_line *line;
208
209 line = syme->lines;
210 while (line) {
211 for (i = 0; i < nr_counters; i++)
212 line->count[i] = 0;
213 line = line->next;
214 }
215}
216
217static void record_precise_ip(struct sym_entry *syme, int counter, u64 ip)
218{
219 struct source_line *line;
220
221 if (syme != sym_filter_entry)
222 return;
223
224 if (pthread_mutex_trylock(&syme->source_lock))
225 return;
226
227 if (!syme->source)
228 goto out_unlock;
229
230 for (line = syme->lines; line; line = line->next) {
231 if (line->eip == ip) {
232 line->count[counter]++;
233 break;
234 }
235 if (line->eip > ip)
236 break;
237 }
238out_unlock:
239 pthread_mutex_unlock(&syme->source_lock);
240}
241
242static void lookup_sym_source(struct sym_entry *syme)
243{
244 struct symbol *symbol = (struct symbol *)(syme + 1);
245 struct source_line *line;
246 char pattern[PATH_MAX];
247 char *idx;
248
249 sprintf(pattern, "<%s>:", symbol->name);
250
251 if (symbol->module) {
252 idx = strstr(pattern, "\t");
253 if (idx)
254 *idx = 0;
255 }
256
257 pthread_mutex_lock(&syme->source_lock);
258 for (line = syme->lines; line; line = line->next) {
259 if (strstr(line->line, pattern)) {
260 syme->source = line;
261 break;
262 }
263 }
264 pthread_mutex_unlock(&syme->source_lock);
265}
266
267static void show_lines(struct source_line *queue, int count, int total)
268{
269 int i;
270 struct source_line *line;
271
272 line = queue;
273 for (i = 0; i < count; i++) {
274 float pcnt = 100.0*(float)line->count[sym_counter]/(float)total;
275
276 printf("%8li %4.1f%%\t%s\n", line->count[sym_counter], pcnt, line->line);
277 line = line->next;
278 }
279}
280
281#define TRACE_COUNT 3
282
283static void show_details(struct sym_entry *syme)
284{
285 struct symbol *symbol;
286 struct source_line *line;
287 struct source_line *line_queue = NULL;
288 int displayed = 0;
289 int line_queue_count = 0, total = 0, more = 0;
290
291 if (!syme)
292 return;
293
294 if (!syme->source)
295 lookup_sym_source(syme);
296
297 if (!syme->source)
298 return;
299
300 symbol = (struct symbol *)(syme + 1);
301 printf("Showing %s for %s\n", event_name(sym_counter), symbol->name);
302 printf(" Events Pcnt (>=%d%%)\n", sym_pcnt_filter);
303
304 pthread_mutex_lock(&syme->source_lock);
305 line = syme->source;
306 while (line) {
307 total += line->count[sym_counter];
308 line = line->next;
309 }
310
311 line = syme->source;
312 while (line) {
313 float pcnt = 0.0;
314
315 if (!line_queue_count)
316 line_queue = line;
317 line_queue_count++;
318
319 if (line->count[sym_counter])
320 pcnt = 100.0 * line->count[sym_counter] / (float)total;
321 if (pcnt >= (float)sym_pcnt_filter) {
322 if (displayed <= print_entries)
323 show_lines(line_queue, line_queue_count, total);
324 else more++;
325 displayed += line_queue_count;
326 line_queue_count = 0;
327 line_queue = NULL;
328 } else if (line_queue_count > TRACE_COUNT) {
329 line_queue = line_queue->next;
330 line_queue_count--;
331 }
332
333 line->count[sym_counter] = zero ? 0 : line->count[sym_counter] * 7 / 8;
334 line = line->next;
335 }
336 pthread_mutex_unlock(&syme->source_lock);
337 if (more)
338 printf("%d lines not displayed, maybe increase display entries [e]\n", more);
339}
97 340
98struct dso *kernel_dso; 341struct dso *kernel_dso;
99 342
@@ -112,6 +355,9 @@ static double sym_weight(const struct sym_entry *sym)
112 double weight = sym->snap_count; 355 double weight = sym->snap_count;
113 int counter; 356 int counter;
114 357
358 if (!display_weighted)
359 return weight;
360
115 for (counter = 1; counter < nr_counters-1; counter++) 361 for (counter = 1; counter < nr_counters-1; counter++)
116 weight *= sym->count[counter]; 362 weight *= sym->count[counter];
117 363
@@ -159,7 +405,7 @@ static void rb_insert_active_sym(struct rb_root *tree, struct sym_entry *se)
159static void print_sym_table(void) 405static void print_sym_table(void)
160{ 406{
161 int printed = 0, j; 407 int printed = 0, j;
162 int counter; 408 int counter, snap = !display_weighted ? sym_counter : 0;
163 float samples_per_sec = samples/delay_secs; 409 float samples_per_sec = samples/delay_secs;
164 float ksamples_per_sec = (samples-userspace_samples)/delay_secs; 410 float ksamples_per_sec = (samples-userspace_samples)/delay_secs;
165 float sum_ksamples = 0.0; 411 float sum_ksamples = 0.0;
@@ -175,7 +421,7 @@ static void print_sym_table(void)
175 pthread_mutex_unlock(&active_symbols_lock); 421 pthread_mutex_unlock(&active_symbols_lock);
176 422
177 list_for_each_entry_safe_from(syme, n, &active_symbols, node) { 423 list_for_each_entry_safe_from(syme, n, &active_symbols, node) {
178 syme->snap_count = syme->count[0]; 424 syme->snap_count = syme->count[snap];
179 if (syme->snap_count != 0) { 425 if (syme->snap_count != 0) {
180 syme->weight = sym_weight(syme); 426 syme->weight = sym_weight(syme);
181 rb_insert_active_sym(&tmp, syme); 427 rb_insert_active_sym(&tmp, syme);
@@ -195,7 +441,7 @@ static void print_sym_table(void)
195 samples_per_sec, 441 samples_per_sec,
196 100.0 - (100.0*((samples_per_sec-ksamples_per_sec)/samples_per_sec))); 442 100.0 - (100.0*((samples_per_sec-ksamples_per_sec)/samples_per_sec)));
197 443
198 if (nr_counters == 1) { 444 if (nr_counters == 1 || !display_weighted) {
199 printf("%Ld", (u64)attrs[0].sample_period); 445 printf("%Ld", (u64)attrs[0].sample_period);
200 if (freq) 446 if (freq)
201 printf("Hz "); 447 printf("Hz ");
@@ -203,7 +449,9 @@ static void print_sym_table(void)
203 printf(" "); 449 printf(" ");
204 } 450 }
205 451
206 for (counter = 0; counter < nr_counters; counter++) { 452 if (!display_weighted)
453 printf("%s", event_name(sym_counter));
454 else for (counter = 0; counter < nr_counters; counter++) {
207 if (counter) 455 if (counter)
208 printf("/"); 456 printf("/");
209 457
@@ -228,6 +476,11 @@ static void print_sym_table(void)
228 476
229 printf("------------------------------------------------------------------------------\n\n"); 477 printf("------------------------------------------------------------------------------\n\n");
230 478
479 if (sym_filter_entry) {
480 show_details(sym_filter_entry);
481 return;
482 }
483
231 if (nr_counters == 1) 484 if (nr_counters == 1)
232 printf(" samples pcnt"); 485 printf(" samples pcnt");
233 else 486 else
@@ -242,13 +495,13 @@ static void print_sym_table(void)
242 struct symbol *sym = (struct symbol *)(syme + 1); 495 struct symbol *sym = (struct symbol *)(syme + 1);
243 double pcnt; 496 double pcnt;
244 497
245 if (++printed > print_entries || syme->snap_count < count_filter) 498 if (++printed > print_entries || (int)syme->snap_count < count_filter)
246 continue; 499 continue;
247 500
248 pcnt = 100.0 - (100.0 * ((sum_ksamples - syme->snap_count) / 501 pcnt = 100.0 - (100.0 * ((sum_ksamples - syme->snap_count) /
249 sum_ksamples)); 502 sum_ksamples));
250 503
251 if (nr_counters == 1) 504 if (nr_counters == 1 || !display_weighted)
252 printf("%20.2f - ", syme->weight); 505 printf("%20.2f - ", syme->weight);
253 else 506 else
254 printf("%9.1f %10ld - ", syme->weight, syme->snap_count); 507 printf("%9.1f %10ld - ", syme->weight, syme->snap_count);
@@ -261,19 +514,250 @@ static void print_sym_table(void)
261 } 514 }
262} 515}
263 516
517static void prompt_integer(int *target, const char *msg)
518{
519 char *buf = malloc(0), *p;
520 size_t dummy = 0;
521 int tmp;
522
523 fprintf(stdout, "\n%s: ", msg);
524 if (getline(&buf, &dummy, stdin) < 0)
525 return;
526
527 p = strchr(buf, '\n');
528 if (p)
529 *p = 0;
530
531 p = buf;
532 while(*p) {
533 if (!isdigit(*p))
534 goto out_free;
535 p++;
536 }
537 tmp = strtoul(buf, NULL, 10);
538 *target = tmp;
539out_free:
540 free(buf);
541}
542
543static void prompt_percent(int *target, const char *msg)
544{
545 int tmp = 0;
546
547 prompt_integer(&tmp, msg);
548 if (tmp >= 0 && tmp <= 100)
549 *target = tmp;
550}
551
552static void prompt_symbol(struct sym_entry **target, const char *msg)
553{
554 char *buf = malloc(0), *p;
555 struct sym_entry *syme = *target, *n, *found = NULL;
556 size_t dummy = 0;
557
558 /* zero counters of active symbol */
559 if (syme) {
560 pthread_mutex_lock(&syme->source_lock);
561 __zero_source_counters(syme);
562 *target = NULL;
563 pthread_mutex_unlock(&syme->source_lock);
564 }
565
566 fprintf(stdout, "\n%s: ", msg);
567 if (getline(&buf, &dummy, stdin) < 0)
568 goto out_free;
569
570 p = strchr(buf, '\n');
571 if (p)
572 *p = 0;
573
574 pthread_mutex_lock(&active_symbols_lock);
575 syme = list_entry(active_symbols.next, struct sym_entry, node);
576 pthread_mutex_unlock(&active_symbols_lock);
577
578 list_for_each_entry_safe_from(syme, n, &active_symbols, node) {
579 struct symbol *sym = (struct symbol *)(syme + 1);
580
581 if (!strcmp(buf, sym->name)) {
582 found = syme;
583 break;
584 }
585 }
586
587 if (!found) {
588 fprintf(stderr, "Sorry, %s is not active.\n", sym_filter);
589 sleep(1);
590 return;
591 } else
592 parse_source(found);
593
594out_free:
595 free(buf);
596}
597
598static void print_mapped_keys(void)
599{
600 char *name = NULL;
601
602 if (sym_filter_entry) {
603 struct symbol *sym = (struct symbol *)(sym_filter_entry+1);
604 name = sym->name;
605 }
606
607 fprintf(stdout, "\nMapped keys:\n");
608 fprintf(stdout, "\t[d] display refresh delay. \t(%d)\n", delay_secs);
609 fprintf(stdout, "\t[e] display entries (lines). \t(%d)\n", print_entries);
610
611 if (nr_counters > 1)
612 fprintf(stdout, "\t[E] active event counter. \t(%s)\n", event_name(sym_counter));
613
614 fprintf(stdout, "\t[f] profile display filter (count). \t(%d)\n", count_filter);
615
616 if (vmlinux) {
617 fprintf(stdout, "\t[F] annotate display filter (percent). \t(%d%%)\n", sym_pcnt_filter);
618 fprintf(stdout, "\t[s] annotate symbol. \t(%s)\n", name?: "NULL");
619 fprintf(stdout, "\t[S] stop annotation.\n");
620 }
621
622 if (nr_counters > 1)
623 fprintf(stdout, "\t[w] toggle display weighted/count[E]r. \t(%d)\n", display_weighted ? 1 : 0);
624
625 fprintf(stdout, "\t[z] toggle sample zeroing. \t(%d)\n", zero ? 1 : 0);
626 fprintf(stdout, "\t[qQ] quit.\n");
627}
628
629static int key_mapped(int c)
630{
631 switch (c) {
632 case 'd':
633 case 'e':
634 case 'f':
635 case 'z':
636 case 'q':
637 case 'Q':
638 return 1;
639 case 'E':
640 case 'w':
641 return nr_counters > 1 ? 1 : 0;
642 case 'F':
643 case 's':
644 case 'S':
645 return vmlinux ? 1 : 0;
646 }
647
648 return 0;
649}
650
651static void handle_keypress(int c)
652{
653 if (!key_mapped(c)) {
654 struct pollfd stdin_poll = { .fd = 0, .events = POLLIN };
655 struct termios tc, save;
656
657 print_mapped_keys();
658 fprintf(stdout, "\nEnter selection, or unmapped key to continue: ");
659 fflush(stdout);
660
661 tcgetattr(0, &save);
662 tc = save;
663 tc.c_lflag &= ~(ICANON | ECHO);
664 tc.c_cc[VMIN] = 0;
665 tc.c_cc[VTIME] = 0;
666 tcsetattr(0, TCSANOW, &tc);
667
668 poll(&stdin_poll, 1, -1);
669 c = getc(stdin);
670
671 tcsetattr(0, TCSAFLUSH, &save);
672 if (!key_mapped(c))
673 return;
674 }
675
676 switch (c) {
677 case 'd':
678 prompt_integer(&delay_secs, "Enter display delay");
679 break;
680 case 'e':
681 prompt_integer(&print_entries, "Enter display entries (lines)");
682 break;
683 case 'E':
684 if (nr_counters > 1) {
685 int i;
686
687 fprintf(stderr, "\nAvailable events:");
688 for (i = 0; i < nr_counters; i++)
689 fprintf(stderr, "\n\t%d %s", i, event_name(i));
690
691 prompt_integer(&sym_counter, "Enter details event counter");
692
693 if (sym_counter >= nr_counters) {
694 fprintf(stderr, "Sorry, no such event, using %s.\n", event_name(0));
695 sym_counter = 0;
696 sleep(1);
697 }
698 } else sym_counter = 0;
699 break;
700 case 'f':
701 prompt_integer(&count_filter, "Enter display event count filter");
702 break;
703 case 'F':
704 prompt_percent(&sym_pcnt_filter, "Enter details display event filter (percent)");
705 break;
706 case 'q':
707 case 'Q':
708 printf("exiting.\n");
709 exit(0);
710 case 's':
711 prompt_symbol(&sym_filter_entry, "Enter details symbol");
712 break;
713 case 'S':
714 if (!sym_filter_entry)
715 break;
716 else {
717 struct sym_entry *syme = sym_filter_entry;
718
719 pthread_mutex_lock(&syme->source_lock);
720 sym_filter_entry = NULL;
721 __zero_source_counters(syme);
722 pthread_mutex_unlock(&syme->source_lock);
723 }
724 break;
725 case 'w':
726 display_weighted = ~display_weighted;
727 break;
728 case 'z':
729 zero = ~zero;
730 break;
731 }
732}
733
264static void *display_thread(void *arg __used) 734static void *display_thread(void *arg __used)
265{ 735{
266 struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; 736 struct pollfd stdin_poll = { .fd = 0, .events = POLLIN };
267 int delay_msecs = delay_secs * 1000; 737 struct termios tc, save;
738 int delay_msecs, c;
739
740 tcgetattr(0, &save);
741 tc = save;
742 tc.c_lflag &= ~(ICANON | ECHO);
743 tc.c_cc[VMIN] = 0;
744 tc.c_cc[VTIME] = 0;
268 745
269 printf("PerfTop refresh period: %d seconds\n", delay_secs); 746repeat:
747 delay_msecs = delay_secs * 1000;
748 tcsetattr(0, TCSANOW, &tc);
749 /* trash return*/
750 getc(stdin);
270 751
271 do { 752 do {
272 print_sym_table(); 753 print_sym_table();
273 } while (!poll(&stdin_poll, 1, delay_msecs) == 1); 754 } while (!poll(&stdin_poll, 1, delay_msecs) == 1);
274 755
275 printf("key pressed - exiting.\n"); 756 c = getc(stdin);
276 exit(0); 757 tcsetattr(0, TCSAFLUSH, &save);
758
759 handle_keypress(c);
760 goto repeat;
277 761
278 return NULL; 762 return NULL;
279} 763}
@@ -285,6 +769,7 @@ static const char *skip_symbols[] = {
285 "enter_idle", 769 "enter_idle",
286 "exit_idle", 770 "exit_idle",
287 "mwait_idle", 771 "mwait_idle",
772 "mwait_idle_with_hints",
288 "ppc64_runlatch_off", 773 "ppc64_runlatch_off",
289 "pseries_dedicated_idle_sleep", 774 "pseries_dedicated_idle_sleep",
290 NULL 775 NULL
@@ -292,7 +777,6 @@ static const char *skip_symbols[] = {
292 777
293static int symbol_filter(struct dso *self, struct symbol *sym) 778static int symbol_filter(struct dso *self, struct symbol *sym)
294{ 779{
295 static int filter_match;
296 struct sym_entry *syme; 780 struct sym_entry *syme;
297 const char *name = sym->name; 781 const char *name = sym->name;
298 int i; 782 int i;
@@ -314,6 +798,10 @@ static int symbol_filter(struct dso *self, struct symbol *sym)
314 return 1; 798 return 1;
315 799
316 syme = dso__sym_priv(self, sym); 800 syme = dso__sym_priv(self, sym);
801 pthread_mutex_init(&syme->source_lock, NULL);
802 if (!sym_filter_entry && sym_filter && !strcmp(name, sym_filter))
803 sym_filter_entry = syme;
804
317 for (i = 0; skip_symbols[i]; i++) { 805 for (i = 0; skip_symbols[i]; i++) {
318 if (!strcmp(skip_symbols[i], name)) { 806 if (!strcmp(skip_symbols[i], name)) {
319 syme->skip = 1; 807 syme->skip = 1;
@@ -321,29 +809,6 @@ static int symbol_filter(struct dso *self, struct symbol *sym)
321 } 809 }
322 } 810 }
323 811
324 if (filter_match == 1) {
325 filter_end = sym->start;
326 filter_match = -1;
327 if (filter_end - filter_start > 10000) {
328 fprintf(stderr,
329 "hm, too large filter symbol <%s> - skipping.\n",
330 sym_filter);
331 fprintf(stderr, "symbol filter start: %016lx\n",
332 filter_start);
333 fprintf(stderr, " end: %016lx\n",
334 filter_end);
335 filter_end = filter_start = 0;
336 sym_filter = NULL;
337 sleep(1);
338 }
339 }
340
341 if (filter_match == 0 && sym_filter && !strcmp(name, sym_filter)) {
342 filter_match = 1;
343 filter_start = sym->start;
344 }
345
346
347 return 0; 812 return 0;
348} 813}
349 814
@@ -379,8 +844,6 @@ out_delete_dso:
379 return -1; 844 return -1;
380} 845}
381 846
382#define TRACE_COUNT 3
383
384/* 847/*
385 * Binary search in the histogram table and record the hit: 848 * Binary search in the histogram table and record the hit:
386 */ 849 */
@@ -393,6 +856,7 @@ static void record_ip(u64 ip, int counter)
393 856
394 if (!syme->skip) { 857 if (!syme->skip) {
395 syme->count[counter]++; 858 syme->count[counter]++;
859 record_precise_ip(syme, counter, ip);
396 pthread_mutex_lock(&active_symbols_lock); 860 pthread_mutex_lock(&active_symbols_lock);
397 if (list_empty(&syme->node) || !syme->node.next) 861 if (list_empty(&syme->node) || !syme->node.next)
398 __list_insert_active_sym(syme); 862 __list_insert_active_sym(syme);
@@ -689,8 +1153,8 @@ static const struct option options[] = {
689 "put the counters into a counter group"), 1153 "put the counters into a counter group"),
690 OPT_BOOLEAN('i', "inherit", &inherit, 1154 OPT_BOOLEAN('i', "inherit", &inherit,
691 "child tasks inherit counters"), 1155 "child tasks inherit counters"),
692 OPT_STRING('s', "sym-filter", &sym_filter, "pattern", 1156 OPT_STRING('s', "sym-annotate", &sym_filter, "symbol name",
693 "only display symbols matchig this pattern"), 1157 "symbol to annotate - requires -k option"),
694 OPT_BOOLEAN('z', "zero", &zero, 1158 OPT_BOOLEAN('z', "zero", &zero,
695 "zero history across updates"), 1159 "zero history across updates"),
696 OPT_INTEGER('F', "freq", &freq, 1160 OPT_INTEGER('F', "freq", &freq,
@@ -733,6 +1197,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
733 delay_secs = 1; 1197 delay_secs = 1;
734 1198
735 parse_symbols(); 1199 parse_symbols();
1200 parse_source(sym_filter_entry);
736 1201
737 /* 1202 /*
738 * Fill in the ones not specifically initialized via -c: 1203 * Fill in the ones not specifically initialized via -c: