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