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 5786470930SIngo Molnar 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 8286470930SIngo Molnar static uint64_t min_ip; 8386470930SIngo Molnar static uint64_t 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) { 19786470930SIngo Molnar printf("%Ld", 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 27286470930SIngo Molnar static void *display_thread(void *arg) 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 28986470930SIngo Molnar static int symbol_filter(struct dso *self, struct symbol *sym) 29086470930SIngo Molnar { 29186470930SIngo Molnar static int filter_match; 29286470930SIngo Molnar struct sym_entry *syme; 29386470930SIngo Molnar const char *name = sym->name; 29486470930SIngo Molnar 29586470930SIngo Molnar if (!strcmp(name, "_text") || 29686470930SIngo Molnar !strcmp(name, "_etext") || 29786470930SIngo Molnar !strcmp(name, "_sinittext") || 29886470930SIngo Molnar !strncmp("init_module", name, 11) || 29986470930SIngo Molnar !strncmp("cleanup_module", name, 14) || 30086470930SIngo Molnar strstr(name, "_text_start") || 30186470930SIngo Molnar strstr(name, "_text_end")) 30286470930SIngo Molnar return 1; 30386470930SIngo Molnar 30486470930SIngo Molnar syme = dso__sym_priv(self, sym); 30586470930SIngo Molnar /* Tag samples to be skipped. */ 30686470930SIngo Molnar if (!strcmp("default_idle", name) || 30786470930SIngo Molnar !strcmp("cpu_idle", name) || 30886470930SIngo Molnar !strcmp("enter_idle", name) || 30986470930SIngo Molnar !strcmp("exit_idle", name) || 31086470930SIngo Molnar !strcmp("mwait_idle", name)) 31186470930SIngo Molnar syme->skip = 1; 31286470930SIngo Molnar 31386470930SIngo Molnar if (filter_match == 1) { 31486470930SIngo Molnar filter_end = sym->start; 31586470930SIngo Molnar filter_match = -1; 31686470930SIngo Molnar if (filter_end - filter_start > 10000) { 31786470930SIngo Molnar fprintf(stderr, 31886470930SIngo Molnar "hm, too large filter symbol <%s> - skipping.\n", 31986470930SIngo Molnar sym_filter); 32086470930SIngo Molnar fprintf(stderr, "symbol filter start: %016lx\n", 32186470930SIngo Molnar filter_start); 32286470930SIngo Molnar fprintf(stderr, " end: %016lx\n", 32386470930SIngo Molnar filter_end); 32486470930SIngo Molnar filter_end = filter_start = 0; 32586470930SIngo Molnar sym_filter = NULL; 32686470930SIngo Molnar sleep(1); 32786470930SIngo Molnar } 32886470930SIngo Molnar } 32986470930SIngo Molnar 33086470930SIngo Molnar if (filter_match == 0 && sym_filter && !strcmp(name, sym_filter)) { 33186470930SIngo Molnar filter_match = 1; 33286470930SIngo Molnar filter_start = sym->start; 33386470930SIngo Molnar } 33486470930SIngo Molnar 33586470930SIngo Molnar 33686470930SIngo Molnar return 0; 33786470930SIngo Molnar } 33886470930SIngo Molnar 33986470930SIngo Molnar static int parse_symbols(void) 34086470930SIngo Molnar { 34186470930SIngo Molnar struct rb_node *node; 34286470930SIngo Molnar struct symbol *sym; 34386470930SIngo Molnar 34486470930SIngo Molnar kernel_dso = dso__new("[kernel]", sizeof(struct sym_entry)); 34586470930SIngo Molnar if (kernel_dso == NULL) 34686470930SIngo Molnar return -1; 34786470930SIngo Molnar 34886470930SIngo Molnar if (dso__load_kernel(kernel_dso, NULL, symbol_filter, 1) != 0) 34986470930SIngo Molnar goto out_delete_dso; 35086470930SIngo Molnar 35186470930SIngo Molnar node = rb_first(&kernel_dso->syms); 35286470930SIngo Molnar sym = rb_entry(node, struct symbol, rb_node); 35386470930SIngo Molnar min_ip = sym->start; 35486470930SIngo Molnar 35586470930SIngo Molnar node = rb_last(&kernel_dso->syms); 35686470930SIngo Molnar sym = rb_entry(node, struct symbol, rb_node); 35786470930SIngo Molnar max_ip = sym->end; 35886470930SIngo Molnar 35986470930SIngo Molnar if (dump_symtab) 36086470930SIngo Molnar dso__fprintf(kernel_dso, stderr); 36186470930SIngo Molnar 36286470930SIngo Molnar return 0; 36386470930SIngo Molnar 36486470930SIngo Molnar out_delete_dso: 36586470930SIngo Molnar dso__delete(kernel_dso); 36686470930SIngo Molnar kernel_dso = NULL; 36786470930SIngo Molnar return -1; 36886470930SIngo Molnar } 36986470930SIngo Molnar 37086470930SIngo Molnar #define TRACE_COUNT 3 37186470930SIngo Molnar 37286470930SIngo Molnar /* 37386470930SIngo Molnar * Binary search in the histogram table and record the hit: 37486470930SIngo Molnar */ 37586470930SIngo Molnar static void record_ip(uint64_t ip, int counter) 37686470930SIngo Molnar { 37786470930SIngo Molnar struct symbol *sym = dso__find_symbol(kernel_dso, ip); 37886470930SIngo Molnar 37986470930SIngo Molnar if (sym != NULL) { 38086470930SIngo Molnar struct sym_entry *syme = dso__sym_priv(kernel_dso, sym); 38186470930SIngo Molnar 38286470930SIngo Molnar if (!syme->skip) { 38386470930SIngo Molnar syme->count[counter]++; 38486470930SIngo Molnar pthread_mutex_lock(&active_symbols_lock); 38586470930SIngo Molnar if (list_empty(&syme->node) || !syme->node.next) 38686470930SIngo Molnar __list_insert_active_sym(syme); 38786470930SIngo Molnar pthread_mutex_unlock(&active_symbols_lock); 38886470930SIngo Molnar return; 38986470930SIngo Molnar } 39086470930SIngo Molnar } 39186470930SIngo Molnar 39286470930SIngo Molnar samples--; 39386470930SIngo Molnar } 39486470930SIngo Molnar 39586470930SIngo Molnar static void process_event(uint64_t ip, int counter) 39686470930SIngo Molnar { 39786470930SIngo Molnar samples++; 39886470930SIngo Molnar 39986470930SIngo Molnar if (ip < min_ip || ip > max_ip) { 40086470930SIngo Molnar userspace_samples++; 40186470930SIngo Molnar return; 40286470930SIngo Molnar } 40386470930SIngo Molnar 40486470930SIngo Molnar record_ip(ip, counter); 40586470930SIngo Molnar } 40686470930SIngo Molnar 40786470930SIngo Molnar struct mmap_data { 40886470930SIngo Molnar int counter; 40986470930SIngo Molnar void *base; 41086470930SIngo Molnar unsigned int mask; 41186470930SIngo Molnar unsigned int prev; 41286470930SIngo Molnar }; 41386470930SIngo Molnar 41486470930SIngo Molnar static unsigned int mmap_read_head(struct mmap_data *md) 41586470930SIngo Molnar { 41686470930SIngo Molnar struct perf_counter_mmap_page *pc = md->base; 41786470930SIngo Molnar int head; 41886470930SIngo Molnar 41986470930SIngo Molnar head = pc->data_head; 42086470930SIngo Molnar rmb(); 42186470930SIngo Molnar 42286470930SIngo Molnar return head; 42386470930SIngo Molnar } 42486470930SIngo Molnar 42586470930SIngo Molnar struct timeval last_read, this_read; 42686470930SIngo Molnar 4272f01190aSFrederic Weisbecker static void mmap_read_counter(struct mmap_data *md) 42886470930SIngo Molnar { 42986470930SIngo Molnar unsigned int head = mmap_read_head(md); 43086470930SIngo Molnar unsigned int old = md->prev; 43186470930SIngo Molnar unsigned char *data = md->base + page_size; 43286470930SIngo Molnar int diff; 43386470930SIngo Molnar 43486470930SIngo Molnar gettimeofday(&this_read, NULL); 43586470930SIngo Molnar 43686470930SIngo Molnar /* 43786470930SIngo Molnar * If we're further behind than half the buffer, there's a chance 43886470930SIngo Molnar * the writer will bite our tail and mess up the samples under us. 43986470930SIngo Molnar * 44086470930SIngo Molnar * If we somehow ended up ahead of the head, we got messed up. 44186470930SIngo Molnar * 44286470930SIngo Molnar * In either case, truncate and restart at head. 44386470930SIngo Molnar */ 44486470930SIngo Molnar diff = head - old; 44586470930SIngo Molnar if (diff > md->mask / 2 || diff < 0) { 44686470930SIngo Molnar struct timeval iv; 44786470930SIngo Molnar unsigned long msecs; 44886470930SIngo Molnar 44986470930SIngo Molnar timersub(&this_read, &last_read, &iv); 45086470930SIngo Molnar msecs = iv.tv_sec*1000 + iv.tv_usec/1000; 45186470930SIngo Molnar 45286470930SIngo Molnar fprintf(stderr, "WARNING: failed to keep up with mmap data." 45386470930SIngo Molnar " Last read %lu msecs ago.\n", msecs); 45486470930SIngo Molnar 45586470930SIngo Molnar /* 45686470930SIngo Molnar * head points to a known good entry, start there. 45786470930SIngo Molnar */ 45886470930SIngo Molnar old = head; 45986470930SIngo Molnar } 46086470930SIngo Molnar 46186470930SIngo Molnar last_read = this_read; 46286470930SIngo Molnar 46386470930SIngo Molnar for (; old != head;) { 46486470930SIngo Molnar struct ip_event { 46586470930SIngo Molnar struct perf_event_header header; 46686470930SIngo Molnar __u64 ip; 46786470930SIngo Molnar __u32 pid, target_pid; 46886470930SIngo Molnar }; 46986470930SIngo Molnar struct mmap_event { 47086470930SIngo Molnar struct perf_event_header header; 47186470930SIngo Molnar __u32 pid, target_pid; 47286470930SIngo Molnar __u64 start; 47386470930SIngo Molnar __u64 len; 47486470930SIngo Molnar __u64 pgoff; 47586470930SIngo Molnar char filename[PATH_MAX]; 47686470930SIngo Molnar }; 47786470930SIngo Molnar 47886470930SIngo Molnar typedef union event_union { 47986470930SIngo Molnar struct perf_event_header header; 48086470930SIngo Molnar struct ip_event ip; 48186470930SIngo Molnar struct mmap_event mmap; 48286470930SIngo Molnar } event_t; 48386470930SIngo Molnar 48486470930SIngo Molnar event_t *event = (event_t *)&data[old & md->mask]; 48586470930SIngo Molnar 48686470930SIngo Molnar event_t event_copy; 48786470930SIngo Molnar 48886470930SIngo Molnar size_t size = event->header.size; 48986470930SIngo Molnar 49086470930SIngo Molnar /* 49186470930SIngo Molnar * Event straddles the mmap boundary -- header should always 49286470930SIngo Molnar * be inside due to u64 alignment of output. 49386470930SIngo Molnar */ 49486470930SIngo Molnar if ((old & md->mask) + size != ((old + size) & md->mask)) { 49586470930SIngo Molnar unsigned int offset = old; 49686470930SIngo Molnar unsigned int len = min(sizeof(*event), size), cpy; 49786470930SIngo Molnar void *dst = &event_copy; 49886470930SIngo Molnar 49986470930SIngo Molnar do { 50086470930SIngo Molnar cpy = min(md->mask + 1 - (offset & md->mask), len); 50186470930SIngo Molnar memcpy(dst, &data[offset & md->mask], cpy); 50286470930SIngo Molnar offset += cpy; 50386470930SIngo Molnar dst += cpy; 50486470930SIngo Molnar len -= cpy; 50586470930SIngo Molnar } while (len); 50686470930SIngo Molnar 50786470930SIngo Molnar event = &event_copy; 50886470930SIngo Molnar } 50986470930SIngo Molnar 51086470930SIngo Molnar old += size; 51186470930SIngo Molnar 51286470930SIngo Molnar if (event->header.misc & PERF_EVENT_MISC_OVERFLOW) { 51386470930SIngo Molnar if (event->header.type & PERF_SAMPLE_IP) 51486470930SIngo Molnar process_event(event->ip.ip, md->counter); 51586470930SIngo Molnar } 51686470930SIngo Molnar } 51786470930SIngo Molnar 51886470930SIngo Molnar md->prev = old; 51986470930SIngo Molnar } 52086470930SIngo Molnar 52186470930SIngo Molnar static struct pollfd event_array[MAX_NR_CPUS * MAX_COUNTERS]; 52286470930SIngo Molnar static struct mmap_data mmap_array[MAX_NR_CPUS][MAX_COUNTERS]; 52386470930SIngo Molnar 5242f01190aSFrederic Weisbecker static void mmap_read(void) 5252f01190aSFrederic Weisbecker { 5262f01190aSFrederic Weisbecker int i, counter; 5272f01190aSFrederic Weisbecker 5282f01190aSFrederic Weisbecker for (i = 0; i < nr_cpus; i++) { 5292f01190aSFrederic Weisbecker for (counter = 0; counter < nr_counters; counter++) 5302f01190aSFrederic Weisbecker mmap_read_counter(&mmap_array[i][counter]); 5312f01190aSFrederic Weisbecker } 5322f01190aSFrederic Weisbecker } 5332f01190aSFrederic Weisbecker 534716c69feSIngo Molnar int nr_poll; 535716c69feSIngo Molnar int group_fd; 536716c69feSIngo Molnar 537716c69feSIngo Molnar static void start_counter(int i, int counter) 53886470930SIngo Molnar { 53986470930SIngo Molnar struct perf_counter_attr *attr; 54086470930SIngo Molnar unsigned int cpu; 54186470930SIngo Molnar 54286470930SIngo Molnar cpu = profile_cpu; 54386470930SIngo Molnar if (target_pid == -1 && profile_cpu == -1) 54486470930SIngo Molnar cpu = i; 54586470930SIngo Molnar 54686470930SIngo Molnar attr = attrs + counter; 54786470930SIngo Molnar 54886470930SIngo Molnar attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID; 54986470930SIngo Molnar attr->freq = freq; 55086470930SIngo Molnar 551716c69feSIngo Molnar try_again: 55286470930SIngo Molnar fd[i][counter] = sys_perf_counter_open(attr, target_pid, cpu, group_fd, 0); 553716c69feSIngo Molnar 55486470930SIngo Molnar if (fd[i][counter] < 0) { 55586470930SIngo Molnar int err = errno; 55686470930SIngo Molnar 55786470930SIngo Molnar if (err == EPERM) 558716c69feSIngo Molnar die("No permission - are you root?\n"); 559716c69feSIngo Molnar /* 560716c69feSIngo Molnar * If it's cycles then fall back to hrtimer 561716c69feSIngo Molnar * based cpu-clock-tick sw counter, which 562716c69feSIngo Molnar * is always available even if no PMU support: 563716c69feSIngo Molnar */ 564716c69feSIngo Molnar if (attr->type == PERF_TYPE_HARDWARE 565716c69feSIngo Molnar && attr->config == PERF_COUNT_CPU_CYCLES) { 566716c69feSIngo Molnar 5673da297a6SIngo Molnar if (verbose) 568716c69feSIngo Molnar warning(" ... trying to fall back to cpu-clock-ticks\n"); 5693da297a6SIngo Molnar 570716c69feSIngo Molnar attr->type = PERF_TYPE_SOFTWARE; 571716c69feSIngo Molnar attr->config = PERF_COUNT_CPU_CLOCK; 572716c69feSIngo Molnar goto try_again; 573716c69feSIngo Molnar } 57430c806a0SIngo Molnar printf("\n"); 57530c806a0SIngo Molnar error("perfcounter syscall returned with %d (%s)\n", 57630c806a0SIngo Molnar fd[i][counter], strerror(err)); 57730c806a0SIngo Molnar die("No CONFIG_PERF_COUNTERS=y kernel support configured?\n"); 57886470930SIngo Molnar exit(-1); 57986470930SIngo Molnar } 58086470930SIngo Molnar assert(fd[i][counter] >= 0); 58186470930SIngo Molnar fcntl(fd[i][counter], F_SETFL, O_NONBLOCK); 58286470930SIngo Molnar 58386470930SIngo Molnar /* 58486470930SIngo Molnar * First counter acts as the group leader: 58586470930SIngo Molnar */ 58686470930SIngo Molnar if (group && group_fd == -1) 58786470930SIngo Molnar group_fd = fd[i][counter]; 58886470930SIngo Molnar 58986470930SIngo Molnar event_array[nr_poll].fd = fd[i][counter]; 59086470930SIngo Molnar event_array[nr_poll].events = POLLIN; 59186470930SIngo Molnar nr_poll++; 59286470930SIngo Molnar 59386470930SIngo Molnar mmap_array[i][counter].counter = counter; 59486470930SIngo Molnar mmap_array[i][counter].prev = 0; 59586470930SIngo Molnar mmap_array[i][counter].mask = mmap_pages*page_size - 1; 59686470930SIngo Molnar mmap_array[i][counter].base = mmap(NULL, (mmap_pages+1)*page_size, 59786470930SIngo Molnar PROT_READ, MAP_SHARED, fd[i][counter], 0); 59886470930SIngo Molnar if (mmap_array[i][counter].base == MAP_FAILED) 59986470930SIngo Molnar die("failed to mmap with %d (%s)\n", errno, strerror(errno)); 60086470930SIngo Molnar } 601716c69feSIngo Molnar 602716c69feSIngo Molnar static int __cmd_top(void) 603716c69feSIngo Molnar { 604716c69feSIngo Molnar pthread_t thread; 605716c69feSIngo Molnar int i, counter; 606716c69feSIngo Molnar int ret; 607716c69feSIngo Molnar 608716c69feSIngo Molnar for (i = 0; i < nr_cpus; i++) { 609716c69feSIngo Molnar group_fd = -1; 610716c69feSIngo Molnar for (counter = 0; counter < nr_counters; counter++) 611716c69feSIngo Molnar start_counter(i, counter); 61286470930SIngo Molnar } 61386470930SIngo Molnar 6142f01190aSFrederic Weisbecker /* Wait for a minimal set of events before starting the snapshot */ 6152f01190aSFrederic Weisbecker poll(event_array, nr_poll, 100); 6162f01190aSFrederic Weisbecker 6172f01190aSFrederic Weisbecker mmap_read(); 6182f01190aSFrederic Weisbecker 61986470930SIngo Molnar if (pthread_create(&thread, NULL, display_thread, NULL)) { 62086470930SIngo Molnar printf("Could not create display thread.\n"); 62186470930SIngo Molnar exit(-1); 62286470930SIngo Molnar } 62386470930SIngo Molnar 62486470930SIngo Molnar if (realtime_prio) { 62586470930SIngo Molnar struct sched_param param; 62686470930SIngo Molnar 62786470930SIngo Molnar param.sched_priority = realtime_prio; 62886470930SIngo Molnar if (sched_setscheduler(0, SCHED_FIFO, ¶m)) { 62986470930SIngo Molnar printf("Could not set realtime priority.\n"); 63086470930SIngo Molnar exit(-1); 63186470930SIngo Molnar } 63286470930SIngo Molnar } 63386470930SIngo Molnar 63486470930SIngo Molnar while (1) { 63586470930SIngo Molnar int hits = samples; 63686470930SIngo Molnar 6372f01190aSFrederic Weisbecker mmap_read(); 63886470930SIngo Molnar 63986470930SIngo Molnar if (hits == samples) 64086470930SIngo Molnar ret = poll(event_array, nr_poll, 100); 64186470930SIngo Molnar } 64286470930SIngo Molnar 64386470930SIngo Molnar return 0; 64486470930SIngo Molnar } 64586470930SIngo Molnar 64686470930SIngo Molnar static const char * const top_usage[] = { 64786470930SIngo Molnar "perf top [<options>]", 64886470930SIngo Molnar NULL 64986470930SIngo Molnar }; 65086470930SIngo Molnar 65186470930SIngo Molnar static const struct option options[] = { 65286470930SIngo Molnar OPT_CALLBACK('e', "event", NULL, "event", 65386470930SIngo Molnar "event selector. use 'perf list' to list available events", 65486470930SIngo Molnar parse_events), 65586470930SIngo Molnar OPT_INTEGER('c', "count", &default_interval, 65686470930SIngo Molnar "event period to sample"), 65786470930SIngo Molnar OPT_INTEGER('p', "pid", &target_pid, 65886470930SIngo Molnar "profile events on existing pid"), 65986470930SIngo Molnar OPT_BOOLEAN('a', "all-cpus", &system_wide, 66086470930SIngo Molnar "system-wide collection from all CPUs"), 66186470930SIngo Molnar OPT_INTEGER('C', "CPU", &profile_cpu, 66286470930SIngo Molnar "CPU to profile on"), 66386470930SIngo Molnar OPT_INTEGER('m', "mmap-pages", &mmap_pages, 66486470930SIngo Molnar "number of mmap data pages"), 66586470930SIngo Molnar OPT_INTEGER('r', "realtime", &realtime_prio, 66686470930SIngo Molnar "collect data with this RT SCHED_FIFO priority"), 66786470930SIngo Molnar OPT_INTEGER('d', "delay", &delay_secs, 66886470930SIngo Molnar "number of seconds to delay between refreshes"), 66986470930SIngo Molnar OPT_BOOLEAN('D', "dump-symtab", &dump_symtab, 67086470930SIngo Molnar "dump the symbol table used for profiling"), 67186470930SIngo Molnar OPT_INTEGER('f', "count-filter", &count_filter, 67286470930SIngo Molnar "only display functions with more events than this"), 67386470930SIngo Molnar OPT_BOOLEAN('g', "group", &group, 67486470930SIngo Molnar "put the counters into a counter group"), 67586470930SIngo Molnar OPT_STRING('s', "sym-filter", &sym_filter, "pattern", 67686470930SIngo Molnar "only display symbols matchig this pattern"), 67786470930SIngo Molnar OPT_BOOLEAN('z', "zero", &group, 67886470930SIngo Molnar "zero history across updates"), 67986470930SIngo Molnar OPT_INTEGER('F', "freq", &freq, 68086470930SIngo Molnar "profile at this frequency"), 68186470930SIngo Molnar OPT_INTEGER('E', "entries", &print_entries, 68286470930SIngo Molnar "display this many functions"), 6833da297a6SIngo Molnar OPT_BOOLEAN('v', "verbose", &verbose, 6843da297a6SIngo Molnar "be more verbose (show counter open errors, etc)"), 68586470930SIngo Molnar OPT_END() 68686470930SIngo Molnar }; 68786470930SIngo Molnar 68886470930SIngo Molnar int cmd_top(int argc, const char **argv, const char *prefix) 68986470930SIngo Molnar { 69086470930SIngo Molnar int counter; 69186470930SIngo Molnar 69286470930SIngo Molnar page_size = sysconf(_SC_PAGE_SIZE); 69386470930SIngo Molnar 69486470930SIngo Molnar argc = parse_options(argc, argv, options, top_usage, 0); 69586470930SIngo Molnar if (argc) 69686470930SIngo Molnar usage_with_options(top_usage, options); 69786470930SIngo Molnar 69886470930SIngo Molnar if (freq) { 69986470930SIngo Molnar default_interval = freq; 70086470930SIngo Molnar freq = 1; 70186470930SIngo Molnar } 70286470930SIngo Molnar 70386470930SIngo Molnar /* CPU and PID are mutually exclusive */ 70486470930SIngo Molnar if (target_pid != -1 && profile_cpu != -1) { 70586470930SIngo Molnar printf("WARNING: PID switch overriding CPU\n"); 70686470930SIngo Molnar sleep(1); 70786470930SIngo Molnar profile_cpu = -1; 70886470930SIngo Molnar } 70986470930SIngo Molnar 71086470930SIngo Molnar if (!nr_counters) 71186470930SIngo Molnar nr_counters = 1; 71286470930SIngo Molnar 71386470930SIngo Molnar if (delay_secs < 1) 71486470930SIngo Molnar delay_secs = 1; 71586470930SIngo Molnar 71686470930SIngo Molnar parse_symbols(); 71786470930SIngo Molnar 71886470930SIngo Molnar /* 71986470930SIngo Molnar * Fill in the ones not specifically initialized via -c: 72086470930SIngo Molnar */ 72186470930SIngo Molnar for (counter = 0; counter < nr_counters; counter++) { 72286470930SIngo Molnar if (attrs[counter].sample_period) 72386470930SIngo Molnar continue; 72486470930SIngo Molnar 72586470930SIngo Molnar attrs[counter].sample_period = default_interval; 72686470930SIngo Molnar } 72786470930SIngo Molnar 72886470930SIngo Molnar nr_cpus = sysconf(_SC_NPROCESSORS_ONLN); 72986470930SIngo Molnar assert(nr_cpus <= MAX_NR_CPUS); 73086470930SIngo Molnar assert(nr_cpus >= 0); 73186470930SIngo Molnar 73286470930SIngo Molnar if (target_pid != -1 || profile_cpu != -1) 73386470930SIngo Molnar nr_cpus = 1; 73486470930SIngo Molnar 73586470930SIngo Molnar return __cmd_top(); 73686470930SIngo Molnar } 737