186470930SIngo Molnar /* 286470930SIngo Molnar * builtin-top.c 386470930SIngo Molnar * 486470930SIngo Molnar * Builtin top command: Display a continuously updated profile of 586470930SIngo Molnar * any workload, CPU or specific PID. 686470930SIngo Molnar * 786470930SIngo Molnar * Copyright (C) 2008, Red Hat Inc, Ingo Molnar <mingo@redhat.com> 886470930SIngo Molnar * 986470930SIngo Molnar * Improvements and fixes by: 1086470930SIngo Molnar * 1186470930SIngo Molnar * Arjan van de Ven <arjan@linux.intel.com> 1286470930SIngo Molnar * Yanmin Zhang <yanmin.zhang@intel.com> 1386470930SIngo Molnar * Wu Fengguang <fengguang.wu@intel.com> 1486470930SIngo Molnar * Mike Galbraith <efault@gmx.de> 1586470930SIngo Molnar * Paul Mackerras <paulus@samba.org> 1686470930SIngo Molnar * 1786470930SIngo Molnar * Released under the GPL v2. (and only v2, not any later version) 1886470930SIngo Molnar */ 1986470930SIngo Molnar #include "builtin.h" 2086470930SIngo Molnar 2186470930SIngo Molnar #include "perf.h" 2286470930SIngo Molnar 2386470930SIngo Molnar #include "util/color.h" 24b3165f41SArnaldo Carvalho de Melo #include "util/session.h" 25b3165f41SArnaldo Carvalho de Melo #include "util/symbol.h" 26439d473bSArnaldo Carvalho de Melo #include "util/thread.h" 2786470930SIngo Molnar #include "util/util.h" 2843cbcd8aSArnaldo Carvalho de Melo #include <linux/rbtree.h> 2986470930SIngo Molnar #include "util/parse-options.h" 3086470930SIngo Molnar #include "util/parse-events.h" 31a12b51c4SPaul Mackerras #include "util/cpumap.h" 3286470930SIngo Molnar 338f28827aSFrederic Weisbecker #include "util/debug.h" 348f28827aSFrederic Weisbecker 3586470930SIngo Molnar #include <assert.h> 3686470930SIngo Molnar #include <fcntl.h> 3786470930SIngo Molnar 3886470930SIngo Molnar #include <stdio.h> 39923c42c1SMike Galbraith #include <termios.h> 40923c42c1SMike Galbraith #include <unistd.h> 4186470930SIngo Molnar 4286470930SIngo Molnar #include <errno.h> 4386470930SIngo Molnar #include <time.h> 4486470930SIngo Molnar #include <sched.h> 4586470930SIngo Molnar #include <pthread.h> 4686470930SIngo Molnar 4786470930SIngo Molnar #include <sys/syscall.h> 4886470930SIngo Molnar #include <sys/ioctl.h> 4986470930SIngo Molnar #include <sys/poll.h> 5086470930SIngo Molnar #include <sys/prctl.h> 5186470930SIngo Molnar #include <sys/wait.h> 5286470930SIngo Molnar #include <sys/uio.h> 5386470930SIngo Molnar #include <sys/mman.h> 5486470930SIngo Molnar 5586470930SIngo Molnar #include <linux/unistd.h> 5686470930SIngo Molnar #include <linux/types.h> 5786470930SIngo Molnar 58d6d901c2SZhang, Yanmin static int *fd[MAX_NR_CPUS][MAX_COUNTERS]; 5986470930SIngo Molnar 60c0555642SIan Munsie static bool system_wide = false; 6186470930SIngo Molnar 627e4ff9e3SMike Galbraith static int default_interval = 0; 6386470930SIngo Molnar 64923c42c1SMike Galbraith static int count_filter = 5; 653b6ed988SArnaldo Carvalho de Melo static int print_entries; 6686470930SIngo Molnar 6786470930SIngo Molnar static int target_pid = -1; 68d6d901c2SZhang, Yanmin static int target_tid = -1; 69d6d901c2SZhang, Yanmin static pid_t *all_tids = NULL; 70d6d901c2SZhang, Yanmin static int thread_num = 0; 71c0555642SIan Munsie static bool inherit = false; 7286470930SIngo Molnar static int profile_cpu = -1; 7386470930SIngo Molnar static int nr_cpus = 0; 741967936dSArnaldo Carvalho de Melo static int realtime_prio = 0; 75c0555642SIan Munsie static bool group = false; 7686470930SIngo Molnar static unsigned int page_size; 7786470930SIngo Molnar static unsigned int mmap_pages = 16; 7842e59d7dSIngo Molnar static int freq = 1000; /* 1 KHz */ 7986470930SIngo Molnar 8086470930SIngo Molnar static int delay_secs = 2; 81c0555642SIan Munsie static bool zero = false; 82c0555642SIan Munsie static bool dump_symtab = false; 8386470930SIngo Molnar 848ffcda17SArnaldo Carvalho de Melo static bool hide_kernel_symbols = false; 858ffcda17SArnaldo Carvalho de Melo static bool hide_user_symbols = false; 8613cc5079SArnaldo Carvalho de Melo static struct winsize winsize; 878ffcda17SArnaldo Carvalho de Melo 8886470930SIngo Molnar /* 89923c42c1SMike Galbraith * Source 90923c42c1SMike Galbraith */ 91923c42c1SMike Galbraith 92923c42c1SMike Galbraith struct source_line { 93923c42c1SMike Galbraith u64 eip; 94923c42c1SMike Galbraith unsigned long count[MAX_COUNTERS]; 95923c42c1SMike Galbraith char *line; 96923c42c1SMike Galbraith struct source_line *next; 97923c42c1SMike Galbraith }; 98923c42c1SMike Galbraith 99edb7c60eSArnaldo Carvalho de Melo static const char *sym_filter = NULL; 100923c42c1SMike Galbraith struct sym_entry *sym_filter_entry = NULL; 1016cff0e8dSKirill Smelkov struct sym_entry *sym_filter_entry_sched = NULL; 102923c42c1SMike Galbraith static int sym_pcnt_filter = 5; 103923c42c1SMike Galbraith static int sym_counter = 0; 10446ab9764SMike Galbraith static int display_weighted = -1; 105c45c6ea2SStephane Eranian static const char *cpu_list; 106923c42c1SMike Galbraith 107923c42c1SMike Galbraith /* 10886470930SIngo Molnar * Symbols 10986470930SIngo Molnar */ 11086470930SIngo Molnar 111b269876cSArnaldo Carvalho de Melo struct sym_entry_source { 112b269876cSArnaldo Carvalho de Melo struct source_line *source; 113b269876cSArnaldo Carvalho de Melo struct source_line *lines; 114b269876cSArnaldo Carvalho de Melo struct source_line **lines_tail; 115b269876cSArnaldo Carvalho de Melo pthread_mutex_t lock; 116b269876cSArnaldo Carvalho de Melo }; 117b269876cSArnaldo Carvalho de Melo 11886470930SIngo Molnar struct sym_entry { 11986470930SIngo Molnar struct rb_node rb_node; 12086470930SIngo Molnar struct list_head node; 12186470930SIngo Molnar unsigned long snap_count; 12286470930SIngo Molnar double weight; 12386470930SIngo Molnar int skip; 12413cc5079SArnaldo Carvalho de Melo u16 name_len; 1258ffcda17SArnaldo Carvalho de Melo u8 origin; 126439d473bSArnaldo Carvalho de Melo struct map *map; 127b269876cSArnaldo Carvalho de Melo struct sym_entry_source *src; 1285a8e5a30SArnaldo Carvalho de Melo unsigned long count[0]; 12986470930SIngo Molnar }; 13086470930SIngo Molnar 131923c42c1SMike Galbraith /* 132923c42c1SMike Galbraith * Source functions 133923c42c1SMike Galbraith */ 134923c42c1SMike Galbraith 13551a472deSArnaldo Carvalho de Melo static inline struct symbol *sym_entry__symbol(struct sym_entry *self) 13651a472deSArnaldo Carvalho de Melo { 137b32d133aSArnaldo Carvalho de Melo return ((void *)self) + symbol_conf.priv_size; 13851a472deSArnaldo Carvalho de Melo } 13951a472deSArnaldo Carvalho de Melo 140895f0edcSArnaldo Carvalho de Melo void get_term_dimensions(struct winsize *ws) 1413b6ed988SArnaldo Carvalho de Melo { 14213cc5079SArnaldo Carvalho de Melo char *s = getenv("LINES"); 1433b6ed988SArnaldo Carvalho de Melo 14413cc5079SArnaldo Carvalho de Melo if (s != NULL) { 14513cc5079SArnaldo Carvalho de Melo ws->ws_row = atoi(s); 14613cc5079SArnaldo Carvalho de Melo s = getenv("COLUMNS"); 14713cc5079SArnaldo Carvalho de Melo if (s != NULL) { 14813cc5079SArnaldo Carvalho de Melo ws->ws_col = atoi(s); 14913cc5079SArnaldo Carvalho de Melo if (ws->ws_row && ws->ws_col) 15013cc5079SArnaldo Carvalho de Melo return; 15113cc5079SArnaldo Carvalho de Melo } 15213cc5079SArnaldo Carvalho de Melo } 1533b6ed988SArnaldo Carvalho de Melo #ifdef TIOCGWINSZ 15413cc5079SArnaldo Carvalho de Melo if (ioctl(1, TIOCGWINSZ, ws) == 0 && 15513cc5079SArnaldo Carvalho de Melo ws->ws_row && ws->ws_col) 15613cc5079SArnaldo Carvalho de Melo return; 1573b6ed988SArnaldo Carvalho de Melo #endif 15813cc5079SArnaldo Carvalho de Melo ws->ws_row = 25; 15913cc5079SArnaldo Carvalho de Melo ws->ws_col = 80; 1603b6ed988SArnaldo Carvalho de Melo } 1613b6ed988SArnaldo Carvalho de Melo 16213cc5079SArnaldo Carvalho de Melo static void update_print_entries(struct winsize *ws) 1633b6ed988SArnaldo Carvalho de Melo { 16413cc5079SArnaldo Carvalho de Melo print_entries = ws->ws_row; 16513cc5079SArnaldo Carvalho de Melo 1663b6ed988SArnaldo Carvalho de Melo if (print_entries > 9) 1673b6ed988SArnaldo Carvalho de Melo print_entries -= 9; 1683b6ed988SArnaldo Carvalho de Melo } 1693b6ed988SArnaldo Carvalho de Melo 1703b6ed988SArnaldo Carvalho de Melo static void sig_winch_handler(int sig __used) 1713b6ed988SArnaldo Carvalho de Melo { 17213cc5079SArnaldo Carvalho de Melo get_term_dimensions(&winsize); 17313cc5079SArnaldo Carvalho de Melo update_print_entries(&winsize); 1743b6ed988SArnaldo Carvalho de Melo } 1753b6ed988SArnaldo Carvalho de Melo 176b0a9ab62SArnaldo Carvalho de Melo static int parse_source(struct sym_entry *syme) 177923c42c1SMike Galbraith { 178923c42c1SMike Galbraith struct symbol *sym; 179b269876cSArnaldo Carvalho de Melo struct sym_entry_source *source; 180439d473bSArnaldo Carvalho de Melo struct map *map; 181923c42c1SMike Galbraith FILE *file; 18283a0944fSIngo Molnar char command[PATH_MAX*2]; 183439d473bSArnaldo Carvalho de Melo const char *path; 184439d473bSArnaldo Carvalho de Melo u64 len; 185923c42c1SMike Galbraith 186923c42c1SMike Galbraith if (!syme) 187b0a9ab62SArnaldo Carvalho de Melo return -1; 188b0a9ab62SArnaldo Carvalho de Melo 189b0a9ab62SArnaldo Carvalho de Melo sym = sym_entry__symbol(syme); 190b0a9ab62SArnaldo Carvalho de Melo map = syme->map; 191b0a9ab62SArnaldo Carvalho de Melo 192b0a9ab62SArnaldo Carvalho de Melo /* 193b0a9ab62SArnaldo Carvalho de Melo * We can't annotate with just /proc/kallsyms 194b0a9ab62SArnaldo Carvalho de Melo */ 195b0a9ab62SArnaldo Carvalho de Melo if (map->dso->origin == DSO__ORIG_KERNEL) 196b0a9ab62SArnaldo Carvalho de Melo return -1; 197923c42c1SMike Galbraith 198b269876cSArnaldo Carvalho de Melo if (syme->src == NULL) { 19936479484SArnaldo Carvalho de Melo syme->src = zalloc(sizeof(*source)); 200b269876cSArnaldo Carvalho de Melo if (syme->src == NULL) 201b0a9ab62SArnaldo Carvalho de Melo return -1; 202b269876cSArnaldo Carvalho de Melo pthread_mutex_init(&syme->src->lock, NULL); 203b269876cSArnaldo Carvalho de Melo } 204b269876cSArnaldo Carvalho de Melo 205b269876cSArnaldo Carvalho de Melo source = syme->src; 206b269876cSArnaldo Carvalho de Melo 207b269876cSArnaldo Carvalho de Melo if (source->lines) { 208b269876cSArnaldo Carvalho de Melo pthread_mutex_lock(&source->lock); 209923c42c1SMike Galbraith goto out_assign; 210923c42c1SMike Galbraith } 211439d473bSArnaldo Carvalho de Melo path = map->dso->long_name; 212923c42c1SMike Galbraith 213923c42c1SMike Galbraith len = sym->end - sym->start; 214923c42c1SMike Galbraith 215439d473bSArnaldo Carvalho de Melo sprintf(command, 2165f485364SArnaldo Carvalho de Melo "objdump --start-address=%#0*Lx --stop-address=%#0*Lx -dS %s", 2175f485364SArnaldo Carvalho de Melo BITS_PER_LONG / 4, map__rip_2objdump(map, sym->start), 2185f485364SArnaldo Carvalho de Melo BITS_PER_LONG / 4, map__rip_2objdump(map, sym->end), path); 219923c42c1SMike Galbraith 220923c42c1SMike Galbraith file = popen(command, "r"); 221923c42c1SMike Galbraith if (!file) 222b0a9ab62SArnaldo Carvalho de Melo return -1; 223923c42c1SMike Galbraith 224b269876cSArnaldo Carvalho de Melo pthread_mutex_lock(&source->lock); 225b269876cSArnaldo Carvalho de Melo source->lines_tail = &source->lines; 226923c42c1SMike Galbraith while (!feof(file)) { 227923c42c1SMike Galbraith struct source_line *src; 228923c42c1SMike Galbraith size_t dummy = 0; 229ee11b90bSKirill Smelkov char *c, *sep; 230923c42c1SMike Galbraith 231923c42c1SMike Galbraith src = malloc(sizeof(struct source_line)); 232923c42c1SMike Galbraith assert(src != NULL); 233923c42c1SMike Galbraith memset(src, 0, sizeof(struct source_line)); 234923c42c1SMike Galbraith 235923c42c1SMike Galbraith if (getline(&src->line, &dummy, file) < 0) 236923c42c1SMike Galbraith break; 237923c42c1SMike Galbraith if (!src->line) 238923c42c1SMike Galbraith break; 239923c42c1SMike Galbraith 240923c42c1SMike Galbraith c = strchr(src->line, '\n'); 241923c42c1SMike Galbraith if (c) 242923c42c1SMike Galbraith *c = 0; 243923c42c1SMike Galbraith 244923c42c1SMike Galbraith src->next = NULL; 245b269876cSArnaldo Carvalho de Melo *source->lines_tail = src; 246b269876cSArnaldo Carvalho de Melo source->lines_tail = &src->next; 247923c42c1SMike Galbraith 248ee11b90bSKirill Smelkov src->eip = strtoull(src->line, &sep, 16); 249ee11b90bSKirill Smelkov if (*sep == ':') 250ee11b90bSKirill Smelkov src->eip = map__objdump_2ip(map, src->eip); 251ee11b90bSKirill Smelkov else /* this line has no ip info (e.g. source line) */ 252ee11b90bSKirill Smelkov src->eip = 0; 253923c42c1SMike Galbraith } 254923c42c1SMike Galbraith pclose(file); 255923c42c1SMike Galbraith out_assign: 256923c42c1SMike Galbraith sym_filter_entry = syme; 257b269876cSArnaldo Carvalho de Melo pthread_mutex_unlock(&source->lock); 258b0a9ab62SArnaldo Carvalho de Melo return 0; 259923c42c1SMike Galbraith } 260923c42c1SMike Galbraith 261923c42c1SMike Galbraith static void __zero_source_counters(struct sym_entry *syme) 262923c42c1SMike Galbraith { 263923c42c1SMike Galbraith int i; 264923c42c1SMike Galbraith struct source_line *line; 265923c42c1SMike Galbraith 266b269876cSArnaldo Carvalho de Melo line = syme->src->lines; 267923c42c1SMike Galbraith while (line) { 268923c42c1SMike Galbraith for (i = 0; i < nr_counters; i++) 269923c42c1SMike Galbraith line->count[i] = 0; 270923c42c1SMike Galbraith line = line->next; 271923c42c1SMike Galbraith } 272923c42c1SMike Galbraith } 273923c42c1SMike Galbraith 274923c42c1SMike Galbraith static void record_precise_ip(struct sym_entry *syme, int counter, u64 ip) 275923c42c1SMike Galbraith { 276923c42c1SMike Galbraith struct source_line *line; 277923c42c1SMike Galbraith 278923c42c1SMike Galbraith if (syme != sym_filter_entry) 279923c42c1SMike Galbraith return; 280923c42c1SMike Galbraith 281b269876cSArnaldo Carvalho de Melo if (pthread_mutex_trylock(&syme->src->lock)) 282923c42c1SMike Galbraith return; 283923c42c1SMike Galbraith 284b269876cSArnaldo Carvalho de Melo if (syme->src == NULL || syme->src->source == NULL) 285923c42c1SMike Galbraith goto out_unlock; 286923c42c1SMike Galbraith 287b269876cSArnaldo Carvalho de Melo for (line = syme->src->lines; line; line = line->next) { 288ee11b90bSKirill Smelkov /* skip lines without IP info */ 289ee11b90bSKirill Smelkov if (line->eip == 0) 290ee11b90bSKirill Smelkov continue; 291923c42c1SMike Galbraith if (line->eip == ip) { 292923c42c1SMike Galbraith line->count[counter]++; 293923c42c1SMike Galbraith break; 294923c42c1SMike Galbraith } 295923c42c1SMike Galbraith if (line->eip > ip) 296923c42c1SMike Galbraith break; 297923c42c1SMike Galbraith } 298923c42c1SMike Galbraith out_unlock: 299b269876cSArnaldo Carvalho de Melo pthread_mutex_unlock(&syme->src->lock); 300923c42c1SMike Galbraith } 301923c42c1SMike Galbraith 302c7ad21afSArnaldo Carvalho de Melo #define PATTERN_LEN (BITS_PER_LONG / 4 + 2) 303c7ad21afSArnaldo Carvalho de Melo 304923c42c1SMike Galbraith static void lookup_sym_source(struct sym_entry *syme) 305923c42c1SMike Galbraith { 30651a472deSArnaldo Carvalho de Melo struct symbol *symbol = sym_entry__symbol(syme); 307923c42c1SMike Galbraith struct source_line *line; 308c7ad21afSArnaldo Carvalho de Melo char pattern[PATTERN_LEN + 1]; 309923c42c1SMike Galbraith 3105f485364SArnaldo Carvalho de Melo sprintf(pattern, "%0*Lx <", BITS_PER_LONG / 4, 3115f485364SArnaldo Carvalho de Melo map__rip_2objdump(syme->map, symbol->start)); 312923c42c1SMike Galbraith 313b269876cSArnaldo Carvalho de Melo pthread_mutex_lock(&syme->src->lock); 314b269876cSArnaldo Carvalho de Melo for (line = syme->src->lines; line; line = line->next) { 315c7ad21afSArnaldo Carvalho de Melo if (memcmp(line->line, pattern, PATTERN_LEN) == 0) { 316b269876cSArnaldo Carvalho de Melo syme->src->source = line; 317923c42c1SMike Galbraith break; 318923c42c1SMike Galbraith } 319923c42c1SMike Galbraith } 320b269876cSArnaldo Carvalho de Melo pthread_mutex_unlock(&syme->src->lock); 321923c42c1SMike Galbraith } 322923c42c1SMike Galbraith 323923c42c1SMike Galbraith static void show_lines(struct source_line *queue, int count, int total) 324923c42c1SMike Galbraith { 325923c42c1SMike Galbraith int i; 326923c42c1SMike Galbraith struct source_line *line; 327923c42c1SMike Galbraith 328923c42c1SMike Galbraith line = queue; 329923c42c1SMike Galbraith for (i = 0; i < count; i++) { 330923c42c1SMike Galbraith float pcnt = 100.0*(float)line->count[sym_counter]/(float)total; 331923c42c1SMike Galbraith 332923c42c1SMike Galbraith printf("%8li %4.1f%%\t%s\n", line->count[sym_counter], pcnt, line->line); 333923c42c1SMike Galbraith line = line->next; 334923c42c1SMike Galbraith } 335923c42c1SMike Galbraith } 336923c42c1SMike Galbraith 337923c42c1SMike Galbraith #define TRACE_COUNT 3 338923c42c1SMike Galbraith 339923c42c1SMike Galbraith static void show_details(struct sym_entry *syme) 340923c42c1SMike Galbraith { 341923c42c1SMike Galbraith struct symbol *symbol; 342923c42c1SMike Galbraith struct source_line *line; 343923c42c1SMike Galbraith struct source_line *line_queue = NULL; 344923c42c1SMike Galbraith int displayed = 0; 345923c42c1SMike Galbraith int line_queue_count = 0, total = 0, more = 0; 346923c42c1SMike Galbraith 347923c42c1SMike Galbraith if (!syme) 348923c42c1SMike Galbraith return; 349923c42c1SMike Galbraith 350b269876cSArnaldo Carvalho de Melo if (!syme->src->source) 351923c42c1SMike Galbraith lookup_sym_source(syme); 352923c42c1SMike Galbraith 353b269876cSArnaldo Carvalho de Melo if (!syme->src->source) 354923c42c1SMike Galbraith return; 355923c42c1SMike Galbraith 35651a472deSArnaldo Carvalho de Melo symbol = sym_entry__symbol(syme); 357923c42c1SMike Galbraith printf("Showing %s for %s\n", event_name(sym_counter), symbol->name); 358923c42c1SMike Galbraith printf(" Events Pcnt (>=%d%%)\n", sym_pcnt_filter); 359923c42c1SMike Galbraith 360b269876cSArnaldo Carvalho de Melo pthread_mutex_lock(&syme->src->lock); 361b269876cSArnaldo Carvalho de Melo line = syme->src->source; 362923c42c1SMike Galbraith while (line) { 363923c42c1SMike Galbraith total += line->count[sym_counter]; 364923c42c1SMike Galbraith line = line->next; 365923c42c1SMike Galbraith } 366923c42c1SMike Galbraith 367b269876cSArnaldo Carvalho de Melo line = syme->src->source; 368923c42c1SMike Galbraith while (line) { 369923c42c1SMike Galbraith float pcnt = 0.0; 370923c42c1SMike Galbraith 371923c42c1SMike Galbraith if (!line_queue_count) 372923c42c1SMike Galbraith line_queue = line; 373923c42c1SMike Galbraith line_queue_count++; 374923c42c1SMike Galbraith 375923c42c1SMike Galbraith if (line->count[sym_counter]) 376923c42c1SMike Galbraith pcnt = 100.0 * line->count[sym_counter] / (float)total; 377923c42c1SMike Galbraith if (pcnt >= (float)sym_pcnt_filter) { 378923c42c1SMike Galbraith if (displayed <= print_entries) 379923c42c1SMike Galbraith show_lines(line_queue, line_queue_count, total); 380923c42c1SMike Galbraith else more++; 381923c42c1SMike Galbraith displayed += line_queue_count; 382923c42c1SMike Galbraith line_queue_count = 0; 383923c42c1SMike Galbraith line_queue = NULL; 384923c42c1SMike Galbraith } else if (line_queue_count > TRACE_COUNT) { 385923c42c1SMike Galbraith line_queue = line_queue->next; 386923c42c1SMike Galbraith line_queue_count--; 387923c42c1SMike Galbraith } 388923c42c1SMike Galbraith 389923c42c1SMike Galbraith line->count[sym_counter] = zero ? 0 : line->count[sym_counter] * 7 / 8; 390923c42c1SMike Galbraith line = line->next; 391923c42c1SMike Galbraith } 392b269876cSArnaldo Carvalho de Melo pthread_mutex_unlock(&syme->src->lock); 393923c42c1SMike Galbraith if (more) 394923c42c1SMike Galbraith printf("%d lines not displayed, maybe increase display entries [e]\n", more); 395923c42c1SMike Galbraith } 39686470930SIngo Molnar 39786470930SIngo Molnar /* 3985b2bb75aSArnaldo Carvalho de Melo * Symbols will be added here in event__process_sample and will get out 39986470930SIngo Molnar * after decayed. 40086470930SIngo Molnar */ 40186470930SIngo Molnar static LIST_HEAD(active_symbols); 40286470930SIngo Molnar static pthread_mutex_t active_symbols_lock = PTHREAD_MUTEX_INITIALIZER; 40386470930SIngo Molnar 40486470930SIngo Molnar /* 40586470930SIngo Molnar * Ordering weight: count-1 * count-2 * ... / count-n 40686470930SIngo Molnar */ 40786470930SIngo Molnar static double sym_weight(const struct sym_entry *sym) 40886470930SIngo Molnar { 40986470930SIngo Molnar double weight = sym->snap_count; 41086470930SIngo Molnar int counter; 41186470930SIngo Molnar 41246ab9764SMike Galbraith if (!display_weighted) 41346ab9764SMike Galbraith return weight; 41446ab9764SMike Galbraith 41586470930SIngo Molnar for (counter = 1; counter < nr_counters-1; counter++) 41686470930SIngo Molnar weight *= sym->count[counter]; 41786470930SIngo Molnar 41886470930SIngo Molnar weight /= (sym->count[counter] + 1); 41986470930SIngo Molnar 42086470930SIngo Molnar return weight; 42186470930SIngo Molnar } 42286470930SIngo Molnar 42386470930SIngo Molnar static long samples; 424a1645ce1SZhang, Yanmin static long kernel_samples, us_samples; 4251676b8a0SPeter Zijlstra static long exact_samples; 426a1645ce1SZhang, Yanmin static long guest_us_samples, guest_kernel_samples; 42786470930SIngo Molnar static const char CONSOLE_CLEAR[] = "[H[2J"; 42886470930SIngo Molnar 42986470930SIngo Molnar static void __list_insert_active_sym(struct sym_entry *syme) 43086470930SIngo Molnar { 43186470930SIngo Molnar list_add(&syme->node, &active_symbols); 43286470930SIngo Molnar } 43386470930SIngo Molnar 43486470930SIngo Molnar static void list_remove_active_sym(struct sym_entry *syme) 43586470930SIngo Molnar { 43686470930SIngo Molnar pthread_mutex_lock(&active_symbols_lock); 43786470930SIngo Molnar list_del_init(&syme->node); 43886470930SIngo Molnar pthread_mutex_unlock(&active_symbols_lock); 43986470930SIngo Molnar } 44086470930SIngo Molnar 44186470930SIngo Molnar static void rb_insert_active_sym(struct rb_root *tree, struct sym_entry *se) 44286470930SIngo Molnar { 44386470930SIngo Molnar struct rb_node **p = &tree->rb_node; 44486470930SIngo Molnar struct rb_node *parent = NULL; 44586470930SIngo Molnar struct sym_entry *iter; 44686470930SIngo Molnar 44786470930SIngo Molnar while (*p != NULL) { 44886470930SIngo Molnar parent = *p; 44986470930SIngo Molnar iter = rb_entry(parent, struct sym_entry, rb_node); 45086470930SIngo Molnar 45186470930SIngo Molnar if (se->weight > iter->weight) 45286470930SIngo Molnar p = &(*p)->rb_left; 45386470930SIngo Molnar else 45486470930SIngo Molnar p = &(*p)->rb_right; 45586470930SIngo Molnar } 45686470930SIngo Molnar 45786470930SIngo Molnar rb_link_node(&se->rb_node, parent, p); 45886470930SIngo Molnar rb_insert_color(&se->rb_node, tree); 45986470930SIngo Molnar } 46086470930SIngo Molnar 46186470930SIngo Molnar static void print_sym_table(void) 46286470930SIngo Molnar { 46386470930SIngo Molnar int printed = 0, j; 46446ab9764SMike Galbraith int counter, snap = !display_weighted ? sym_counter : 0; 46586470930SIngo Molnar float samples_per_sec = samples/delay_secs; 466a1645ce1SZhang, Yanmin float ksamples_per_sec = kernel_samples/delay_secs; 467a1645ce1SZhang, Yanmin float us_samples_per_sec = (us_samples)/delay_secs; 468a1645ce1SZhang, Yanmin float guest_kernel_samples_per_sec = (guest_kernel_samples)/delay_secs; 469a1645ce1SZhang, Yanmin float guest_us_samples_per_sec = (guest_us_samples)/delay_secs; 4701676b8a0SPeter Zijlstra float esamples_percent = (100.0*exact_samples)/samples; 47186470930SIngo Molnar float sum_ksamples = 0.0; 47286470930SIngo Molnar struct sym_entry *syme, *n; 47386470930SIngo Molnar struct rb_root tmp = RB_ROOT; 47486470930SIngo Molnar struct rb_node *nd; 47500909e95SArnaldo Carvalho de Melo int sym_width = 0, dso_width = 0, dso_short_width = 0; 47613cc5079SArnaldo Carvalho de Melo const int win_width = winsize.ws_col - 1; 47786470930SIngo Molnar 478a1645ce1SZhang, Yanmin samples = us_samples = kernel_samples = exact_samples = 0; 479a1645ce1SZhang, Yanmin guest_kernel_samples = guest_us_samples = 0; 48086470930SIngo Molnar 48186470930SIngo Molnar /* Sort the active symbols */ 48286470930SIngo Molnar pthread_mutex_lock(&active_symbols_lock); 48386470930SIngo Molnar syme = list_entry(active_symbols.next, struct sym_entry, node); 48486470930SIngo Molnar pthread_mutex_unlock(&active_symbols_lock); 48586470930SIngo Molnar 48686470930SIngo Molnar list_for_each_entry_safe_from(syme, n, &active_symbols, node) { 48746ab9764SMike Galbraith syme->snap_count = syme->count[snap]; 48886470930SIngo Molnar if (syme->snap_count != 0) { 48913cc5079SArnaldo Carvalho de Melo 4908ffcda17SArnaldo Carvalho de Melo if ((hide_user_symbols && 4918ffcda17SArnaldo Carvalho de Melo syme->origin == PERF_RECORD_MISC_USER) || 4928ffcda17SArnaldo Carvalho de Melo (hide_kernel_symbols && 4938ffcda17SArnaldo Carvalho de Melo syme->origin == PERF_RECORD_MISC_KERNEL)) { 4948ffcda17SArnaldo Carvalho de Melo list_remove_active_sym(syme); 4958ffcda17SArnaldo Carvalho de Melo continue; 4968ffcda17SArnaldo Carvalho de Melo } 49786470930SIngo Molnar syme->weight = sym_weight(syme); 49886470930SIngo Molnar rb_insert_active_sym(&tmp, syme); 49986470930SIngo Molnar sum_ksamples += syme->snap_count; 50086470930SIngo Molnar 50186470930SIngo Molnar for (j = 0; j < nr_counters; j++) 50286470930SIngo Molnar syme->count[j] = zero ? 0 : syme->count[j] * 7 / 8; 50386470930SIngo Molnar } else 50486470930SIngo Molnar list_remove_active_sym(syme); 50586470930SIngo Molnar } 50686470930SIngo Molnar 50786470930SIngo Molnar puts(CONSOLE_CLEAR); 50886470930SIngo Molnar 50913cc5079SArnaldo Carvalho de Melo printf("%-*.*s\n", win_width, win_width, graph_dotted_line); 510a1645ce1SZhang, Yanmin if (!perf_guest) { 511a1645ce1SZhang, Yanmin printf(" PerfTop:%8.0f irqs/sec kernel:%4.1f%%" 512a1645ce1SZhang, Yanmin " exact: %4.1f%% [", 51386470930SIngo Molnar samples_per_sec, 514a1645ce1SZhang, Yanmin 100.0 - (100.0 * ((samples_per_sec - ksamples_per_sec) / 515a1645ce1SZhang, Yanmin samples_per_sec)), 5161676b8a0SPeter Zijlstra esamples_percent); 517a1645ce1SZhang, Yanmin } else { 518a1645ce1SZhang, Yanmin printf(" PerfTop:%8.0f irqs/sec kernel:%4.1f%% us:%4.1f%%" 519a1645ce1SZhang, Yanmin " guest kernel:%4.1f%% guest us:%4.1f%%" 520a1645ce1SZhang, Yanmin " exact: %4.1f%% [", 521a1645ce1SZhang, Yanmin samples_per_sec, 522a1645ce1SZhang, Yanmin 100.0 - (100.0 * ((samples_per_sec-ksamples_per_sec) / 523a1645ce1SZhang, Yanmin samples_per_sec)), 524a1645ce1SZhang, Yanmin 100.0 - (100.0 * ((samples_per_sec-us_samples_per_sec) / 525a1645ce1SZhang, Yanmin samples_per_sec)), 526a1645ce1SZhang, Yanmin 100.0 - (100.0 * ((samples_per_sec - 527a1645ce1SZhang, Yanmin guest_kernel_samples_per_sec) / 528a1645ce1SZhang, Yanmin samples_per_sec)), 529a1645ce1SZhang, Yanmin 100.0 - (100.0 * ((samples_per_sec - 530a1645ce1SZhang, Yanmin guest_us_samples_per_sec) / 531a1645ce1SZhang, Yanmin samples_per_sec)), 532a1645ce1SZhang, Yanmin esamples_percent); 533a1645ce1SZhang, Yanmin } 53486470930SIngo Molnar 53546ab9764SMike Galbraith if (nr_counters == 1 || !display_weighted) { 5369cffa8d5SPaul Mackerras printf("%Ld", (u64)attrs[0].sample_period); 53786470930SIngo Molnar if (freq) 53886470930SIngo Molnar printf("Hz "); 53986470930SIngo Molnar else 54086470930SIngo Molnar printf(" "); 54186470930SIngo Molnar } 54286470930SIngo Molnar 54346ab9764SMike Galbraith if (!display_weighted) 54446ab9764SMike Galbraith printf("%s", event_name(sym_counter)); 54546ab9764SMike Galbraith else for (counter = 0; counter < nr_counters; counter++) { 54686470930SIngo Molnar if (counter) 54786470930SIngo Molnar printf("/"); 54886470930SIngo Molnar 54986470930SIngo Molnar printf("%s", event_name(counter)); 55086470930SIngo Molnar } 55186470930SIngo Molnar 55286470930SIngo Molnar printf( "], "); 55386470930SIngo Molnar 55486470930SIngo Molnar if (target_pid != -1) 55586470930SIngo Molnar printf(" (target_pid: %d", target_pid); 556d6d901c2SZhang, Yanmin else if (target_tid != -1) 557d6d901c2SZhang, Yanmin printf(" (target_tid: %d", target_tid); 55886470930SIngo Molnar else 55986470930SIngo Molnar printf(" (all"); 56086470930SIngo Molnar 56186470930SIngo Molnar if (profile_cpu != -1) 56286470930SIngo Molnar printf(", cpu: %d)\n", profile_cpu); 56386470930SIngo Molnar else { 564d6d901c2SZhang, Yanmin if (target_tid != -1) 56586470930SIngo Molnar printf(")\n"); 56686470930SIngo Molnar else 56786470930SIngo Molnar printf(", %d CPUs)\n", nr_cpus); 56886470930SIngo Molnar } 56986470930SIngo Molnar 5701a105f74SArnaldo Carvalho de Melo printf("%-*.*s\n", win_width, win_width, graph_dotted_line); 57186470930SIngo Molnar 572923c42c1SMike Galbraith if (sym_filter_entry) { 573923c42c1SMike Galbraith show_details(sym_filter_entry); 574923c42c1SMike Galbraith return; 575923c42c1SMike Galbraith } 576923c42c1SMike Galbraith 57713cc5079SArnaldo Carvalho de Melo /* 57813cc5079SArnaldo Carvalho de Melo * Find the longest symbol name that will be displayed 57913cc5079SArnaldo Carvalho de Melo */ 58013cc5079SArnaldo Carvalho de Melo for (nd = rb_first(&tmp); nd; nd = rb_next(nd)) { 58113cc5079SArnaldo Carvalho de Melo syme = rb_entry(nd, struct sym_entry, rb_node); 58213cc5079SArnaldo Carvalho de Melo if (++printed > print_entries || 58313cc5079SArnaldo Carvalho de Melo (int)syme->snap_count < count_filter) 58413cc5079SArnaldo Carvalho de Melo continue; 58513cc5079SArnaldo Carvalho de Melo 5861a105f74SArnaldo Carvalho de Melo if (syme->map->dso->long_name_len > dso_width) 5871a105f74SArnaldo Carvalho de Melo dso_width = syme->map->dso->long_name_len; 5881a105f74SArnaldo Carvalho de Melo 589b63be8d7SArnaldo Carvalho de Melo if (syme->map->dso->short_name_len > dso_short_width) 590b63be8d7SArnaldo Carvalho de Melo dso_short_width = syme->map->dso->short_name_len; 591b63be8d7SArnaldo Carvalho de Melo 59213cc5079SArnaldo Carvalho de Melo if (syme->name_len > sym_width) 59313cc5079SArnaldo Carvalho de Melo sym_width = syme->name_len; 59413cc5079SArnaldo Carvalho de Melo } 59513cc5079SArnaldo Carvalho de Melo 59613cc5079SArnaldo Carvalho de Melo printed = 0; 59713cc5079SArnaldo Carvalho de Melo 598b63be8d7SArnaldo Carvalho de Melo if (sym_width + dso_width > winsize.ws_col - 29) { 599b63be8d7SArnaldo Carvalho de Melo dso_width = dso_short_width; 600b63be8d7SArnaldo Carvalho de Melo if (sym_width + dso_width > winsize.ws_col - 29) 601b63be8d7SArnaldo Carvalho de Melo sym_width = winsize.ws_col - dso_width - 29; 602b63be8d7SArnaldo Carvalho de Melo } 6031a105f74SArnaldo Carvalho de Melo putchar('\n'); 60486470930SIngo Molnar if (nr_counters == 1) 60586470930SIngo Molnar printf(" samples pcnt"); 60686470930SIngo Molnar else 60786470930SIngo Molnar printf(" weight samples pcnt"); 60886470930SIngo Molnar 6097ced156bSArnaldo Carvalho de Melo if (verbose) 6107ced156bSArnaldo Carvalho de Melo printf(" RIP "); 6117cc017edSArnaldo Carvalho de Melo printf(" %-*.*s DSO\n", sym_width, sym_width, "function"); 6127ced156bSArnaldo Carvalho de Melo printf(" %s _______ _____", 6137ced156bSArnaldo Carvalho de Melo nr_counters == 1 ? " " : "______"); 6147ced156bSArnaldo Carvalho de Melo if (verbose) 6157ced156bSArnaldo Carvalho de Melo printf(" ________________"); 6161a105f74SArnaldo Carvalho de Melo printf(" %-*.*s", sym_width, sym_width, graph_line); 6171a105f74SArnaldo Carvalho de Melo printf(" %-*.*s", dso_width, dso_width, graph_line); 6181a105f74SArnaldo Carvalho de Melo puts("\n"); 61986470930SIngo Molnar 62086470930SIngo Molnar for (nd = rb_first(&tmp); nd; nd = rb_next(nd)) { 62183a0944fSIngo Molnar struct symbol *sym; 62286470930SIngo Molnar double pcnt; 62386470930SIngo Molnar 62483a0944fSIngo Molnar syme = rb_entry(nd, struct sym_entry, rb_node); 62551a472deSArnaldo Carvalho de Melo sym = sym_entry__symbol(syme); 626923c42c1SMike Galbraith if (++printed > print_entries || (int)syme->snap_count < count_filter) 62786470930SIngo Molnar continue; 62886470930SIngo Molnar 62986470930SIngo Molnar pcnt = 100.0 - (100.0 * ((sum_ksamples - syme->snap_count) / 63086470930SIngo Molnar sum_ksamples)); 63186470930SIngo Molnar 63246ab9764SMike Galbraith if (nr_counters == 1 || !display_weighted) 6335b2bb75aSArnaldo Carvalho de Melo printf("%20.2f ", syme->weight); 63486470930SIngo Molnar else 6355b2bb75aSArnaldo Carvalho de Melo printf("%9.1f %10ld ", syme->weight, syme->snap_count); 63686470930SIngo Molnar 6371e11fd82SFrederic Weisbecker percent_color_fprintf(stdout, "%4.1f%%", pcnt); 6387ced156bSArnaldo Carvalho de Melo if (verbose) 6395b2bb75aSArnaldo Carvalho de Melo printf(" %016llx", sym->start); 64013cc5079SArnaldo Carvalho de Melo printf(" %-*.*s", sym_width, sym_width, sym->name); 6417cc017edSArnaldo Carvalho de Melo printf(" %-*.*s\n", dso_width, dso_width, 64213cc5079SArnaldo Carvalho de Melo dso_width >= syme->map->dso->long_name_len ? 64313cc5079SArnaldo Carvalho de Melo syme->map->dso->long_name : 64413cc5079SArnaldo Carvalho de Melo syme->map->dso->short_name); 64586470930SIngo Molnar } 64686470930SIngo Molnar } 64786470930SIngo Molnar 648923c42c1SMike Galbraith static void prompt_integer(int *target, const char *msg) 649923c42c1SMike Galbraith { 650923c42c1SMike Galbraith char *buf = malloc(0), *p; 651923c42c1SMike Galbraith size_t dummy = 0; 652923c42c1SMike Galbraith int tmp; 653923c42c1SMike Galbraith 654923c42c1SMike Galbraith fprintf(stdout, "\n%s: ", msg); 655923c42c1SMike Galbraith if (getline(&buf, &dummy, stdin) < 0) 656923c42c1SMike Galbraith return; 657923c42c1SMike Galbraith 658923c42c1SMike Galbraith p = strchr(buf, '\n'); 659923c42c1SMike Galbraith if (p) 660923c42c1SMike Galbraith *p = 0; 661923c42c1SMike Galbraith 662923c42c1SMike Galbraith p = buf; 663923c42c1SMike Galbraith while(*p) { 664923c42c1SMike Galbraith if (!isdigit(*p)) 665923c42c1SMike Galbraith goto out_free; 666923c42c1SMike Galbraith p++; 667923c42c1SMike Galbraith } 668923c42c1SMike Galbraith tmp = strtoul(buf, NULL, 10); 669923c42c1SMike Galbraith *target = tmp; 670923c42c1SMike Galbraith out_free: 671923c42c1SMike Galbraith free(buf); 672923c42c1SMike Galbraith } 673923c42c1SMike Galbraith 674923c42c1SMike Galbraith static void prompt_percent(int *target, const char *msg) 675923c42c1SMike Galbraith { 676923c42c1SMike Galbraith int tmp = 0; 677923c42c1SMike Galbraith 678923c42c1SMike Galbraith prompt_integer(&tmp, msg); 679923c42c1SMike Galbraith if (tmp >= 0 && tmp <= 100) 680923c42c1SMike Galbraith *target = tmp; 681923c42c1SMike Galbraith } 682923c42c1SMike Galbraith 683923c42c1SMike Galbraith static void prompt_symbol(struct sym_entry **target, const char *msg) 684923c42c1SMike Galbraith { 685923c42c1SMike Galbraith char *buf = malloc(0), *p; 686923c42c1SMike Galbraith struct sym_entry *syme = *target, *n, *found = NULL; 687923c42c1SMike Galbraith size_t dummy = 0; 688923c42c1SMike Galbraith 689923c42c1SMike Galbraith /* zero counters of active symbol */ 690923c42c1SMike Galbraith if (syme) { 691b269876cSArnaldo Carvalho de Melo pthread_mutex_lock(&syme->src->lock); 692923c42c1SMike Galbraith __zero_source_counters(syme); 693923c42c1SMike Galbraith *target = NULL; 694b269876cSArnaldo Carvalho de Melo pthread_mutex_unlock(&syme->src->lock); 695923c42c1SMike Galbraith } 696923c42c1SMike Galbraith 697923c42c1SMike Galbraith fprintf(stdout, "\n%s: ", msg); 698923c42c1SMike Galbraith if (getline(&buf, &dummy, stdin) < 0) 699923c42c1SMike Galbraith goto out_free; 700923c42c1SMike Galbraith 701923c42c1SMike Galbraith p = strchr(buf, '\n'); 702923c42c1SMike Galbraith if (p) 703923c42c1SMike Galbraith *p = 0; 704923c42c1SMike Galbraith 705923c42c1SMike Galbraith pthread_mutex_lock(&active_symbols_lock); 706923c42c1SMike Galbraith syme = list_entry(active_symbols.next, struct sym_entry, node); 707923c42c1SMike Galbraith pthread_mutex_unlock(&active_symbols_lock); 708923c42c1SMike Galbraith 709923c42c1SMike Galbraith list_for_each_entry_safe_from(syme, n, &active_symbols, node) { 71051a472deSArnaldo Carvalho de Melo struct symbol *sym = sym_entry__symbol(syme); 711923c42c1SMike Galbraith 712923c42c1SMike Galbraith if (!strcmp(buf, sym->name)) { 713923c42c1SMike Galbraith found = syme; 714923c42c1SMike Galbraith break; 715923c42c1SMike Galbraith } 716923c42c1SMike Galbraith } 717923c42c1SMike Galbraith 718923c42c1SMike Galbraith if (!found) { 71966aeb6d5SKirill Smelkov fprintf(stderr, "Sorry, %s is not active.\n", buf); 720923c42c1SMike Galbraith sleep(1); 721923c42c1SMike Galbraith return; 722923c42c1SMike Galbraith } else 723923c42c1SMike Galbraith parse_source(found); 724923c42c1SMike Galbraith 725923c42c1SMike Galbraith out_free: 726923c42c1SMike Galbraith free(buf); 727923c42c1SMike Galbraith } 728923c42c1SMike Galbraith 729091bd2e9SMike Galbraith static void print_mapped_keys(void) 730923c42c1SMike Galbraith { 731091bd2e9SMike Galbraith char *name = NULL; 732091bd2e9SMike Galbraith 733091bd2e9SMike Galbraith if (sym_filter_entry) { 73451a472deSArnaldo Carvalho de Melo struct symbol *sym = sym_entry__symbol(sym_filter_entry); 735091bd2e9SMike Galbraith name = sym->name; 736091bd2e9SMike Galbraith } 737091bd2e9SMike Galbraith 738091bd2e9SMike Galbraith fprintf(stdout, "\nMapped keys:\n"); 739091bd2e9SMike Galbraith fprintf(stdout, "\t[d] display refresh delay. \t(%d)\n", delay_secs); 740091bd2e9SMike Galbraith fprintf(stdout, "\t[e] display entries (lines). \t(%d)\n", print_entries); 741091bd2e9SMike Galbraith 742091bd2e9SMike Galbraith if (nr_counters > 1) 74346ab9764SMike Galbraith fprintf(stdout, "\t[E] active event counter. \t(%s)\n", event_name(sym_counter)); 744091bd2e9SMike Galbraith 745091bd2e9SMike Galbraith fprintf(stdout, "\t[f] profile display filter (count). \t(%d)\n", count_filter); 746091bd2e9SMike Galbraith 747091bd2e9SMike Galbraith fprintf(stdout, "\t[F] annotate display filter (percent). \t(%d%%)\n", sym_pcnt_filter); 748091bd2e9SMike Galbraith fprintf(stdout, "\t[s] annotate symbol. \t(%s)\n", name?: "NULL"); 749091bd2e9SMike Galbraith fprintf(stdout, "\t[S] stop annotation.\n"); 750091bd2e9SMike Galbraith 751091bd2e9SMike Galbraith if (nr_counters > 1) 75246ab9764SMike Galbraith fprintf(stdout, "\t[w] toggle display weighted/count[E]r. \t(%d)\n", display_weighted ? 1 : 0); 753091bd2e9SMike Galbraith 7548ffcda17SArnaldo Carvalho de Melo fprintf(stdout, 7558ffcda17SArnaldo Carvalho de Melo "\t[K] hide kernel_symbols symbols. \t(%s)\n", 7568ffcda17SArnaldo Carvalho de Melo hide_kernel_symbols ? "yes" : "no"); 7578ffcda17SArnaldo Carvalho de Melo fprintf(stdout, 7588ffcda17SArnaldo Carvalho de Melo "\t[U] hide user symbols. \t(%s)\n", 7598ffcda17SArnaldo Carvalho de Melo hide_user_symbols ? "yes" : "no"); 76046ab9764SMike Galbraith fprintf(stdout, "\t[z] toggle sample zeroing. \t(%d)\n", zero ? 1 : 0); 761091bd2e9SMike Galbraith fprintf(stdout, "\t[qQ] quit.\n"); 762091bd2e9SMike Galbraith } 763091bd2e9SMike Galbraith 764091bd2e9SMike Galbraith static int key_mapped(int c) 765091bd2e9SMike Galbraith { 766091bd2e9SMike Galbraith switch (c) { 767091bd2e9SMike Galbraith case 'd': 768091bd2e9SMike Galbraith case 'e': 769091bd2e9SMike Galbraith case 'f': 770091bd2e9SMike Galbraith case 'z': 771091bd2e9SMike Galbraith case 'q': 772091bd2e9SMike Galbraith case 'Q': 7738ffcda17SArnaldo Carvalho de Melo case 'K': 7748ffcda17SArnaldo Carvalho de Melo case 'U': 7756cff0e8dSKirill Smelkov case 'F': 7766cff0e8dSKirill Smelkov case 's': 7776cff0e8dSKirill Smelkov case 'S': 778091bd2e9SMike Galbraith return 1; 779091bd2e9SMike Galbraith case 'E': 780091bd2e9SMike Galbraith case 'w': 781091bd2e9SMike Galbraith return nr_counters > 1 ? 1 : 0; 78283a0944fSIngo Molnar default: 78383a0944fSIngo Molnar break; 784091bd2e9SMike Galbraith } 785091bd2e9SMike Galbraith 786091bd2e9SMike Galbraith return 0; 787923c42c1SMike Galbraith } 788923c42c1SMike Galbraith 789a1645ce1SZhang, Yanmin static void handle_keypress(struct perf_session *session, int c) 790923c42c1SMike Galbraith { 791091bd2e9SMike Galbraith if (!key_mapped(c)) { 792091bd2e9SMike Galbraith struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; 793091bd2e9SMike Galbraith struct termios tc, save; 794091bd2e9SMike Galbraith 795091bd2e9SMike Galbraith print_mapped_keys(); 796091bd2e9SMike Galbraith fprintf(stdout, "\nEnter selection, or unmapped key to continue: "); 797091bd2e9SMike Galbraith fflush(stdout); 798091bd2e9SMike Galbraith 799091bd2e9SMike Galbraith tcgetattr(0, &save); 800091bd2e9SMike Galbraith tc = save; 801091bd2e9SMike Galbraith tc.c_lflag &= ~(ICANON | ECHO); 802091bd2e9SMike Galbraith tc.c_cc[VMIN] = 0; 803091bd2e9SMike Galbraith tc.c_cc[VTIME] = 0; 804091bd2e9SMike Galbraith tcsetattr(0, TCSANOW, &tc); 805091bd2e9SMike Galbraith 806091bd2e9SMike Galbraith poll(&stdin_poll, 1, -1); 807091bd2e9SMike Galbraith c = getc(stdin); 808091bd2e9SMike Galbraith 809091bd2e9SMike Galbraith tcsetattr(0, TCSAFLUSH, &save); 810091bd2e9SMike Galbraith if (!key_mapped(c)) 811091bd2e9SMike Galbraith return; 812091bd2e9SMike Galbraith } 813091bd2e9SMike Galbraith 814923c42c1SMike Galbraith switch (c) { 815923c42c1SMike Galbraith case 'd': 816923c42c1SMike Galbraith prompt_integer(&delay_secs, "Enter display delay"); 817dc79959aSTim Blechmann if (delay_secs < 1) 818dc79959aSTim Blechmann delay_secs = 1; 819923c42c1SMike Galbraith break; 820923c42c1SMike Galbraith case 'e': 821923c42c1SMike Galbraith prompt_integer(&print_entries, "Enter display entries (lines)"); 8223b6ed988SArnaldo Carvalho de Melo if (print_entries == 0) { 82313cc5079SArnaldo Carvalho de Melo sig_winch_handler(SIGWINCH); 8243b6ed988SArnaldo Carvalho de Melo signal(SIGWINCH, sig_winch_handler); 8253b6ed988SArnaldo Carvalho de Melo } else 8263b6ed988SArnaldo Carvalho de Melo signal(SIGWINCH, SIG_DFL); 827923c42c1SMike Galbraith break; 828923c42c1SMike Galbraith case 'E': 829923c42c1SMike Galbraith if (nr_counters > 1) { 830923c42c1SMike Galbraith int i; 831923c42c1SMike Galbraith 832923c42c1SMike Galbraith fprintf(stderr, "\nAvailable events:"); 833923c42c1SMike Galbraith for (i = 0; i < nr_counters; i++) 834923c42c1SMike Galbraith fprintf(stderr, "\n\t%d %s", i, event_name(i)); 835923c42c1SMike Galbraith 836923c42c1SMike Galbraith prompt_integer(&sym_counter, "Enter details event counter"); 837923c42c1SMike Galbraith 838923c42c1SMike Galbraith if (sym_counter >= nr_counters) { 839923c42c1SMike Galbraith fprintf(stderr, "Sorry, no such event, using %s.\n", event_name(0)); 840923c42c1SMike Galbraith sym_counter = 0; 841923c42c1SMike Galbraith sleep(1); 842923c42c1SMike Galbraith } 843923c42c1SMike Galbraith } else sym_counter = 0; 844923c42c1SMike Galbraith break; 845923c42c1SMike Galbraith case 'f': 846923c42c1SMike Galbraith prompt_integer(&count_filter, "Enter display event count filter"); 847923c42c1SMike Galbraith break; 848923c42c1SMike Galbraith case 'F': 849923c42c1SMike Galbraith prompt_percent(&sym_pcnt_filter, "Enter details display event filter (percent)"); 850923c42c1SMike Galbraith break; 8518ffcda17SArnaldo Carvalho de Melo case 'K': 8528ffcda17SArnaldo Carvalho de Melo hide_kernel_symbols = !hide_kernel_symbols; 8538ffcda17SArnaldo Carvalho de Melo break; 854923c42c1SMike Galbraith case 'q': 855923c42c1SMike Galbraith case 'Q': 856923c42c1SMike Galbraith printf("exiting.\n"); 857c338aee8SArnaldo Carvalho de Melo if (dump_symtab) 858cbf69680SArnaldo Carvalho de Melo perf_session__fprintf_dsos(session, stderr); 859923c42c1SMike Galbraith exit(0); 860923c42c1SMike Galbraith case 's': 861923c42c1SMike Galbraith prompt_symbol(&sym_filter_entry, "Enter details symbol"); 862923c42c1SMike Galbraith break; 863923c42c1SMike Galbraith case 'S': 864923c42c1SMike Galbraith if (!sym_filter_entry) 865923c42c1SMike Galbraith break; 866923c42c1SMike Galbraith else { 867923c42c1SMike Galbraith struct sym_entry *syme = sym_filter_entry; 868923c42c1SMike Galbraith 869b269876cSArnaldo Carvalho de Melo pthread_mutex_lock(&syme->src->lock); 870923c42c1SMike Galbraith sym_filter_entry = NULL; 871923c42c1SMike Galbraith __zero_source_counters(syme); 872b269876cSArnaldo Carvalho de Melo pthread_mutex_unlock(&syme->src->lock); 873923c42c1SMike Galbraith } 874923c42c1SMike Galbraith break; 8758ffcda17SArnaldo Carvalho de Melo case 'U': 8768ffcda17SArnaldo Carvalho de Melo hide_user_symbols = !hide_user_symbols; 8778ffcda17SArnaldo Carvalho de Melo break; 87846ab9764SMike Galbraith case 'w': 87946ab9764SMike Galbraith display_weighted = ~display_weighted; 88046ab9764SMike Galbraith break; 881923c42c1SMike Galbraith case 'z': 882c0555642SIan Munsie zero = !zero; 883923c42c1SMike Galbraith break; 88483a0944fSIngo Molnar default: 88583a0944fSIngo Molnar break; 886923c42c1SMike Galbraith } 887923c42c1SMike Galbraith } 888923c42c1SMike Galbraith 889f37a291cSIngo Molnar static void *display_thread(void *arg __used) 89086470930SIngo Molnar { 89186470930SIngo Molnar struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; 892923c42c1SMike Galbraith struct termios tc, save; 893923c42c1SMike Galbraith int delay_msecs, c; 894a1645ce1SZhang, Yanmin struct perf_session *session = (struct perf_session *) arg; 89586470930SIngo Molnar 896923c42c1SMike Galbraith tcgetattr(0, &save); 897923c42c1SMike Galbraith tc = save; 898923c42c1SMike Galbraith tc.c_lflag &= ~(ICANON | ECHO); 899923c42c1SMike Galbraith tc.c_cc[VMIN] = 0; 900923c42c1SMike Galbraith tc.c_cc[VTIME] = 0; 901091bd2e9SMike Galbraith 902923c42c1SMike Galbraith repeat: 903923c42c1SMike Galbraith delay_msecs = delay_secs * 1000; 904923c42c1SMike Galbraith tcsetattr(0, TCSANOW, &tc); 905923c42c1SMike Galbraith /* trash return*/ 906923c42c1SMike Galbraith getc(stdin); 90786470930SIngo Molnar 90886470930SIngo Molnar do { 90986470930SIngo Molnar print_sym_table(); 91086470930SIngo Molnar } while (!poll(&stdin_poll, 1, delay_msecs) == 1); 91186470930SIngo Molnar 912923c42c1SMike Galbraith c = getc(stdin); 913923c42c1SMike Galbraith tcsetattr(0, TCSAFLUSH, &save); 914923c42c1SMike Galbraith 915a1645ce1SZhang, Yanmin handle_keypress(session, c); 916923c42c1SMike Galbraith goto repeat; 91786470930SIngo Molnar 91886470930SIngo Molnar return NULL; 91986470930SIngo Molnar } 92086470930SIngo Molnar 9212ab52083SAnton Blanchard /* Tag samples to be skipped. */ 922f37a291cSIngo Molnar static const char *skip_symbols[] = { 9232ab52083SAnton Blanchard "default_idle", 9242ab52083SAnton Blanchard "cpu_idle", 9252ab52083SAnton Blanchard "enter_idle", 9262ab52083SAnton Blanchard "exit_idle", 9272ab52083SAnton Blanchard "mwait_idle", 92859b90056SArnaldo Carvalho de Melo "mwait_idle_with_hints", 9298357275bSArnaldo Carvalho de Melo "poll_idle", 9303a3393efSAnton Blanchard "ppc64_runlatch_off", 9313a3393efSAnton Blanchard "pseries_dedicated_idle_sleep", 9322ab52083SAnton Blanchard NULL 9332ab52083SAnton Blanchard }; 9342ab52083SAnton Blanchard 935439d473bSArnaldo Carvalho de Melo static int symbol_filter(struct map *map, struct symbol *sym) 93686470930SIngo Molnar { 93786470930SIngo Molnar struct sym_entry *syme; 93886470930SIngo Molnar const char *name = sym->name; 9392ab52083SAnton Blanchard int i; 94086470930SIngo Molnar 9413a3393efSAnton Blanchard /* 9423a3393efSAnton Blanchard * ppc64 uses function descriptors and appends a '.' to the 9433a3393efSAnton Blanchard * start of every instruction address. Remove it. 9443a3393efSAnton Blanchard */ 9453a3393efSAnton Blanchard if (name[0] == '.') 9463a3393efSAnton Blanchard name++; 9473a3393efSAnton Blanchard 94886470930SIngo Molnar if (!strcmp(name, "_text") || 94986470930SIngo Molnar !strcmp(name, "_etext") || 95086470930SIngo Molnar !strcmp(name, "_sinittext") || 95186470930SIngo Molnar !strncmp("init_module", name, 11) || 95286470930SIngo Molnar !strncmp("cleanup_module", name, 14) || 95386470930SIngo Molnar strstr(name, "_text_start") || 95486470930SIngo Molnar strstr(name, "_text_end")) 95586470930SIngo Molnar return 1; 95686470930SIngo Molnar 95700a192b3SArnaldo Carvalho de Melo syme = symbol__priv(sym); 958439d473bSArnaldo Carvalho de Melo syme->map = map; 959b269876cSArnaldo Carvalho de Melo syme->src = NULL; 9606cff0e8dSKirill Smelkov 9616cff0e8dSKirill Smelkov if (!sym_filter_entry && sym_filter && !strcmp(name, sym_filter)) { 9626cff0e8dSKirill Smelkov /* schedule initial sym_filter_entry setup */ 9636cff0e8dSKirill Smelkov sym_filter_entry_sched = syme; 9646cff0e8dSKirill Smelkov sym_filter = NULL; 9656cff0e8dSKirill Smelkov } 966923c42c1SMike Galbraith 9672ab52083SAnton Blanchard for (i = 0; skip_symbols[i]; i++) { 9682ab52083SAnton Blanchard if (!strcmp(skip_symbols[i], name)) { 96986470930SIngo Molnar syme->skip = 1; 9702ab52083SAnton Blanchard break; 9712ab52083SAnton Blanchard } 9722ab52083SAnton Blanchard } 97386470930SIngo Molnar 97413cc5079SArnaldo Carvalho de Melo if (!syme->skip) 97513cc5079SArnaldo Carvalho de Melo syme->name_len = strlen(sym->name); 97613cc5079SArnaldo Carvalho de Melo 97786470930SIngo Molnar return 0; 97886470930SIngo Molnar } 97986470930SIngo Molnar 980b3165f41SArnaldo Carvalho de Melo static void event__process_sample(const event_t *self, 981b3165f41SArnaldo Carvalho de Melo struct perf_session *session, int counter) 98286470930SIngo Molnar { 9835b2bb75aSArnaldo Carvalho de Melo u64 ip = self->ip.ip; 9845b2bb75aSArnaldo Carvalho de Melo struct sym_entry *syme; 9851ed091c4SArnaldo Carvalho de Melo struct addr_location al; 98641a37e20SArnaldo Carvalho de Melo struct sample_data data; 98723346f21SArnaldo Carvalho de Melo struct machine *machine; 9888ffcda17SArnaldo Carvalho de Melo u8 origin = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 98986470930SIngo Molnar 99024bfef0fSArnaldo Carvalho de Melo ++samples; 99124bfef0fSArnaldo Carvalho de Melo 9928ffcda17SArnaldo Carvalho de Melo switch (origin) { 9931ed091c4SArnaldo Carvalho de Melo case PERF_RECORD_MISC_USER: 994a1645ce1SZhang, Yanmin ++us_samples; 9958ffcda17SArnaldo Carvalho de Melo if (hide_user_symbols) 9968ffcda17SArnaldo Carvalho de Melo return; 99723346f21SArnaldo Carvalho de Melo machine = perf_session__find_host_machine(session); 9985b2bb75aSArnaldo Carvalho de Melo break; 9995b2bb75aSArnaldo Carvalho de Melo case PERF_RECORD_MISC_KERNEL: 1000a1645ce1SZhang, Yanmin ++kernel_samples; 10018ffcda17SArnaldo Carvalho de Melo if (hide_kernel_symbols) 10028ffcda17SArnaldo Carvalho de Melo return; 100323346f21SArnaldo Carvalho de Melo machine = perf_session__find_host_machine(session); 10045b2bb75aSArnaldo Carvalho de Melo break; 1005a1645ce1SZhang, Yanmin case PERF_RECORD_MISC_GUEST_KERNEL: 1006a1645ce1SZhang, Yanmin ++guest_kernel_samples; 100723346f21SArnaldo Carvalho de Melo machine = perf_session__find_machine(session, self->ip.pid); 1008a1645ce1SZhang, Yanmin break; 1009a1645ce1SZhang, Yanmin case PERF_RECORD_MISC_GUEST_USER: 1010a1645ce1SZhang, Yanmin ++guest_us_samples; 1011a1645ce1SZhang, Yanmin /* 1012a1645ce1SZhang, Yanmin * TODO: we don't process guest user from host side 1013a1645ce1SZhang, Yanmin * except simple counting. 1014a1645ce1SZhang, Yanmin */ 1015a1645ce1SZhang, Yanmin return; 10165b2bb75aSArnaldo Carvalho de Melo default: 10175b2bb75aSArnaldo Carvalho de Melo return; 10185b2bb75aSArnaldo Carvalho de Melo } 10195b2bb75aSArnaldo Carvalho de Melo 102023346f21SArnaldo Carvalho de Melo if (!machine && perf_guest) { 1021a1645ce1SZhang, Yanmin pr_err("Can't find guest [%d]'s kernel information\n", 1022a1645ce1SZhang, Yanmin self->ip.pid); 1023a1645ce1SZhang, Yanmin return; 1024a1645ce1SZhang, Yanmin } 1025a1645ce1SZhang, Yanmin 1026ab608344SPeter Zijlstra if (self->header.misc & PERF_RECORD_MISC_EXACT_IP) 10271676b8a0SPeter Zijlstra exact_samples++; 10281676b8a0SPeter Zijlstra 102941a37e20SArnaldo Carvalho de Melo if (event__preprocess_sample(self, session, &al, &data, 103041a37e20SArnaldo Carvalho de Melo symbol_filter) < 0 || 103172b8fa17SArnaldo Carvalho de Melo al.filtered) 10321ed091c4SArnaldo Carvalho de Melo return; 103386470930SIngo Molnar 103472b8fa17SArnaldo Carvalho de Melo if (al.sym == NULL) { 103572b8fa17SArnaldo Carvalho de Melo /* 103672b8fa17SArnaldo Carvalho de Melo * As we do lazy loading of symtabs we only will know if the 103772b8fa17SArnaldo Carvalho de Melo * specified vmlinux file is invalid when we actually have a 103872b8fa17SArnaldo Carvalho de Melo * hit in kernel space and then try to load it. So if we get 103972b8fa17SArnaldo Carvalho de Melo * here and there are _no_ symbols in the DSO backing the 104072b8fa17SArnaldo Carvalho de Melo * kernel map, bail out. 104172b8fa17SArnaldo Carvalho de Melo * 104272b8fa17SArnaldo Carvalho de Melo * We may never get here, for instance, if we use -K/ 104372b8fa17SArnaldo Carvalho de Melo * --hide-kernel-symbols, even if the user specifies an 104472b8fa17SArnaldo Carvalho de Melo * invalid --vmlinux ;-) 104572b8fa17SArnaldo Carvalho de Melo */ 104623346f21SArnaldo Carvalho de Melo if (al.map == machine->vmlinux_maps[MAP__FUNCTION] && 104772b8fa17SArnaldo Carvalho de Melo RB_EMPTY_ROOT(&al.map->dso->symbols[MAP__FUNCTION])) { 104872b8fa17SArnaldo Carvalho de Melo pr_err("The %s file can't be used\n", 104972b8fa17SArnaldo Carvalho de Melo symbol_conf.vmlinux_name); 105072b8fa17SArnaldo Carvalho de Melo exit(1); 105172b8fa17SArnaldo Carvalho de Melo } 105272b8fa17SArnaldo Carvalho de Melo 105372b8fa17SArnaldo Carvalho de Melo return; 105472b8fa17SArnaldo Carvalho de Melo } 105572b8fa17SArnaldo Carvalho de Melo 10566cff0e8dSKirill Smelkov /* let's see, whether we need to install initial sym_filter_entry */ 10576cff0e8dSKirill Smelkov if (sym_filter_entry_sched) { 10586cff0e8dSKirill Smelkov sym_filter_entry = sym_filter_entry_sched; 10596cff0e8dSKirill Smelkov sym_filter_entry_sched = NULL; 1060b0a9ab62SArnaldo Carvalho de Melo if (parse_source(sym_filter_entry) < 0) { 1061b0a9ab62SArnaldo Carvalho de Melo struct symbol *sym = sym_entry__symbol(sym_filter_entry); 1062b0a9ab62SArnaldo Carvalho de Melo 1063b0a9ab62SArnaldo Carvalho de Melo pr_err("Can't annotate %s", sym->name); 1064b0a9ab62SArnaldo Carvalho de Melo if (sym_filter_entry->map->dso->origin == DSO__ORIG_KERNEL) { 1065b0a9ab62SArnaldo Carvalho de Melo pr_err(": No vmlinux file was found in the path:\n"); 10665ad90e4eSArnaldo Carvalho de Melo machine__fprintf_vmlinux_path(machine, stderr); 1067b0a9ab62SArnaldo Carvalho de Melo } else 1068b0a9ab62SArnaldo Carvalho de Melo pr_err(".\n"); 1069b0a9ab62SArnaldo Carvalho de Melo exit(1); 1070b0a9ab62SArnaldo Carvalho de Melo } 10716cff0e8dSKirill Smelkov } 10726cff0e8dSKirill Smelkov 10731ed091c4SArnaldo Carvalho de Melo syme = symbol__priv(al.sym); 107486470930SIngo Molnar if (!syme->skip) { 107586470930SIngo Molnar syme->count[counter]++; 10768ffcda17SArnaldo Carvalho de Melo syme->origin = origin; 1077923c42c1SMike Galbraith record_precise_ip(syme, counter, ip); 107886470930SIngo Molnar pthread_mutex_lock(&active_symbols_lock); 107986470930SIngo Molnar if (list_empty(&syme->node) || !syme->node.next) 108086470930SIngo Molnar __list_insert_active_sym(syme); 108186470930SIngo Molnar pthread_mutex_unlock(&active_symbols_lock); 108286470930SIngo Molnar } 108386470930SIngo Molnar } 108486470930SIngo Molnar 1085d8f66248SArnaldo Carvalho de Melo static int event__process(event_t *event, struct perf_session *session) 10865b2bb75aSArnaldo Carvalho de Melo { 10875b2bb75aSArnaldo Carvalho de Melo switch (event->header.type) { 10885b2bb75aSArnaldo Carvalho de Melo case PERF_RECORD_COMM: 1089d8f66248SArnaldo Carvalho de Melo event__process_comm(event, session); 10905b2bb75aSArnaldo Carvalho de Melo break; 10915b2bb75aSArnaldo Carvalho de Melo case PERF_RECORD_MMAP: 1092d8f66248SArnaldo Carvalho de Melo event__process_mmap(event, session); 10935b2bb75aSArnaldo Carvalho de Melo break; 10940f35cd4cSArnaldo Carvalho de Melo case PERF_RECORD_FORK: 10950f35cd4cSArnaldo Carvalho de Melo case PERF_RECORD_EXIT: 10960f35cd4cSArnaldo Carvalho de Melo event__process_task(event, session); 10970f35cd4cSArnaldo Carvalho de Melo break; 10985b2bb75aSArnaldo Carvalho de Melo default: 10995b2bb75aSArnaldo Carvalho de Melo break; 11005b2bb75aSArnaldo Carvalho de Melo } 11015b2bb75aSArnaldo Carvalho de Melo 11025b2bb75aSArnaldo Carvalho de Melo return 0; 110386470930SIngo Molnar } 110486470930SIngo Molnar 110586470930SIngo Molnar struct mmap_data { 110686470930SIngo Molnar int counter; 110786470930SIngo Molnar void *base; 1108f37a291cSIngo Molnar int mask; 110986470930SIngo Molnar unsigned int prev; 111086470930SIngo Molnar }; 111186470930SIngo Molnar 111286470930SIngo Molnar static unsigned int mmap_read_head(struct mmap_data *md) 111386470930SIngo Molnar { 1114cdd6c482SIngo Molnar struct perf_event_mmap_page *pc = md->base; 111586470930SIngo Molnar int head; 111686470930SIngo Molnar 111786470930SIngo Molnar head = pc->data_head; 111886470930SIngo Molnar rmb(); 111986470930SIngo Molnar 112086470930SIngo Molnar return head; 112186470930SIngo Molnar } 112286470930SIngo Molnar 1123d8f66248SArnaldo Carvalho de Melo static void perf_session__mmap_read_counter(struct perf_session *self, 1124d8f66248SArnaldo Carvalho de Melo struct mmap_data *md) 112586470930SIngo Molnar { 112686470930SIngo Molnar unsigned int head = mmap_read_head(md); 112786470930SIngo Molnar unsigned int old = md->prev; 112886470930SIngo Molnar unsigned char *data = md->base + page_size; 112986470930SIngo Molnar int diff; 113086470930SIngo Molnar 113186470930SIngo Molnar /* 113286470930SIngo Molnar * If we're further behind than half the buffer, there's a chance 113386470930SIngo Molnar * the writer will bite our tail and mess up the samples under us. 113486470930SIngo Molnar * 113586470930SIngo Molnar * If we somehow ended up ahead of the head, we got messed up. 113686470930SIngo Molnar * 113786470930SIngo Molnar * In either case, truncate and restart at head. 113886470930SIngo Molnar */ 113986470930SIngo Molnar diff = head - old; 114086470930SIngo Molnar if (diff > md->mask / 2 || diff < 0) { 1141f4f0b418SMike Galbraith fprintf(stderr, "WARNING: failed to keep up with mmap data.\n"); 114286470930SIngo Molnar 114386470930SIngo Molnar /* 114486470930SIngo Molnar * head points to a known good entry, start there. 114586470930SIngo Molnar */ 114686470930SIngo Molnar old = head; 114786470930SIngo Molnar } 114886470930SIngo Molnar 114986470930SIngo Molnar for (; old != head;) { 115086470930SIngo Molnar event_t *event = (event_t *)&data[old & md->mask]; 115186470930SIngo Molnar 115286470930SIngo Molnar event_t event_copy; 115386470930SIngo Molnar 115486470930SIngo Molnar size_t size = event->header.size; 115586470930SIngo Molnar 115686470930SIngo Molnar /* 115786470930SIngo Molnar * Event straddles the mmap boundary -- header should always 115886470930SIngo Molnar * be inside due to u64 alignment of output. 115986470930SIngo Molnar */ 116086470930SIngo Molnar if ((old & md->mask) + size != ((old + size) & md->mask)) { 116186470930SIngo Molnar unsigned int offset = old; 116286470930SIngo Molnar unsigned int len = min(sizeof(*event), size), cpy; 116386470930SIngo Molnar void *dst = &event_copy; 116486470930SIngo Molnar 116586470930SIngo Molnar do { 116686470930SIngo Molnar cpy = min(md->mask + 1 - (offset & md->mask), len); 116786470930SIngo Molnar memcpy(dst, &data[offset & md->mask], cpy); 116886470930SIngo Molnar offset += cpy; 116986470930SIngo Molnar dst += cpy; 117086470930SIngo Molnar len -= cpy; 117186470930SIngo Molnar } while (len); 117286470930SIngo Molnar 117386470930SIngo Molnar event = &event_copy; 117486470930SIngo Molnar } 117586470930SIngo Molnar 11765b2bb75aSArnaldo Carvalho de Melo if (event->header.type == PERF_RECORD_SAMPLE) 1177b3165f41SArnaldo Carvalho de Melo event__process_sample(event, self, md->counter); 11785b2bb75aSArnaldo Carvalho de Melo else 1179d8f66248SArnaldo Carvalho de Melo event__process(event, self); 118086470930SIngo Molnar old += size; 118186470930SIngo Molnar } 118286470930SIngo Molnar 118386470930SIngo Molnar md->prev = old; 118486470930SIngo Molnar } 118586470930SIngo Molnar 1186d6d901c2SZhang, Yanmin static struct pollfd *event_array; 1187d6d901c2SZhang, Yanmin static struct mmap_data *mmap_array[MAX_NR_CPUS][MAX_COUNTERS]; 118886470930SIngo Molnar 1189d8f66248SArnaldo Carvalho de Melo static void perf_session__mmap_read(struct perf_session *self) 11902f01190aSFrederic Weisbecker { 1191d6d901c2SZhang, Yanmin int i, counter, thread_index; 11922f01190aSFrederic Weisbecker 11932f01190aSFrederic Weisbecker for (i = 0; i < nr_cpus; i++) { 11942f01190aSFrederic Weisbecker for (counter = 0; counter < nr_counters; counter++) 1195d6d901c2SZhang, Yanmin for (thread_index = 0; 1196d6d901c2SZhang, Yanmin thread_index < thread_num; 1197d6d901c2SZhang, Yanmin thread_index++) { 1198d6d901c2SZhang, Yanmin perf_session__mmap_read_counter(self, 1199d6d901c2SZhang, Yanmin &mmap_array[i][counter][thread_index]); 1200d6d901c2SZhang, Yanmin } 12012f01190aSFrederic Weisbecker } 12022f01190aSFrederic Weisbecker } 12032f01190aSFrederic Weisbecker 1204716c69feSIngo Molnar int nr_poll; 1205716c69feSIngo Molnar int group_fd; 1206716c69feSIngo Molnar 1207716c69feSIngo Molnar static void start_counter(int i, int counter) 120886470930SIngo Molnar { 1209cdd6c482SIngo Molnar struct perf_event_attr *attr; 12100fdc7e67SMike Galbraith int cpu; 1211d6d901c2SZhang, Yanmin int thread_index; 121286470930SIngo Molnar 121386470930SIngo Molnar cpu = profile_cpu; 1214d6d901c2SZhang, Yanmin if (target_tid == -1 && profile_cpu == -1) 1215a12b51c4SPaul Mackerras cpu = cpumap[i]; 121686470930SIngo Molnar 121786470930SIngo Molnar attr = attrs + counter; 121886470930SIngo Molnar 121986470930SIngo Molnar attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID; 12207e4ff9e3SMike Galbraith 12217e4ff9e3SMike Galbraith if (freq) { 12227e4ff9e3SMike Galbraith attr->sample_type |= PERF_SAMPLE_PERIOD; 12237e4ff9e3SMike Galbraith attr->freq = 1; 12247e4ff9e3SMike Galbraith attr->sample_freq = freq; 12257e4ff9e3SMike Galbraith } 12267e4ff9e3SMike Galbraith 12270fdc7e67SMike Galbraith attr->inherit = (cpu < 0) && inherit; 12285b2bb75aSArnaldo Carvalho de Melo attr->mmap = 1; 122986470930SIngo Molnar 1230d6d901c2SZhang, Yanmin for (thread_index = 0; thread_index < thread_num; thread_index++) { 1231716c69feSIngo Molnar try_again: 1232d6d901c2SZhang, Yanmin fd[i][counter][thread_index] = sys_perf_event_open(attr, 1233d6d901c2SZhang, Yanmin all_tids[thread_index], cpu, group_fd, 0); 1234716c69feSIngo Molnar 1235d6d901c2SZhang, Yanmin if (fd[i][counter][thread_index] < 0) { 123686470930SIngo Molnar int err = errno; 123786470930SIngo Molnar 1238c10edee2SPekka Enberg if (err == EPERM || err == EACCES) 1239716c69feSIngo Molnar die("No permission - are you root?\n"); 1240716c69feSIngo Molnar /* 1241716c69feSIngo Molnar * If it's cycles then fall back to hrtimer 1242716c69feSIngo Molnar * based cpu-clock-tick sw counter, which 1243716c69feSIngo Molnar * is always available even if no PMU support: 1244716c69feSIngo Molnar */ 1245716c69feSIngo Molnar if (attr->type == PERF_TYPE_HARDWARE 1246f4dbfa8fSPeter Zijlstra && attr->config == PERF_COUNT_HW_CPU_CYCLES) { 1247716c69feSIngo Molnar 12483da297a6SIngo Molnar if (verbose) 1249716c69feSIngo Molnar warning(" ... trying to fall back to cpu-clock-ticks\n"); 12503da297a6SIngo Molnar 1251716c69feSIngo Molnar attr->type = PERF_TYPE_SOFTWARE; 1252f4dbfa8fSPeter Zijlstra attr->config = PERF_COUNT_SW_CPU_CLOCK; 1253716c69feSIngo Molnar goto try_again; 1254716c69feSIngo Molnar } 125530c806a0SIngo Molnar printf("\n"); 125630c806a0SIngo Molnar error("perfcounter syscall returned with %d (%s)\n", 1257d6d901c2SZhang, Yanmin fd[i][counter][thread_index], strerror(err)); 1258cdd6c482SIngo Molnar die("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); 125986470930SIngo Molnar exit(-1); 126086470930SIngo Molnar } 1261d6d901c2SZhang, Yanmin assert(fd[i][counter][thread_index] >= 0); 1262d6d901c2SZhang, Yanmin fcntl(fd[i][counter][thread_index], F_SETFL, O_NONBLOCK); 126386470930SIngo Molnar 126486470930SIngo Molnar /* 126586470930SIngo Molnar * First counter acts as the group leader: 126686470930SIngo Molnar */ 126786470930SIngo Molnar if (group && group_fd == -1) 1268d6d901c2SZhang, Yanmin group_fd = fd[i][counter][thread_index]; 126986470930SIngo Molnar 1270d6d901c2SZhang, Yanmin event_array[nr_poll].fd = fd[i][counter][thread_index]; 127186470930SIngo Molnar event_array[nr_poll].events = POLLIN; 127286470930SIngo Molnar nr_poll++; 127386470930SIngo Molnar 1274d6d901c2SZhang, Yanmin mmap_array[i][counter][thread_index].counter = counter; 1275d6d901c2SZhang, Yanmin mmap_array[i][counter][thread_index].prev = 0; 1276d6d901c2SZhang, Yanmin mmap_array[i][counter][thread_index].mask = mmap_pages*page_size - 1; 1277d6d901c2SZhang, Yanmin mmap_array[i][counter][thread_index].base = mmap(NULL, (mmap_pages+1)*page_size, 1278d6d901c2SZhang, Yanmin PROT_READ, MAP_SHARED, fd[i][counter][thread_index], 0); 1279d6d901c2SZhang, Yanmin if (mmap_array[i][counter][thread_index].base == MAP_FAILED) 128086470930SIngo Molnar die("failed to mmap with %d (%s)\n", errno, strerror(errno)); 128186470930SIngo Molnar } 1282d6d901c2SZhang, Yanmin } 1283716c69feSIngo Molnar 1284716c69feSIngo Molnar static int __cmd_top(void) 1285716c69feSIngo Molnar { 1286716c69feSIngo Molnar pthread_t thread; 1287716c69feSIngo Molnar int i, counter; 1288716c69feSIngo Molnar int ret; 1289d8f66248SArnaldo Carvalho de Melo /* 1290b3165f41SArnaldo Carvalho de Melo * FIXME: perf_session__new should allow passing a O_MMAP, so that all this 1291b3165f41SArnaldo Carvalho de Melo * mmap reading, etc is encapsulated in it. Use O_WRONLY for now. 1292d8f66248SArnaldo Carvalho de Melo */ 1293454c407eSTom Zanussi struct perf_session *session = perf_session__new(NULL, O_WRONLY, false, false); 1294b3165f41SArnaldo Carvalho de Melo if (session == NULL) 1295b3165f41SArnaldo Carvalho de Melo return -ENOMEM; 1296716c69feSIngo Molnar 1297d6d901c2SZhang, Yanmin if (target_tid != -1) 1298d6d901c2SZhang, Yanmin event__synthesize_thread(target_tid, event__process, session); 12995b2bb75aSArnaldo Carvalho de Melo else 1300d8f66248SArnaldo Carvalho de Melo event__synthesize_threads(event__process, session); 13015b2bb75aSArnaldo Carvalho de Melo 1302716c69feSIngo Molnar for (i = 0; i < nr_cpus; i++) { 1303716c69feSIngo Molnar group_fd = -1; 1304716c69feSIngo Molnar for (counter = 0; counter < nr_counters; counter++) 1305716c69feSIngo Molnar start_counter(i, counter); 130686470930SIngo Molnar } 130786470930SIngo Molnar 13082f01190aSFrederic Weisbecker /* Wait for a minimal set of events before starting the snapshot */ 1309d6d901c2SZhang, Yanmin poll(&event_array[0], nr_poll, 100); 13102f01190aSFrederic Weisbecker 1311d8f66248SArnaldo Carvalho de Melo perf_session__mmap_read(session); 13122f01190aSFrederic Weisbecker 1313a1645ce1SZhang, Yanmin if (pthread_create(&thread, NULL, display_thread, session)) { 131486470930SIngo Molnar printf("Could not create display thread.\n"); 131586470930SIngo Molnar exit(-1); 131686470930SIngo Molnar } 131786470930SIngo Molnar 131886470930SIngo Molnar if (realtime_prio) { 131986470930SIngo Molnar struct sched_param param; 132086470930SIngo Molnar 132186470930SIngo Molnar param.sched_priority = realtime_prio; 132286470930SIngo Molnar if (sched_setscheduler(0, SCHED_FIFO, ¶m)) { 132386470930SIngo Molnar printf("Could not set realtime priority.\n"); 132486470930SIngo Molnar exit(-1); 132586470930SIngo Molnar } 132686470930SIngo Molnar } 132786470930SIngo Molnar 132886470930SIngo Molnar while (1) { 132986470930SIngo Molnar int hits = samples; 133086470930SIngo Molnar 1331d8f66248SArnaldo Carvalho de Melo perf_session__mmap_read(session); 133286470930SIngo Molnar 133386470930SIngo Molnar if (hits == samples) 133486470930SIngo Molnar ret = poll(event_array, nr_poll, 100); 133586470930SIngo Molnar } 133686470930SIngo Molnar 133786470930SIngo Molnar return 0; 133886470930SIngo Molnar } 133986470930SIngo Molnar 134086470930SIngo Molnar static const char * const top_usage[] = { 134186470930SIngo Molnar "perf top [<options>]", 134286470930SIngo Molnar NULL 134386470930SIngo Molnar }; 134486470930SIngo Molnar 134586470930SIngo Molnar static const struct option options[] = { 134686470930SIngo Molnar OPT_CALLBACK('e', "event", NULL, "event", 134786470930SIngo Molnar "event selector. use 'perf list' to list available events", 134886470930SIngo Molnar parse_events), 134986470930SIngo Molnar OPT_INTEGER('c', "count", &default_interval, 135086470930SIngo Molnar "event period to sample"), 135186470930SIngo Molnar OPT_INTEGER('p', "pid", &target_pid, 1352d6d901c2SZhang, Yanmin "profile events on existing process id"), 1353d6d901c2SZhang, Yanmin OPT_INTEGER('t', "tid", &target_tid, 1354d6d901c2SZhang, Yanmin "profile events on existing thread id"), 135586470930SIngo Molnar OPT_BOOLEAN('a', "all-cpus", &system_wide, 135686470930SIngo Molnar "system-wide collection from all CPUs"), 1357c45c6ea2SStephane Eranian OPT_STRING('C', "cpu", &cpu_list, "cpu", 1358c45c6ea2SStephane Eranian "list of cpus to monitor"), 1359b32d133aSArnaldo Carvalho de Melo OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, 1360b32d133aSArnaldo Carvalho de Melo "file", "vmlinux pathname"), 13618ffcda17SArnaldo Carvalho de Melo OPT_BOOLEAN('K', "hide_kernel_symbols", &hide_kernel_symbols, 13628ffcda17SArnaldo Carvalho de Melo "hide kernel symbols"), 13631967936dSArnaldo Carvalho de Melo OPT_UINTEGER('m', "mmap-pages", &mmap_pages, "number of mmap data pages"), 136486470930SIngo Molnar OPT_INTEGER('r', "realtime", &realtime_prio, 136586470930SIngo Molnar "collect data with this RT SCHED_FIFO priority"), 136686470930SIngo Molnar OPT_INTEGER('d', "delay", &delay_secs, 136786470930SIngo Molnar "number of seconds to delay between refreshes"), 136886470930SIngo Molnar OPT_BOOLEAN('D', "dump-symtab", &dump_symtab, 136986470930SIngo Molnar "dump the symbol table used for profiling"), 137086470930SIngo Molnar OPT_INTEGER('f', "count-filter", &count_filter, 137186470930SIngo Molnar "only display functions with more events than this"), 137286470930SIngo Molnar OPT_BOOLEAN('g', "group", &group, 137386470930SIngo Molnar "put the counters into a counter group"), 13740fdc7e67SMike Galbraith OPT_BOOLEAN('i', "inherit", &inherit, 13750fdc7e67SMike Galbraith "child tasks inherit counters"), 1376923c42c1SMike Galbraith OPT_STRING('s', "sym-annotate", &sym_filter, "symbol name", 13776cff0e8dSKirill Smelkov "symbol to annotate"), 13781f208ea6SAnton Blanchard OPT_BOOLEAN('z', "zero", &zero, 137986470930SIngo Molnar "zero history across updates"), 138086470930SIngo Molnar OPT_INTEGER('F', "freq", &freq, 138186470930SIngo Molnar "profile at this frequency"), 138286470930SIngo Molnar OPT_INTEGER('E', "entries", &print_entries, 138386470930SIngo Molnar "display this many functions"), 13848ffcda17SArnaldo Carvalho de Melo OPT_BOOLEAN('U', "hide_user_symbols", &hide_user_symbols, 13858ffcda17SArnaldo Carvalho de Melo "hide user symbols"), 1386c0555642SIan Munsie OPT_INCR('v', "verbose", &verbose, 13873da297a6SIngo Molnar "be more verbose (show counter open errors, etc)"), 138886470930SIngo Molnar OPT_END() 138986470930SIngo Molnar }; 139086470930SIngo Molnar 1391f37a291cSIngo Molnar int cmd_top(int argc, const char **argv, const char *prefix __used) 139286470930SIngo Molnar { 1393b32d133aSArnaldo Carvalho de Melo int counter; 1394d6d901c2SZhang, Yanmin int i,j; 139586470930SIngo Molnar 139686470930SIngo Molnar page_size = sysconf(_SC_PAGE_SIZE); 139786470930SIngo Molnar 139886470930SIngo Molnar argc = parse_options(argc, argv, options, top_usage, 0); 139986470930SIngo Molnar if (argc) 140086470930SIngo Molnar usage_with_options(top_usage, options); 140186470930SIngo Molnar 1402d6d901c2SZhang, Yanmin if (target_pid != -1) { 1403d6d901c2SZhang, Yanmin target_tid = target_pid; 1404d6d901c2SZhang, Yanmin thread_num = find_all_tid(target_pid, &all_tids); 1405d6d901c2SZhang, Yanmin if (thread_num <= 0) { 1406d6d901c2SZhang, Yanmin fprintf(stderr, "Can't find all threads of pid %d\n", 1407d6d901c2SZhang, Yanmin target_pid); 1408d6d901c2SZhang, Yanmin usage_with_options(top_usage, options); 1409d6d901c2SZhang, Yanmin } 1410d6d901c2SZhang, Yanmin } else { 1411d6d901c2SZhang, Yanmin all_tids=malloc(sizeof(pid_t)); 1412d6d901c2SZhang, Yanmin if (!all_tids) 1413d6d901c2SZhang, Yanmin return -ENOMEM; 1414d6d901c2SZhang, Yanmin 1415d6d901c2SZhang, Yanmin all_tids[0] = target_tid; 1416d6d901c2SZhang, Yanmin thread_num = 1; 1417d6d901c2SZhang, Yanmin } 1418d6d901c2SZhang, Yanmin 1419d6d901c2SZhang, Yanmin for (i = 0; i < MAX_NR_CPUS; i++) { 1420d6d901c2SZhang, Yanmin for (j = 0; j < MAX_COUNTERS; j++) { 1421d6d901c2SZhang, Yanmin fd[i][j] = malloc(sizeof(int)*thread_num); 14225a103174SZhang, Yanmin mmap_array[i][j] = zalloc( 1423d6d901c2SZhang, Yanmin sizeof(struct mmap_data)*thread_num); 1424d6d901c2SZhang, Yanmin if (!fd[i][j] || !mmap_array[i][j]) 1425d6d901c2SZhang, Yanmin return -ENOMEM; 1426d6d901c2SZhang, Yanmin } 1427d6d901c2SZhang, Yanmin } 1428d6d901c2SZhang, Yanmin event_array = malloc( 1429d6d901c2SZhang, Yanmin sizeof(struct pollfd)*MAX_NR_CPUS*MAX_COUNTERS*thread_num); 1430d6d901c2SZhang, Yanmin if (!event_array) 1431d6d901c2SZhang, Yanmin return -ENOMEM; 1432d6d901c2SZhang, Yanmin 143386470930SIngo Molnar /* CPU and PID are mutually exclusive */ 1434c45c6ea2SStephane Eranian if (target_tid > 0 && cpu_list) { 143586470930SIngo Molnar printf("WARNING: PID switch overriding CPU\n"); 143686470930SIngo Molnar sleep(1); 1437c45c6ea2SStephane Eranian cpu_list = NULL; 143886470930SIngo Molnar } 143986470930SIngo Molnar 144086470930SIngo Molnar if (!nr_counters) 144186470930SIngo Molnar nr_counters = 1; 144286470930SIngo Molnar 1443b32d133aSArnaldo Carvalho de Melo symbol_conf.priv_size = (sizeof(struct sym_entry) + 14445a8e5a30SArnaldo Carvalho de Melo (nr_counters + 1) * sizeof(unsigned long)); 14456cff0e8dSKirill Smelkov 14466cff0e8dSKirill Smelkov symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL); 144775be6cf4SArnaldo Carvalho de Melo if (symbol__init() < 0) 1448b32d133aSArnaldo Carvalho de Melo return -1; 14495a8e5a30SArnaldo Carvalho de Melo 145086470930SIngo Molnar if (delay_secs < 1) 145186470930SIngo Molnar delay_secs = 1; 145286470930SIngo Molnar 14537e4ff9e3SMike Galbraith /* 14547e4ff9e3SMike Galbraith * User specified count overrides default frequency. 14557e4ff9e3SMike Galbraith */ 14567e4ff9e3SMike Galbraith if (default_interval) 14577e4ff9e3SMike Galbraith freq = 0; 14587e4ff9e3SMike Galbraith else if (freq) { 14597e4ff9e3SMike Galbraith default_interval = freq; 14607e4ff9e3SMike Galbraith } else { 14617e4ff9e3SMike Galbraith fprintf(stderr, "frequency and count are zero, aborting\n"); 14627e4ff9e3SMike Galbraith exit(EXIT_FAILURE); 14637e4ff9e3SMike Galbraith } 14647e4ff9e3SMike Galbraith 146586470930SIngo Molnar /* 146686470930SIngo Molnar * Fill in the ones not specifically initialized via -c: 146786470930SIngo Molnar */ 146886470930SIngo Molnar for (counter = 0; counter < nr_counters; counter++) { 146986470930SIngo Molnar if (attrs[counter].sample_period) 147086470930SIngo Molnar continue; 147186470930SIngo Molnar 147286470930SIngo Molnar attrs[counter].sample_period = default_interval; 147386470930SIngo Molnar } 147486470930SIngo Molnar 1475c45c6ea2SStephane Eranian if (target_tid != -1) 147686470930SIngo Molnar nr_cpus = 1; 1477a12b51c4SPaul Mackerras else 1478c45c6ea2SStephane Eranian nr_cpus = read_cpu_map(cpu_list); 1479c45c6ea2SStephane Eranian 1480c45c6ea2SStephane Eranian if (nr_cpus < 1) 1481c45c6ea2SStephane Eranian usage_with_options(top_usage, options); 148286470930SIngo Molnar 148313cc5079SArnaldo Carvalho de Melo get_term_dimensions(&winsize); 14843b6ed988SArnaldo Carvalho de Melo if (print_entries == 0) { 148513cc5079SArnaldo Carvalho de Melo update_print_entries(&winsize); 14863b6ed988SArnaldo Carvalho de Melo signal(SIGWINCH, sig_winch_handler); 14873b6ed988SArnaldo Carvalho de Melo } 14883b6ed988SArnaldo Carvalho de Melo 148986470930SIngo Molnar return __cmd_top(); 149086470930SIngo Molnar } 1491