diff options
author | Arnaldo Carvalho de Melo <acme@redhat.com> | 2011-11-28 06:37:05 -0500 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2011-11-28 07:39:44 -0500 |
commit | 1758af10cf13d156014035b29ff50eab3773d849 (patch) | |
tree | 782ee9c4ee5589081b52d3894f4728f4e692cf86 | |
parent | 45694aa7702bc44d538a3bcb51bb2bb96cf190c0 (diff) |
perf top: Stop using globals for tool state
Use its 'perf_tool' base class instead.
Cc: David Ahern <dsahern@gmail.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/n/tip-i33q40wwvk2zna8fd36ex6sm@git.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-rw-r--r-- | tools/perf/builtin-top.c | 464 | ||||
-rw-r--r-- | tools/perf/util/top.h | 16 |
2 files changed, 245 insertions, 235 deletions
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 42a7d96b4dbe..50ff362ff012 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c | |||
@@ -64,44 +64,6 @@ | |||
64 | #include <linux/unistd.h> | 64 | #include <linux/unistd.h> |
65 | #include <linux/types.h> | 65 | #include <linux/types.h> |
66 | 66 | ||
67 | static struct perf_top top = { | ||
68 | .count_filter = 5, | ||
69 | .delay_secs = 2, | ||
70 | .target_pid = -1, | ||
71 | .target_tid = -1, | ||
72 | .freq = 1000, /* 1 KHz */ | ||
73 | }; | ||
74 | |||
75 | static bool system_wide = false; | ||
76 | |||
77 | static bool use_tui, use_stdio; | ||
78 | |||
79 | static bool sort_has_symbols; | ||
80 | |||
81 | static bool dont_use_callchains; | ||
82 | static char callchain_default_opt[] = "fractal,0.5,callee"; | ||
83 | |||
84 | |||
85 | static int default_interval = 0; | ||
86 | |||
87 | static bool kptr_restrict_warned; | ||
88 | static bool vmlinux_warned; | ||
89 | static bool inherit = false; | ||
90 | static int realtime_prio = 0; | ||
91 | static bool group = false; | ||
92 | static bool sample_id_all_avail = true; | ||
93 | static unsigned int mmap_pages = 128; | ||
94 | |||
95 | static bool dump_symtab = false; | ||
96 | |||
97 | static struct winsize winsize; | ||
98 | |||
99 | static const char *sym_filter = NULL; | ||
100 | static int sym_pcnt_filter = 5; | ||
101 | |||
102 | /* | ||
103 | * Source functions | ||
104 | */ | ||
105 | 67 | ||
106 | void get_term_dimensions(struct winsize *ws) | 68 | void get_term_dimensions(struct winsize *ws) |
107 | { | 69 | { |
@@ -125,21 +87,23 @@ void get_term_dimensions(struct winsize *ws) | |||
125 | ws->ws_col = 80; | 87 | ws->ws_col = 80; |
126 | } | 88 | } |
127 | 89 | ||
128 | static void update_print_entries(struct winsize *ws) | 90 | static void perf_top__update_print_entries(struct perf_top *top) |
129 | { | 91 | { |
130 | top.print_entries = ws->ws_row; | 92 | top->print_entries = top->winsize.ws_row; |
131 | 93 | ||
132 | if (top.print_entries > 9) | 94 | if (top->print_entries > 9) |
133 | top.print_entries -= 9; | 95 | top->print_entries -= 9; |
134 | } | 96 | } |
135 | 97 | ||
136 | static void sig_winch_handler(int sig __used) | 98 | static void perf_top__sig_winch(int sig __used, siginfo_t *info __used, void *arg) |
137 | { | 99 | { |
138 | get_term_dimensions(&winsize); | 100 | struct perf_top *top = arg; |
139 | update_print_entries(&winsize); | 101 | |
102 | get_term_dimensions(&top->winsize); | ||
103 | perf_top__update_print_entries(top); | ||
140 | } | 104 | } |
141 | 105 | ||
142 | static int parse_source(struct hist_entry *he) | 106 | static int perf_top__parse_source(struct perf_top *top, struct hist_entry *he) |
143 | { | 107 | { |
144 | struct symbol *sym; | 108 | struct symbol *sym; |
145 | struct annotation *notes; | 109 | struct annotation *notes; |
@@ -181,7 +145,7 @@ static int parse_source(struct hist_entry *he) | |||
181 | err = symbol__annotate(sym, map, 0); | 145 | err = symbol__annotate(sym, map, 0); |
182 | if (err == 0) { | 146 | if (err == 0) { |
183 | out_assign: | 147 | out_assign: |
184 | top.sym_filter_entry = he; | 148 | top->sym_filter_entry = he; |
185 | } | 149 | } |
186 | 150 | ||
187 | pthread_mutex_unlock(¬es->lock); | 151 | pthread_mutex_unlock(¬es->lock); |
@@ -194,14 +158,16 @@ static void __zero_source_counters(struct hist_entry *he) | |||
194 | symbol__annotate_zero_histograms(sym); | 158 | symbol__annotate_zero_histograms(sym); |
195 | } | 159 | } |
196 | 160 | ||
197 | static void record_precise_ip(struct hist_entry *he, int counter, u64 ip) | 161 | static void perf_top__record_precise_ip(struct perf_top *top, |
162 | struct hist_entry *he, | ||
163 | int counter, u64 ip) | ||
198 | { | 164 | { |
199 | struct annotation *notes; | 165 | struct annotation *notes; |
200 | struct symbol *sym; | 166 | struct symbol *sym; |
201 | 167 | ||
202 | if (he == NULL || he->ms.sym == NULL || | 168 | if (he == NULL || he->ms.sym == NULL || |
203 | ((top.sym_filter_entry == NULL || | 169 | ((top->sym_filter_entry == NULL || |
204 | top.sym_filter_entry->ms.sym != he->ms.sym) && use_browser != 1)) | 170 | top->sym_filter_entry->ms.sym != he->ms.sym) && use_browser != 1)) |
205 | return; | 171 | return; |
206 | 172 | ||
207 | sym = he->ms.sym; | 173 | sym = he->ms.sym; |
@@ -224,8 +190,9 @@ static void record_precise_ip(struct hist_entry *he, int counter, u64 ip) | |||
224 | pthread_mutex_unlock(¬es->lock); | 190 | pthread_mutex_unlock(¬es->lock); |
225 | } | 191 | } |
226 | 192 | ||
227 | static void show_details(struct hist_entry *he) | 193 | static void perf_top__show_details(struct perf_top *top) |
228 | { | 194 | { |
195 | struct hist_entry *he = top->sym_filter_entry; | ||
229 | struct annotation *notes; | 196 | struct annotation *notes; |
230 | struct symbol *symbol; | 197 | struct symbol *symbol; |
231 | int more; | 198 | int more; |
@@ -241,15 +208,15 @@ static void show_details(struct hist_entry *he) | |||
241 | if (notes->src == NULL) | 208 | if (notes->src == NULL) |
242 | goto out_unlock; | 209 | goto out_unlock; |
243 | 210 | ||
244 | printf("Showing %s for %s\n", event_name(top.sym_evsel), symbol->name); | 211 | printf("Showing %s for %s\n", event_name(top->sym_evsel), symbol->name); |
245 | printf(" Events Pcnt (>=%d%%)\n", sym_pcnt_filter); | 212 | printf(" Events Pcnt (>=%d%%)\n", top->sym_pcnt_filter); |
246 | 213 | ||
247 | more = symbol__annotate_printf(symbol, he->ms.map, top.sym_evsel->idx, | 214 | more = symbol__annotate_printf(symbol, he->ms.map, top->sym_evsel->idx, |
248 | 0, sym_pcnt_filter, top.print_entries, 4); | 215 | 0, top->sym_pcnt_filter, top->print_entries, 4); |
249 | if (top.zero) | 216 | if (top->zero) |
250 | symbol__annotate_zero_histogram(symbol, top.sym_evsel->idx); | 217 | symbol__annotate_zero_histogram(symbol, top->sym_evsel->idx); |
251 | else | 218 | else |
252 | symbol__annotate_decay_histogram(symbol, top.sym_evsel->idx); | 219 | symbol__annotate_decay_histogram(symbol, top->sym_evsel->idx); |
253 | if (more != 0) | 220 | if (more != 0) |
254 | printf("%d lines not displayed, maybe increase display entries [e]\n", more); | 221 | printf("%d lines not displayed, maybe increase display entries [e]\n", more); |
255 | out_unlock: | 222 | out_unlock: |
@@ -273,45 +240,46 @@ static struct hist_entry *perf_evsel__add_hist_entry(struct perf_evsel *evsel, | |||
273 | return he; | 240 | return he; |
274 | } | 241 | } |
275 | 242 | ||
276 | static void print_sym_table(void) | 243 | static void perf_top__print_sym_table(struct perf_top *top) |
277 | { | 244 | { |
278 | char bf[160]; | 245 | char bf[160]; |
279 | int printed = 0; | 246 | int printed = 0; |
280 | const int win_width = winsize.ws_col - 1; | 247 | const int win_width = top->winsize.ws_col - 1; |
281 | 248 | ||
282 | puts(CONSOLE_CLEAR); | 249 | puts(CONSOLE_CLEAR); |
283 | 250 | ||
284 | perf_top__header_snprintf(&top, bf, sizeof(bf)); | 251 | perf_top__header_snprintf(top, bf, sizeof(bf)); |
285 | printf("%s\n", bf); | 252 | printf("%s\n", bf); |
286 | 253 | ||
287 | perf_top__reset_sample_counters(&top); | 254 | perf_top__reset_sample_counters(top); |
288 | 255 | ||
289 | printf("%-*.*s\n", win_width, win_width, graph_dotted_line); | 256 | printf("%-*.*s\n", win_width, win_width, graph_dotted_line); |
290 | 257 | ||
291 | if (top.sym_evsel->hists.stats.nr_lost_warned != | 258 | if (top->sym_evsel->hists.stats.nr_lost_warned != |
292 | top.sym_evsel->hists.stats.nr_events[PERF_RECORD_LOST]) { | 259 | top->sym_evsel->hists.stats.nr_events[PERF_RECORD_LOST]) { |
293 | top.sym_evsel->hists.stats.nr_lost_warned = | 260 | top->sym_evsel->hists.stats.nr_lost_warned = |
294 | top.sym_evsel->hists.stats.nr_events[PERF_RECORD_LOST]; | 261 | top->sym_evsel->hists.stats.nr_events[PERF_RECORD_LOST]; |
295 | color_fprintf(stdout, PERF_COLOR_RED, | 262 | color_fprintf(stdout, PERF_COLOR_RED, |
296 | "WARNING: LOST %d chunks, Check IO/CPU overload", | 263 | "WARNING: LOST %d chunks, Check IO/CPU overload", |
297 | top.sym_evsel->hists.stats.nr_lost_warned); | 264 | top->sym_evsel->hists.stats.nr_lost_warned); |
298 | ++printed; | 265 | ++printed; |
299 | } | 266 | } |
300 | 267 | ||
301 | if (top.sym_filter_entry) { | 268 | if (top->sym_filter_entry) { |
302 | show_details(top.sym_filter_entry); | 269 | perf_top__show_details(top); |
303 | return; | 270 | return; |
304 | } | 271 | } |
305 | 272 | ||
306 | hists__collapse_resort_threaded(&top.sym_evsel->hists); | 273 | hists__collapse_resort_threaded(&top->sym_evsel->hists); |
307 | hists__output_resort_threaded(&top.sym_evsel->hists); | 274 | hists__output_resort_threaded(&top->sym_evsel->hists); |
308 | hists__decay_entries_threaded(&top.sym_evsel->hists, | 275 | hists__decay_entries_threaded(&top->sym_evsel->hists, |
309 | top.hide_user_symbols, | 276 | top->hide_user_symbols, |
310 | top.hide_kernel_symbols); | 277 | top->hide_kernel_symbols); |
311 | hists__output_recalc_col_len(&top.sym_evsel->hists, winsize.ws_row - 3); | 278 | hists__output_recalc_col_len(&top->sym_evsel->hists, |
279 | top->winsize.ws_row - 3); | ||
312 | putchar('\n'); | 280 | putchar('\n'); |
313 | hists__fprintf(&top.sym_evsel->hists, NULL, false, false, | 281 | hists__fprintf(&top->sym_evsel->hists, NULL, false, false, |
314 | winsize.ws_row - 4 - printed, win_width, stdout); | 282 | top->winsize.ws_row - 4 - printed, win_width, stdout); |
315 | } | 283 | } |
316 | 284 | ||
317 | static void prompt_integer(int *target, const char *msg) | 285 | static void prompt_integer(int *target, const char *msg) |
@@ -349,17 +317,17 @@ static void prompt_percent(int *target, const char *msg) | |||
349 | *target = tmp; | 317 | *target = tmp; |
350 | } | 318 | } |
351 | 319 | ||
352 | static void prompt_symbol(struct hist_entry **target, const char *msg) | 320 | static void perf_top__prompt_symbol(struct perf_top *top, const char *msg) |
353 | { | 321 | { |
354 | char *buf = malloc(0), *p; | 322 | char *buf = malloc(0), *p; |
355 | struct hist_entry *syme = *target, *n, *found = NULL; | 323 | struct hist_entry *syme = top->sym_filter_entry, *n, *found = NULL; |
356 | struct rb_node *next; | 324 | struct rb_node *next; |
357 | size_t dummy = 0; | 325 | size_t dummy = 0; |
358 | 326 | ||
359 | /* zero counters of active symbol */ | 327 | /* zero counters of active symbol */ |
360 | if (syme) { | 328 | if (syme) { |
361 | __zero_source_counters(syme); | 329 | __zero_source_counters(syme); |
362 | *target = NULL; | 330 | top->sym_filter_entry = NULL; |
363 | } | 331 | } |
364 | 332 | ||
365 | fprintf(stdout, "\n%s: ", msg); | 333 | fprintf(stdout, "\n%s: ", msg); |
@@ -370,7 +338,7 @@ static void prompt_symbol(struct hist_entry **target, const char *msg) | |||
370 | if (p) | 338 | if (p) |
371 | *p = 0; | 339 | *p = 0; |
372 | 340 | ||
373 | next = rb_first(&top.sym_evsel->hists.entries); | 341 | next = rb_first(&top->sym_evsel->hists.entries); |
374 | while (next) { | 342 | while (next) { |
375 | n = rb_entry(next, struct hist_entry, rb_node); | 343 | n = rb_entry(next, struct hist_entry, rb_node); |
376 | if (n->ms.sym && !strcmp(buf, n->ms.sym->name)) { | 344 | if (n->ms.sym && !strcmp(buf, n->ms.sym->name)) { |
@@ -385,45 +353,45 @@ static void prompt_symbol(struct hist_entry **target, const char *msg) | |||
385 | sleep(1); | 353 | sleep(1); |
386 | return; | 354 | return; |
387 | } else | 355 | } else |
388 | parse_source(found); | 356 | perf_top__parse_source(top, found); |
389 | 357 | ||
390 | out_free: | 358 | out_free: |
391 | free(buf); | 359 | free(buf); |
392 | } | 360 | } |
393 | 361 | ||
394 | static void print_mapped_keys(void) | 362 | static void perf_top__print_mapped_keys(struct perf_top *top) |
395 | { | 363 | { |
396 | char *name = NULL; | 364 | char *name = NULL; |
397 | 365 | ||
398 | if (top.sym_filter_entry) { | 366 | if (top->sym_filter_entry) { |
399 | struct symbol *sym = top.sym_filter_entry->ms.sym; | 367 | struct symbol *sym = top->sym_filter_entry->ms.sym; |
400 | name = sym->name; | 368 | name = sym->name; |
401 | } | 369 | } |
402 | 370 | ||
403 | fprintf(stdout, "\nMapped keys:\n"); | 371 | fprintf(stdout, "\nMapped keys:\n"); |
404 | fprintf(stdout, "\t[d] display refresh delay. \t(%d)\n", top.delay_secs); | 372 | fprintf(stdout, "\t[d] display refresh delay. \t(%d)\n", top->delay_secs); |
405 | fprintf(stdout, "\t[e] display entries (lines). \t(%d)\n", top.print_entries); | 373 | fprintf(stdout, "\t[e] display entries (lines). \t(%d)\n", top->print_entries); |
406 | 374 | ||
407 | if (top.evlist->nr_entries > 1) | 375 | if (top->evlist->nr_entries > 1) |
408 | fprintf(stdout, "\t[E] active event counter. \t(%s)\n", event_name(top.sym_evsel)); | 376 | fprintf(stdout, "\t[E] active event counter. \t(%s)\n", event_name(top->sym_evsel)); |
409 | 377 | ||
410 | fprintf(stdout, "\t[f] profile display filter (count). \t(%d)\n", top.count_filter); | 378 | fprintf(stdout, "\t[f] profile display filter (count). \t(%d)\n", top->count_filter); |
411 | 379 | ||
412 | fprintf(stdout, "\t[F] annotate display filter (percent). \t(%d%%)\n", sym_pcnt_filter); | 380 | fprintf(stdout, "\t[F] annotate display filter (percent). \t(%d%%)\n", top->sym_pcnt_filter); |
413 | fprintf(stdout, "\t[s] annotate symbol. \t(%s)\n", name?: "NULL"); | 381 | fprintf(stdout, "\t[s] annotate symbol. \t(%s)\n", name?: "NULL"); |
414 | fprintf(stdout, "\t[S] stop annotation.\n"); | 382 | fprintf(stdout, "\t[S] stop annotation.\n"); |
415 | 383 | ||
416 | fprintf(stdout, | 384 | fprintf(stdout, |
417 | "\t[K] hide kernel_symbols symbols. \t(%s)\n", | 385 | "\t[K] hide kernel_symbols symbols. \t(%s)\n", |
418 | top.hide_kernel_symbols ? "yes" : "no"); | 386 | top->hide_kernel_symbols ? "yes" : "no"); |
419 | fprintf(stdout, | 387 | fprintf(stdout, |
420 | "\t[U] hide user symbols. \t(%s)\n", | 388 | "\t[U] hide user symbols. \t(%s)\n", |
421 | top.hide_user_symbols ? "yes" : "no"); | 389 | top->hide_user_symbols ? "yes" : "no"); |
422 | fprintf(stdout, "\t[z] toggle sample zeroing. \t(%d)\n", top.zero ? 1 : 0); | 390 | fprintf(stdout, "\t[z] toggle sample zeroing. \t(%d)\n", top->zero ? 1 : 0); |
423 | fprintf(stdout, "\t[qQ] quit.\n"); | 391 | fprintf(stdout, "\t[qQ] quit.\n"); |
424 | } | 392 | } |
425 | 393 | ||
426 | static int key_mapped(int c) | 394 | static int perf_top__key_mapped(struct perf_top *top, int c) |
427 | { | 395 | { |
428 | switch (c) { | 396 | switch (c) { |
429 | case 'd': | 397 | case 'd': |
@@ -439,7 +407,7 @@ static int key_mapped(int c) | |||
439 | case 'S': | 407 | case 'S': |
440 | return 1; | 408 | return 1; |
441 | case 'E': | 409 | case 'E': |
442 | return top.evlist->nr_entries > 1 ? 1 : 0; | 410 | return top->evlist->nr_entries > 1 ? 1 : 0; |
443 | default: | 411 | default: |
444 | break; | 412 | break; |
445 | } | 413 | } |
@@ -447,13 +415,13 @@ static int key_mapped(int c) | |||
447 | return 0; | 415 | return 0; |
448 | } | 416 | } |
449 | 417 | ||
450 | static void handle_keypress(int c) | 418 | static void perf_top__handle_keypress(struct perf_top *top, int c) |
451 | { | 419 | { |
452 | if (!key_mapped(c)) { | 420 | if (!perf_top__key_mapped(top, c)) { |
453 | struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; | 421 | struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; |
454 | struct termios tc, save; | 422 | struct termios tc, save; |
455 | 423 | ||
456 | print_mapped_keys(); | 424 | perf_top__print_mapped_keys(top); |
457 | fprintf(stdout, "\nEnter selection, or unmapped key to continue: "); | 425 | fprintf(stdout, "\nEnter selection, or unmapped key to continue: "); |
458 | fflush(stdout); | 426 | fflush(stdout); |
459 | 427 | ||
@@ -468,81 +436,86 @@ static void handle_keypress(int c) | |||
468 | c = getc(stdin); | 436 | c = getc(stdin); |
469 | 437 | ||
470 | tcsetattr(0, TCSAFLUSH, &save); | 438 | tcsetattr(0, TCSAFLUSH, &save); |
471 | if (!key_mapped(c)) | 439 | if (!perf_top__key_mapped(top, c)) |
472 | return; | 440 | return; |
473 | } | 441 | } |
474 | 442 | ||
475 | switch (c) { | 443 | switch (c) { |
476 | case 'd': | 444 | case 'd': |
477 | prompt_integer(&top.delay_secs, "Enter display delay"); | 445 | prompt_integer(&top->delay_secs, "Enter display delay"); |
478 | if (top.delay_secs < 1) | 446 | if (top->delay_secs < 1) |
479 | top.delay_secs = 1; | 447 | top->delay_secs = 1; |
480 | break; | 448 | break; |
481 | case 'e': | 449 | case 'e': |
482 | prompt_integer(&top.print_entries, "Enter display entries (lines)"); | 450 | prompt_integer(&top->print_entries, "Enter display entries (lines)"); |
483 | if (top.print_entries == 0) { | 451 | if (top->print_entries == 0) { |
484 | sig_winch_handler(SIGWINCH); | 452 | struct sigaction act = { |
485 | signal(SIGWINCH, sig_winch_handler); | 453 | .sa_sigaction = perf_top__sig_winch, |
454 | .sa_flags = SA_SIGINFO, | ||
455 | }; | ||
456 | perf_top__sig_winch(SIGWINCH, NULL, top); | ||
457 | sigaction(SIGWINCH, &act, NULL); | ||
486 | } else | 458 | } else |
487 | signal(SIGWINCH, SIG_DFL); | 459 | signal(SIGWINCH, SIG_DFL); |
488 | break; | 460 | break; |
489 | case 'E': | 461 | case 'E': |
490 | if (top.evlist->nr_entries > 1) { | 462 | if (top->evlist->nr_entries > 1) { |
491 | /* Select 0 as the default event: */ | 463 | /* Select 0 as the default event: */ |
492 | int counter = 0; | 464 | int counter = 0; |
493 | 465 | ||
494 | fprintf(stderr, "\nAvailable events:"); | 466 | fprintf(stderr, "\nAvailable events:"); |
495 | 467 | ||
496 | list_for_each_entry(top.sym_evsel, &top.evlist->entries, node) | 468 | list_for_each_entry(top->sym_evsel, &top->evlist->entries, node) |
497 | fprintf(stderr, "\n\t%d %s", top.sym_evsel->idx, event_name(top.sym_evsel)); | 469 | fprintf(stderr, "\n\t%d %s", top->sym_evsel->idx, event_name(top->sym_evsel)); |
498 | 470 | ||
499 | prompt_integer(&counter, "Enter details event counter"); | 471 | prompt_integer(&counter, "Enter details event counter"); |
500 | 472 | ||
501 | if (counter >= top.evlist->nr_entries) { | 473 | if (counter >= top->evlist->nr_entries) { |
502 | top.sym_evsel = list_entry(top.evlist->entries.next, struct perf_evsel, node); | 474 | top->sym_evsel = list_entry(top->evlist->entries.next, struct perf_evsel, node); |
503 | fprintf(stderr, "Sorry, no such event, using %s.\n", event_name(top.sym_evsel)); | 475 | fprintf(stderr, "Sorry, no such event, using %s.\n", event_name(top->sym_evsel)); |
504 | sleep(1); | 476 | sleep(1); |
505 | break; | 477 | break; |
506 | } | 478 | } |
507 | list_for_each_entry(top.sym_evsel, &top.evlist->entries, node) | 479 | list_for_each_entry(top->sym_evsel, &top->evlist->entries, node) |
508 | if (top.sym_evsel->idx == counter) | 480 | if (top->sym_evsel->idx == counter) |
509 | break; | 481 | break; |
510 | } else | 482 | } else |
511 | top.sym_evsel = list_entry(top.evlist->entries.next, struct perf_evsel, node); | 483 | top->sym_evsel = list_entry(top->evlist->entries.next, struct perf_evsel, node); |
512 | break; | 484 | break; |
513 | case 'f': | 485 | case 'f': |
514 | prompt_integer(&top.count_filter, "Enter display event count filter"); | 486 | prompt_integer(&top->count_filter, "Enter display event count filter"); |
515 | break; | 487 | break; |
516 | case 'F': | 488 | case 'F': |
517 | prompt_percent(&sym_pcnt_filter, "Enter details display event filter (percent)"); | 489 | prompt_percent(&top->sym_pcnt_filter, |
490 | "Enter details display event filter (percent)"); | ||
518 | break; | 491 | break; |
519 | case 'K': | 492 | case 'K': |
520 | top.hide_kernel_symbols = !top.hide_kernel_symbols; | 493 | top->hide_kernel_symbols = !top->hide_kernel_symbols; |
521 | break; | 494 | break; |
522 | case 'q': | 495 | case 'q': |
523 | case 'Q': | 496 | case 'Q': |
524 | printf("exiting.\n"); | 497 | printf("exiting.\n"); |
525 | if (dump_symtab) | 498 | if (top->dump_symtab) |
526 | perf_session__fprintf_dsos(top.session, stderr); | 499 | perf_session__fprintf_dsos(top->session, stderr); |
527 | exit(0); | 500 | exit(0); |
528 | case 's': | 501 | case 's': |
529 | prompt_symbol(&top.sym_filter_entry, "Enter details symbol"); | 502 | perf_top__prompt_symbol(top, "Enter details symbol"); |
530 | break; | 503 | break; |
531 | case 'S': | 504 | case 'S': |
532 | if (!top.sym_filter_entry) | 505 | if (!top->sym_filter_entry) |
533 | break; | 506 | break; |
534 | else { | 507 | else { |
535 | struct hist_entry *syme = top.sym_filter_entry; | 508 | struct hist_entry *syme = top->sym_filter_entry; |
536 | 509 | ||
537 | top.sym_filter_entry = NULL; | 510 | top->sym_filter_entry = NULL; |
538 | __zero_source_counters(syme); | 511 | __zero_source_counters(syme); |
539 | } | 512 | } |
540 | break; | 513 | break; |
541 | case 'U': | 514 | case 'U': |
542 | top.hide_user_symbols = !top.hide_user_symbols; | 515 | top->hide_user_symbols = !top->hide_user_symbols; |
543 | break; | 516 | break; |
544 | case 'z': | 517 | case 'z': |
545 | top.zero = !top.zero; | 518 | top->zero = !top->zero; |
546 | break; | 519 | break; |
547 | default: | 520 | default: |
548 | break; | 521 | break; |
@@ -560,28 +533,30 @@ static void perf_top__sort_new_samples(void *arg) | |||
560 | hists__collapse_resort_threaded(&t->sym_evsel->hists); | 533 | hists__collapse_resort_threaded(&t->sym_evsel->hists); |
561 | hists__output_resort_threaded(&t->sym_evsel->hists); | 534 | hists__output_resort_threaded(&t->sym_evsel->hists); |
562 | hists__decay_entries_threaded(&t->sym_evsel->hists, | 535 | hists__decay_entries_threaded(&t->sym_evsel->hists, |
563 | top.hide_user_symbols, | 536 | t->hide_user_symbols, |
564 | top.hide_kernel_symbols); | 537 | t->hide_kernel_symbols); |
565 | } | 538 | } |
566 | 539 | ||
567 | static void *display_thread_tui(void *arg __used) | 540 | static void *display_thread_tui(void *arg) |
568 | { | 541 | { |
542 | struct perf_top *top = arg; | ||
569 | const char *help = "For a higher level overview, try: perf top --sort comm,dso"; | 543 | const char *help = "For a higher level overview, try: perf top --sort comm,dso"; |
570 | 544 | ||
571 | perf_top__sort_new_samples(&top); | 545 | perf_top__sort_new_samples(top); |
572 | perf_evlist__tui_browse_hists(top.evlist, help, | 546 | perf_evlist__tui_browse_hists(top->evlist, help, |
573 | perf_top__sort_new_samples, | 547 | perf_top__sort_new_samples, |
574 | &top, top.delay_secs); | 548 | top, top->delay_secs); |
575 | 549 | ||
576 | exit_browser(0); | 550 | exit_browser(0); |
577 | exit(0); | 551 | exit(0); |
578 | return NULL; | 552 | return NULL; |
579 | } | 553 | } |
580 | 554 | ||
581 | static void *display_thread(void *arg __used) | 555 | static void *display_thread(void *arg) |
582 | { | 556 | { |
583 | struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; | 557 | struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; |
584 | struct termios tc, save; | 558 | struct termios tc, save; |
559 | struct perf_top *top = arg; | ||
585 | int delay_msecs, c; | 560 | int delay_msecs, c; |
586 | 561 | ||
587 | tcgetattr(0, &save); | 562 | tcgetattr(0, &save); |
@@ -592,13 +567,13 @@ static void *display_thread(void *arg __used) | |||
592 | 567 | ||
593 | pthread__unblock_sigwinch(); | 568 | pthread__unblock_sigwinch(); |
594 | repeat: | 569 | repeat: |
595 | delay_msecs = top.delay_secs * 1000; | 570 | delay_msecs = top->delay_secs * 1000; |
596 | tcsetattr(0, TCSANOW, &tc); | 571 | tcsetattr(0, TCSANOW, &tc); |
597 | /* trash return*/ | 572 | /* trash return*/ |
598 | getc(stdin); | 573 | getc(stdin); |
599 | 574 | ||
600 | while (1) { | 575 | while (1) { |
601 | print_sym_table(); | 576 | perf_top__print_sym_table(top); |
602 | /* | 577 | /* |
603 | * Either timeout expired or we got an EINTR due to SIGWINCH, | 578 | * Either timeout expired or we got an EINTR due to SIGWINCH, |
604 | * refresh screen in both cases. | 579 | * refresh screen in both cases. |
@@ -618,7 +593,7 @@ process_hotkey: | |||
618 | c = getc(stdin); | 593 | c = getc(stdin); |
619 | tcsetattr(0, TCSAFLUSH, &save); | 594 | tcsetattr(0, TCSAFLUSH, &save); |
620 | 595 | ||
621 | handle_keypress(c); | 596 | perf_top__handle_keypress(top, c); |
622 | goto repeat; | 597 | goto repeat; |
623 | 598 | ||
624 | return NULL; | 599 | return NULL; |
@@ -670,11 +645,13 @@ static int symbol_filter(struct map *map __used, struct symbol *sym) | |||
670 | return 0; | 645 | return 0; |
671 | } | 646 | } |
672 | 647 | ||
673 | static void perf_event__process_sample(const union perf_event *event, | 648 | static void perf_event__process_sample(struct perf_tool *tool, |
649 | const union perf_event *event, | ||
674 | struct perf_evsel *evsel, | 650 | struct perf_evsel *evsel, |
675 | struct perf_sample *sample, | 651 | struct perf_sample *sample, |
676 | struct machine *machine) | 652 | struct machine *machine) |
677 | { | 653 | { |
654 | struct perf_top *top = container_of(tool, struct perf_top, tool); | ||
678 | struct symbol *parent = NULL; | 655 | struct symbol *parent = NULL; |
679 | u64 ip = event->ip.ip; | 656 | u64 ip = event->ip.ip; |
680 | struct addr_location al; | 657 | struct addr_location al; |
@@ -687,14 +664,14 @@ static void perf_event__process_sample(const union perf_event *event, | |||
687 | } | 664 | } |
688 | 665 | ||
689 | if (event->header.misc & PERF_RECORD_MISC_EXACT_IP) | 666 | if (event->header.misc & PERF_RECORD_MISC_EXACT_IP) |
690 | top.exact_samples++; | 667 | top->exact_samples++; |
691 | 668 | ||
692 | if (perf_event__preprocess_sample(event, machine, &al, sample, | 669 | if (perf_event__preprocess_sample(event, machine, &al, sample, |
693 | symbol_filter) < 0 || | 670 | symbol_filter) < 0 || |
694 | al.filtered) | 671 | al.filtered) |
695 | return; | 672 | return; |
696 | 673 | ||
697 | if (!kptr_restrict_warned && | 674 | if (!top->kptr_restrict_warned && |
698 | symbol_conf.kptr_restrict && | 675 | symbol_conf.kptr_restrict && |
699 | al.cpumode == PERF_RECORD_MISC_KERNEL) { | 676 | al.cpumode == PERF_RECORD_MISC_KERNEL) { |
700 | ui__warning( | 677 | ui__warning( |
@@ -705,7 +682,7 @@ static void perf_event__process_sample(const union perf_event *event, | |||
705 | " modules" : ""); | 682 | " modules" : ""); |
706 | if (use_browser <= 0) | 683 | if (use_browser <= 0) |
707 | sleep(5); | 684 | sleep(5); |
708 | kptr_restrict_warned = true; | 685 | top->kptr_restrict_warned = true; |
709 | } | 686 | } |
710 | 687 | ||
711 | if (al.sym == NULL) { | 688 | if (al.sym == NULL) { |
@@ -721,7 +698,7 @@ static void perf_event__process_sample(const union perf_event *event, | |||
721 | * --hide-kernel-symbols, even if the user specifies an | 698 | * --hide-kernel-symbols, even if the user specifies an |
722 | * invalid --vmlinux ;-) | 699 | * invalid --vmlinux ;-) |
723 | */ | 700 | */ |
724 | if (!kptr_restrict_warned && !vmlinux_warned && | 701 | if (!top->kptr_restrict_warned && !top->vmlinux_warned && |
725 | al.map == machine->vmlinux_maps[MAP__FUNCTION] && | 702 | al.map == machine->vmlinux_maps[MAP__FUNCTION] && |
726 | RB_EMPTY_ROOT(&al.map->dso->symbols[MAP__FUNCTION])) { | 703 | RB_EMPTY_ROOT(&al.map->dso->symbols[MAP__FUNCTION])) { |
727 | if (symbol_conf.vmlinux_name) { | 704 | if (symbol_conf.vmlinux_name) { |
@@ -734,7 +711,7 @@ static void perf_event__process_sample(const union perf_event *event, | |||
734 | 711 | ||
735 | if (use_browser <= 0) | 712 | if (use_browser <= 0) |
736 | sleep(5); | 713 | sleep(5); |
737 | vmlinux_warned = true; | 714 | top->vmlinux_warned = true; |
738 | } | 715 | } |
739 | } | 716 | } |
740 | 717 | ||
@@ -762,56 +739,57 @@ static void perf_event__process_sample(const union perf_event *event, | |||
762 | return; | 739 | return; |
763 | } | 740 | } |
764 | 741 | ||
765 | if (sort_has_symbols) | 742 | if (top->sort_has_symbols) |
766 | record_precise_ip(he, evsel->idx, ip); | 743 | perf_top__record_precise_ip(top, he, evsel->idx, ip); |
767 | } | 744 | } |
768 | 745 | ||
769 | return; | 746 | return; |
770 | } | 747 | } |
771 | 748 | ||
772 | static void perf_session__mmap_read_idx(struct perf_session *self, int idx) | 749 | static void perf_top__mmap_read_idx(struct perf_top *top, int idx) |
773 | { | 750 | { |
774 | struct perf_sample sample; | 751 | struct perf_sample sample; |
775 | struct perf_evsel *evsel; | 752 | struct perf_evsel *evsel; |
753 | struct perf_session *session = top->session; | ||
776 | union perf_event *event; | 754 | union perf_event *event; |
777 | struct machine *machine; | 755 | struct machine *machine; |
778 | u8 origin; | 756 | u8 origin; |
779 | int ret; | 757 | int ret; |
780 | 758 | ||
781 | while ((event = perf_evlist__mmap_read(top.evlist, idx)) != NULL) { | 759 | while ((event = perf_evlist__mmap_read(top->evlist, idx)) != NULL) { |
782 | ret = perf_session__parse_sample(self, event, &sample); | 760 | ret = perf_session__parse_sample(session, event, &sample); |
783 | if (ret) { | 761 | if (ret) { |
784 | pr_err("Can't parse sample, err = %d\n", ret); | 762 | pr_err("Can't parse sample, err = %d\n", ret); |
785 | continue; | 763 | continue; |
786 | } | 764 | } |
787 | 765 | ||
788 | evsel = perf_evlist__id2evsel(self->evlist, sample.id); | 766 | evsel = perf_evlist__id2evsel(session->evlist, sample.id); |
789 | assert(evsel != NULL); | 767 | assert(evsel != NULL); |
790 | 768 | ||
791 | origin = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; | 769 | origin = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; |
792 | 770 | ||
793 | if (event->header.type == PERF_RECORD_SAMPLE) | 771 | if (event->header.type == PERF_RECORD_SAMPLE) |
794 | ++top.samples; | 772 | ++top->samples; |
795 | 773 | ||
796 | switch (origin) { | 774 | switch (origin) { |
797 | case PERF_RECORD_MISC_USER: | 775 | case PERF_RECORD_MISC_USER: |
798 | ++top.us_samples; | 776 | ++top->us_samples; |
799 | if (top.hide_user_symbols) | 777 | if (top->hide_user_symbols) |
800 | continue; | 778 | continue; |
801 | machine = perf_session__find_host_machine(self); | 779 | machine = perf_session__find_host_machine(session); |
802 | break; | 780 | break; |
803 | case PERF_RECORD_MISC_KERNEL: | 781 | case PERF_RECORD_MISC_KERNEL: |
804 | ++top.kernel_samples; | 782 | ++top->kernel_samples; |
805 | if (top.hide_kernel_symbols) | 783 | if (top->hide_kernel_symbols) |
806 | continue; | 784 | continue; |
807 | machine = perf_session__find_host_machine(self); | 785 | machine = perf_session__find_host_machine(session); |
808 | break; | 786 | break; |
809 | case PERF_RECORD_MISC_GUEST_KERNEL: | 787 | case PERF_RECORD_MISC_GUEST_KERNEL: |
810 | ++top.guest_kernel_samples; | 788 | ++top->guest_kernel_samples; |
811 | machine = perf_session__find_machine(self, event->ip.pid); | 789 | machine = perf_session__find_machine(session, event->ip.pid); |
812 | break; | 790 | break; |
813 | case PERF_RECORD_MISC_GUEST_USER: | 791 | case PERF_RECORD_MISC_GUEST_USER: |
814 | ++top.guest_us_samples; | 792 | ++top->guest_us_samples; |
815 | /* | 793 | /* |
816 | * TODO: we don't process guest user from host side | 794 | * TODO: we don't process guest user from host side |
817 | * except simple counting. | 795 | * except simple counting. |
@@ -822,27 +800,29 @@ static void perf_session__mmap_read_idx(struct perf_session *self, int idx) | |||
822 | } | 800 | } |
823 | 801 | ||
824 | 802 | ||
825 | if (event->header.type == PERF_RECORD_SAMPLE) | 803 | if (event->header.type == PERF_RECORD_SAMPLE) { |
826 | perf_event__process_sample(event, evsel, &sample, machine); | 804 | perf_event__process_sample(&top->tool, event, evsel, |
827 | else if (event->header.type < PERF_RECORD_MAX) { | 805 | &sample, machine); |
806 | } else if (event->header.type < PERF_RECORD_MAX) { | ||
828 | hists__inc_nr_events(&evsel->hists, event->header.type); | 807 | hists__inc_nr_events(&evsel->hists, event->header.type); |
829 | perf_event__process(&top.tool, event, &sample, machine); | 808 | perf_event__process(&top->tool, event, &sample, machine); |
830 | } else | 809 | } else |
831 | ++self->hists.stats.nr_unknown_events; | 810 | ++session->hists.stats.nr_unknown_events; |
832 | } | 811 | } |
833 | } | 812 | } |
834 | 813 | ||
835 | static void perf_session__mmap_read(struct perf_session *self) | 814 | static void perf_top__mmap_read(struct perf_top *top) |
836 | { | 815 | { |
837 | int i; | 816 | int i; |
838 | 817 | ||
839 | for (i = 0; i < top.evlist->nr_mmaps; i++) | 818 | for (i = 0; i < top->evlist->nr_mmaps; i++) |
840 | perf_session__mmap_read_idx(self, i); | 819 | perf_top__mmap_read_idx(top, i); |
841 | } | 820 | } |
842 | 821 | ||
843 | static void start_counters(struct perf_evlist *evlist) | 822 | static void perf_top__start_counters(struct perf_top *top) |
844 | { | 823 | { |
845 | struct perf_evsel *counter, *first; | 824 | struct perf_evsel *counter, *first; |
825 | struct perf_evlist *evlist = top->evlist; | ||
846 | 826 | ||
847 | first = list_entry(evlist->entries.next, struct perf_evsel, node); | 827 | first = list_entry(evlist->entries.next, struct perf_evsel, node); |
848 | 828 | ||
@@ -850,15 +830,15 @@ static void start_counters(struct perf_evlist *evlist) | |||
850 | struct perf_event_attr *attr = &counter->attr; | 830 | struct perf_event_attr *attr = &counter->attr; |
851 | struct xyarray *group_fd = NULL; | 831 | struct xyarray *group_fd = NULL; |
852 | 832 | ||
853 | if (group && counter != first) | 833 | if (top->group && counter != first) |
854 | group_fd = first->fd; | 834 | group_fd = first->fd; |
855 | 835 | ||
856 | attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID; | 836 | attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID; |
857 | 837 | ||
858 | if (top.freq) { | 838 | if (top->freq) { |
859 | attr->sample_type |= PERF_SAMPLE_PERIOD; | 839 | attr->sample_type |= PERF_SAMPLE_PERIOD; |
860 | attr->freq = 1; | 840 | attr->freq = 1; |
861 | attr->sample_freq = top.freq; | 841 | attr->sample_freq = top->freq; |
862 | } | 842 | } |
863 | 843 | ||
864 | if (evlist->nr_entries > 1) { | 844 | if (evlist->nr_entries > 1) { |
@@ -871,23 +851,23 @@ static void start_counters(struct perf_evlist *evlist) | |||
871 | 851 | ||
872 | attr->mmap = 1; | 852 | attr->mmap = 1; |
873 | attr->comm = 1; | 853 | attr->comm = 1; |
874 | attr->inherit = inherit; | 854 | attr->inherit = top->inherit; |
875 | retry_sample_id: | 855 | retry_sample_id: |
876 | attr->sample_id_all = sample_id_all_avail ? 1 : 0; | 856 | attr->sample_id_all = top->sample_id_all_avail ? 1 : 0; |
877 | try_again: | 857 | try_again: |
878 | if (perf_evsel__open(counter, top.evlist->cpus, | 858 | if (perf_evsel__open(counter, top->evlist->cpus, |
879 | top.evlist->threads, group, | 859 | top->evlist->threads, top->group, |
880 | group_fd) < 0) { | 860 | group_fd) < 0) { |
881 | int err = errno; | 861 | int err = errno; |
882 | 862 | ||
883 | if (err == EPERM || err == EACCES) { | 863 | if (err == EPERM || err == EACCES) { |
884 | ui__error_paranoid(); | 864 | ui__error_paranoid(); |
885 | goto out_err; | 865 | goto out_err; |
886 | } else if (err == EINVAL && sample_id_all_avail) { | 866 | } else if (err == EINVAL && top->sample_id_all_avail) { |
887 | /* | 867 | /* |
888 | * Old kernel, no attr->sample_id_type_all field | 868 | * Old kernel, no attr->sample_id_type_all field |
889 | */ | 869 | */ |
890 | sample_id_all_avail = false; | 870 | top->sample_id_all_avail = false; |
891 | goto retry_sample_id; | 871 | goto retry_sample_id; |
892 | } | 872 | } |
893 | /* | 873 | /* |
@@ -921,7 +901,7 @@ try_again: | |||
921 | } | 901 | } |
922 | } | 902 | } |
923 | 903 | ||
924 | if (perf_evlist__mmap(evlist, mmap_pages, false) < 0) { | 904 | if (perf_evlist__mmap(evlist, top->mmap_pages, false) < 0) { |
925 | ui__warning("Failed to mmap with %d (%s)\n", | 905 | ui__warning("Failed to mmap with %d (%s)\n", |
926 | errno, strerror(errno)); | 906 | errno, strerror(errno)); |
927 | goto out_err; | 907 | goto out_err; |
@@ -934,14 +914,14 @@ out_err: | |||
934 | exit(0); | 914 | exit(0); |
935 | } | 915 | } |
936 | 916 | ||
937 | static int setup_sample_type(void) | 917 | static int perf_top__setup_sample_type(struct perf_top *top) |
938 | { | 918 | { |
939 | if (!sort_has_symbols) { | 919 | if (!top->sort_has_symbols) { |
940 | if (symbol_conf.use_callchain) { | 920 | if (symbol_conf.use_callchain) { |
941 | ui__warning("Selected -g but \"sym\" not present in --sort/-s."); | 921 | ui__warning("Selected -g but \"sym\" not present in --sort/-s."); |
942 | return -EINVAL; | 922 | return -EINVAL; |
943 | } | 923 | } |
944 | } else if (!dont_use_callchains && callchain_param.mode != CHAIN_NONE) { | 924 | } else if (!top->dont_use_callchains && callchain_param.mode != CHAIN_NONE) { |
945 | if (callchain_register_param(&callchain_param) < 0) { | 925 | if (callchain_register_param(&callchain_param) < 0) { |
946 | ui__warning("Can't register callchain params.\n"); | 926 | ui__warning("Can't register callchain params.\n"); |
947 | return -EINVAL; | 927 | return -EINVAL; |
@@ -951,7 +931,7 @@ static int setup_sample_type(void) | |||
951 | return 0; | 931 | return 0; |
952 | } | 932 | } |
953 | 933 | ||
954 | static int __cmd_top(void) | 934 | static int __cmd_top(struct perf_top *top) |
955 | { | 935 | { |
956 | pthread_t thread; | 936 | pthread_t thread; |
957 | int ret; | 937 | int ret; |
@@ -959,40 +939,40 @@ static int __cmd_top(void) | |||
959 | * FIXME: perf_session__new should allow passing a O_MMAP, so that all this | 939 | * FIXME: perf_session__new should allow passing a O_MMAP, so that all this |
960 | * mmap reading, etc is encapsulated in it. Use O_WRONLY for now. | 940 | * mmap reading, etc is encapsulated in it. Use O_WRONLY for now. |
961 | */ | 941 | */ |
962 | top.session = perf_session__new(NULL, O_WRONLY, false, false, NULL); | 942 | top->session = perf_session__new(NULL, O_WRONLY, false, false, NULL); |
963 | if (top.session == NULL) | 943 | if (top->session == NULL) |
964 | return -ENOMEM; | 944 | return -ENOMEM; |
965 | 945 | ||
966 | ret = setup_sample_type(); | 946 | ret = perf_top__setup_sample_type(top); |
967 | if (ret) | 947 | if (ret) |
968 | goto out_delete; | 948 | goto out_delete; |
969 | 949 | ||
970 | if (top.target_tid != -1) | 950 | if (top->target_tid != -1) |
971 | perf_event__synthesize_thread_map(&top.tool, top.evlist->threads, | 951 | perf_event__synthesize_thread_map(&top->tool, top->evlist->threads, |
972 | perf_event__process, | 952 | perf_event__process, |
973 | &top.session->host_machine); | 953 | &top->session->host_machine); |
974 | else | 954 | else |
975 | perf_event__synthesize_threads(&top.tool, perf_event__process, | 955 | perf_event__synthesize_threads(&top->tool, perf_event__process, |
976 | &top.session->host_machine); | 956 | &top->session->host_machine); |
977 | start_counters(top.evlist); | 957 | perf_top__start_counters(top); |
978 | top.session->evlist = top.evlist; | 958 | top->session->evlist = top->evlist; |
979 | perf_session__update_sample_type(top.session); | 959 | perf_session__update_sample_type(top->session); |
980 | 960 | ||
981 | /* Wait for a minimal set of events before starting the snapshot */ | 961 | /* Wait for a minimal set of events before starting the snapshot */ |
982 | poll(top.evlist->pollfd, top.evlist->nr_fds, 100); | 962 | poll(top->evlist->pollfd, top->evlist->nr_fds, 100); |
983 | 963 | ||
984 | perf_session__mmap_read(top.session); | 964 | perf_top__mmap_read(top); |
985 | 965 | ||
986 | if (pthread_create(&thread, NULL, (use_browser > 0 ? display_thread_tui : | 966 | if (pthread_create(&thread, NULL, (use_browser > 0 ? display_thread_tui : |
987 | display_thread), NULL)) { | 967 | display_thread), top)) { |
988 | printf("Could not create display thread.\n"); | 968 | printf("Could not create display thread.\n"); |
989 | exit(-1); | 969 | exit(-1); |
990 | } | 970 | } |
991 | 971 | ||
992 | if (realtime_prio) { | 972 | if (top->realtime_prio) { |
993 | struct sched_param param; | 973 | struct sched_param param; |
994 | 974 | ||
995 | param.sched_priority = realtime_prio; | 975 | param.sched_priority = top->realtime_prio; |
996 | if (sched_setscheduler(0, SCHED_FIFO, ¶m)) { | 976 | if (sched_setscheduler(0, SCHED_FIFO, ¶m)) { |
997 | printf("Could not set realtime priority.\n"); | 977 | printf("Could not set realtime priority.\n"); |
998 | exit(-1); | 978 | exit(-1); |
@@ -1000,25 +980,25 @@ static int __cmd_top(void) | |||
1000 | } | 980 | } |
1001 | 981 | ||
1002 | while (1) { | 982 | while (1) { |
1003 | u64 hits = top.samples; | 983 | u64 hits = top->samples; |
1004 | 984 | ||
1005 | perf_session__mmap_read(top.session); | 985 | perf_top__mmap_read(top); |
1006 | 986 | ||
1007 | if (hits == top.samples) | 987 | if (hits == top->samples) |
1008 | ret = poll(top.evlist->pollfd, top.evlist->nr_fds, 100); | 988 | ret = poll(top->evlist->pollfd, top->evlist->nr_fds, 100); |
1009 | } | 989 | } |
1010 | 990 | ||
1011 | out_delete: | 991 | out_delete: |
1012 | perf_session__delete(top.session); | 992 | perf_session__delete(top->session); |
1013 | top.session = NULL; | 993 | top->session = NULL; |
1014 | 994 | ||
1015 | return 0; | 995 | return 0; |
1016 | } | 996 | } |
1017 | 997 | ||
1018 | static int | 998 | static int |
1019 | parse_callchain_opt(const struct option *opt __used, const char *arg, | 999 | parse_callchain_opt(const struct option *opt, const char *arg, int unset) |
1020 | int unset) | ||
1021 | { | 1000 | { |
1001 | struct perf_top *top = (struct perf_top *)opt->value; | ||
1022 | char *tok, *tok2; | 1002 | char *tok, *tok2; |
1023 | char *endptr; | 1003 | char *endptr; |
1024 | 1004 | ||
@@ -1026,7 +1006,7 @@ parse_callchain_opt(const struct option *opt __used, const char *arg, | |||
1026 | * --no-call-graph | 1006 | * --no-call-graph |
1027 | */ | 1007 | */ |
1028 | if (unset) { | 1008 | if (unset) { |
1029 | dont_use_callchains = true; | 1009 | top->dont_use_callchains = true; |
1030 | return 0; | 1010 | return 0; |
1031 | } | 1011 | } |
1032 | 1012 | ||
@@ -1100,17 +1080,32 @@ static const char * const top_usage[] = { | |||
1100 | NULL | 1080 | NULL |
1101 | }; | 1081 | }; |
1102 | 1082 | ||
1103 | static const struct option options[] = { | 1083 | int cmd_top(int argc, const char **argv, const char *prefix __used) |
1084 | { | ||
1085 | struct perf_evsel *pos; | ||
1086 | int status = -ENOMEM; | ||
1087 | struct perf_top top = { | ||
1088 | .count_filter = 5, | ||
1089 | .delay_secs = 2, | ||
1090 | .target_pid = -1, | ||
1091 | .target_tid = -1, | ||
1092 | .freq = 1000, /* 1 KHz */ | ||
1093 | .sample_id_all_avail = true, | ||
1094 | .mmap_pages = 128, | ||
1095 | .sym_pcnt_filter = 5, | ||
1096 | }; | ||
1097 | char callchain_default_opt[] = "fractal,0.5,callee"; | ||
1098 | const struct option options[] = { | ||
1104 | OPT_CALLBACK('e', "event", &top.evlist, "event", | 1099 | OPT_CALLBACK('e', "event", &top.evlist, "event", |
1105 | "event selector. use 'perf list' to list available events", | 1100 | "event selector. use 'perf list' to list available events", |
1106 | parse_events_option), | 1101 | parse_events_option), |
1107 | OPT_INTEGER('c', "count", &default_interval, | 1102 | OPT_INTEGER('c', "count", &top.default_interval, |
1108 | "event period to sample"), | 1103 | "event period to sample"), |
1109 | OPT_INTEGER('p', "pid", &top.target_pid, | 1104 | OPT_INTEGER('p', "pid", &top.target_pid, |
1110 | "profile events on existing process id"), | 1105 | "profile events on existing process id"), |
1111 | OPT_INTEGER('t', "tid", &top.target_tid, | 1106 | OPT_INTEGER('t', "tid", &top.target_tid, |
1112 | "profile events on existing thread id"), | 1107 | "profile events on existing thread id"), |
1113 | OPT_BOOLEAN('a', "all-cpus", &system_wide, | 1108 | OPT_BOOLEAN('a', "all-cpus", &top.system_wide, |
1114 | "system-wide collection from all CPUs"), | 1109 | "system-wide collection from all CPUs"), |
1115 | OPT_STRING('C', "cpu", &top.cpu_list, "cpu", | 1110 | OPT_STRING('C', "cpu", &top.cpu_list, "cpu", |
1116 | "list of cpus to monitor"), | 1111 | "list of cpus to monitor"), |
@@ -1118,20 +1113,20 @@ static const struct option options[] = { | |||
1118 | "file", "vmlinux pathname"), | 1113 | "file", "vmlinux pathname"), |
1119 | OPT_BOOLEAN('K', "hide_kernel_symbols", &top.hide_kernel_symbols, | 1114 | OPT_BOOLEAN('K', "hide_kernel_symbols", &top.hide_kernel_symbols, |
1120 | "hide kernel symbols"), | 1115 | "hide kernel symbols"), |
1121 | OPT_UINTEGER('m', "mmap-pages", &mmap_pages, "number of mmap data pages"), | 1116 | OPT_UINTEGER('m', "mmap-pages", &top.mmap_pages, "number of mmap data pages"), |
1122 | OPT_INTEGER('r', "realtime", &realtime_prio, | 1117 | OPT_INTEGER('r', "realtime", &top.realtime_prio, |
1123 | "collect data with this RT SCHED_FIFO priority"), | 1118 | "collect data with this RT SCHED_FIFO priority"), |
1124 | OPT_INTEGER('d', "delay", &top.delay_secs, | 1119 | OPT_INTEGER('d', "delay", &top.delay_secs, |
1125 | "number of seconds to delay between refreshes"), | 1120 | "number of seconds to delay between refreshes"), |
1126 | OPT_BOOLEAN('D', "dump-symtab", &dump_symtab, | 1121 | OPT_BOOLEAN('D', "dump-symtab", &top.dump_symtab, |
1127 | "dump the symbol table used for profiling"), | 1122 | "dump the symbol table used for profiling"), |
1128 | OPT_INTEGER('f', "count-filter", &top.count_filter, | 1123 | OPT_INTEGER('f', "count-filter", &top.count_filter, |
1129 | "only display functions with more events than this"), | 1124 | "only display functions with more events than this"), |
1130 | OPT_BOOLEAN('g', "group", &group, | 1125 | OPT_BOOLEAN('g', "group", &top.group, |
1131 | "put the counters into a counter group"), | 1126 | "put the counters into a counter group"), |
1132 | OPT_BOOLEAN('i', "inherit", &inherit, | 1127 | OPT_BOOLEAN('i', "inherit", &top.inherit, |
1133 | "child tasks inherit counters"), | 1128 | "child tasks inherit counters"), |
1134 | OPT_STRING(0, "sym-annotate", &sym_filter, "symbol name", | 1129 | OPT_STRING(0, "sym-annotate", &top.sym_filter, "symbol name", |
1135 | "symbol to annotate"), | 1130 | "symbol to annotate"), |
1136 | OPT_BOOLEAN('z', "zero", &top.zero, | 1131 | OPT_BOOLEAN('z', "zero", &top.zero, |
1137 | "zero history across updates"), | 1132 | "zero history across updates"), |
@@ -1141,15 +1136,15 @@ static const struct option options[] = { | |||
1141 | "display this many functions"), | 1136 | "display this many functions"), |
1142 | OPT_BOOLEAN('U', "hide_user_symbols", &top.hide_user_symbols, | 1137 | OPT_BOOLEAN('U', "hide_user_symbols", &top.hide_user_symbols, |
1143 | "hide user symbols"), | 1138 | "hide user symbols"), |
1144 | OPT_BOOLEAN(0, "tui", &use_tui, "Use the TUI interface"), | 1139 | OPT_BOOLEAN(0, "tui", &top.use_tui, "Use the TUI interface"), |
1145 | OPT_BOOLEAN(0, "stdio", &use_stdio, "Use the stdio interface"), | 1140 | OPT_BOOLEAN(0, "stdio", &top.use_stdio, "Use the stdio interface"), |
1146 | OPT_INCR('v', "verbose", &verbose, | 1141 | OPT_INCR('v', "verbose", &verbose, |
1147 | "be more verbose (show counter open errors, etc)"), | 1142 | "be more verbose (show counter open errors, etc)"), |
1148 | OPT_STRING('s', "sort", &sort_order, "key[,key2...]", | 1143 | OPT_STRING('s', "sort", &sort_order, "key[,key2...]", |
1149 | "sort by key(s): pid, comm, dso, symbol, parent"), | 1144 | "sort by key(s): pid, comm, dso, symbol, parent"), |
1150 | OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples, | 1145 | OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples, |
1151 | "Show a column with the number of samples"), | 1146 | "Show a column with the number of samples"), |
1152 | OPT_CALLBACK_DEFAULT('G', "call-graph", NULL, "output_type,min_percent, call_order", | 1147 | OPT_CALLBACK_DEFAULT('G', "call-graph", &top, "output_type,min_percent, call_order", |
1153 | "Display callchains using output_type (graph, flat, fractal, or none), min percent threshold and callchain order. " | 1148 | "Display callchains using output_type (graph, flat, fractal, or none), min percent threshold and callchain order. " |
1154 | "Default: fractal,0.5,callee", &parse_callchain_opt, | 1149 | "Default: fractal,0.5,callee", &parse_callchain_opt, |
1155 | callchain_default_opt), | 1150 | callchain_default_opt), |
@@ -1168,12 +1163,7 @@ static const struct option options[] = { | |||
1168 | OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style", | 1163 | OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style", |
1169 | "Specify disassembler style (e.g. -M intel for intel syntax)"), | 1164 | "Specify disassembler style (e.g. -M intel for intel syntax)"), |
1170 | OPT_END() | 1165 | OPT_END() |
1171 | }; | 1166 | }; |
1172 | |||
1173 | int cmd_top(int argc, const char **argv, const char *prefix __used) | ||
1174 | { | ||
1175 | struct perf_evsel *pos; | ||
1176 | int status = -ENOMEM; | ||
1177 | 1167 | ||
1178 | top.evlist = perf_evlist__new(NULL, NULL); | 1168 | top.evlist = perf_evlist__new(NULL, NULL); |
1179 | if (top.evlist == NULL) | 1169 | if (top.evlist == NULL) |
@@ -1190,9 +1180,9 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) | |||
1190 | 1180 | ||
1191 | setup_sorting(top_usage, options); | 1181 | setup_sorting(top_usage, options); |
1192 | 1182 | ||
1193 | if (use_stdio) | 1183 | if (top.use_stdio) |
1194 | use_browser = 0; | 1184 | use_browser = 0; |
1195 | else if (use_tui) | 1185 | else if (top.use_tui) |
1196 | use_browser = 1; | 1186 | use_browser = 1; |
1197 | 1187 | ||
1198 | setup_browser(false); | 1188 | setup_browser(false); |
@@ -1225,10 +1215,10 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) | |||
1225 | /* | 1215 | /* |
1226 | * User specified count overrides default frequency. | 1216 | * User specified count overrides default frequency. |
1227 | */ | 1217 | */ |
1228 | if (default_interval) | 1218 | if (top.default_interval) |
1229 | top.freq = 0; | 1219 | top.freq = 0; |
1230 | else if (top.freq) { | 1220 | else if (top.freq) { |
1231 | default_interval = top.freq; | 1221 | top.default_interval = top.freq; |
1232 | } else { | 1222 | } else { |
1233 | fprintf(stderr, "frequency and count are zero, aborting\n"); | 1223 | fprintf(stderr, "frequency and count are zero, aborting\n"); |
1234 | exit(EXIT_FAILURE); | 1224 | exit(EXIT_FAILURE); |
@@ -1244,7 +1234,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) | |||
1244 | if (pos->attr.sample_period) | 1234 | if (pos->attr.sample_period) |
1245 | continue; | 1235 | continue; |
1246 | 1236 | ||
1247 | pos->attr.sample_period = default_interval; | 1237 | pos->attr.sample_period = top.default_interval; |
1248 | } | 1238 | } |
1249 | 1239 | ||
1250 | if (perf_evlist__alloc_pollfd(top.evlist) < 0 || | 1240 | if (perf_evlist__alloc_pollfd(top.evlist) < 0 || |
@@ -1267,15 +1257,19 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) | |||
1267 | * Avoid annotation data structures overhead when symbols aren't on the | 1257 | * Avoid annotation data structures overhead when symbols aren't on the |
1268 | * sort list. | 1258 | * sort list. |
1269 | */ | 1259 | */ |
1270 | sort_has_symbols = sort_sym.list.next != NULL; | 1260 | top.sort_has_symbols = sort_sym.list.next != NULL; |
1271 | 1261 | ||
1272 | get_term_dimensions(&winsize); | 1262 | get_term_dimensions(&top.winsize); |
1273 | if (top.print_entries == 0) { | 1263 | if (top.print_entries == 0) { |
1274 | update_print_entries(&winsize); | 1264 | struct sigaction act = { |
1275 | signal(SIGWINCH, sig_winch_handler); | 1265 | .sa_sigaction = perf_top__sig_winch, |
1266 | .sa_flags = SA_SIGINFO, | ||
1267 | }; | ||
1268 | perf_top__update_print_entries(&top); | ||
1269 | sigaction(SIGWINCH, &act, NULL); | ||
1276 | } | 1270 | } |
1277 | 1271 | ||
1278 | status = __cmd_top(); | 1272 | status = __cmd_top(&top); |
1279 | out_free_fd: | 1273 | out_free_fd: |
1280 | perf_evlist__delete(top.evlist); | 1274 | perf_evlist__delete(top.evlist); |
1281 | 1275 | ||
diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h index 40430ec5c267..a248f3c2c60d 100644 --- a/tools/perf/util/top.h +++ b/tools/perf/util/top.h | |||
@@ -25,10 +25,26 @@ struct perf_top { | |||
25 | int freq; | 25 | int freq; |
26 | pid_t target_pid, target_tid; | 26 | pid_t target_pid, target_tid; |
27 | bool hide_kernel_symbols, hide_user_symbols, zero; | 27 | bool hide_kernel_symbols, hide_user_symbols, zero; |
28 | bool system_wide; | ||
29 | bool use_tui, use_stdio; | ||
30 | bool sort_has_symbols; | ||
31 | bool dont_use_callchains; | ||
32 | bool kptr_restrict_warned; | ||
33 | bool vmlinux_warned; | ||
34 | bool inherit; | ||
35 | bool group; | ||
36 | bool sample_id_all_avail; | ||
37 | bool dump_symtab; | ||
28 | const char *cpu_list; | 38 | const char *cpu_list; |
29 | struct hist_entry *sym_filter_entry; | 39 | struct hist_entry *sym_filter_entry; |
30 | struct perf_evsel *sym_evsel; | 40 | struct perf_evsel *sym_evsel; |
31 | struct perf_session *session; | 41 | struct perf_session *session; |
42 | struct winsize winsize; | ||
43 | unsigned int mmap_pages; | ||
44 | int default_interval; | ||
45 | int realtime_prio; | ||
46 | int sym_pcnt_filter; | ||
47 | const char *sym_filter; | ||
32 | }; | 48 | }; |
33 | 49 | ||
34 | size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size); | 50 | size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size); |