aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/builtin-top.c
diff options
context:
space:
mode:
authorMike Galbraith <efault@gmx.de>2009-07-22 14:36:03 -0400
committerIngo Molnar <mingo@elte.hu>2009-08-09 06:54:29 -0400
commit923c42c19944da214d697e312a040384a0e33e78 (patch)
tree6cfbb04b457a26ed993c0df7b895edc7630d125f /tools/perf/builtin-top.c
parentf413cdb80ce00ec1a4d0ab949b5d96c81cae7f75 (diff)
perf_counter tools: Fix/resurrect perf top annotation in a simple interactive form
perf top used to have annotation support, but it has bitrotted and removed. This patch restores that: it allows the user to select any symbol in kernel space for source level annotation on the fly, switch between event counters and alter display variables. When symbol details are being displayed, stopping annotation reverts to normal. known keys: [d] select display delay. [e] select display entries (lines). [E] select annotation event counter. [f] select normal display count filter. [F] select annotation display count filter (percentage). [qQ] quit. [s] select annotation symbol and start annotation. [S] stop annotation, revert to normal display. [z] toggle event count zeroing. Sample: ------------------------------------------------------------------------------ PerfTop: 16719 irqs/sec kernel:78.7% [cache-misses/cache-references/instructions/cycles], (all, 4 CPUs) ------------------------------------------------------------------------------ Showing cache-misses for e1000_clean_rx_irq Events Pcnt (>=3%) 0 0.0% /* adjust length to remove Ethernet CRC */ 0 0.0% if (!(adapter->flags2 & FLAG2_CRC_STRIPPING)) 0 0.0% length -= 4; 436 5.0% f039: 41 f6 84 24 5c 29 00 testb $0x1,0x295c(%r12) 0 0.0% f089: 8b 4d 84 mov -0x7c(%rbp),%ecx 0 0.0% f08c: 48 83 ef 02 sub $0x2,%rdi 0 0.0% f090: 48 83 ee 02 sub $0x2,%rsi 811 9.3% f094: f3 a4 rep movsb %ds:(%rsi),%es:(%rdi) 0 0.0% 0 0.0% while (rx_desc->status & E1000_RXD_STAT_DD) { 0 0.0% f114: 41 f6 47 0c 01 testb $0x1,0xc(%r15) 7226 82.6% f119: 0f 85 24 fe ff ff jne ef43 <e1000_clean_rx_irq+0x84> Available events: 0 cache-misses 1 cache-references 2 instructions 3 cycles Enter details event counter: 2 ------------------------------------------------------------------------------ PerfTop: 15035 irqs/sec kernel:79.0% [cache-misses/cache-references/instructions/cycles], (all, 4 CPUs) ------------------------------------------------------------------------------ Showing instructions for e1000_clean_rx_irq Events Pcnt (>=3%) 0 0.0% int *work_done, int work_to_do) 0 0.0% { 175 0.9% eebf: 55 push %rbp 1898 9.8% eec0: 48 89 e5 mov %rsp,%rbp 0 0.0% 0 0.0% i = rx_ring->next_to_clean; 140 0.7% ef0a: 0f b7 41 1a movzwl 0x1a(%rcx),%eax 670 3.4% ef0e: 89 45 ac mov %eax,-0x54(%rbp) 0 0.0% { 0 0.0% memcpy(skb->data + offset, from, len); 91 0.5% f07b: 49 8b b6 e8 00 00 00 mov 0xe8(%r14),%rsi 1153 5.9% f082: 48 8b b8 e8 00 00 00 mov 0xe8(%rax),%rdi 42 0.2% f089: 8b 4d 84 mov -0x7c(%rbp),%ecx 14 0.1% f08c: 48 83 ef 02 sub $0x2,%rdi 0 0.0% f090: 48 83 ee 02 sub $0x2,%rsi 1618 8.3% f094: f3 a4 rep movsb %ds:(%rsi),%es:(%rdi) 0 0.0% 0 0.0% /* return some buffers to hardware, one at a time is too slow */ 0 0.0% if (cleaned_count >= E1000_RX_BUFFER_WRITE) { 867 4.5% f0e7: 83 7d b0 0f cmpl $0xf,-0x50(%rbp) 0 0.0% 0 0.0% while (rx_desc->status & E1000_RXD_STAT_DD) { 37 0.2% f114: 41 f6 47 0c 01 testb $0x1,0xc(%r15) 4047 20.8% f119: 0f 85 24 fe ff ff jne ef43 <e1000_clean_rx_irq+0x84> Signed-off-by: Mike Galbraith <efault@gmx.de> Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Paul Mackerras <paulus@samba.org> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'tools/perf/builtin-top.c')
-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: