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/symbol.h" 2486470930SIngo Molnar #include "util/color.h" 2586470930SIngo Molnar #include "util/util.h" 2686470930SIngo Molnar #include "util/rbtree.h" 2786470930SIngo Molnar #include "util/parse-options.h" 2886470930SIngo Molnar #include "util/parse-events.h" 2986470930SIngo Molnar 3086470930SIngo Molnar #include <assert.h> 3186470930SIngo Molnar #include <fcntl.h> 3286470930SIngo Molnar 3386470930SIngo Molnar #include <stdio.h> 3486470930SIngo Molnar 3586470930SIngo Molnar #include <errno.h> 3686470930SIngo Molnar #include <time.h> 3786470930SIngo Molnar #include <sched.h> 3886470930SIngo Molnar #include <pthread.h> 3986470930SIngo Molnar 4086470930SIngo Molnar #include <sys/syscall.h> 4186470930SIngo Molnar #include <sys/ioctl.h> 4286470930SIngo Molnar #include <sys/poll.h> 4386470930SIngo Molnar #include <sys/prctl.h> 4486470930SIngo Molnar #include <sys/wait.h> 4586470930SIngo Molnar #include <sys/uio.h> 4686470930SIngo Molnar #include <sys/mman.h> 4786470930SIngo Molnar 4886470930SIngo Molnar #include <linux/unistd.h> 4986470930SIngo Molnar #include <linux/types.h> 5086470930SIngo Molnar 5186470930SIngo Molnar static int fd[MAX_NR_CPUS][MAX_COUNTERS]; 5286470930SIngo Molnar 5386470930SIngo Molnar static int system_wide = 0; 5486470930SIngo Molnar 5586470930SIngo Molnar static int default_interval = 100000; 5686470930SIngo Molnar 579cffa8d5SPaul Mackerras static u64 count_filter = 5; 5886470930SIngo Molnar static int print_entries = 15; 5986470930SIngo Molnar 6086470930SIngo Molnar static int target_pid = -1; 6186470930SIngo Molnar static int profile_cpu = -1; 6286470930SIngo Molnar static int nr_cpus = 0; 6386470930SIngo Molnar static unsigned int realtime_prio = 0; 6486470930SIngo Molnar static int group = 0; 6586470930SIngo Molnar static unsigned int page_size; 6686470930SIngo Molnar static unsigned int mmap_pages = 16; 6786470930SIngo Molnar static int freq = 0; 683da297a6SIngo Molnar static int verbose = 0; 6986470930SIngo Molnar 7086470930SIngo Molnar static char *sym_filter; 7186470930SIngo Molnar static unsigned long filter_start; 7286470930SIngo Molnar static unsigned long filter_end; 7386470930SIngo Molnar 7486470930SIngo Molnar static int delay_secs = 2; 7586470930SIngo Molnar static int zero; 7686470930SIngo Molnar static int dump_symtab; 7786470930SIngo Molnar 7886470930SIngo Molnar /* 7986470930SIngo Molnar * Symbols 8086470930SIngo Molnar */ 8186470930SIngo Molnar 829cffa8d5SPaul Mackerras static u64 min_ip; 839cffa8d5SPaul Mackerras static u64 max_ip = -1ll; 8486470930SIngo Molnar 8586470930SIngo Molnar struct sym_entry { 8686470930SIngo Molnar struct rb_node rb_node; 8786470930SIngo Molnar struct list_head node; 8886470930SIngo Molnar unsigned long count[MAX_COUNTERS]; 8986470930SIngo Molnar unsigned long snap_count; 9086470930SIngo Molnar double weight; 9186470930SIngo Molnar int skip; 9286470930SIngo Molnar }; 9386470930SIngo Molnar 9486470930SIngo Molnar struct sym_entry *sym_filter_entry; 9586470930SIngo Molnar 9686470930SIngo Molnar struct dso *kernel_dso; 9786470930SIngo Molnar 9886470930SIngo Molnar /* 9986470930SIngo Molnar * Symbols will be added here in record_ip and will get out 10086470930SIngo Molnar * after decayed. 10186470930SIngo Molnar */ 10286470930SIngo Molnar static LIST_HEAD(active_symbols); 10386470930SIngo Molnar static pthread_mutex_t active_symbols_lock = PTHREAD_MUTEX_INITIALIZER; 10486470930SIngo Molnar 10586470930SIngo Molnar /* 10686470930SIngo Molnar * Ordering weight: count-1 * count-2 * ... / count-n 10786470930SIngo Molnar */ 10886470930SIngo Molnar static double sym_weight(const struct sym_entry *sym) 10986470930SIngo Molnar { 11086470930SIngo Molnar double weight = sym->snap_count; 11186470930SIngo Molnar int counter; 11286470930SIngo Molnar 11386470930SIngo Molnar for (counter = 1; counter < nr_counters-1; counter++) 11486470930SIngo Molnar weight *= sym->count[counter]; 11586470930SIngo Molnar 11686470930SIngo Molnar weight /= (sym->count[counter] + 1); 11786470930SIngo Molnar 11886470930SIngo Molnar return weight; 11986470930SIngo Molnar } 12086470930SIngo Molnar 12186470930SIngo Molnar static long samples; 12286470930SIngo Molnar static long userspace_samples; 12386470930SIngo Molnar static const char CONSOLE_CLEAR[] = "[H[2J"; 12486470930SIngo Molnar 12586470930SIngo Molnar static void __list_insert_active_sym(struct sym_entry *syme) 12686470930SIngo Molnar { 12786470930SIngo Molnar list_add(&syme->node, &active_symbols); 12886470930SIngo Molnar } 12986470930SIngo Molnar 13086470930SIngo Molnar static void list_remove_active_sym(struct sym_entry *syme) 13186470930SIngo Molnar { 13286470930SIngo Molnar pthread_mutex_lock(&active_symbols_lock); 13386470930SIngo Molnar list_del_init(&syme->node); 13486470930SIngo Molnar pthread_mutex_unlock(&active_symbols_lock); 13586470930SIngo Molnar } 13686470930SIngo Molnar 13786470930SIngo Molnar static void rb_insert_active_sym(struct rb_root *tree, struct sym_entry *se) 13886470930SIngo Molnar { 13986470930SIngo Molnar struct rb_node **p = &tree->rb_node; 14086470930SIngo Molnar struct rb_node *parent = NULL; 14186470930SIngo Molnar struct sym_entry *iter; 14286470930SIngo Molnar 14386470930SIngo Molnar while (*p != NULL) { 14486470930SIngo Molnar parent = *p; 14586470930SIngo Molnar iter = rb_entry(parent, struct sym_entry, rb_node); 14686470930SIngo Molnar 14786470930SIngo Molnar if (se->weight > iter->weight) 14886470930SIngo Molnar p = &(*p)->rb_left; 14986470930SIngo Molnar else 15086470930SIngo Molnar p = &(*p)->rb_right; 15186470930SIngo Molnar } 15286470930SIngo Molnar 15386470930SIngo Molnar rb_link_node(&se->rb_node, parent, p); 15486470930SIngo Molnar rb_insert_color(&se->rb_node, tree); 15586470930SIngo Molnar } 15686470930SIngo Molnar 15786470930SIngo Molnar static void print_sym_table(void) 15886470930SIngo Molnar { 15986470930SIngo Molnar int printed = 0, j; 16086470930SIngo Molnar int counter; 16186470930SIngo Molnar float samples_per_sec = samples/delay_secs; 16286470930SIngo Molnar float ksamples_per_sec = (samples-userspace_samples)/delay_secs; 16386470930SIngo Molnar float sum_ksamples = 0.0; 16486470930SIngo Molnar struct sym_entry *syme, *n; 16586470930SIngo Molnar struct rb_root tmp = RB_ROOT; 16686470930SIngo Molnar struct rb_node *nd; 16786470930SIngo Molnar 16886470930SIngo Molnar samples = userspace_samples = 0; 16986470930SIngo Molnar 17086470930SIngo Molnar /* Sort the active symbols */ 17186470930SIngo Molnar pthread_mutex_lock(&active_symbols_lock); 17286470930SIngo Molnar syme = list_entry(active_symbols.next, struct sym_entry, node); 17386470930SIngo Molnar pthread_mutex_unlock(&active_symbols_lock); 17486470930SIngo Molnar 17586470930SIngo Molnar list_for_each_entry_safe_from(syme, n, &active_symbols, node) { 17686470930SIngo Molnar syme->snap_count = syme->count[0]; 17786470930SIngo Molnar if (syme->snap_count != 0) { 17886470930SIngo Molnar syme->weight = sym_weight(syme); 17986470930SIngo Molnar rb_insert_active_sym(&tmp, syme); 18086470930SIngo Molnar sum_ksamples += syme->snap_count; 18186470930SIngo Molnar 18286470930SIngo Molnar for (j = 0; j < nr_counters; j++) 18386470930SIngo Molnar syme->count[j] = zero ? 0 : syme->count[j] * 7 / 8; 18486470930SIngo Molnar } else 18586470930SIngo Molnar list_remove_active_sym(syme); 18686470930SIngo Molnar } 18786470930SIngo Molnar 18886470930SIngo Molnar puts(CONSOLE_CLEAR); 18986470930SIngo Molnar 19086470930SIngo Molnar printf( 19186470930SIngo Molnar "------------------------------------------------------------------------------\n"); 19286470930SIngo Molnar printf( " PerfTop:%8.0f irqs/sec kernel:%4.1f%% [", 19386470930SIngo Molnar samples_per_sec, 19486470930SIngo Molnar 100.0 - (100.0*((samples_per_sec-ksamples_per_sec)/samples_per_sec))); 19586470930SIngo Molnar 19686470930SIngo Molnar if (nr_counters == 1) { 1979cffa8d5SPaul Mackerras printf("%Ld", (u64)attrs[0].sample_period); 19886470930SIngo Molnar if (freq) 19986470930SIngo Molnar printf("Hz "); 20086470930SIngo Molnar else 20186470930SIngo Molnar printf(" "); 20286470930SIngo Molnar } 20386470930SIngo Molnar 20486470930SIngo Molnar for (counter = 0; counter < nr_counters; counter++) { 20586470930SIngo Molnar if (counter) 20686470930SIngo Molnar printf("/"); 20786470930SIngo Molnar 20886470930SIngo Molnar printf("%s", event_name(counter)); 20986470930SIngo Molnar } 21086470930SIngo Molnar 21186470930SIngo Molnar printf( "], "); 21286470930SIngo Molnar 21386470930SIngo Molnar if (target_pid != -1) 21486470930SIngo Molnar printf(" (target_pid: %d", target_pid); 21586470930SIngo Molnar else 21686470930SIngo Molnar printf(" (all"); 21786470930SIngo Molnar 21886470930SIngo Molnar if (profile_cpu != -1) 21986470930SIngo Molnar printf(", cpu: %d)\n", profile_cpu); 22086470930SIngo Molnar else { 22186470930SIngo Molnar if (target_pid != -1) 22286470930SIngo Molnar printf(")\n"); 22386470930SIngo Molnar else 22486470930SIngo Molnar printf(", %d CPUs)\n", nr_cpus); 22586470930SIngo Molnar } 22686470930SIngo Molnar 22786470930SIngo Molnar printf("------------------------------------------------------------------------------\n\n"); 22886470930SIngo Molnar 22986470930SIngo Molnar if (nr_counters == 1) 23086470930SIngo Molnar printf(" samples pcnt"); 23186470930SIngo Molnar else 23286470930SIngo Molnar printf(" weight samples pcnt"); 23386470930SIngo Molnar 23486470930SIngo Molnar printf(" RIP kernel function\n" 23586470930SIngo Molnar " ______ _______ _____ ________________ _______________\n\n" 23686470930SIngo Molnar ); 23786470930SIngo Molnar 23886470930SIngo Molnar for (nd = rb_first(&tmp); nd; nd = rb_next(nd)) { 23986470930SIngo Molnar struct sym_entry *syme = rb_entry(nd, struct sym_entry, rb_node); 24086470930SIngo Molnar struct symbol *sym = (struct symbol *)(syme + 1); 24186470930SIngo Molnar char *color = PERF_COLOR_NORMAL; 24286470930SIngo Molnar double pcnt; 24386470930SIngo Molnar 24486470930SIngo Molnar if (++printed > print_entries || syme->snap_count < count_filter) 24586470930SIngo Molnar continue; 24686470930SIngo Molnar 24786470930SIngo Molnar pcnt = 100.0 - (100.0 * ((sum_ksamples - syme->snap_count) / 24886470930SIngo Molnar sum_ksamples)); 24986470930SIngo Molnar 25086470930SIngo Molnar /* 251aefcf37bSIngo Molnar * We color high-overhead entries in red, mid-overhead 252aefcf37bSIngo Molnar * entries in green - and keep the low overhead places 253aefcf37bSIngo Molnar * normal: 25486470930SIngo Molnar */ 255aefcf37bSIngo Molnar if (pcnt >= 5.0) { 25686470930SIngo Molnar color = PERF_COLOR_RED; 257aefcf37bSIngo Molnar } else { 258aefcf37bSIngo Molnar if (pcnt >= 0.5) 25986470930SIngo Molnar color = PERF_COLOR_GREEN; 260aefcf37bSIngo Molnar } 26186470930SIngo Molnar 26286470930SIngo Molnar if (nr_counters == 1) 26386470930SIngo Molnar printf("%20.2f - ", syme->weight); 26486470930SIngo Molnar else 26586470930SIngo Molnar printf("%9.1f %10ld - ", syme->weight, syme->snap_count); 26686470930SIngo Molnar 26786470930SIngo Molnar color_fprintf(stdout, color, "%4.1f%%", pcnt); 26886470930SIngo Molnar printf(" - %016llx : %s\n", sym->start, sym->name); 26986470930SIngo Molnar } 27086470930SIngo Molnar } 27186470930SIngo Molnar 272f37a291cSIngo Molnar static void *display_thread(void *arg __used) 27386470930SIngo Molnar { 27486470930SIngo Molnar struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; 27586470930SIngo Molnar int delay_msecs = delay_secs * 1000; 27686470930SIngo Molnar 27786470930SIngo Molnar printf("PerfTop refresh period: %d seconds\n", delay_secs); 27886470930SIngo Molnar 27986470930SIngo Molnar do { 28086470930SIngo Molnar print_sym_table(); 28186470930SIngo Molnar } while (!poll(&stdin_poll, 1, delay_msecs) == 1); 28286470930SIngo Molnar 28386470930SIngo Molnar printf("key pressed - exiting.\n"); 28486470930SIngo Molnar exit(0); 28586470930SIngo Molnar 28686470930SIngo Molnar return NULL; 28786470930SIngo Molnar } 28886470930SIngo Molnar 2892ab52083SAnton Blanchard /* Tag samples to be skipped. */ 290f37a291cSIngo Molnar static const char *skip_symbols[] = { 2912ab52083SAnton Blanchard "default_idle", 2922ab52083SAnton Blanchard "cpu_idle", 2932ab52083SAnton Blanchard "enter_idle", 2942ab52083SAnton Blanchard "exit_idle", 2952ab52083SAnton Blanchard "mwait_idle", 2963a3393efSAnton Blanchard "ppc64_runlatch_off", 2973a3393efSAnton Blanchard "pseries_dedicated_idle_sleep", 2982ab52083SAnton Blanchard NULL 2992ab52083SAnton Blanchard }; 3002ab52083SAnton Blanchard 30186470930SIngo Molnar static int symbol_filter(struct dso *self, struct symbol *sym) 30286470930SIngo Molnar { 30386470930SIngo Molnar static int filter_match; 30486470930SIngo Molnar struct sym_entry *syme; 30586470930SIngo Molnar const char *name = sym->name; 3062ab52083SAnton Blanchard int i; 30786470930SIngo Molnar 3083a3393efSAnton Blanchard /* 3093a3393efSAnton Blanchard * ppc64 uses function descriptors and appends a '.' to the 3103a3393efSAnton Blanchard * start of every instruction address. Remove it. 3113a3393efSAnton Blanchard */ 3123a3393efSAnton Blanchard if (name[0] == '.') 3133a3393efSAnton Blanchard name++; 3143a3393efSAnton Blanchard 31586470930SIngo Molnar if (!strcmp(name, "_text") || 31686470930SIngo Molnar !strcmp(name, "_etext") || 31786470930SIngo Molnar !strcmp(name, "_sinittext") || 31886470930SIngo Molnar !strncmp("init_module", name, 11) || 31986470930SIngo Molnar !strncmp("cleanup_module", name, 14) || 32086470930SIngo Molnar strstr(name, "_text_start") || 32186470930SIngo Molnar strstr(name, "_text_end")) 32286470930SIngo Molnar return 1; 32386470930SIngo Molnar 32486470930SIngo Molnar syme = dso__sym_priv(self, sym); 3252ab52083SAnton Blanchard for (i = 0; skip_symbols[i]; i++) { 3262ab52083SAnton Blanchard if (!strcmp(skip_symbols[i], name)) { 32786470930SIngo Molnar syme->skip = 1; 3282ab52083SAnton Blanchard break; 3292ab52083SAnton Blanchard } 3302ab52083SAnton Blanchard } 33186470930SIngo Molnar 33286470930SIngo Molnar if (filter_match == 1) { 33386470930SIngo Molnar filter_end = sym->start; 33486470930SIngo Molnar filter_match = -1; 33586470930SIngo Molnar if (filter_end - filter_start > 10000) { 33686470930SIngo Molnar fprintf(stderr, 33786470930SIngo Molnar "hm, too large filter symbol <%s> - skipping.\n", 33886470930SIngo Molnar sym_filter); 33986470930SIngo Molnar fprintf(stderr, "symbol filter start: %016lx\n", 34086470930SIngo Molnar filter_start); 34186470930SIngo Molnar fprintf(stderr, " end: %016lx\n", 34286470930SIngo Molnar filter_end); 34386470930SIngo Molnar filter_end = filter_start = 0; 34486470930SIngo Molnar sym_filter = NULL; 34586470930SIngo Molnar sleep(1); 34686470930SIngo Molnar } 34786470930SIngo Molnar } 34886470930SIngo Molnar 34986470930SIngo Molnar if (filter_match == 0 && sym_filter && !strcmp(name, sym_filter)) { 35086470930SIngo Molnar filter_match = 1; 35186470930SIngo Molnar filter_start = sym->start; 35286470930SIngo Molnar } 35386470930SIngo Molnar 35486470930SIngo Molnar 35586470930SIngo Molnar return 0; 35686470930SIngo Molnar } 35786470930SIngo Molnar 35886470930SIngo Molnar static int parse_symbols(void) 35986470930SIngo Molnar { 36086470930SIngo Molnar struct rb_node *node; 36186470930SIngo Molnar struct symbol *sym; 36286470930SIngo Molnar 36386470930SIngo Molnar kernel_dso = dso__new("[kernel]", sizeof(struct sym_entry)); 36486470930SIngo Molnar if (kernel_dso == NULL) 36586470930SIngo Molnar return -1; 36686470930SIngo Molnar 36786470930SIngo Molnar if (dso__load_kernel(kernel_dso, NULL, symbol_filter, 1) != 0) 36886470930SIngo Molnar goto out_delete_dso; 36986470930SIngo Molnar 37086470930SIngo Molnar node = rb_first(&kernel_dso->syms); 37186470930SIngo Molnar sym = rb_entry(node, struct symbol, rb_node); 37286470930SIngo Molnar min_ip = sym->start; 37386470930SIngo Molnar 37486470930SIngo Molnar node = rb_last(&kernel_dso->syms); 37586470930SIngo Molnar sym = rb_entry(node, struct symbol, rb_node); 37686470930SIngo Molnar max_ip = sym->end; 37786470930SIngo Molnar 37886470930SIngo Molnar if (dump_symtab) 37986470930SIngo Molnar dso__fprintf(kernel_dso, stderr); 38086470930SIngo Molnar 38186470930SIngo Molnar return 0; 38286470930SIngo Molnar 38386470930SIngo Molnar out_delete_dso: 38486470930SIngo Molnar dso__delete(kernel_dso); 38586470930SIngo Molnar kernel_dso = NULL; 38686470930SIngo Molnar return -1; 38786470930SIngo Molnar } 38886470930SIngo Molnar 38986470930SIngo Molnar #define TRACE_COUNT 3 39086470930SIngo Molnar 39186470930SIngo Molnar /* 39286470930SIngo Molnar * Binary search in the histogram table and record the hit: 39386470930SIngo Molnar */ 3949cffa8d5SPaul Mackerras static void record_ip(u64 ip, int counter) 39586470930SIngo Molnar { 39686470930SIngo Molnar struct symbol *sym = dso__find_symbol(kernel_dso, ip); 39786470930SIngo Molnar 39886470930SIngo Molnar if (sym != NULL) { 39986470930SIngo Molnar struct sym_entry *syme = dso__sym_priv(kernel_dso, sym); 40086470930SIngo Molnar 40186470930SIngo Molnar if (!syme->skip) { 40286470930SIngo Molnar syme->count[counter]++; 40386470930SIngo Molnar pthread_mutex_lock(&active_symbols_lock); 40486470930SIngo Molnar if (list_empty(&syme->node) || !syme->node.next) 40586470930SIngo Molnar __list_insert_active_sym(syme); 40686470930SIngo Molnar pthread_mutex_unlock(&active_symbols_lock); 40786470930SIngo Molnar return; 40886470930SIngo Molnar } 40986470930SIngo Molnar } 41086470930SIngo Molnar 41186470930SIngo Molnar samples--; 41286470930SIngo Molnar } 41386470930SIngo Molnar 414e6e18ec7SPeter Zijlstra static void process_event(u64 ip, int counter, int user) 41586470930SIngo Molnar { 41686470930SIngo Molnar samples++; 41786470930SIngo Molnar 418e6e18ec7SPeter Zijlstra if (user) { 41986470930SIngo Molnar userspace_samples++; 42086470930SIngo Molnar return; 42186470930SIngo Molnar } 42286470930SIngo Molnar 42386470930SIngo Molnar record_ip(ip, counter); 42486470930SIngo Molnar } 42586470930SIngo Molnar 42686470930SIngo Molnar struct mmap_data { 42786470930SIngo Molnar int counter; 42886470930SIngo Molnar void *base; 429f37a291cSIngo Molnar int mask; 43086470930SIngo Molnar unsigned int prev; 43186470930SIngo Molnar }; 43286470930SIngo Molnar 43386470930SIngo Molnar static unsigned int mmap_read_head(struct mmap_data *md) 43486470930SIngo Molnar { 43586470930SIngo Molnar struct perf_counter_mmap_page *pc = md->base; 43686470930SIngo Molnar int head; 43786470930SIngo Molnar 43886470930SIngo Molnar head = pc->data_head; 43986470930SIngo Molnar rmb(); 44086470930SIngo Molnar 44186470930SIngo Molnar return head; 44286470930SIngo Molnar } 44386470930SIngo Molnar 44486470930SIngo Molnar struct timeval last_read, this_read; 44586470930SIngo Molnar 4462f01190aSFrederic Weisbecker static void mmap_read_counter(struct mmap_data *md) 44786470930SIngo Molnar { 44886470930SIngo Molnar unsigned int head = mmap_read_head(md); 44986470930SIngo Molnar unsigned int old = md->prev; 45086470930SIngo Molnar unsigned char *data = md->base + page_size; 45186470930SIngo Molnar int diff; 45286470930SIngo Molnar 45386470930SIngo Molnar gettimeofday(&this_read, NULL); 45486470930SIngo Molnar 45586470930SIngo Molnar /* 45686470930SIngo Molnar * If we're further behind than half the buffer, there's a chance 45786470930SIngo Molnar * the writer will bite our tail and mess up the samples under us. 45886470930SIngo Molnar * 45986470930SIngo Molnar * If we somehow ended up ahead of the head, we got messed up. 46086470930SIngo Molnar * 46186470930SIngo Molnar * In either case, truncate and restart at head. 46286470930SIngo Molnar */ 46386470930SIngo Molnar diff = head - old; 46486470930SIngo Molnar if (diff > md->mask / 2 || diff < 0) { 46586470930SIngo Molnar struct timeval iv; 46686470930SIngo Molnar unsigned long msecs; 46786470930SIngo Molnar 46886470930SIngo Molnar timersub(&this_read, &last_read, &iv); 46986470930SIngo Molnar msecs = iv.tv_sec*1000 + iv.tv_usec/1000; 47086470930SIngo Molnar 47186470930SIngo Molnar fprintf(stderr, "WARNING: failed to keep up with mmap data." 47286470930SIngo Molnar " Last read %lu msecs ago.\n", msecs); 47386470930SIngo Molnar 47486470930SIngo Molnar /* 47586470930SIngo Molnar * head points to a known good entry, start there. 47686470930SIngo Molnar */ 47786470930SIngo Molnar old = head; 47886470930SIngo Molnar } 47986470930SIngo Molnar 48086470930SIngo Molnar last_read = this_read; 48186470930SIngo Molnar 48286470930SIngo Molnar for (; old != head;) { 48386470930SIngo Molnar struct ip_event { 48486470930SIngo Molnar struct perf_event_header header; 4859cffa8d5SPaul Mackerras u64 ip; 4869cffa8d5SPaul Mackerras u32 pid, target_pid; 48786470930SIngo Molnar }; 48886470930SIngo Molnar struct mmap_event { 48986470930SIngo Molnar struct perf_event_header header; 4909cffa8d5SPaul Mackerras u32 pid, target_pid; 4919cffa8d5SPaul Mackerras u64 start; 4929cffa8d5SPaul Mackerras u64 len; 4939cffa8d5SPaul Mackerras u64 pgoff; 49486470930SIngo Molnar char filename[PATH_MAX]; 49586470930SIngo Molnar }; 49686470930SIngo Molnar 49786470930SIngo Molnar typedef union event_union { 49886470930SIngo Molnar struct perf_event_header header; 49986470930SIngo Molnar struct ip_event ip; 50086470930SIngo Molnar struct mmap_event mmap; 50186470930SIngo Molnar } event_t; 50286470930SIngo Molnar 50386470930SIngo Molnar event_t *event = (event_t *)&data[old & md->mask]; 50486470930SIngo Molnar 50586470930SIngo Molnar event_t event_copy; 50686470930SIngo Molnar 50786470930SIngo Molnar size_t size = event->header.size; 50886470930SIngo Molnar 50986470930SIngo Molnar /* 51086470930SIngo Molnar * Event straddles the mmap boundary -- header should always 51186470930SIngo Molnar * be inside due to u64 alignment of output. 51286470930SIngo Molnar */ 51386470930SIngo Molnar if ((old & md->mask) + size != ((old + size) & md->mask)) { 51486470930SIngo Molnar unsigned int offset = old; 51586470930SIngo Molnar unsigned int len = min(sizeof(*event), size), cpy; 51686470930SIngo Molnar void *dst = &event_copy; 51786470930SIngo Molnar 51886470930SIngo Molnar do { 51986470930SIngo Molnar cpy = min(md->mask + 1 - (offset & md->mask), len); 52086470930SIngo Molnar memcpy(dst, &data[offset & md->mask], cpy); 52186470930SIngo Molnar offset += cpy; 52286470930SIngo Molnar dst += cpy; 52386470930SIngo Molnar len -= cpy; 52486470930SIngo Molnar } while (len); 52586470930SIngo Molnar 52686470930SIngo Molnar event = &event_copy; 52786470930SIngo Molnar } 52886470930SIngo Molnar 52986470930SIngo Molnar old += size; 53086470930SIngo Molnar 531e6e18ec7SPeter Zijlstra if (event->header.type == PERF_EVENT_SAMPLE) { 532e6e18ec7SPeter Zijlstra int user = 533e6e18ec7SPeter Zijlstra (event->header.misc & PERF_EVENT_MISC_CPUMODE_MASK) == PERF_EVENT_MISC_USER; 534e6e18ec7SPeter Zijlstra process_event(event->ip.ip, md->counter, user); 53586470930SIngo Molnar } 53686470930SIngo Molnar } 53786470930SIngo Molnar 53886470930SIngo Molnar md->prev = old; 53986470930SIngo Molnar } 54086470930SIngo Molnar 54186470930SIngo Molnar static struct pollfd event_array[MAX_NR_CPUS * MAX_COUNTERS]; 54286470930SIngo Molnar static struct mmap_data mmap_array[MAX_NR_CPUS][MAX_COUNTERS]; 54386470930SIngo Molnar 5442f01190aSFrederic Weisbecker static void mmap_read(void) 5452f01190aSFrederic Weisbecker { 5462f01190aSFrederic Weisbecker int i, counter; 5472f01190aSFrederic Weisbecker 5482f01190aSFrederic Weisbecker for (i = 0; i < nr_cpus; i++) { 5492f01190aSFrederic Weisbecker for (counter = 0; counter < nr_counters; counter++) 5502f01190aSFrederic Weisbecker mmap_read_counter(&mmap_array[i][counter]); 5512f01190aSFrederic Weisbecker } 5522f01190aSFrederic Weisbecker } 5532f01190aSFrederic Weisbecker 554716c69feSIngo Molnar int nr_poll; 555716c69feSIngo Molnar int group_fd; 556716c69feSIngo Molnar 557716c69feSIngo Molnar static void start_counter(int i, int counter) 55886470930SIngo Molnar { 55986470930SIngo Molnar struct perf_counter_attr *attr; 56086470930SIngo Molnar unsigned int cpu; 56186470930SIngo Molnar 56286470930SIngo Molnar cpu = profile_cpu; 56386470930SIngo Molnar if (target_pid == -1 && profile_cpu == -1) 56486470930SIngo Molnar cpu = i; 56586470930SIngo Molnar 56686470930SIngo Molnar attr = attrs + counter; 56786470930SIngo Molnar 56886470930SIngo Molnar attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID; 56986470930SIngo Molnar attr->freq = freq; 57086470930SIngo Molnar 571716c69feSIngo Molnar try_again: 57286470930SIngo Molnar fd[i][counter] = sys_perf_counter_open(attr, target_pid, cpu, group_fd, 0); 573716c69feSIngo Molnar 57486470930SIngo Molnar if (fd[i][counter] < 0) { 57586470930SIngo Molnar int err = errno; 57686470930SIngo Molnar 57786470930SIngo Molnar if (err == EPERM) 578716c69feSIngo Molnar die("No permission - are you root?\n"); 579716c69feSIngo Molnar /* 580716c69feSIngo Molnar * If it's cycles then fall back to hrtimer 581716c69feSIngo Molnar * based cpu-clock-tick sw counter, which 582716c69feSIngo Molnar * is always available even if no PMU support: 583716c69feSIngo Molnar */ 584716c69feSIngo Molnar if (attr->type == PERF_TYPE_HARDWARE 585f4dbfa8fSPeter Zijlstra && attr->config == PERF_COUNT_HW_CPU_CYCLES) { 586716c69feSIngo Molnar 5873da297a6SIngo Molnar if (verbose) 588716c69feSIngo Molnar warning(" ... trying to fall back to cpu-clock-ticks\n"); 5893da297a6SIngo Molnar 590716c69feSIngo Molnar attr->type = PERF_TYPE_SOFTWARE; 591f4dbfa8fSPeter Zijlstra attr->config = PERF_COUNT_SW_CPU_CLOCK; 592716c69feSIngo Molnar goto try_again; 593716c69feSIngo Molnar } 59430c806a0SIngo Molnar printf("\n"); 59530c806a0SIngo Molnar error("perfcounter syscall returned with %d (%s)\n", 59630c806a0SIngo Molnar fd[i][counter], strerror(err)); 59730c806a0SIngo Molnar die("No CONFIG_PERF_COUNTERS=y kernel support configured?\n"); 59886470930SIngo Molnar exit(-1); 59986470930SIngo Molnar } 60086470930SIngo Molnar assert(fd[i][counter] >= 0); 60186470930SIngo Molnar fcntl(fd[i][counter], F_SETFL, O_NONBLOCK); 60286470930SIngo Molnar 60386470930SIngo Molnar /* 60486470930SIngo Molnar * First counter acts as the group leader: 60586470930SIngo Molnar */ 60686470930SIngo Molnar if (group && group_fd == -1) 60786470930SIngo Molnar group_fd = fd[i][counter]; 60886470930SIngo Molnar 60986470930SIngo Molnar event_array[nr_poll].fd = fd[i][counter]; 61086470930SIngo Molnar event_array[nr_poll].events = POLLIN; 61186470930SIngo Molnar nr_poll++; 61286470930SIngo Molnar 61386470930SIngo Molnar mmap_array[i][counter].counter = counter; 61486470930SIngo Molnar mmap_array[i][counter].prev = 0; 61586470930SIngo Molnar mmap_array[i][counter].mask = mmap_pages*page_size - 1; 61686470930SIngo Molnar mmap_array[i][counter].base = mmap(NULL, (mmap_pages+1)*page_size, 61786470930SIngo Molnar PROT_READ, MAP_SHARED, fd[i][counter], 0); 61886470930SIngo Molnar if (mmap_array[i][counter].base == MAP_FAILED) 61986470930SIngo Molnar die("failed to mmap with %d (%s)\n", errno, strerror(errno)); 62086470930SIngo Molnar } 621716c69feSIngo Molnar 622716c69feSIngo Molnar static int __cmd_top(void) 623716c69feSIngo Molnar { 624716c69feSIngo Molnar pthread_t thread; 625716c69feSIngo Molnar int i, counter; 626716c69feSIngo Molnar int ret; 627716c69feSIngo Molnar 628716c69feSIngo Molnar for (i = 0; i < nr_cpus; i++) { 629716c69feSIngo Molnar group_fd = -1; 630716c69feSIngo Molnar for (counter = 0; counter < nr_counters; counter++) 631716c69feSIngo Molnar start_counter(i, counter); 63286470930SIngo Molnar } 63386470930SIngo Molnar 6342f01190aSFrederic Weisbecker /* Wait for a minimal set of events before starting the snapshot */ 6352f01190aSFrederic Weisbecker poll(event_array, nr_poll, 100); 6362f01190aSFrederic Weisbecker 6372f01190aSFrederic Weisbecker mmap_read(); 6382f01190aSFrederic Weisbecker 63986470930SIngo Molnar if (pthread_create(&thread, NULL, display_thread, NULL)) { 64086470930SIngo Molnar printf("Could not create display thread.\n"); 64186470930SIngo Molnar exit(-1); 64286470930SIngo Molnar } 64386470930SIngo Molnar 64486470930SIngo Molnar if (realtime_prio) { 64586470930SIngo Molnar struct sched_param param; 64686470930SIngo Molnar 64786470930SIngo Molnar param.sched_priority = realtime_prio; 64886470930SIngo Molnar if (sched_setscheduler(0, SCHED_FIFO, ¶m)) { 64986470930SIngo Molnar printf("Could not set realtime priority.\n"); 65086470930SIngo Molnar exit(-1); 65186470930SIngo Molnar } 65286470930SIngo Molnar } 65386470930SIngo Molnar 65486470930SIngo Molnar while (1) { 65586470930SIngo Molnar int hits = samples; 65686470930SIngo Molnar 6572f01190aSFrederic Weisbecker mmap_read(); 65886470930SIngo Molnar 65986470930SIngo Molnar if (hits == samples) 66086470930SIngo Molnar ret = poll(event_array, nr_poll, 100); 66186470930SIngo Molnar } 66286470930SIngo Molnar 66386470930SIngo Molnar return 0; 66486470930SIngo Molnar } 66586470930SIngo Molnar 66686470930SIngo Molnar static const char * const top_usage[] = { 66786470930SIngo Molnar "perf top [<options>]", 66886470930SIngo Molnar NULL 66986470930SIngo Molnar }; 67086470930SIngo Molnar 67186470930SIngo Molnar static const struct option options[] = { 67286470930SIngo Molnar OPT_CALLBACK('e', "event", NULL, "event", 67386470930SIngo Molnar "event selector. use 'perf list' to list available events", 67486470930SIngo Molnar parse_events), 67586470930SIngo Molnar OPT_INTEGER('c', "count", &default_interval, 67686470930SIngo Molnar "event period to sample"), 67786470930SIngo Molnar OPT_INTEGER('p', "pid", &target_pid, 67886470930SIngo Molnar "profile events on existing pid"), 67986470930SIngo Molnar OPT_BOOLEAN('a', "all-cpus", &system_wide, 68086470930SIngo Molnar "system-wide collection from all CPUs"), 68186470930SIngo Molnar OPT_INTEGER('C', "CPU", &profile_cpu, 68286470930SIngo Molnar "CPU to profile on"), 68386470930SIngo Molnar OPT_INTEGER('m', "mmap-pages", &mmap_pages, 68486470930SIngo Molnar "number of mmap data pages"), 68586470930SIngo Molnar OPT_INTEGER('r', "realtime", &realtime_prio, 68686470930SIngo Molnar "collect data with this RT SCHED_FIFO priority"), 68786470930SIngo Molnar OPT_INTEGER('d', "delay", &delay_secs, 68886470930SIngo Molnar "number of seconds to delay between refreshes"), 68986470930SIngo Molnar OPT_BOOLEAN('D', "dump-symtab", &dump_symtab, 69086470930SIngo Molnar "dump the symbol table used for profiling"), 69186470930SIngo Molnar OPT_INTEGER('f', "count-filter", &count_filter, 69286470930SIngo Molnar "only display functions with more events than this"), 69386470930SIngo Molnar OPT_BOOLEAN('g', "group", &group, 69486470930SIngo Molnar "put the counters into a counter group"), 69586470930SIngo Molnar OPT_STRING('s', "sym-filter", &sym_filter, "pattern", 69686470930SIngo Molnar "only display symbols matchig this pattern"), 6971f208ea6SAnton Blanchard OPT_BOOLEAN('z', "zero", &zero, 69886470930SIngo Molnar "zero history across updates"), 69986470930SIngo Molnar OPT_INTEGER('F', "freq", &freq, 70086470930SIngo Molnar "profile at this frequency"), 70186470930SIngo Molnar OPT_INTEGER('E', "entries", &print_entries, 70286470930SIngo Molnar "display this many functions"), 7033da297a6SIngo Molnar OPT_BOOLEAN('v', "verbose", &verbose, 7043da297a6SIngo Molnar "be more verbose (show counter open errors, etc)"), 70586470930SIngo Molnar OPT_END() 70686470930SIngo Molnar }; 70786470930SIngo Molnar 708f37a291cSIngo Molnar int cmd_top(int argc, const char **argv, const char *prefix __used) 70986470930SIngo Molnar { 71086470930SIngo Molnar int counter; 71186470930SIngo Molnar 71286470930SIngo Molnar page_size = sysconf(_SC_PAGE_SIZE); 71386470930SIngo Molnar 71486470930SIngo Molnar argc = parse_options(argc, argv, options, top_usage, 0); 71586470930SIngo Molnar if (argc) 71686470930SIngo Molnar usage_with_options(top_usage, options); 71786470930SIngo Molnar 71886470930SIngo Molnar if (freq) { 71986470930SIngo Molnar default_interval = freq; 72086470930SIngo Molnar freq = 1; 72186470930SIngo Molnar } 72286470930SIngo Molnar 72386470930SIngo Molnar /* CPU and PID are mutually exclusive */ 72486470930SIngo Molnar if (target_pid != -1 && profile_cpu != -1) { 72586470930SIngo Molnar printf("WARNING: PID switch overriding CPU\n"); 72686470930SIngo Molnar sleep(1); 72786470930SIngo Molnar profile_cpu = -1; 72886470930SIngo Molnar } 72986470930SIngo Molnar 73086470930SIngo Molnar if (!nr_counters) 73186470930SIngo Molnar nr_counters = 1; 73286470930SIngo Molnar 73386470930SIngo Molnar if (delay_secs < 1) 73486470930SIngo Molnar delay_secs = 1; 73586470930SIngo Molnar 73686470930SIngo Molnar parse_symbols(); 73786470930SIngo Molnar 73886470930SIngo Molnar /* 73986470930SIngo Molnar * Fill in the ones not specifically initialized via -c: 74086470930SIngo Molnar */ 74186470930SIngo Molnar for (counter = 0; counter < nr_counters; counter++) { 74286470930SIngo Molnar if (attrs[counter].sample_period) 74386470930SIngo Molnar continue; 74486470930SIngo Molnar 74586470930SIngo Molnar attrs[counter].sample_period = default_interval; 74686470930SIngo Molnar } 74786470930SIngo Molnar 74886470930SIngo Molnar nr_cpus = sysconf(_SC_NPROCESSORS_ONLN); 74986470930SIngo Molnar assert(nr_cpus <= MAX_NR_CPUS); 75086470930SIngo Molnar assert(nr_cpus >= 0); 75186470930SIngo Molnar 75286470930SIngo Molnar if (target_pid != -1 || profile_cpu != -1) 75386470930SIngo Molnar nr_cpus = 1; 75486470930SIngo Molnar 75586470930SIngo Molnar return __cmd_top(); 75686470930SIngo Molnar } 757