Root/tools/perf/builtin-top.c

1/*
2 * builtin-top.c
3 *
4 * Builtin top command: Display a continuously updated profile of
5 * any workload, CPU or specific PID.
6 *
7 * Copyright (C) 2008, Red Hat Inc, Ingo Molnar <mingo@redhat.com>
8 * 2011, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
9 *
10 * Improvements and fixes by:
11 *
12 * Arjan van de Ven <arjan@linux.intel.com>
13 * Yanmin Zhang <yanmin.zhang@intel.com>
14 * Wu Fengguang <fengguang.wu@intel.com>
15 * Mike Galbraith <efault@gmx.de>
16 * Paul Mackerras <paulus@samba.org>
17 *
18 * Released under the GPL v2. (and only v2, not any later version)
19 */
20#include "builtin.h"
21
22#include "perf.h"
23
24#include "util/annotate.h"
25#include "util/cache.h"
26#include "util/color.h"
27#include "util/evlist.h"
28#include "util/evsel.h"
29#include "util/session.h"
30#include "util/symbol.h"
31#include "util/thread.h"
32#include "util/thread_map.h"
33#include "util/top.h"
34#include "util/util.h"
35#include <linux/rbtree.h>
36#include "util/parse-options.h"
37#include "util/parse-events.h"
38#include "util/cpumap.h"
39#include "util/xyarray.h"
40#include "util/sort.h"
41
42#include "util/debug.h"
43
44#include <assert.h>
45#include <elf.h>
46#include <fcntl.h>
47
48#include <stdio.h>
49#include <termios.h>
50#include <unistd.h>
51#include <inttypes.h>
52
53#include <errno.h>
54#include <time.h>
55#include <sched.h>
56
57#include <sys/syscall.h>
58#include <sys/ioctl.h>
59#include <sys/poll.h>
60#include <sys/prctl.h>
61#include <sys/wait.h>
62#include <sys/uio.h>
63#include <sys/utsname.h>
64#include <sys/mman.h>
65
66#include <linux/unistd.h>
67#include <linux/types.h>
68
69void get_term_dimensions(struct winsize *ws)
70{
71    char *s = getenv("LINES");
72
73    if (s != NULL) {
74        ws->ws_row = atoi(s);
75        s = getenv("COLUMNS");
76        if (s != NULL) {
77            ws->ws_col = atoi(s);
78            if (ws->ws_row && ws->ws_col)
79                return;
80        }
81    }
82#ifdef TIOCGWINSZ
83    if (ioctl(1, TIOCGWINSZ, ws) == 0 &&
84        ws->ws_row && ws->ws_col)
85        return;
86#endif
87    ws->ws_row = 25;
88    ws->ws_col = 80;
89}
90
91static void perf_top__update_print_entries(struct perf_top *top)
92{
93    if (top->print_entries > 9)
94        top->print_entries -= 9;
95}
96
97static void perf_top__sig_winch(int sig __used, siginfo_t *info __used, void *arg)
98{
99    struct perf_top *top = arg;
100
101    get_term_dimensions(&top->winsize);
102    if (!top->print_entries
103        || (top->print_entries+4) > top->winsize.ws_row) {
104        top->print_entries = top->winsize.ws_row;
105    } else {
106        top->print_entries += 4;
107        top->winsize.ws_row = top->print_entries;
108    }
109    perf_top__update_print_entries(top);
110}
111
112static int perf_top__parse_source(struct perf_top *top, struct hist_entry *he)
113{
114    struct symbol *sym;
115    struct annotation *notes;
116    struct map *map;
117    int err = -1;
118
119    if (!he || !he->ms.sym)
120        return -1;
121
122    sym = he->ms.sym;
123    map = he->ms.map;
124
125    /*
126     * We can't annotate with just /proc/kallsyms
127     */
128    if (map->dso->symtab_type == SYMTAB__KALLSYMS) {
129        pr_err("Can't annotate %s: No vmlinux file was found in the "
130               "path\n", sym->name);
131        sleep(1);
132        return -1;
133    }
134
135    notes = symbol__annotation(sym);
136    if (notes->src != NULL) {
137        pthread_mutex_lock(&notes->lock);
138        goto out_assign;
139    }
140
141    pthread_mutex_lock(&notes->lock);
142
143    if (symbol__alloc_hist(sym) < 0) {
144        pthread_mutex_unlock(&notes->lock);
145        pr_err("Not enough memory for annotating '%s' symbol!\n",
146               sym->name);
147        sleep(1);
148        return err;
149    }
150
151    err = symbol__annotate(sym, map, 0);
152    if (err == 0) {
153out_assign:
154        top->sym_filter_entry = he;
155    }
156
157    pthread_mutex_unlock(&notes->lock);
158    return err;
159}
160
161static void __zero_source_counters(struct hist_entry *he)
162{
163    struct symbol *sym = he->ms.sym;
164    symbol__annotate_zero_histograms(sym);
165}
166
167static void ui__warn_map_erange(struct map *map, struct symbol *sym, u64 ip)
168{
169    struct utsname uts;
170    int err = uname(&uts);
171
172    ui__warning("Out of bounds address found:\n\n"
173            "Addr: %" PRIx64 "\n"
174            "DSO: %s %c\n"
175            "Map: %" PRIx64 "-%" PRIx64 "\n"
176            "Symbol: %" PRIx64 "-%" PRIx64 " %c %s\n"
177            "Arch: %s\n"
178            "Kernel: %s\n"
179            "Tools: %s\n\n"
180            "Not all samples will be on the annotation output.\n\n"
181            "Please report to linux-kernel@vger.kernel.org\n",
182            ip, map->dso->long_name, dso__symtab_origin(map->dso),
183            map->start, map->end, sym->start, sym->end,
184            sym->binding == STB_GLOBAL ? 'g' :
185            sym->binding == STB_LOCAL ? 'l' : 'w', sym->name,
186            err ? "[unknown]" : uts.machine,
187            err ? "[unknown]" : uts.release, perf_version_string);
188    if (use_browser <= 0)
189        sleep(5);
190    
191    map->erange_warned = true;
192}
193
194static void perf_top__record_precise_ip(struct perf_top *top,
195                    struct hist_entry *he,
196                    int counter, u64 ip)
197{
198    struct annotation *notes;
199    struct symbol *sym;
200    int err;
201
202    if (he == NULL || he->ms.sym == NULL ||
203        ((top->sym_filter_entry == NULL ||
204          top->sym_filter_entry->ms.sym != he->ms.sym) && use_browser != 1))
205        return;
206
207    sym = he->ms.sym;
208    notes = symbol__annotation(sym);
209
210    if (pthread_mutex_trylock(&notes->lock))
211        return;
212
213    if (notes->src == NULL && symbol__alloc_hist(sym) < 0) {
214        pthread_mutex_unlock(&notes->lock);
215        pr_err("Not enough memory for annotating '%s' symbol!\n",
216               sym->name);
217        sleep(1);
218        return;
219    }
220
221    ip = he->ms.map->map_ip(he->ms.map, ip);
222    err = symbol__inc_addr_samples(sym, he->ms.map, counter, ip);
223
224    pthread_mutex_unlock(&notes->lock);
225
226    if (err == -ERANGE && !he->ms.map->erange_warned)
227        ui__warn_map_erange(he->ms.map, sym, ip);
228}
229
230static void perf_top__show_details(struct perf_top *top)
231{
232    struct hist_entry *he = top->sym_filter_entry;
233    struct annotation *notes;
234    struct symbol *symbol;
235    int more;
236
237    if (!he)
238        return;
239
240    symbol = he->ms.sym;
241    notes = symbol__annotation(symbol);
242
243    pthread_mutex_lock(&notes->lock);
244
245    if (notes->src == NULL)
246        goto out_unlock;
247
248    printf("Showing %s for %s\n", event_name(top->sym_evsel), symbol->name);
249    printf(" Events Pcnt (>=%d%%)\n", top->sym_pcnt_filter);
250
251    more = symbol__annotate_printf(symbol, he->ms.map, top->sym_evsel->idx,
252                       0, top->sym_pcnt_filter, top->print_entries, 4);
253    if (top->zero)
254        symbol__annotate_zero_histogram(symbol, top->sym_evsel->idx);
255    else
256        symbol__annotate_decay_histogram(symbol, top->sym_evsel->idx);
257    if (more != 0)
258        printf("%d lines not displayed, maybe increase display entries [e]\n", more);
259out_unlock:
260    pthread_mutex_unlock(&notes->lock);
261}
262
263static const char CONSOLE_CLEAR[] = "";
264
265static struct hist_entry *perf_evsel__add_hist_entry(struct perf_evsel *evsel,
266                             struct addr_location *al,
267                             struct perf_sample *sample)
268{
269    struct hist_entry *he;
270
271    he = __hists__add_entry(&evsel->hists, al, NULL, sample->period);
272    if (he == NULL)
273        return NULL;
274
275    hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
276    return he;
277}
278
279static void perf_top__print_sym_table(struct perf_top *top)
280{
281    char bf[160];
282    int printed = 0;
283    const int win_width = top->winsize.ws_col - 1;
284
285    puts(CONSOLE_CLEAR);
286
287    perf_top__header_snprintf(top, bf, sizeof(bf));
288    printf("%s\n", bf);
289
290    perf_top__reset_sample_counters(top);
291
292    printf("%-*.*s\n", win_width, win_width, graph_dotted_line);
293
294    if (top->sym_evsel->hists.stats.nr_lost_warned !=
295        top->sym_evsel->hists.stats.nr_events[PERF_RECORD_LOST]) {
296        top->sym_evsel->hists.stats.nr_lost_warned =
297            top->sym_evsel->hists.stats.nr_events[PERF_RECORD_LOST];
298        color_fprintf(stdout, PERF_COLOR_RED,
299                  "WARNING: LOST %d chunks, Check IO/CPU overload",
300                  top->sym_evsel->hists.stats.nr_lost_warned);
301        ++printed;
302    }
303
304    if (top->sym_filter_entry) {
305        perf_top__show_details(top);
306        return;
307    }
308
309    hists__collapse_resort_threaded(&top->sym_evsel->hists);
310    hists__output_resort_threaded(&top->sym_evsel->hists);
311    hists__decay_entries_threaded(&top->sym_evsel->hists,
312                      top->hide_user_symbols,
313                      top->hide_kernel_symbols);
314    hists__output_recalc_col_len(&top->sym_evsel->hists,
315                     top->winsize.ws_row - 3);
316    putchar('\n');
317    hists__fprintf(&top->sym_evsel->hists, NULL, false, false,
318               top->winsize.ws_row - 4 - printed, win_width, stdout);
319}
320
321static void prompt_integer(int *target, const char *msg)
322{
323    char *buf = malloc(0), *p;
324    size_t dummy = 0;
325    int tmp;
326
327    fprintf(stdout, "\n%s: ", msg);
328    if (getline(&buf, &dummy, stdin) < 0)
329        return;
330
331    p = strchr(buf, '\n');
332    if (p)
333        *p = 0;
334
335    p = buf;
336    while(*p) {
337        if (!isdigit(*p))
338            goto out_free;
339        p++;
340    }
341    tmp = strtoul(buf, NULL, 10);
342    *target = tmp;
343out_free:
344    free(buf);
345}
346
347static void prompt_percent(int *target, const char *msg)
348{
349    int tmp = 0;
350
351    prompt_integer(&tmp, msg);
352    if (tmp >= 0 && tmp <= 100)
353        *target = tmp;
354}
355
356static void perf_top__prompt_symbol(struct perf_top *top, const char *msg)
357{
358    char *buf = malloc(0), *p;
359    struct hist_entry *syme = top->sym_filter_entry, *n, *found = NULL;
360    struct rb_node *next;
361    size_t dummy = 0;
362
363    /* zero counters of active symbol */
364    if (syme) {
365        __zero_source_counters(syme);
366        top->sym_filter_entry = NULL;
367    }
368
369    fprintf(stdout, "\n%s: ", msg);
370    if (getline(&buf, &dummy, stdin) < 0)
371        goto out_free;
372
373    p = strchr(buf, '\n');
374    if (p)
375        *p = 0;
376
377    next = rb_first(&top->sym_evsel->hists.entries);
378    while (next) {
379        n = rb_entry(next, struct hist_entry, rb_node);
380        if (n->ms.sym && !strcmp(buf, n->ms.sym->name)) {
381            found = n;
382            break;
383        }
384        next = rb_next(&n->rb_node);
385    }
386
387    if (!found) {
388        fprintf(stderr, "Sorry, %s is not active.\n", buf);
389        sleep(1);
390    } else
391        perf_top__parse_source(top, found);
392
393out_free:
394    free(buf);
395}
396
397static void perf_top__print_mapped_keys(struct perf_top *top)
398{
399    char *name = NULL;
400
401    if (top->sym_filter_entry) {
402        struct symbol *sym = top->sym_filter_entry->ms.sym;
403        name = sym->name;
404    }
405
406    fprintf(stdout, "\nMapped keys:\n");
407    fprintf(stdout, "\t[d] display refresh delay. \t(%d)\n", top->delay_secs);
408    fprintf(stdout, "\t[e] display entries (lines). \t(%d)\n", top->print_entries);
409
410    if (top->evlist->nr_entries > 1)
411        fprintf(stdout, "\t[E] active event counter. \t(%s)\n", event_name(top->sym_evsel));
412
413    fprintf(stdout, "\t[f] profile display filter (count). \t(%d)\n", top->count_filter);
414
415    fprintf(stdout, "\t[F] annotate display filter (percent). \t(%d%%)\n", top->sym_pcnt_filter);
416    fprintf(stdout, "\t[s] annotate symbol. \t(%s)\n", name?: "NULL");
417    fprintf(stdout, "\t[S] stop annotation.\n");
418
419    fprintf(stdout,
420        "\t[K] hide kernel_symbols symbols. \t(%s)\n",
421        top->hide_kernel_symbols ? "yes" : "no");
422    fprintf(stdout,
423        "\t[U] hide user symbols. \t(%s)\n",
424        top->hide_user_symbols ? "yes" : "no");
425    fprintf(stdout, "\t[z] toggle sample zeroing. \t(%d)\n", top->zero ? 1 : 0);
426    fprintf(stdout, "\t[qQ] quit.\n");
427}
428
429static int perf_top__key_mapped(struct perf_top *top, int c)
430{
431    switch (c) {
432        case 'd':
433        case 'e':
434        case 'f':
435        case 'z':
436        case 'q':
437        case 'Q':
438        case 'K':
439        case 'U':
440        case 'F':
441        case 's':
442        case 'S':
443            return 1;
444        case 'E':
445            return top->evlist->nr_entries > 1 ? 1 : 0;
446        default:
447            break;
448    }
449
450    return 0;
451}
452
453static void perf_top__handle_keypress(struct perf_top *top, int c)
454{
455    if (!perf_top__key_mapped(top, c)) {
456        struct pollfd stdin_poll = { .fd = 0, .events = POLLIN };
457        struct termios tc, save;
458
459        perf_top__print_mapped_keys(top);
460        fprintf(stdout, "\nEnter selection, or unmapped key to continue: ");
461        fflush(stdout);
462
463        tcgetattr(0, &save);
464        tc = save;
465        tc.c_lflag &= ~(ICANON | ECHO);
466        tc.c_cc[VMIN] = 0;
467        tc.c_cc[VTIME] = 0;
468        tcsetattr(0, TCSANOW, &tc);
469
470        poll(&stdin_poll, 1, -1);
471        c = getc(stdin);
472
473        tcsetattr(0, TCSAFLUSH, &save);
474        if (!perf_top__key_mapped(top, c))
475            return;
476    }
477
478    switch (c) {
479        case 'd':
480            prompt_integer(&top->delay_secs, "Enter display delay");
481            if (top->delay_secs < 1)
482                top->delay_secs = 1;
483            break;
484        case 'e':
485            prompt_integer(&top->print_entries, "Enter display entries (lines)");
486            if (top->print_entries == 0) {
487                struct sigaction act = {
488                    .sa_sigaction = perf_top__sig_winch,
489                    .sa_flags = SA_SIGINFO,
490                };
491                perf_top__sig_winch(SIGWINCH, NULL, top);
492                sigaction(SIGWINCH, &act, NULL);
493            } else {
494                perf_top__sig_winch(SIGWINCH, NULL, top);
495                signal(SIGWINCH, SIG_DFL);
496            }
497            break;
498        case 'E':
499            if (top->evlist->nr_entries > 1) {
500                /* Select 0 as the default event: */
501                int counter = 0;
502
503                fprintf(stderr, "\nAvailable events:");
504
505                list_for_each_entry(top->sym_evsel, &top->evlist->entries, node)
506                    fprintf(stderr, "\n\t%d %s", top->sym_evsel->idx, event_name(top->sym_evsel));
507
508                prompt_integer(&counter, "Enter details event counter");
509
510                if (counter >= top->evlist->nr_entries) {
511                    top->sym_evsel = list_entry(top->evlist->entries.next, struct perf_evsel, node);
512                    fprintf(stderr, "Sorry, no such event, using %s.\n", event_name(top->sym_evsel));
513                    sleep(1);
514                    break;
515                }
516                list_for_each_entry(top->sym_evsel, &top->evlist->entries, node)
517                    if (top->sym_evsel->idx == counter)
518                        break;
519            } else
520                top->sym_evsel = list_entry(top->evlist->entries.next, struct perf_evsel, node);
521            break;
522        case 'f':
523            prompt_integer(&top->count_filter, "Enter display event count filter");
524            break;
525        case 'F':
526            prompt_percent(&top->sym_pcnt_filter,
527                       "Enter details display event filter (percent)");
528            break;
529        case 'K':
530            top->hide_kernel_symbols = !top->hide_kernel_symbols;
531            break;
532        case 'q':
533        case 'Q':
534            printf("exiting.\n");
535            if (top->dump_symtab)
536                perf_session__fprintf_dsos(top->session, stderr);
537            exit(0);
538        case 's':
539            perf_top__prompt_symbol(top, "Enter details symbol");
540            break;
541        case 'S':
542            if (!top->sym_filter_entry)
543                break;
544            else {
545                struct hist_entry *syme = top->sym_filter_entry;
546
547                top->sym_filter_entry = NULL;
548                __zero_source_counters(syme);
549            }
550            break;
551        case 'U':
552            top->hide_user_symbols = !top->hide_user_symbols;
553            break;
554        case 'z':
555            top->zero = !top->zero;
556            break;
557        default:
558            break;
559    }
560}
561
562static void perf_top__sort_new_samples(void *arg)
563{
564    struct perf_top *t = arg;
565    perf_top__reset_sample_counters(t);
566
567    if (t->evlist->selected != NULL)
568        t->sym_evsel = t->evlist->selected;
569
570    hists__collapse_resort_threaded(&t->sym_evsel->hists);
571    hists__output_resort_threaded(&t->sym_evsel->hists);
572    hists__decay_entries_threaded(&t->sym_evsel->hists,
573                      t->hide_user_symbols,
574                      t->hide_kernel_symbols);
575}
576
577static void *display_thread_tui(void *arg)
578{
579    struct perf_evsel *pos;
580    struct perf_top *top = arg;
581    const char *help = "For a higher level overview, try: perf top --sort comm,dso";
582
583    perf_top__sort_new_samples(top);
584
585    /*
586     * Initialize the uid_filter_str, in the future the TUI will allow
587     * Zooming in/out UIDs. For now juse use whatever the user passed
588     * via --uid.
589     */
590    list_for_each_entry(pos, &top->evlist->entries, node)
591        pos->hists.uid_filter_str = top->uid_str;
592
593    perf_evlist__tui_browse_hists(top->evlist, help,
594                      perf_top__sort_new_samples,
595                      top, top->delay_secs);
596
597    exit_browser(0);
598    exit(0);
599    return NULL;
600}
601
602static void *display_thread(void *arg)
603{
604    struct pollfd stdin_poll = { .fd = 0, .events = POLLIN };
605    struct termios tc, save;
606    struct perf_top *top = arg;
607    int delay_msecs, c;
608
609    tcgetattr(0, &save);
610    tc = save;
611    tc.c_lflag &= ~(ICANON | ECHO);
612    tc.c_cc[VMIN] = 0;
613    tc.c_cc[VTIME] = 0;
614
615    pthread__unblock_sigwinch();
616repeat:
617    delay_msecs = top->delay_secs * 1000;
618    tcsetattr(0, TCSANOW, &tc);
619    /* trash return*/
620    getc(stdin);
621
622    while (1) {
623        perf_top__print_sym_table(top);
624        /*
625         * Either timeout expired or we got an EINTR due to SIGWINCH,
626         * refresh screen in both cases.
627         */
628        switch (poll(&stdin_poll, 1, delay_msecs)) {
629        case 0:
630            continue;
631        case -1:
632            if (errno == EINTR)
633                continue;
634            /* Fall trhu */
635        default:
636            goto process_hotkey;
637        }
638    }
639process_hotkey:
640    c = getc(stdin);
641    tcsetattr(0, TCSAFLUSH, &save);
642
643    perf_top__handle_keypress(top, c);
644    goto repeat;
645
646    return NULL;
647}
648
649/* Tag samples to be skipped. */
650static const char *skip_symbols[] = {
651    "intel_idle",
652    "default_idle",
653    "native_safe_halt",
654    "cpu_idle",
655    "enter_idle",
656    "exit_idle",
657    "mwait_idle",
658    "mwait_idle_with_hints",
659    "poll_idle",
660    "ppc64_runlatch_off",
661    "pseries_dedicated_idle_sleep",
662    NULL
663};
664
665static int symbol_filter(struct map *map __used, struct symbol *sym)
666{
667    const char *name = sym->name;
668    int i;
669
670    /*
671     * ppc64 uses function descriptors and appends a '.' to the
672     * start of every instruction address. Remove it.
673     */
674    if (name[0] == '.')
675        name++;
676
677    if (!strcmp(name, "_text") ||
678        !strcmp(name, "_etext") ||
679        !strcmp(name, "_sinittext") ||
680        !strncmp("init_module", name, 11) ||
681        !strncmp("cleanup_module", name, 14) ||
682        strstr(name, "_text_start") ||
683        strstr(name, "_text_end"))
684        return 1;
685
686    for (i = 0; skip_symbols[i]; i++) {
687        if (!strcmp(skip_symbols[i], name)) {
688            sym->ignore = true;
689            break;
690        }
691    }
692
693    return 0;
694}
695
696static void perf_event__process_sample(struct perf_tool *tool,
697                       const union perf_event *event,
698                       struct perf_evsel *evsel,
699                       struct perf_sample *sample,
700                       struct machine *machine)
701{
702    struct perf_top *top = container_of(tool, struct perf_top, tool);
703    struct symbol *parent = NULL;
704    u64 ip = event->ip.ip;
705    struct addr_location al;
706    int err;
707
708    if (!machine && perf_guest) {
709        pr_err("Can't find guest [%d]'s kernel information\n",
710            event->ip.pid);
711        return;
712    }
713
714    if (!machine) {
715        pr_err("%u unprocessable samples recorded.",
716               top->session->hists.stats.nr_unprocessable_samples++);
717        return;
718    }
719
720    if (event->header.misc & PERF_RECORD_MISC_EXACT_IP)
721        top->exact_samples++;
722
723    if (perf_event__preprocess_sample(event, machine, &al, sample,
724                      symbol_filter) < 0 ||
725        al.filtered)
726        return;
727
728    if (!top->kptr_restrict_warned &&
729        symbol_conf.kptr_restrict &&
730        al.cpumode == PERF_RECORD_MISC_KERNEL) {
731        ui__warning(
732"Kernel address maps (/proc/{kallsyms,modules}) are restricted.\n\n"
733"Check /proc/sys/kernel/kptr_restrict.\n\n"
734"Kernel%s samples will not be resolved.\n",
735              !RB_EMPTY_ROOT(&al.map->dso->symbols[MAP__FUNCTION]) ?
736              " modules" : "");
737        if (use_browser <= 0)
738            sleep(5);
739        top->kptr_restrict_warned = true;
740    }
741
742    if (al.sym == NULL) {
743        const char *msg = "Kernel samples will not be resolved.\n";
744        /*
745         * As we do lazy loading of symtabs we only will know if the
746         * specified vmlinux file is invalid when we actually have a
747         * hit in kernel space and then try to load it. So if we get
748         * here and there are _no_ symbols in the DSO backing the
749         * kernel map, bail out.
750         *
751         * We may never get here, for instance, if we use -K/
752         * --hide-kernel-symbols, even if the user specifies an
753         * invalid --vmlinux ;-)
754         */
755        if (!top->kptr_restrict_warned && !top->vmlinux_warned &&
756            al.map == machine->vmlinux_maps[MAP__FUNCTION] &&
757            RB_EMPTY_ROOT(&al.map->dso->symbols[MAP__FUNCTION])) {
758            if (symbol_conf.vmlinux_name) {
759                ui__warning("The %s file can't be used.\n%s",
760                        symbol_conf.vmlinux_name, msg);
761            } else {
762                ui__warning("A vmlinux file was not found.\n%s",
763                        msg);
764            }
765
766            if (use_browser <= 0)
767                sleep(5);
768            top->vmlinux_warned = true;
769        }
770    }
771
772    if (al.sym == NULL || !al.sym->ignore) {
773        struct hist_entry *he;
774
775        if ((sort__has_parent || symbol_conf.use_callchain) &&
776            sample->callchain) {
777            err = machine__resolve_callchain(machine, evsel, al.thread,
778                             sample->callchain, &parent);
779            if (err)
780                return;
781        }
782
783        he = perf_evsel__add_hist_entry(evsel, &al, sample);
784        if (he == NULL) {
785            pr_err("Problem incrementing symbol period, skipping event\n");
786            return;
787        }
788
789        if (symbol_conf.use_callchain) {
790            err = callchain_append(he->callchain, &evsel->hists.callchain_cursor,
791                           sample->period);
792            if (err)
793                return;
794        }
795
796        if (top->sort_has_symbols)
797            perf_top__record_precise_ip(top, he, evsel->idx, ip);
798    }
799
800    return;
801}
802
803static void perf_top__mmap_read_idx(struct perf_top *top, int idx)
804{
805    struct perf_sample sample;
806    struct perf_evsel *evsel;
807    struct perf_session *session = top->session;
808    union perf_event *event;
809    struct machine *machine;
810    u8 origin;
811    int ret;
812
813    while ((event = perf_evlist__mmap_read(top->evlist, idx)) != NULL) {
814        ret = perf_session__parse_sample(session, event, &sample);
815        if (ret) {
816            pr_err("Can't parse sample, err = %d\n", ret);
817            continue;
818        }
819
820        evsel = perf_evlist__id2evsel(session->evlist, sample.id);
821        assert(evsel != NULL);
822
823        origin = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
824
825        if (event->header.type == PERF_RECORD_SAMPLE)
826            ++top->samples;
827
828        switch (origin) {
829        case PERF_RECORD_MISC_USER:
830            ++top->us_samples;
831            if (top->hide_user_symbols)
832                continue;
833            machine = perf_session__find_host_machine(session);
834            break;
835        case PERF_RECORD_MISC_KERNEL:
836            ++top->kernel_samples;
837            if (top->hide_kernel_symbols)
838                continue;
839            machine = perf_session__find_host_machine(session);
840            break;
841        case PERF_RECORD_MISC_GUEST_KERNEL:
842            ++top->guest_kernel_samples;
843            machine = perf_session__find_machine(session, event->ip.pid);
844            break;
845        case PERF_RECORD_MISC_GUEST_USER:
846            ++top->guest_us_samples;
847            /*
848             * TODO: we don't process guest user from host side
849             * except simple counting.
850             */
851            /* Fall thru */
852        default:
853            continue;
854        }
855
856
857        if (event->header.type == PERF_RECORD_SAMPLE) {
858            perf_event__process_sample(&top->tool, event, evsel,
859                           &sample, machine);
860        } else if (event->header.type < PERF_RECORD_MAX) {
861            hists__inc_nr_events(&evsel->hists, event->header.type);
862            perf_event__process(&top->tool, event, &sample, machine);
863        } else
864            ++session->hists.stats.nr_unknown_events;
865    }
866}
867
868static void perf_top__mmap_read(struct perf_top *top)
869{
870    int i;
871
872    for (i = 0; i < top->evlist->nr_mmaps; i++)
873        perf_top__mmap_read_idx(top, i);
874}
875
876static void perf_top__start_counters(struct perf_top *top)
877{
878    struct perf_evsel *counter, *first;
879    struct perf_evlist *evlist = top->evlist;
880
881    first = list_entry(evlist->entries.next, struct perf_evsel, node);
882
883    list_for_each_entry(counter, &evlist->entries, node) {
884        struct perf_event_attr *attr = &counter->attr;
885        struct xyarray *group_fd = NULL;
886
887        if (top->group && counter != first)
888            group_fd = first->fd;
889
890        attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID;
891
892        if (top->freq) {
893            attr->sample_type |= PERF_SAMPLE_PERIOD;
894            attr->freq = 1;
895            attr->sample_freq = top->freq;
896        }
897
898        if (evlist->nr_entries > 1) {
899            attr->sample_type |= PERF_SAMPLE_ID;
900            attr->read_format |= PERF_FORMAT_ID;
901        }
902
903        if (symbol_conf.use_callchain)
904            attr->sample_type |= PERF_SAMPLE_CALLCHAIN;
905
906        attr->mmap = 1;
907        attr->comm = 1;
908        attr->inherit = top->inherit;
909fallback_missing_features:
910        if (top->exclude_guest_missing)
911            attr->exclude_guest = attr->exclude_host = 0;
912retry_sample_id:
913        attr->sample_id_all = top->sample_id_all_missing ? 0 : 1;
914try_again:
915        if (perf_evsel__open(counter, top->evlist->cpus,
916                     top->evlist->threads, top->group,
917                     group_fd) < 0) {
918            int err = errno;
919
920            if (err == EPERM || err == EACCES) {
921                ui__error_paranoid();
922                goto out_err;
923            } else if (err == EINVAL) {
924                if (!top->exclude_guest_missing &&
925                    (attr->exclude_guest || attr->exclude_host)) {
926                    pr_debug("Old kernel, cannot exclude "
927                         "guest or host samples.\n");
928                    top->exclude_guest_missing = true;
929                    goto fallback_missing_features;
930                } else if (!top->sample_id_all_missing) {
931                    /*
932                     * Old kernel, no attr->sample_id_type_all field
933                     */
934                    top->sample_id_all_missing = true;
935                    goto retry_sample_id;
936                }
937            }
938            /*
939             * If it's cycles then fall back to hrtimer
940             * based cpu-clock-tick sw counter, which
941             * is always available even if no PMU support:
942             */
943            if (attr->type == PERF_TYPE_HARDWARE &&
944                attr->config == PERF_COUNT_HW_CPU_CYCLES) {
945                if (verbose)
946                    ui__warning("Cycles event not supported,\n"
947                            "trying to fall back to cpu-clock-ticks\n");
948
949                attr->type = PERF_TYPE_SOFTWARE;
950                attr->config = PERF_COUNT_SW_CPU_CLOCK;
951                goto try_again;
952            }
953
954            if (err == ENOENT) {
955                ui__warning("The %s event is not supported.\n",
956                        event_name(counter));
957                goto out_err;
958            } else if (err == EMFILE) {
959                ui__warning("Too many events are opened.\n"
960                        "Try again after reducing the number of events\n");
961                goto out_err;
962            }
963
964            ui__warning("The sys_perf_event_open() syscall "
965                    "returned with %d (%s). /bin/dmesg "
966                    "may provide additional information.\n"
967                    "No CONFIG_PERF_EVENTS=y kernel support "
968                    "configured?\n", err, strerror(err));
969            goto out_err;
970        }
971    }
972
973    if (perf_evlist__mmap(evlist, top->mmap_pages, false) < 0) {
974        ui__warning("Failed to mmap with %d (%s)\n",
975                errno, strerror(errno));
976        goto out_err;
977    }
978
979    return;
980
981out_err:
982    exit_browser(0);
983    exit(0);
984}
985
986static int perf_top__setup_sample_type(struct perf_top *top)
987{
988    if (!top->sort_has_symbols) {
989        if (symbol_conf.use_callchain) {
990            ui__warning("Selected -g but \"sym\" not present in --sort/-s.");
991            return -EINVAL;
992        }
993    } else if (!top->dont_use_callchains && callchain_param.mode != CHAIN_NONE) {
994        if (callchain_register_param(&callchain_param) < 0) {
995            ui__warning("Can't register callchain params.\n");
996            return -EINVAL;
997        }
998    }
999
1000    return 0;
1001}
1002
1003static int __cmd_top(struct perf_top *top)
1004{
1005    pthread_t thread;
1006    int ret;
1007    /*
1008     * FIXME: perf_session__new should allow passing a O_MMAP, so that all this
1009     * mmap reading, etc is encapsulated in it. Use O_WRONLY for now.
1010     */
1011    top->session = perf_session__new(NULL, O_WRONLY, false, false, NULL);
1012    if (top->session == NULL)
1013        return -ENOMEM;
1014
1015    ret = perf_top__setup_sample_type(top);
1016    if (ret)
1017        goto out_delete;
1018
1019    if (top->target_tid || top->uid != UINT_MAX)
1020        perf_event__synthesize_thread_map(&top->tool, top->evlist->threads,
1021                          perf_event__process,
1022                          &top->session->host_machine);
1023    else
1024        perf_event__synthesize_threads(&top->tool, perf_event__process,
1025                           &top->session->host_machine);
1026    perf_top__start_counters(top);
1027    top->session->evlist = top->evlist;
1028    perf_session__update_sample_type(top->session);
1029
1030    /* Wait for a minimal set of events before starting the snapshot */
1031    poll(top->evlist->pollfd, top->evlist->nr_fds, 100);
1032
1033    perf_top__mmap_read(top);
1034
1035    if (pthread_create(&thread, NULL, (use_browser > 0 ? display_thread_tui :
1036                                display_thread), top)) {
1037        printf("Could not create display thread.\n");
1038        exit(-1);
1039    }
1040
1041    if (top->realtime_prio) {
1042        struct sched_param param;
1043
1044        param.sched_priority = top->realtime_prio;
1045        if (sched_setscheduler(0, SCHED_FIFO, &param)) {
1046            printf("Could not set realtime priority.\n");
1047            exit(-1);
1048        }
1049    }
1050
1051    while (1) {
1052        u64 hits = top->samples;
1053
1054        perf_top__mmap_read(top);
1055
1056        if (hits == top->samples)
1057            ret = poll(top->evlist->pollfd, top->evlist->nr_fds, 100);
1058    }
1059
1060out_delete:
1061    perf_session__delete(top->session);
1062    top->session = NULL;
1063
1064    return 0;
1065}
1066
1067static int
1068parse_callchain_opt(const struct option *opt, const char *arg, int unset)
1069{
1070    struct perf_top *top = (struct perf_top *)opt->value;
1071    char *tok, *tok2;
1072    char *endptr;
1073
1074    /*
1075     * --no-call-graph
1076     */
1077    if (unset) {
1078        top->dont_use_callchains = true;
1079        return 0;
1080    }
1081
1082    symbol_conf.use_callchain = true;
1083
1084    if (!arg)
1085        return 0;
1086
1087    tok = strtok((char *)arg, ",");
1088    if (!tok)
1089        return -1;
1090
1091    /* get the output mode */
1092    if (!strncmp(tok, "graph", strlen(arg)))
1093        callchain_param.mode = CHAIN_GRAPH_ABS;
1094
1095    else if (!strncmp(tok, "flat", strlen(arg)))
1096        callchain_param.mode = CHAIN_FLAT;
1097
1098    else if (!strncmp(tok, "fractal", strlen(arg)))
1099        callchain_param.mode = CHAIN_GRAPH_REL;
1100
1101    else if (!strncmp(tok, "none", strlen(arg))) {
1102        callchain_param.mode = CHAIN_NONE;
1103        symbol_conf.use_callchain = false;
1104
1105        return 0;
1106    } else
1107        return -1;
1108
1109    /* get the min percentage */
1110    tok = strtok(NULL, ",");
1111    if (!tok)
1112        goto setup;
1113
1114    callchain_param.min_percent = strtod(tok, &endptr);
1115    if (tok == endptr)
1116        return -1;
1117
1118    /* get the print limit */
1119    tok2 = strtok(NULL, ",");
1120    if (!tok2)
1121        goto setup;
1122
1123    if (tok2[0] != 'c') {
1124        callchain_param.print_limit = strtod(tok2, &endptr);
1125        tok2 = strtok(NULL, ",");
1126        if (!tok2)
1127            goto setup;
1128    }
1129
1130    /* get the call chain order */
1131    if (!strcmp(tok2, "caller"))
1132        callchain_param.order = ORDER_CALLER;
1133    else if (!strcmp(tok2, "callee"))
1134        callchain_param.order = ORDER_CALLEE;
1135    else
1136        return -1;
1137setup:
1138    if (callchain_register_param(&callchain_param) < 0) {
1139        fprintf(stderr, "Can't register callchain params\n");
1140        return -1;
1141    }
1142    return 0;
1143}
1144
1145static const char * const top_usage[] = {
1146    "perf top [<options>]",
1147    NULL
1148};
1149
1150int cmd_top(int argc, const char **argv, const char *prefix __used)
1151{
1152    struct perf_evsel *pos;
1153    int status = -ENOMEM;
1154    struct perf_top top = {
1155        .count_filter = 5,
1156        .delay_secs = 2,
1157        .uid = UINT_MAX,
1158        .freq = 1000, /* 1 KHz */
1159        .mmap_pages = 128,
1160        .sym_pcnt_filter = 5,
1161    };
1162    char callchain_default_opt[] = "fractal,0.5,callee";
1163    const struct option options[] = {
1164    OPT_CALLBACK('e', "event", &top.evlist, "event",
1165             "event selector. use 'perf list' to list available events",
1166             parse_events_option),
1167    OPT_INTEGER('c', "count", &top.default_interval,
1168            "event period to sample"),
1169    OPT_STRING('p', "pid", &top.target_pid, "pid",
1170            "profile events on existing process id"),
1171    OPT_STRING('t', "tid", &top.target_tid, "tid",
1172            "profile events on existing thread id"),
1173    OPT_BOOLEAN('a', "all-cpus", &top.system_wide,
1174                "system-wide collection from all CPUs"),
1175    OPT_STRING('C', "cpu", &top.cpu_list, "cpu",
1176            "list of cpus to monitor"),
1177    OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
1178           "file", "vmlinux pathname"),
1179    OPT_BOOLEAN('K', "hide_kernel_symbols", &top.hide_kernel_symbols,
1180            "hide kernel symbols"),
1181    OPT_UINTEGER('m', "mmap-pages", &top.mmap_pages, "number of mmap data pages"),
1182    OPT_INTEGER('r', "realtime", &top.realtime_prio,
1183            "collect data with this RT SCHED_FIFO priority"),
1184    OPT_INTEGER('d', "delay", &top.delay_secs,
1185            "number of seconds to delay between refreshes"),
1186    OPT_BOOLEAN('D', "dump-symtab", &top.dump_symtab,
1187                "dump the symbol table used for profiling"),
1188    OPT_INTEGER('f', "count-filter", &top.count_filter,
1189            "only display functions with more events than this"),
1190    OPT_BOOLEAN('g', "group", &top.group,
1191                "put the counters into a counter group"),
1192    OPT_BOOLEAN('i', "inherit", &top.inherit,
1193            "child tasks inherit counters"),
1194    OPT_STRING(0, "sym-annotate", &top.sym_filter, "symbol name",
1195            "symbol to annotate"),
1196    OPT_BOOLEAN('z', "zero", &top.zero,
1197            "zero history across updates"),
1198    OPT_INTEGER('F', "freq", &top.freq,
1199            "profile at this frequency"),
1200    OPT_INTEGER('E', "entries", &top.print_entries,
1201            "display this many functions"),
1202    OPT_BOOLEAN('U', "hide_user_symbols", &top.hide_user_symbols,
1203            "hide user symbols"),
1204    OPT_BOOLEAN(0, "tui", &top.use_tui, "Use the TUI interface"),
1205    OPT_BOOLEAN(0, "stdio", &top.use_stdio, "Use the stdio interface"),
1206    OPT_INCR('v', "verbose", &verbose,
1207            "be more verbose (show counter open errors, etc)"),
1208    OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
1209           "sort by key(s): pid, comm, dso, symbol, parent"),
1210    OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples,
1211            "Show a column with the number of samples"),
1212    OPT_CALLBACK_DEFAULT('G', "call-graph", &top, "output_type,min_percent, call_order",
1213             "Display callchains using output_type (graph, flat, fractal, or none), min percent threshold and callchain order. "
1214             "Default: fractal,0.5,callee", &parse_callchain_opt,
1215             callchain_default_opt),
1216    OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period,
1217            "Show a column with the sum of periods"),
1218    OPT_STRING(0, "dsos", &symbol_conf.dso_list_str, "dso[,dso...]",
1219           "only consider symbols in these dsos"),
1220    OPT_STRING(0, "comms", &symbol_conf.comm_list_str, "comm[,comm...]",
1221           "only consider symbols in these comms"),
1222    OPT_STRING(0, "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]",
1223           "only consider these symbols"),
1224    OPT_BOOLEAN(0, "source", &symbol_conf.annotate_src,
1225            "Interleave source code with assembly code (default)"),
1226    OPT_BOOLEAN(0, "asm-raw", &symbol_conf.annotate_asm_raw,
1227            "Display raw encoding of assembly instructions (default)"),
1228    OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style",
1229           "Specify disassembler style (e.g. -M intel for intel syntax)"),
1230    OPT_STRING('u', "uid", &top.uid_str, "user", "user to profile"),
1231    OPT_END()
1232    };
1233
1234    top.evlist = perf_evlist__new(NULL, NULL);
1235    if (top.evlist == NULL)
1236        return -ENOMEM;
1237
1238    symbol_conf.exclude_other = false;
1239
1240    argc = parse_options(argc, argv, options, top_usage, 0);
1241    if (argc)
1242        usage_with_options(top_usage, options);
1243
1244    if (sort_order == default_sort_order)
1245        sort_order = "dso,symbol";
1246
1247    setup_sorting(top_usage, options);
1248
1249    if (top.use_stdio)
1250        use_browser = 0;
1251    else if (top.use_tui)
1252        use_browser = 1;
1253
1254    setup_browser(false);
1255
1256    top.uid = parse_target_uid(top.uid_str, top.target_tid, top.target_pid);
1257    if (top.uid_str != NULL && top.uid == UINT_MAX - 1)
1258        goto out_delete_evlist;
1259
1260    /* CPU and PID are mutually exclusive */
1261    if (top.target_tid && top.cpu_list) {
1262        printf("WARNING: PID switch overriding CPU\n");
1263        sleep(1);
1264        top.cpu_list = NULL;
1265    }
1266
1267    if (top.target_pid)
1268        top.target_tid = top.target_pid;
1269
1270    if (perf_evlist__create_maps(top.evlist, top.target_pid,
1271                     top.target_tid, top.uid, top.cpu_list) < 0)
1272        usage_with_options(top_usage, options);
1273
1274    if (!top.evlist->nr_entries &&
1275        perf_evlist__add_default(top.evlist) < 0) {
1276        pr_err("Not enough memory for event selector list\n");
1277        return -ENOMEM;
1278    }
1279
1280    symbol_conf.nr_events = top.evlist->nr_entries;
1281
1282    if (top.delay_secs < 1)
1283        top.delay_secs = 1;
1284
1285    /*
1286     * User specified count overrides default frequency.
1287     */
1288    if (top.default_interval)
1289        top.freq = 0;
1290    else if (top.freq) {
1291        top.default_interval = top.freq;
1292    } else {
1293        fprintf(stderr, "frequency and count are zero, aborting\n");
1294        exit(EXIT_FAILURE);
1295    }
1296
1297    list_for_each_entry(pos, &top.evlist->entries, node) {
1298        /*
1299         * Fill in the ones not specifically initialized via -c:
1300         */
1301        if (!pos->attr.sample_period)
1302            pos->attr.sample_period = top.default_interval;
1303    }
1304
1305    top.sym_evsel = list_entry(top.evlist->entries.next, struct perf_evsel, node);
1306
1307    symbol_conf.priv_size = sizeof(struct annotation);
1308
1309    symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL);
1310    if (symbol__init() < 0)
1311        return -1;
1312
1313    sort_entry__setup_elide(&sort_dso, symbol_conf.dso_list, "dso", stdout);
1314    sort_entry__setup_elide(&sort_comm, symbol_conf.comm_list, "comm", stdout);
1315    sort_entry__setup_elide(&sort_sym, symbol_conf.sym_list, "symbol", stdout);
1316
1317    /*
1318     * Avoid annotation data structures overhead when symbols aren't on the
1319     * sort list.
1320     */
1321    top.sort_has_symbols = sort_sym.list.next != NULL;
1322
1323    get_term_dimensions(&top.winsize);
1324    if (top.print_entries == 0) {
1325        struct sigaction act = {
1326            .sa_sigaction = perf_top__sig_winch,
1327            .sa_flags = SA_SIGINFO,
1328        };
1329        perf_top__update_print_entries(&top);
1330        sigaction(SIGWINCH, &act, NULL);
1331    }
1332
1333    status = __cmd_top(&top);
1334
1335out_delete_evlist:
1336    perf_evlist__delete(top.evlist);
1337
1338    return status;
1339}
1340

Archive Download this file



interactive