Blame view
tools/perf/builtin-top.c
31.1 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> |
8c3e10eb1 perf top: Move di... |
65 66 67 |
static struct perf_top top = { .count_filter = 5, .delay_secs = 2, |
8c3e10eb1 perf top: Move di... |
68 69 |
.target_pid = -1, .target_tid = -1, |
8c3e10eb1 perf top: Move di... |
70 71 |
.freq = 1000, /* 1 KHz */ }; |
361c99a66 perf evsel: Intro... |
72 |
|
c05556421 perf: Fix endiann... |
73 |
static bool system_wide = false; |
078006012 perf_counter tool... |
74 |
|
c0443df1b perf top: Introdu... |
75 |
static bool use_tui, use_stdio; |
19d4ac3c1 perf top: Add cal... |
76 77 78 79 |
static bool sort_has_symbols; static bool dont_use_callchains; static char callchain_default_opt[] = "fractal,0.5,callee"; |
7e4ff9e3e perf tools: Fix c... |
80 |
static int default_interval = 0; |
078006012 perf_counter tool... |
81 |
|
5f6f55809 perf top: Handle ... |
82 |
static bool kptr_restrict_warned; |
e4a338d05 perf top: Don't s... |
83 |
static bool vmlinux_warned; |
c05556421 perf: Fix endiann... |
84 |
static bool inherit = false; |
1967936d6 perf options: Che... |
85 |
static int realtime_prio = 0; |
c05556421 perf: Fix endiann... |
86 |
static bool group = false; |
7b27509fc perf hists browse... |
87 |
static bool sample_id_all_avail = true; |
70db7533c perf evlist: Move... |
88 |
static unsigned int mmap_pages = 128; |
078006012 perf_counter tool... |
89 |
|
c05556421 perf: Fix endiann... |
90 |
static bool dump_symtab = false; |
078006012 perf_counter tool... |
91 |
|
13cc5079f perf top: Auto ad... |
92 |
static struct winsize winsize; |
8ffcda173 perf top: Introdu... |
93 |
|
edb7c60e2 perf options: Typ... |
94 |
static const char *sym_filter = NULL; |
42e59d7d1 perf tools: Defau... |
95 |
static int sym_pcnt_filter = 5; |
078006012 perf_counter tool... |
96 |
|
923c42c19 perf_counter tool... |
97 98 99 |
/* * Source functions */ |
895f0edc3 perf top: Export ... |
100 |
void get_term_dimensions(struct winsize *ws) |
3b6ed9889 perf top: Use all... |
101 |
{ |
13cc5079f perf top: Auto ad... |
102 103 104 105 106 107 108 109 110 111 |
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... |
112 |
} |
13cc5079f perf top: Auto ad... |
113 114 115 116 |
#ifdef TIOCGWINSZ if (ioctl(1, TIOCGWINSZ, ws) == 0 && ws->ws_row && ws->ws_col) return; |
3b6ed9889 perf top: Use all... |
117 |
#endif |
13cc5079f perf top: Auto ad... |
118 119 |
ws->ws_row = 25; ws->ws_col = 80; |
3b6ed9889 perf top: Use all... |
120 |
} |
13cc5079f perf top: Auto ad... |
121 |
static void update_print_entries(struct winsize *ws) |
3b6ed9889 perf top: Use all... |
122 |
{ |
8c3e10eb1 perf top: Move di... |
123 |
top.print_entries = ws->ws_row; |
13cc5079f perf top: Auto ad... |
124 |
|
8c3e10eb1 perf top: Move di... |
125 126 |
if (top.print_entries > 9) top.print_entries -= 9; |
3b6ed9889 perf top: Use all... |
127 128 129 130 |
} static void sig_winch_handler(int sig __used) { |
13cc5079f perf top: Auto ad... |
131 132 |
get_term_dimensions(&winsize); update_print_entries(&winsize); |
3b6ed9889 perf top: Use all... |
133 |
} |
ab81f3fd3 perf top: Reuse t... |
134 |
static int parse_source(struct hist_entry *he) |
923c42c19 perf_counter tool... |
135 136 |
{ struct symbol *sym; |
ce6f4fab4 perf annotate: Mo... |
137 |
struct annotation *notes; |
439d473b4 perf tools: Rewri... |
138 |
struct map *map; |
36532461a perf top: Ditch p... |
139 |
int err = -1; |
923c42c19 perf_counter tool... |
140 |
|
ab81f3fd3 perf top: Reuse t... |
141 |
if (!he || !he->ms.sym) |
b0a9ab62a perf top: Properl... |
142 |
return -1; |
ab81f3fd3 perf top: Reuse t... |
143 144 |
sym = he->ms.sym; map = he->ms.map; |
b0a9ab62a perf top: Properl... |
145 146 147 148 |
/* * We can't annotate with just /proc/kallsyms */ |
878b439dc perf symbols: Ren... |
149 |
if (map->dso->symtab_type == SYMTAB__KALLSYMS) { |
ce6f4fab4 perf annotate: Mo... |
150 151 152 153 |
pr_err("Can't annotate %s: No vmlinux file was found in the " "path ", sym->name); sleep(1); |
b0a9ab62a perf top: Properl... |
154 |
return -1; |
b269876c8 perf top: Don't a... |
155 |
} |
ce6f4fab4 perf annotate: Mo... |
156 157 158 |
notes = symbol__annotation(sym); if (notes->src != NULL) { pthread_mutex_lock(¬es->lock); |
923c42c19 perf_counter tool... |
159 160 |
goto out_assign; } |
923c42c19 perf_counter tool... |
161 |
|
ce6f4fab4 perf annotate: Mo... |
162 |
pthread_mutex_lock(¬es->lock); |
923c42c19 perf_counter tool... |
163 |
|
36532461a perf top: Ditch p... |
164 |
if (symbol__alloc_hist(sym, top.evlist->nr_entries) < 0) { |
c97cf4221 perf top: Live TU... |
165 |
pthread_mutex_unlock(¬es->lock); |
36532461a perf top: Ditch p... |
166 167 168 |
pr_err("Not enough memory for annotating '%s' symbol! ", sym->name); |
ce6f4fab4 perf annotate: Mo... |
169 |
sleep(1); |
c97cf4221 perf top: Live TU... |
170 |
return err; |
923c42c19 perf_counter tool... |
171 |
} |
36532461a perf top: Ditch p... |
172 |
|
ab81f3fd3 perf top: Reuse t... |
173 |
err = symbol__annotate(sym, map, 0); |
36532461a perf top: Ditch p... |
174 |
if (err == 0) { |
923c42c19 perf_counter tool... |
175 |
out_assign: |
ab81f3fd3 perf top: Reuse t... |
176 |
top.sym_filter_entry = he; |
36532461a perf top: Ditch p... |
177 |
} |
c97cf4221 perf top: Live TU... |
178 |
|
ce6f4fab4 perf annotate: Mo... |
179 |
pthread_mutex_unlock(¬es->lock); |
36532461a perf top: Ditch p... |
180 |
return err; |
923c42c19 perf_counter tool... |
181 |
} |
ab81f3fd3 perf top: Reuse t... |
182 |
static void __zero_source_counters(struct hist_entry *he) |
923c42c19 perf_counter tool... |
183 |
{ |
ab81f3fd3 perf top: Reuse t... |
184 |
struct symbol *sym = he->ms.sym; |
36532461a perf top: Ditch p... |
185 |
symbol__annotate_zero_histograms(sym); |
923c42c19 perf_counter tool... |
186 |
} |
ab81f3fd3 perf top: Reuse t... |
187 |
static void record_precise_ip(struct hist_entry *he, int counter, u64 ip) |
923c42c19 perf_counter tool... |
188 |
{ |
ce6f4fab4 perf annotate: Mo... |
189 190 |
struct annotation *notes; struct symbol *sym; |
ab81f3fd3 perf top: Reuse t... |
191 |
if (he == NULL || he->ms.sym == NULL || |
f9e3d4b1a perf top: Fix liv... |
192 193 |
((top.sym_filter_entry == NULL || top.sym_filter_entry->ms.sym != he->ms.sym) && use_browser != 1)) |
923c42c19 perf_counter tool... |
194 |
return; |
ab81f3fd3 perf top: Reuse t... |
195 |
sym = he->ms.sym; |
ce6f4fab4 perf annotate: Mo... |
196 197 198 |
notes = symbol__annotation(sym); if (pthread_mutex_trylock(¬es->lock)) |
923c42c19 perf_counter tool... |
199 |
return; |
ab81f3fd3 perf top: Reuse t... |
200 201 202 203 204 205 206 207 208 209 210 211 |
if (notes->src == NULL && symbol__alloc_hist(sym, top.evlist->nr_entries) < 0) { 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... |
212 |
|
ce6f4fab4 perf annotate: Mo... |
213 |
pthread_mutex_unlock(¬es->lock); |
923c42c19 perf_counter tool... |
214 |
} |
ab81f3fd3 perf top: Reuse t... |
215 |
static void show_details(struct hist_entry *he) |
923c42c19 perf_counter tool... |
216 |
{ |
ce6f4fab4 perf annotate: Mo... |
217 |
struct annotation *notes; |
923c42c19 perf_counter tool... |
218 |
struct symbol *symbol; |
36532461a perf top: Ditch p... |
219 |
int more; |
923c42c19 perf_counter tool... |
220 |
|
ab81f3fd3 perf top: Reuse t... |
221 |
if (!he) |
923c42c19 perf_counter tool... |
222 |
return; |
ab81f3fd3 perf top: Reuse t... |
223 |
symbol = he->ms.sym; |
ce6f4fab4 perf annotate: Mo... |
224 225 226 227 228 229 |
notes = symbol__annotation(symbol); pthread_mutex_lock(¬es->lock); if (notes->src == NULL) goto out_unlock; |
923c42c19 perf_counter tool... |
230 |
|
8c3e10eb1 perf top: Move di... |
231 232 |
printf("Showing %s for %s ", event_name(top.sym_evsel), symbol->name); |
923c42c19 perf_counter tool... |
233 234 |
printf(" Events Pcnt (>=%d%%) ", sym_pcnt_filter); |
ab81f3fd3 perf top: Reuse t... |
235 |
more = symbol__annotate_printf(symbol, he->ms.map, top.sym_evsel->idx, |
d5e3d7470 perf annotate: Fi... |
236 |
0, sym_pcnt_filter, top.print_entries, 4); |
36532461a perf top: Ditch p... |
237 238 239 |
if (top.zero) symbol__annotate_zero_histogram(symbol, top.sym_evsel->idx); else |
ce6f4fab4 perf annotate: Mo... |
240 |
symbol__annotate_decay_histogram(symbol, top.sym_evsel->idx); |
36532461a perf top: Ditch p... |
241 |
if (more != 0) |
923c42c19 perf_counter tool... |
242 243 |
printf("%d lines not displayed, maybe increase display entries [e] ", more); |
ce6f4fab4 perf annotate: Mo... |
244 245 |
out_unlock: pthread_mutex_unlock(¬es->lock); |
923c42c19 perf_counter tool... |
246 |
} |
078006012 perf_counter tool... |
247 |
|
078006012 perf_counter tool... |
248 |
static const char CONSOLE_CLEAR[] = "[H[2J"; |
ab81f3fd3 perf top: Reuse t... |
249 250 251 252 253 |
static struct hist_entry * perf_session__add_hist_entry(struct perf_session *session, struct addr_location *al, struct perf_sample *sample, struct perf_evsel *evsel) |
de04687f8 perf_counter tool... |
254 |
{ |
ab81f3fd3 perf top: Reuse t... |
255 256 257 258 259 260 261 262 263 |
struct hist_entry *he; he = __hists__add_entry(&evsel->hists, al, NULL, sample->period); if (he == NULL) return NULL; session->hists.stats.total_period += sample->period; hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE); return he; |
de04687f8 perf_counter tool... |
264 |
} |
078006012 perf_counter tool... |
265 |
|
dcc101d1d perf top: Improve... |
266 |
static void print_sym_table(void) |
078006012 perf_counter tool... |
267 |
{ |
8c3e10eb1 perf top: Move di... |
268 269 |
char bf[160]; int printed = 0; |
13cc5079f perf top: Auto ad... |
270 |
const int win_width = winsize.ws_col - 1; |
d94b94305 perf top: Reduce ... |
271 |
|
0f5486b5c perf_counter: Sle... |
272 |
puts(CONSOLE_CLEAR); |
078006012 perf_counter tool... |
273 |
|
8c3e10eb1 perf top: Move di... |
274 275 276 |
perf_top__header_snprintf(&top, bf, sizeof(bf)); printf("%s ", bf); |
078006012 perf_counter tool... |
277 |
|
8c3e10eb1 perf top: Move di... |
278 |
perf_top__reset_sample_counters(&top); |
078006012 perf_counter tool... |
279 |
|
1a105f743 perf top: Suppres... |
280 281 |
printf("%-*.*s ", win_width, win_width, graph_dotted_line); |
078006012 perf_counter tool... |
282 |
|
7b27509fc perf hists browse... |
283 284 285 286 287 288 289 |
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]; color_fprintf(stdout, PERF_COLOR_RED, "WARNING: LOST %d chunks, Check IO/CPU overload", top.sym_evsel->hists.stats.nr_lost_warned); |
ab81f3fd3 perf top: Reuse t... |
290 |
++printed; |
93fc64f14 perf top: Switch ... |
291 |
} |
c97cf4221 perf top: Live TU... |
292 293 |
if (top.sym_filter_entry) { show_details(top.sym_filter_entry); |
923c42c19 perf_counter tool... |
294 295 |
return; } |
ab81f3fd3 perf top: Reuse t... |
296 297 |
hists__collapse_resort_threaded(&top.sym_evsel->hists); hists__output_resort_threaded(&top.sym_evsel->hists); |
b079d4e97 perf top: Honour ... |
298 299 300 |
hists__decay_entries_threaded(&top.sym_evsel->hists, top.hide_user_symbols, top.hide_kernel_symbols); |
ab81f3fd3 perf top: Reuse t... |
301 |
hists__output_recalc_col_len(&top.sym_evsel->hists, winsize.ws_row - 3); |
7cc017edb perf top: Always ... |
302 303 |
putchar(' '); |
ab81f3fd3 perf top: Reuse t... |
304 305 |
hists__fprintf(&top.sym_evsel->hists, NULL, false, false, winsize.ws_row - 4 - printed, win_width, stdout); |
078006012 perf_counter tool... |
306 |
} |
923c42c19 perf_counter tool... |
307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 |
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; } |
ab81f3fd3 perf top: Reuse t... |
343 |
static void prompt_symbol(struct hist_entry **target, const char *msg) |
923c42c19 perf_counter tool... |
344 345 |
{ char *buf = malloc(0), *p; |
ab81f3fd3 perf top: Reuse t... |
346 347 |
struct hist_entry *syme = *target, *n, *found = NULL; struct rb_node *next; |
923c42c19 perf_counter tool... |
348 349 350 351 |
size_t dummy = 0; /* zero counters of active symbol */ if (syme) { |
923c42c19 perf_counter tool... |
352 353 |
__zero_source_counters(syme); *target = NULL; |
923c42c19 perf_counter tool... |
354 355 356 357 358 359 360 361 362 363 364 |
} fprintf(stdout, " %s: ", msg); if (getline(&buf, &dummy, stdin) < 0) goto out_free; p = strchr(buf, ' '); if (p) *p = 0; |
ab81f3fd3 perf top: Reuse t... |
365 366 367 368 369 |
next = rb_first(&top.sym_evsel->hists.entries); 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... |
370 371 |
break; } |
ab81f3fd3 perf top: Reuse t... |
372 |
next = rb_next(&n->rb_node); |
923c42c19 perf_counter tool... |
373 374 375 |
} if (!found) { |
66aeb6d5c perf top: Fix cod... |
376 377 |
fprintf(stderr, "Sorry, %s is not active. ", buf); |
923c42c19 perf_counter tool... |
378 379 380 381 382 383 384 385 |
sleep(1); return; } else parse_source(found); out_free: free(buf); } |
091bd2e99 perf top: Improve... |
386 |
static void print_mapped_keys(void) |
923c42c19 perf_counter tool... |
387 |
{ |
091bd2e99 perf top: Improve... |
388 |
char *name = NULL; |
c97cf4221 perf top: Live TU... |
389 |
if (top.sym_filter_entry) { |
ab81f3fd3 perf top: Reuse t... |
390 |
struct symbol *sym = top.sym_filter_entry->ms.sym; |
091bd2e99 perf top: Improve... |
391 392 393 394 395 396 |
name = sym->name; } fprintf(stdout, " Mapped keys: "); |
8c3e10eb1 perf top: Move di... |
397 398 399 400 |
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... |
401 |
|
8c3e10eb1 perf top: Move di... |
402 403 404 |
if (top.evlist->nr_entries > 1) fprintf(stdout, "\t[E] active event counter. \t(%s) ", event_name(top.sym_evsel)); |
091bd2e99 perf top: Improve... |
405 |
|
8c3e10eb1 perf top: Move di... |
406 407 |
fprintf(stdout, "\t[f] profile display filter (count). \t(%d) ", top.count_filter); |
091bd2e99 perf top: Improve... |
408 |
|
6cff0e8db perf top: Teach i... |
409 410 411 412 413 414 |
fprintf(stdout, "\t[F] annotate display filter (percent). \t(%d%%) ", sym_pcnt_filter); fprintf(stdout, "\t[s] annotate symbol. \t(%s) ", name?: "NULL"); fprintf(stdout, "\t[S] stop annotation. "); |
091bd2e99 perf top: Improve... |
415 |
|
8ffcda173 perf top: Introdu... |
416 |
fprintf(stdout, |
1a72cfa68 perf top: Fix hel... |
417 418 |
"\t[K] hide kernel_symbols symbols. \t(%s) ", |
8c3e10eb1 perf top: Move di... |
419 |
top.hide_kernel_symbols ? "yes" : "no"); |
8ffcda173 perf top: Introdu... |
420 421 422 |
fprintf(stdout, "\t[U] hide user symbols. \t(%s) ", |
8c3e10eb1 perf top: Move di... |
423 424 425 |
top.hide_user_symbols ? "yes" : "no"); fprintf(stdout, "\t[z] toggle sample zeroing. \t(%d) ", top.zero ? 1 : 0); |
091bd2e99 perf top: Improve... |
426 427 428 429 430 431 432 433 434 435 436 437 438 |
fprintf(stdout, "\t[qQ] quit. "); } static int key_mapped(int c) { switch (c) { case 'd': case 'e': case 'f': case 'z': case 'q': case 'Q': |
8ffcda173 perf top: Introdu... |
439 440 |
case 'K': case 'U': |
6cff0e8db perf top: Teach i... |
441 442 443 |
case 'F': case 's': case 'S': |
091bd2e99 perf top: Improve... |
444 445 |
return 1; case 'E': |
b2b7e9eb2 perf top: Fix the... |
446 |
return top.evlist->nr_entries > 1 ? 1 : 0; |
83a0944fa perf: Enable more... |
447 448 |
default: break; |
091bd2e99 perf top: Improve... |
449 450 451 |
} return 0; |
923c42c19 perf_counter tool... |
452 |
} |
dcc101d1d perf top: Improve... |
453 |
static void handle_keypress(int c) |
923c42c19 perf_counter tool... |
454 |
{ |
091bd2e99 perf top: Improve... |
455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 |
if (!key_mapped(c)) { struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; struct termios tc, save; print_mapped_keys(); 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); if (!key_mapped(c)) return; } |
923c42c19 perf_counter tool... |
478 479 |
switch (c) { case 'd': |
8c3e10eb1 perf top: Move di... |
480 481 482 |
prompt_integer(&top.delay_secs, "Enter display delay"); if (top.delay_secs < 1) top.delay_secs = 1; |
923c42c19 perf_counter tool... |
483 484 |
break; case 'e': |
8c3e10eb1 perf top: Move di... |
485 486 |
prompt_integer(&top.print_entries, "Enter display entries (lines)"); if (top.print_entries == 0) { |
13cc5079f perf top: Auto ad... |
487 |
sig_winch_handler(SIGWINCH); |
3b6ed9889 perf top: Use all... |
488 489 490 |
signal(SIGWINCH, sig_winch_handler); } else signal(SIGWINCH, SIG_DFL); |
923c42c19 perf_counter tool... |
491 492 |
break; case 'E': |
8c3e10eb1 perf top: Move di... |
493 |
if (top.evlist->nr_entries > 1) { |
ce2d17ca7 perf top: Fix uni... |
494 495 |
/* Select 0 as the default event: */ int counter = 0; |
923c42c19 perf_counter tool... |
496 497 |
fprintf(stderr, " Available events:"); |
69aad6f1e perf tools: Intro... |
498 |
|
8c3e10eb1 perf top: Move di... |
499 500 501 |
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... |
502 |
|
ec52d9765 perf top: Remove ... |
503 |
prompt_integer(&counter, "Enter details event counter"); |
923c42c19 perf_counter tool... |
504 |
|
ec52d9765 perf top: Remove ... |
505 |
if (counter >= top.evlist->nr_entries) { |
8c3e10eb1 perf top: Move di... |
506 |
top.sym_evsel = list_entry(top.evlist->entries.next, struct perf_evsel, node); |
8c3e10eb1 perf top: Move di... |
507 508 |
fprintf(stderr, "Sorry, no such event, using %s. ", event_name(top.sym_evsel)); |
923c42c19 perf_counter tool... |
509 |
sleep(1); |
69aad6f1e perf tools: Intro... |
510 |
break; |
923c42c19 perf_counter tool... |
511 |
} |
8c3e10eb1 perf top: Move di... |
512 |
list_for_each_entry(top.sym_evsel, &top.evlist->entries, node) |
ec52d9765 perf top: Remove ... |
513 |
if (top.sym_evsel->idx == counter) |
69aad6f1e perf tools: Intro... |
514 |
break; |
ec52d9765 perf top: Remove ... |
515 516 |
} else top.sym_evsel = list_entry(top.evlist->entries.next, struct perf_evsel, node); |
923c42c19 perf_counter tool... |
517 518 |
break; case 'f': |
8c3e10eb1 perf top: Move di... |
519 |
prompt_integer(&top.count_filter, "Enter display event count filter"); |
923c42c19 perf_counter tool... |
520 521 522 523 |
break; case 'F': prompt_percent(&sym_pcnt_filter, "Enter details display event filter (percent)"); break; |
8ffcda173 perf top: Introdu... |
524 |
case 'K': |
8c3e10eb1 perf top: Move di... |
525 |
top.hide_kernel_symbols = !top.hide_kernel_symbols; |
8ffcda173 perf top: Introdu... |
526 |
break; |
923c42c19 perf_counter tool... |
527 528 529 530 |
case 'q': case 'Q': printf("exiting. "); |
c338aee85 perf symbols: Do ... |
531 |
if (dump_symtab) |
dcc101d1d perf top: Improve... |
532 |
perf_session__fprintf_dsos(top.session, stderr); |
923c42c19 perf_counter tool... |
533 534 |
exit(0); case 's': |
c97cf4221 perf top: Live TU... |
535 |
prompt_symbol(&top.sym_filter_entry, "Enter details symbol"); |
923c42c19 perf_counter tool... |
536 537 |
break; case 'S': |
c97cf4221 perf top: Live TU... |
538 |
if (!top.sym_filter_entry) |
923c42c19 perf_counter tool... |
539 540 |
break; else { |
ab81f3fd3 perf top: Reuse t... |
541 |
struct hist_entry *syme = top.sym_filter_entry; |
923c42c19 perf_counter tool... |
542 |
|
c97cf4221 perf top: Live TU... |
543 |
top.sym_filter_entry = NULL; |
923c42c19 perf_counter tool... |
544 |
__zero_source_counters(syme); |
923c42c19 perf_counter tool... |
545 546 |
} break; |
8ffcda173 perf top: Introdu... |
547 |
case 'U': |
8c3e10eb1 perf top: Move di... |
548 |
top.hide_user_symbols = !top.hide_user_symbols; |
8ffcda173 perf top: Introdu... |
549 |
break; |
923c42c19 perf_counter tool... |
550 |
case 'z': |
8c3e10eb1 perf top: Move di... |
551 |
top.zero = !top.zero; |
923c42c19 perf_counter tool... |
552 |
break; |
83a0944fa perf: Enable more... |
553 554 |
default: break; |
923c42c19 perf_counter tool... |
555 556 |
} } |
ab81f3fd3 perf top: Reuse t... |
557 558 559 560 561 562 563 564 565 566 |
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 ... |
567 568 569 |
hists__decay_entries_threaded(&t->sym_evsel->hists, top.hide_user_symbols, top.hide_kernel_symbols); |
ab81f3fd3 perf top: Reuse t... |
570 |
} |
c0443df1b perf top: Introdu... |
571 572 |
static void *display_thread_tui(void *arg __used) { |
ab81f3fd3 perf top: Reuse t... |
573 574 575 576 577 578 |
const char *help = "For a higher level overview, try: perf top --sort comm,dso"; perf_top__sort_new_samples(&top); perf_evlist__tui_browse_hists(top.evlist, help, perf_top__sort_new_samples, &top, top.delay_secs); |
c0443df1b perf top: Introdu... |
579 580 581 582 |
exit_browser(0); exit(0); return NULL; } |
f37a291c5 perf_counter tool... |
583 |
static void *display_thread(void *arg __used) |
078006012 perf_counter tool... |
584 |
{ |
0f5486b5c perf_counter: Sle... |
585 |
struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; |
923c42c19 perf_counter tool... |
586 587 588 589 590 591 592 593 |
struct termios tc, save; 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... |
594 |
|
3af6e3386 perf ui browser: ... |
595 |
pthread__unblock_sigwinch(); |
923c42c19 perf_counter tool... |
596 |
repeat: |
8c3e10eb1 perf top: Move di... |
597 |
delay_msecs = top.delay_secs * 1000; |
923c42c19 perf_counter tool... |
598 599 600 |
tcsetattr(0, TCSANOW, &tc); /* trash return*/ getc(stdin); |
078006012 perf_counter tool... |
601 |
|
3af6e3386 perf ui browser: ... |
602 |
while (1) { |
dcc101d1d perf top: Improve... |
603 |
print_sym_table(); |
3af6e3386 perf ui browser: ... |
604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 |
/* * 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... |
620 621 |
c = getc(stdin); tcsetattr(0, TCSAFLUSH, &save); |
dcc101d1d perf top: Improve... |
622 |
handle_keypress(c); |
923c42c19 perf_counter tool... |
623 |
goto repeat; |
078006012 perf_counter tool... |
624 625 626 |
return NULL; } |
2ab52083f perf top: Move sk... |
627 |
/* Tag samples to be skipped. */ |
f37a291c5 perf_counter tool... |
628 |
static const char *skip_symbols[] = { |
2ab52083f perf top: Move sk... |
629 |
"default_idle", |
b0e8572f3 perf top: Add nat... |
630 |
"native_safe_halt", |
2ab52083f perf top: Move sk... |
631 632 633 634 |
"cpu_idle", "enter_idle", "exit_idle", "mwait_idle", |
59b900569 perf top: Add mwa... |
635 |
"mwait_idle_with_hints", |
8357275bb perf top: Add pol... |
636 |
"poll_idle", |
3a3393ef7 perf top: Add ppc... |
637 638 |
"ppc64_runlatch_off", "pseries_dedicated_idle_sleep", |
2ab52083f perf top: Move sk... |
639 640 |
NULL }; |
ab81f3fd3 perf top: Reuse t... |
641 |
static int symbol_filter(struct map *map __used, struct symbol *sym) |
078006012 perf_counter tool... |
642 |
{ |
de04687f8 perf_counter tool... |
643 |
const char *name = sym->name; |
2ab52083f perf top: Move sk... |
644 |
int i; |
de04687f8 perf_counter tool... |
645 |
|
3a3393ef7 perf top: Add ppc... |
646 647 648 649 650 651 |
/* * ppc64 uses function descriptors and appends a '.' to the * start of every instruction address. Remove it. */ if (name[0] == '.') name++; |
de04687f8 perf_counter tool... |
652 653 654 655 656 657 658 |
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... |
659 |
return 1; |
078006012 perf_counter tool... |
660 |
|
2ab52083f perf top: Move sk... |
661 662 |
for (i = 0; skip_symbols[i]; i++) { if (!strcmp(skip_symbols[i], name)) { |
171b3be9c perf symbol: Move... |
663 |
sym->ignore = true; |
2ab52083f perf top: Move sk... |
664 665 666 |
break; } } |
078006012 perf_counter tool... |
667 |
|
078006012 perf_counter tool... |
668 669 |
return 0; } |
8115d60c3 perf tools: Kill ... |
670 |
static void perf_event__process_sample(const union perf_event *event, |
7b27509fc perf hists browse... |
671 |
struct perf_evsel *evsel, |
8115d60c3 perf tools: Kill ... |
672 673 |
struct perf_sample *sample, struct perf_session *session) |
078006012 perf_counter tool... |
674 |
{ |
19d4ac3c1 perf top: Add cal... |
675 |
struct symbol *parent = NULL; |
8115d60c3 perf tools: Kill ... |
676 |
u64 ip = event->ip.ip; |
1ed091c45 perf tools: Conso... |
677 |
struct addr_location al; |
23346f21b perf tools: Renam... |
678 |
struct machine *machine; |
19d4ac3c1 perf top: Add cal... |
679 |
int err; |
8115d60c3 perf tools: Kill ... |
680 |
u8 origin = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; |
5b2bb75a0 perf top: Support... |
681 |
|
8c3e10eb1 perf top: Move di... |
682 |
++top.samples; |
24bfef0f9 perf top: Fix sam... |
683 |
|
8ffcda173 perf top: Introdu... |
684 |
switch (origin) { |
1ed091c45 perf tools: Conso... |
685 |
case PERF_RECORD_MISC_USER: |
8c3e10eb1 perf top: Move di... |
686 687 |
++top.us_samples; if (top.hide_user_symbols) |
8ffcda173 perf top: Introdu... |
688 |
return; |
23346f21b perf tools: Renam... |
689 |
machine = perf_session__find_host_machine(session); |
1ed091c45 perf tools: Conso... |
690 |
break; |
5b2bb75a0 perf top: Support... |
691 |
case PERF_RECORD_MISC_KERNEL: |
8c3e10eb1 perf top: Move di... |
692 693 |
++top.kernel_samples; if (top.hide_kernel_symbols) |
8ffcda173 perf top: Introdu... |
694 |
return; |
23346f21b perf tools: Renam... |
695 |
machine = perf_session__find_host_machine(session); |
a1645ce12 perf: 'perf kvm' ... |
696 697 |
break; case PERF_RECORD_MISC_GUEST_KERNEL: |
8c3e10eb1 perf top: Move di... |
698 |
++top.guest_kernel_samples; |
8115d60c3 perf tools: Kill ... |
699 |
machine = perf_session__find_machine(session, event->ip.pid); |
5b2bb75a0 perf top: Support... |
700 |
break; |
a1645ce12 perf: 'perf kvm' ... |
701 |
case PERF_RECORD_MISC_GUEST_USER: |
8c3e10eb1 perf top: Move di... |
702 |
++top.guest_us_samples; |
a1645ce12 perf: 'perf kvm' ... |
703 704 705 706 707 |
/* * TODO: we don't process guest user from host side * except simple counting. */ return; |
5b2bb75a0 perf top: Support... |
708 709 710 |
default: return; } |
23346f21b perf tools: Renam... |
711 |
if (!machine && perf_guest) { |
a1645ce12 perf: 'perf kvm' ... |
712 713 |
pr_err("Can't find guest [%d]'s kernel information ", |
8115d60c3 perf tools: Kill ... |
714 |
event->ip.pid); |
a1645ce12 perf: 'perf kvm' ... |
715 716 |
return; } |
8115d60c3 perf tools: Kill ... |
717 |
if (event->header.misc & PERF_RECORD_MISC_EXACT_IP) |
8c3e10eb1 perf top: Move di... |
718 |
top.exact_samples++; |
1676b8a07 perf-top: Show th... |
719 |
|
8115d60c3 perf tools: Kill ... |
720 721 |
if (perf_event__preprocess_sample(event, session, &al, sample, symbol_filter) < 0 || |
72b8fa173 perf top: Exit if... |
722 |
al.filtered) |
1ed091c45 perf tools: Conso... |
723 |
return; |
078006012 perf_counter tool... |
724 |
|
5f6f55809 perf top: Handle ... |
725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 |
if (!kptr_restrict_warned && 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); kptr_restrict_warned = true; } |
72b8fa173 perf top: Exit if... |
743 |
if (al.sym == NULL) { |
e4a338d05 perf top: Don't s... |
744 745 |
const char *msg = "Kernel samples will not be resolved. "; |
72b8fa173 perf top: Exit if... |
746 747 748 749 750 751 752 753 754 755 756 |
/* * 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 ;-) */ |
e4a338d05 perf top: Don't s... |
757 758 |
if (!kptr_restrict_warned && !vmlinux_warned && al.map == machine->vmlinux_maps[MAP__FUNCTION] && |
72b8fa173 perf top: Exit if... |
759 |
RB_EMPTY_ROOT(&al.map->dso->symbols[MAP__FUNCTION])) { |
e4a338d05 perf top: Don't s... |
760 761 762 763 764 765 766 767 768 769 770 771 772 |
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); vmlinux_warned = true; |
72b8fa173 perf top: Exit if... |
773 |
} |
6cff0e8db perf top: Teach i... |
774 |
} |
ab81f3fd3 perf top: Reuse t... |
775 |
if (al.sym == NULL || !al.sym->ignore) { |
ab81f3fd3 perf top: Reuse t... |
776 |
struct hist_entry *he; |
70db7533c perf evlist: Move... |
777 |
|
19d4ac3c1 perf top: Add cal... |
778 779 780 781 782 783 784 |
if ((sort__has_parent || symbol_conf.use_callchain) && sample->callchain) { err = perf_session__resolve_callchain(session, al.thread, sample->callchain, &parent); if (err) return; } |
ab81f3fd3 perf top: Reuse t... |
785 786 787 788 789 |
he = perf_session__add_hist_entry(session, &al, sample, evsel); if (he == NULL) { pr_err("Problem incrementing symbol period, skipping event "); return; |
5807806a9 perf top tui: Wai... |
790 |
} |
ab81f3fd3 perf top: Reuse t... |
791 |
|
19d4ac3c1 perf top: Add cal... |
792 793 794 795 796 797 798 799 800 |
if (symbol_conf.use_callchain) { err = callchain_append(he->callchain, &session->callchain_cursor, sample->period); if (err) return; } if (sort_has_symbols) record_precise_ip(he, evsel->idx, ip); |
5b2bb75a0 perf top: Support... |
801 |
} |
ab81f3fd3 perf top: Reuse t... |
802 803 |
return; |
078006012 perf_counter tool... |
804 |
} |
aece948f5 perf evlist: Fix ... |
805 |
static void perf_session__mmap_read_idx(struct perf_session *self, int idx) |
078006012 perf_counter tool... |
806 |
{ |
8d50e5b41 perf tools: Renam... |
807 |
struct perf_sample sample; |
7b27509fc perf hists browse... |
808 |
struct perf_evsel *evsel; |
8115d60c3 perf tools: Kill ... |
809 |
union perf_event *event; |
5538becae perf tools: Propa... |
810 |
int ret; |
078006012 perf_counter tool... |
811 |
|
aece948f5 perf evlist: Fix ... |
812 |
while ((event = perf_evlist__mmap_read(top.evlist, idx)) != NULL) { |
5538becae perf tools: Propa... |
813 814 815 816 817 818 |
ret = perf_session__parse_sample(self, event, &sample); if (ret) { pr_err("Can't parse sample, err = %d ", ret); continue; } |
04391debc perf evlist: Stea... |
819 |
|
7b27509fc perf hists browse... |
820 821 |
evsel = perf_evlist__id2evsel(self->evlist, sample.id); assert(evsel != NULL); |
5b2bb75a0 perf top: Support... |
822 |
if (event->header.type == PERF_RECORD_SAMPLE) |
7b27509fc perf hists browse... |
823 824 825 |
perf_event__process_sample(event, evsel, &sample, self); else if (event->header.type < PERF_RECORD_MAX) { hists__inc_nr_events(&evsel->hists, event->header.type); |
8115d60c3 perf tools: Kill ... |
826 |
perf_event__process(event, &sample, self); |
7b27509fc perf hists browse... |
827 828 |
} else ++self->hists.stats.nr_unknown_events; |
078006012 perf_counter tool... |
829 |
} |
078006012 perf_counter tool... |
830 |
} |
d8f66248d perf session: Pas... |
831 |
static void perf_session__mmap_read(struct perf_session *self) |
2f01190aa perf top: Wait fo... |
832 |
{ |
70db7533c perf evlist: Move... |
833 |
int i; |
aece948f5 perf evlist: Fix ... |
834 835 |
for (i = 0; i < top.evlist->nr_mmaps; i++) perf_session__mmap_read_idx(self, i); |
2f01190aa perf top: Wait fo... |
836 |
} |
72cb7013e perf top: Use per... |
837 838 |
static void start_counters(struct perf_evlist *evlist) { |
727ab04ed perf evlist: Fix ... |
839 840 841 |
struct perf_evsel *counter, *first; first = list_entry(evlist->entries.next, struct perf_evsel, node); |
7e4ff9e3e perf tools: Fix c... |
842 |
|
72cb7013e perf top: Use per... |
843 844 |
list_for_each_entry(counter, &evlist->entries, node) { struct perf_event_attr *attr = &counter->attr; |
727ab04ed perf evlist: Fix ... |
845 846 847 848 |
struct xyarray *group_fd = NULL; if (group && counter != first) group_fd = first->fd; |
716c69fec perf top: Fall ba... |
849 |
|
72cb7013e perf top: Use per... |
850 |
attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID; |
8c3e10eb1 perf top: Move di... |
851 |
if (top.freq) { |
72cb7013e perf top: Use per... |
852 853 |
attr->sample_type |= PERF_SAMPLE_PERIOD; attr->freq = 1; |
8c3e10eb1 perf top: Move di... |
854 |
attr->sample_freq = top.freq; |
72cb7013e perf top: Use per... |
855 |
} |
d6d901c23 perf events: Chan... |
856 |
|
70db7533c perf evlist: Move... |
857 858 859 860 |
if (evlist->nr_entries > 1) { attr->sample_type |= PERF_SAMPLE_ID; attr->read_format |= PERF_FORMAT_ID; } |
19d4ac3c1 perf top: Add cal... |
861 862 |
if (symbol_conf.use_callchain) attr->sample_type |= PERF_SAMPLE_CALLCHAIN; |
72cb7013e perf top: Use per... |
863 |
attr->mmap = 1; |
ab81f3fd3 perf top: Reuse t... |
864 |
attr->comm = 1; |
5d2cd9092 perf evsel: Fix u... |
865 |
attr->inherit = inherit; |
7b27509fc perf hists browse... |
866 867 |
retry_sample_id: attr->sample_id_all = sample_id_all_avail ? 1 : 0; |
72cb7013e perf top: Use per... |
868 |
try_again: |
8c3e10eb1 perf top: Move di... |
869 |
if (perf_evsel__open(counter, top.evlist->cpus, |
727ab04ed perf evlist: Fix ... |
870 871 |
top.evlist->threads, group, group_fd) < 0) { |
d6d901c23 perf events: Chan... |
872 |
int err = errno; |
c286c419c perf tools: Fixup... |
873 |
if (err == EPERM || err == EACCES) { |
b8631e6eb perf ui: Rename u... |
874 |
ui__error_paranoid(); |
c286c419c perf tools: Fixup... |
875 |
goto out_err; |
7b27509fc perf hists browse... |
876 877 878 879 880 881 |
} else if (err == EINVAL && sample_id_all_avail) { /* * Old kernel, no attr->sample_id_type_all field */ sample_id_all_avail = false; goto retry_sample_id; |
c286c419c perf tools: Fixup... |
882 |
} |
d6d901c23 perf events: Chan... |
883 884 885 886 887 |
/* * 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... |
888 889 |
if (attr->type == PERF_TYPE_HARDWARE && attr->config == PERF_COUNT_HW_CPU_CYCLES) { |
d6d901c23 perf events: Chan... |
890 |
if (verbose) |
c286c419c perf tools: Fixup... |
891 892 893 894 |
ui__warning("Cycles event not supported, " "trying to fall back to cpu-clock-ticks "); |
d6d901c23 perf events: Chan... |
895 896 897 898 899 |
attr->type = PERF_TYPE_SOFTWARE; attr->config = PERF_COUNT_SW_CPU_CLOCK; goto try_again; } |
c286c419c perf tools: Fixup... |
900 |
|
ca6a42586 perf tools: Emit ... |
901 902 903 904 905 906 |
if (err == ENOENT) { ui__warning("The %s event is not supported. ", event_name(counter)); goto out_err; } |
c286c419c perf tools: Fixup... |
907 908 909 910 911 912 913 914 |
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... |
915 |
} |
716c69fec perf top: Fall ba... |
916 |
} |
70db7533c perf evlist: Move... |
917 |
|
c286c419c perf tools: Fixup... |
918 919 920 921 922 923 924 925 926 927 928 929 |
if (perf_evlist__mmap(evlist, mmap_pages, false) < 0) { 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... |
930 |
} |
19d4ac3c1 perf top: Add cal... |
931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 |
static int setup_sample_type(void) { if (!sort_has_symbols) { if (symbol_conf.use_callchain) { ui__warning("Selected -g but \"sym\" not present in --sort/-s."); return -EINVAL; } } else if (!dont_use_callchains && callchain_param.mode != CHAIN_NONE) { if (callchain_register_param(&callchain_param) < 0) { ui__warning("Can't register callchain params. "); return -EINVAL; } } return 0; } |
716c69fec perf top: Fall ba... |
948 949 950 |
static int __cmd_top(void) { pthread_t thread; |
19d4ac3c1 perf top: Add cal... |
951 |
int ret; |
d8f66248d perf session: Pas... |
952 |
/* |
b3165f414 perf session: Mov... |
953 954 |
* 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... |
955 |
*/ |
dcc101d1d perf top: Improve... |
956 957 |
top.session = perf_session__new(NULL, O_WRONLY, false, false, NULL); if (top.session == NULL) |
b3165f414 perf session: Mov... |
958 |
return -ENOMEM; |
078006012 perf_counter tool... |
959 |
|
19d4ac3c1 perf top: Add cal... |
960 961 962 |
ret = setup_sample_type(); if (ret) goto out_delete; |
8c3e10eb1 perf top: Move di... |
963 |
if (top.target_tid != -1) |
7c940c18c Merge remote bran... |
964 |
perf_event__synthesize_thread_map(top.evlist->threads, |
dcc101d1d perf top: Improve... |
965 |
perf_event__process, top.session); |
5b2bb75a0 perf top: Support... |
966 |
else |
dcc101d1d perf top: Improve... |
967 |
perf_event__synthesize_threads(perf_event__process, top.session); |
5b2bb75a0 perf top: Support... |
968 |
|
8c3e10eb1 perf top: Move di... |
969 |
start_counters(top.evlist); |
dcc101d1d perf top: Improve... |
970 971 |
top.session->evlist = top.evlist; perf_session__update_sample_type(top.session); |
078006012 perf_counter tool... |
972 |
|
2f01190aa perf top: Wait fo... |
973 |
/* Wait for a minimal set of events before starting the snapshot */ |
8c3e10eb1 perf top: Move di... |
974 |
poll(top.evlist->pollfd, top.evlist->nr_fds, 100); |
2f01190aa perf top: Wait fo... |
975 |
|
dcc101d1d perf top: Improve... |
976 |
perf_session__mmap_read(top.session); |
2f01190aa perf top: Wait fo... |
977 |
|
c0443df1b perf top: Introdu... |
978 |
if (pthread_create(&thread, NULL, (use_browser > 0 ? display_thread_tui : |
dcc101d1d perf top: Improve... |
979 |
display_thread), NULL)) { |
078006012 perf_counter tool... |
980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 |
printf("Could not create display thread. "); exit(-1); } if (realtime_prio) { struct sched_param param; param.sched_priority = realtime_prio; if (sched_setscheduler(0, SCHED_FIFO, ¶m)) { printf("Could not set realtime priority. "); exit(-1); } } while (1) { |
8c3e10eb1 perf top: Move di... |
997 |
u64 hits = top.samples; |
078006012 perf_counter tool... |
998 |
|
dcc101d1d perf top: Improve... |
999 |
perf_session__mmap_read(top.session); |
078006012 perf_counter tool... |
1000 |
|
8c3e10eb1 perf top: Move di... |
1001 1002 |
if (hits == top.samples) ret = poll(top.evlist->pollfd, top.evlist->nr_fds, 100); |
078006012 perf_counter tool... |
1003 |
} |
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 1031 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 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 |
out_delete: perf_session__delete(top.session); top.session = NULL; return 0; } static int parse_callchain_opt(const struct option *opt __used, const char *arg, int unset) { char *tok, *tok2; char *endptr; /* * --no-call-graph */ if (unset) { dont_use_callchains = true; 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; } else 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... |
1089 1090 |
return 0; } |
b456bae0f perf top: Convert... |
1091 1092 1093 1094 1095 |
static const char * const top_usage[] = { "perf top [<options>]", NULL }; |
b456bae0f perf top: Convert... |
1096 |
static const struct option options[] = { |
8c3e10eb1 perf top: Move di... |
1097 |
OPT_CALLBACK('e', "event", &top.evlist, "event", |
86847b62f perf_counter tool... |
1098 |
"event selector. use 'perf list' to list available events", |
f120f9d51 perf tools: De-op... |
1099 |
parse_events_option), |
b456bae0f perf top: Convert... |
1100 1101 |
OPT_INTEGER('c', "count", &default_interval, "event period to sample"), |
8c3e10eb1 perf top: Move di... |
1102 |
OPT_INTEGER('p', "pid", &top.target_pid, |
d6d901c23 perf events: Chan... |
1103 |
"profile events on existing process id"), |
8c3e10eb1 perf top: Move di... |
1104 |
OPT_INTEGER('t', "tid", &top.target_tid, |
d6d901c23 perf events: Chan... |
1105 |
"profile events on existing thread id"), |
b456bae0f perf top: Convert... |
1106 1107 |
OPT_BOOLEAN('a', "all-cpus", &system_wide, "system-wide collection from all CPUs"), |
8c3e10eb1 perf top: Move di... |
1108 |
OPT_STRING('C', "cpu", &top.cpu_list, "cpu", |
c45c6ea2e perf tools: Add t... |
1109 |
"list of cpus to monitor"), |
b32d133ae perf symbols: Sim... |
1110 1111 |
OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, "file", "vmlinux pathname"), |
8c3e10eb1 perf top: Move di... |
1112 |
OPT_BOOLEAN('K', "hide_kernel_symbols", &top.hide_kernel_symbols, |
8ffcda173 perf top: Introdu... |
1113 |
"hide kernel symbols"), |
1967936d6 perf options: Che... |
1114 |
OPT_UINTEGER('m', "mmap-pages", &mmap_pages, "number of mmap data pages"), |
b456bae0f perf top: Convert... |
1115 1116 |
OPT_INTEGER('r', "realtime", &realtime_prio, "collect data with this RT SCHED_FIFO priority"), |
8c3e10eb1 perf top: Move di... |
1117 |
OPT_INTEGER('d', "delay", &top.delay_secs, |
b456bae0f perf top: Convert... |
1118 1119 1120 |
"number of seconds to delay between refreshes"), OPT_BOOLEAN('D', "dump-symtab", &dump_symtab, "dump the symbol table used for profiling"), |
8c3e10eb1 perf top: Move di... |
1121 |
OPT_INTEGER('f', "count-filter", &top.count_filter, |
b456bae0f perf top: Convert... |
1122 1123 1124 |
"only display functions with more events than this"), OPT_BOOLEAN('g', "group", &group, "put the counters into a counter group"), |
0fdc7e67d perf_counter tool... |
1125 1126 |
OPT_BOOLEAN('i', "inherit", &inherit, "child tasks inherit counters"), |
ab81f3fd3 perf top: Reuse t... |
1127 |
OPT_STRING(0, "sym-annotate", &sym_filter, "symbol name", |
6cff0e8db perf top: Teach i... |
1128 |
"symbol to annotate"), |
8c3e10eb1 perf top: Move di... |
1129 |
OPT_BOOLEAN('z', "zero", &top.zero, |
b456bae0f perf top: Convert... |
1130 |
"zero history across updates"), |
8c3e10eb1 perf top: Move di... |
1131 |
OPT_INTEGER('F', "freq", &top.freq, |
b456bae0f perf top: Convert... |
1132 |
"profile at this frequency"), |
8c3e10eb1 perf top: Move di... |
1133 |
OPT_INTEGER('E', "entries", &top.print_entries, |
6e53cdf11 perf top: Reduce ... |
1134 |
"display this many functions"), |
8c3e10eb1 perf top: Move di... |
1135 |
OPT_BOOLEAN('U', "hide_user_symbols", &top.hide_user_symbols, |
8ffcda173 perf top: Introdu... |
1136 |
"hide user symbols"), |
c0443df1b perf top: Introdu... |
1137 1138 |
OPT_BOOLEAN(0, "tui", &use_tui, "Use the TUI interface"), OPT_BOOLEAN(0, "stdio", &use_stdio, "Use the stdio interface"), |
c05556421 perf: Fix endiann... |
1139 |
OPT_INCR('v', "verbose", &verbose, |
3da297a60 perf record: Fall... |
1140 |
"be more verbose (show counter open errors, etc)"), |
ab81f3fd3 perf top: Reuse t... |
1141 1142 1143 1144 |
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"), |
19d4ac3c1 perf top: Add cal... |
1145 1146 1147 1148 |
OPT_CALLBACK_DEFAULT('G', "call-graph", NULL, "output_type,min_percent, call_order", "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... |
1149 1150 1151 1152 1153 1154 1155 1156 |
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 ... |
1157 1158 1159 1160 1161 1162 |
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... |
1163 1164 |
OPT_END() }; |
f37a291c5 perf_counter tool... |
1165 |
int cmd_top(int argc, const char **argv, const char *prefix __used) |
b456bae0f perf top: Convert... |
1166 |
{ |
69aad6f1e perf tools: Intro... |
1167 1168 |
struct perf_evsel *pos; int status = -ENOMEM; |
b456bae0f perf top: Convert... |
1169 |
|
8c3e10eb1 perf top: Move di... |
1170 1171 |
top.evlist = perf_evlist__new(NULL, NULL); if (top.evlist == NULL) |
361c99a66 perf evsel: Intro... |
1172 |
return -ENOMEM; |
ab81f3fd3 perf top: Reuse t... |
1173 |
symbol_conf.exclude_other = false; |
b456bae0f perf top: Convert... |
1174 |
|
b456bae0f perf top: Convert... |
1175 1176 1177 |
argc = parse_options(argc, argv, options, top_usage, 0); if (argc) usage_with_options(top_usage, options); |
ab81f3fd3 perf top: Reuse t... |
1178 1179 1180 1181 |
if (sort_order == default_sort_order) sort_order = "dso,symbol"; setup_sorting(top_usage, options); |
c0443df1b perf top: Introdu... |
1182 1183 1184 1185 1186 1187 |
if (use_stdio) use_browser = 0; else if (use_tui) use_browser = 1; setup_browser(false); |
b456bae0f perf top: Convert... |
1188 |
/* CPU and PID are mutually exclusive */ |
8c3e10eb1 perf top: Move di... |
1189 |
if (top.target_tid > 0 && top.cpu_list) { |
b456bae0f perf top: Convert... |
1190 1191 1192 |
printf("WARNING: PID switch overriding CPU "); sleep(1); |
8c3e10eb1 perf top: Move di... |
1193 |
top.cpu_list = NULL; |
b456bae0f perf top: Convert... |
1194 |
} |
8c3e10eb1 perf top: Move di... |
1195 1196 |
if (top.target_pid != -1) top.target_tid = top.target_pid; |
7e2ed0975 perf evlist: Stor... |
1197 |
|
8c3e10eb1 perf top: Move di... |
1198 1199 |
if (perf_evlist__create_maps(top.evlist, top.target_pid, top.target_tid, top.cpu_list) < 0) |
7e2ed0975 perf evlist: Stor... |
1200 |
usage_with_options(top_usage, options); |
8c3e10eb1 perf top: Move di... |
1201 1202 |
if (!top.evlist->nr_entries && perf_evlist__add_default(top.evlist) < 0) { |
69aad6f1e perf tools: Intro... |
1203 1204 1205 1206 |
pr_err("Not enough memory for event selector list "); return -ENOMEM; } |
5a8e5a306 perf top: Allocat... |
1207 |
|
8c3e10eb1 perf top: Move di... |
1208 1209 |
if (top.delay_secs < 1) top.delay_secs = 1; |
2f335a02b perf top: Fix zer... |
1210 |
|
7e4ff9e3e perf tools: Fix c... |
1211 1212 1213 1214 |
/* * User specified count overrides default frequency. */ if (default_interval) |
8c3e10eb1 perf top: Move di... |
1215 1216 1217 |
top.freq = 0; else if (top.freq) { default_interval = top.freq; |
7e4ff9e3e perf tools: Fix c... |
1218 1219 1220 1221 1222 |
} else { fprintf(stderr, "frequency and count are zero, aborting "); exit(EXIT_FAILURE); } |
8c3e10eb1 perf top: Move di... |
1223 1224 1225 |
list_for_each_entry(pos, &top.evlist->entries, node) { if (perf_evsel__alloc_fd(pos, top.evlist->cpus->nr, top.evlist->threads->nr) < 0) |
69aad6f1e perf tools: Intro... |
1226 1227 1228 1229 1230 1231 1232 1233 1234 |
goto out_free_fd; /* * Fill in the ones not specifically initialized via -c: */ if (pos->attr.sample_period) continue; pos->attr.sample_period = default_interval; } |
8c3e10eb1 perf top: Move di... |
1235 1236 |
if (perf_evlist__alloc_pollfd(top.evlist) < 0 || perf_evlist__alloc_mmap(top.evlist) < 0) |
5c581041c perf evlist: Adop... |
1237 |
goto out_free_fd; |
8c3e10eb1 perf top: Move di... |
1238 |
top.sym_evsel = list_entry(top.evlist->entries.next, struct perf_evsel, node); |
cc841580a perf top: Fix ann... |
1239 |
|
ab81f3fd3 perf top: Reuse t... |
1240 |
symbol_conf.priv_size = sizeof(struct annotation); |
69aad6f1e perf tools: Intro... |
1241 1242 1243 1244 |
symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL); if (symbol__init() < 0) return -1; |
ab81f3fd3 perf top: Reuse t... |
1245 1246 1247 |
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... |
1248 1249 1250 1251 1252 |
/* * Avoid annotation data structures overhead when symbols aren't on the * sort list. */ sort_has_symbols = sort_sym.list.next != NULL; |
13cc5079f perf top: Auto ad... |
1253 |
get_term_dimensions(&winsize); |
8c3e10eb1 perf top: Move di... |
1254 |
if (top.print_entries == 0) { |
13cc5079f perf top: Auto ad... |
1255 |
update_print_entries(&winsize); |
3b6ed9889 perf top: Use all... |
1256 1257 |
signal(SIGWINCH, sig_winch_handler); } |
69aad6f1e perf tools: Intro... |
1258 1259 |
status = __cmd_top(); out_free_fd: |
8c3e10eb1 perf top: Move di... |
1260 |
perf_evlist__delete(top.evlist); |
69aad6f1e perf tools: Intro... |
1261 1262 |
return status; |
b456bae0f perf top: Convert... |
1263 |
} |