From 01797c599816d39dfea47864c0f90cd50845811f Mon Sep 17 00:00:00 2001 From: Corey Ashford Date: Mon, 8 Nov 2010 18:20:45 -0800 Subject: perf: Fix usages of profile_cpu in builtin-top.c to use cpu_list profile_cpu was left over from an earlier implementation that supported running perf top on a single CPU. profile_cpu was no longer set by any switch and usages of it resulted in dead code. Instead, convert the code to use cpu_list, which is set by the -C option. Also improved the printing of nr_cpus and cpu_list by correcting the plurals. Signed-off-by: Corey Ashford Cc: a.p.zijlstra@chello.nl Cc: acme@redhat.com LKML-Reference: <1289269245-9388-1-git-send-email-cjashfor@linux.vnet.ibm.com> Signed-off-by: Ingo Molnar --- tools/perf/builtin-top.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'tools/perf/builtin-top.c') diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index b513e40974f4..dd625808c2a5 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -69,7 +69,6 @@ static int target_tid = -1; static pid_t *all_tids = NULL; static int thread_num = 0; static bool inherit = false; -static int profile_cpu = -1; static int nr_cpus = 0; static int realtime_prio = 0; static bool group = false; @@ -558,13 +557,13 @@ static void print_sym_table(void) else printf(" (all"); - if (profile_cpu != -1) - printf(", cpu: %d)\n", profile_cpu); + if (cpu_list) + printf(", CPU%s: %s)\n", nr_cpus > 1 ? "s" : "", cpu_list); else { if (target_tid != -1) printf(")\n"); else - printf(", %d CPUs)\n", nr_cpus); + printf(", %d CPU%s)\n", nr_cpus, nr_cpus > 1 ? "s" : ""); } printf("%-*.*s\n", win_width, win_width, graph_dotted_line); @@ -1187,11 +1186,10 @@ int group_fd; static void start_counter(int i, int counter) { struct perf_event_attr *attr; - int cpu; + int cpu = -1; int thread_index; - cpu = profile_cpu; - if (target_tid == -1 && profile_cpu == -1) + if (target_tid == -1) cpu = cpumap[i]; attr = attrs + counter; -- cgit v1.2.2 From d9cf837ef9629ab34167bd6fc0141383ddb8813a Mon Sep 17 00:00:00 2001 From: Corey Ashford Date: Fri, 19 Nov 2010 17:37:24 -0800 Subject: perf stat: Change and clean up sys_perf_event_open error handling This patch makes several changes to "perf stat": - "perf stat" will no longer go ahead and run the application when one or more of the specified events could not be opened. - Use error() and die() instead of pr_err() so that the output is more consistent with "perf top" and "perf record". - Handle permission errors in a more robust way, and in a similar way to "perf record" and "perf top". In addition, the sys_perf_event_open() error handling of "perf top" and "perf record" is made more consistent and adds the following phrase when an event doesn't open (with something ther than an access or permission error): "/bin/dmesg may provide additional information." This is added because kernel code doesn't have a good way of expressing detailed errors to user space, so its only avenue is to use printk's. However, many users may not think of looking at dmesg to find out why an event is being rejected. Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Peter Zijlstra Cc: Ian Munsie Cc: Michael Ellerman LKML-Reference: <1290217044-26293-1-git-send-email-cjashfor@linux.vnet.ibm.com> Signed-off-by: Corey Ashford Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-top.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'tools/perf/builtin-top.c') diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index dd625808c2a5..3d2b47d5121a 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -1214,7 +1214,9 @@ try_again: int err = errno; if (err == EPERM || err == EACCES) - die("No permission - are you root?\n"); + die("Permission error - are you root?\n" + "\t Consider tweaking" + " /proc/sys/kernel/perf_event_paranoid.\n"); /* * If it's cycles then fall back to hrtimer * based cpu-clock-tick sw counter, which @@ -1231,7 +1233,7 @@ try_again: goto try_again; } printf("\n"); - error("perfcounter syscall returned with %d (%s)\n", + error("sys_perf_event_open() syscall returned with %d (%s). /bin/dmesg may provide additional information.\n", fd[i][counter][thread_index], strerror(err)); die("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); exit(-1); -- cgit v1.2.2 From 640c03ce837fe8d4b56342aba376ea0da3960459 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 2 Dec 2010 14:10:21 -0200 Subject: perf session: Parse sample earlier MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit At perf_session__process_event, so that we reduce the number of lines in eache tool sample processing routine that now receives a sample_data pointer already parsed. This will also be useful in the next patch, where we'll allow sample the identity fields in MMAP, FORK, EXIT, etc, when it will be possible to see (cpu, timestamp) just after before every event. Also validate callchains in perf_session__process_event, i.e. as early as possible, and keep a counter of the number of events discarded due to invalid callchains, warning the user about it if it happens. There is an assumption that was kept that all events have the same sample_type, that will be dealt with in the future, when this preexisting limitation will be removed. Tested-by: Thomas Gleixner Reviewed-by: Thomas Gleixner Acked-by: Ian Munsie Acked-by: Thomas Gleixner Cc: Frédéric Weisbecker Cc: Ian Munsie Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Paul Mackerras Cc: Stephane Eranian LKML-Reference: <1291318772-30880-4-git-send-email-acme@infradead.org> Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-top.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'tools/perf/builtin-top.c') diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 3d2b47d5121a..5aa29e1e855a 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -1025,6 +1025,8 @@ static void event__process_sample(const event_t *self, if (self->header.misc & PERF_RECORD_MISC_EXACT_IP) exact_samples++; + event__parse_sample(self, session->sample_type, &data); + if (event__preprocess_sample(self, session, &al, &data, symbol_filter) < 0 || al.filtered) @@ -1155,7 +1157,7 @@ static void perf_session__mmap_read_counter(struct perf_session *self, if (event->header.type == PERF_RECORD_SAMPLE) event__process_sample(event, self, md->counter); else - event__process(event, self); + event__process(event, NULL, self); old += size; } -- cgit v1.2.2 From 9c90a61c7e4286aa5a38b314a2d8f5a1e70b5135 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 2 Dec 2010 10:25:28 -0200 Subject: perf tools: Ask for ID PERF_SAMPLE_ info on all PERF_RECORD_ events MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit So that we can use -T == --timestamp, asking for PERF_SAMPLE_TIME: $ perf record -aT $ perf report -D | grep PERF_RECORD_ 3 5951915425 0x47530 [0x58]: PERF_RECORD_SAMPLE(IP, 1): 16811/16811: 0xffffffff8138c1a2 period: 215979 cpu:3 3 5952026879 0x47588 [0x90]: PERF_RECORD_SAMPLE(IP, 1): 16811/16811: 0xffffffff810cb480 period: 215979 cpu:3 3 5952059959 0x47618 [0x38]: PERF_RECORD_FORK(6853:6853):(16811:16811) 3 5952138878 0x47650 [0x78]: PERF_RECORD_SAMPLE(IP, 1): 16811/16811: 0xffffffff811bac35 period: 431478 cpu:3 3 5952375068 0x476c8 [0x30]: PERF_RECORD_COMM: find:6853 3 5952395923 0x476f8 [0x50]: PERF_RECORD_MMAP 6853/6853: [0x400000(0x25000) @ 0]: /usr/bin/find 3 5952413756 0x47748 [0xa0]: PERF_RECORD_SAMPLE(IP, 1): 6853/6853: 0xffffffff810d080f period: 859332 cpu:3 3 5952419837 0x477e8 [0x58]: PERF_RECORD_MMAP 6853/6853: [0x3f44600000(0x21d000) @ 0]: /lib64/ld-2.5.so 3 5952437929 0x47840 [0x48]: PERF_RECORD_MMAP 6853/6853: [0x7fff7e1c9000(0x1000) @ 0x7fff7e1c9000]: [vdso] 3 5952570127 0x47888 [0x58]: PERF_RECORD_MMAP 6853/6853: [0x3f46200000(0x218000) @ 0]: /lib64/libselinux.so.1 3 5952623637 0x478e0 [0x58]: PERF_RECORD_MMAP 6853/6853: [0x3f44a00000(0x356000) @ 0]: /lib64/libc-2.5.so 3 5952675720 0x47938 [0x58]: PERF_RECORD_MMAP 6853/6853: [0x3f44e00000(0x204000) @ 0]: /lib64/libdl-2.5.so 3 5952710080 0x47990 [0x58]: PERF_RECORD_MMAP 6853/6853: [0x3f45a00000(0x246000) @ 0]: /lib64/libsepol.so.1 3 5952847802 0x479e8 [0x58]: PERF_RECORD_SAMPLE(IP, 1): 6853/6853: 0xffffffff813897f0 period: 1142536 cpu:3 First column is the cpu and the second the timestamp. That way we can investigate problems in the event stream. If the new perf binary is run on an older kernel, it will disable this feature automatically. Tested-by: Thomas Gleixner Reviewed-by: Thomas Gleixner Acked-by: Ian Munsie Acked-by: Thomas Gleixner Cc: Frédéric Weisbecker Cc: Ian Munsie Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Paul Mackerras Cc: Stephane Eranian LKML-Reference: <1291318772-30880-5-git-send-email-acme@infradead.org> Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-top.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'tools/perf/builtin-top.c') diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 5aa29e1e855a..0515ce9d3d3e 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -977,12 +977,12 @@ static int symbol_filter(struct map *map, struct symbol *sym) } static void event__process_sample(const event_t *self, - struct perf_session *session, int counter) + struct sample_data *sample, + struct perf_session *session, int counter) { u64 ip = self->ip.ip; struct sym_entry *syme; struct addr_location al; - struct sample_data data; struct machine *machine; u8 origin = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; @@ -1025,9 +1025,7 @@ static void event__process_sample(const event_t *self, if (self->header.misc & PERF_RECORD_MISC_EXACT_IP) exact_samples++; - event__parse_sample(self, session->sample_type, &data); - - if (event__preprocess_sample(self, session, &al, &data, + if (event__preprocess_sample(self, session, &al, sample, symbol_filter) < 0 || al.filtered) return; @@ -1107,6 +1105,7 @@ static void perf_session__mmap_read_counter(struct perf_session *self, unsigned int head = mmap_read_head(md); unsigned int old = md->prev; unsigned char *data = md->base + page_size; + struct sample_data sample; int diff; /* @@ -1154,10 +1153,11 @@ static void perf_session__mmap_read_counter(struct perf_session *self, event = &event_copy; } + event__parse_sample(event, self, &sample); if (event->header.type == PERF_RECORD_SAMPLE) - event__process_sample(event, self, md->counter); + event__process_sample(event, &sample, self, md->counter); else - event__process(event, NULL, self); + event__process(event, &sample, self); old += size; } -- cgit v1.2.2 From 21ef97f05a7da5bc23b26cb34d6746f83ca9bf20 Mon Sep 17 00:00:00 2001 From: Ian Munsie Date: Fri, 10 Dec 2010 14:09:16 +1100 Subject: perf session: Fallback to unordered processing if no sample_id_all If we are running the new perf on an old kernel without support for sample_id_all, we should fall back to the old unordered processing of events. If we didn't than we would *always* process events without timestamps out of order, whether or not we hit a reordering race. In other words, instead of there being a chance of not attributing samples correctly, we would guarantee that samples would not be attributed. While processing all events without timestamps before events with timestamps may seem like an intuitive solution, it falls down as PERF_RECORD_EXIT events would also be processed before any samples. Even with a workaround for that case, samples before/after an exec would not be attributed correctly. This patch allows commands to indicate whether they need to fall back to unordered processing, so that commands that do not care about timestamps on every event will not be affected. If we do fallback, this will print out a warning if report -D was invoked. This patch adds the test in perf_session__new so that we only need to test once per session. Commands that do not use an event_ops (such as record and top) can simply pass NULL in it's place. Acked-by: Thomas Gleixner Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Peter Zijlstra Cc: Thomas Gleixner LKML-Reference: <1291951882-sup-6069@au1.ibm.com> Signed-off-by: Ian Munsie Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-top.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools/perf/builtin-top.c') diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 0515ce9d3d3e..ae15f046c405 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -1272,7 +1272,7 @@ static int __cmd_top(void) * FIXME: perf_session__new should allow passing a O_MMAP, so that all this * mmap reading, etc is encapsulated in it. Use O_WRONLY for now. */ - struct perf_session *session = perf_session__new(NULL, O_WRONLY, false, false); + struct perf_session *session = perf_session__new(NULL, O_WRONLY, false, false, NULL); if (session == NULL) return -ENOMEM; -- cgit v1.2.2 From 69aad6f1ee69546dea8535ab8f3da9f445d57328 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 3 Jan 2011 16:39:04 -0200 Subject: perf tools: Introduce event selectors Out of ad-hoc code and global arrays with hard coded sizes. This is the first step on having a library that will be first used on regression tests in the 'perf test' tool. [acme@felicio linux]$ size /tmp/perf.before text data bss dec hex filename 1273776 97384 5104416 6475576 62cf38 /tmp/perf.before [acme@felicio linux]$ size /tmp/perf.new text data bss dec hex filename 1275422 97416 1392416 2765254 2a31c6 /tmp/perf.new Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Tom Zanussi LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-top.c | 176 ++++++++++++++++++++++++++++------------------- 1 file changed, 104 insertions(+), 72 deletions(-) (limited to 'tools/perf/builtin-top.c') diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index ae15f046c405..13a836efa1e1 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -21,6 +21,7 @@ #include "perf.h" #include "util/color.h" +#include "util/evsel.h" #include "util/session.h" #include "util/symbol.h" #include "util/thread.h" @@ -29,6 +30,7 @@ #include "util/parse-options.h" #include "util/parse-events.h" #include "util/cpumap.h" +#include "util/xyarray.h" #include "util/debug.h" @@ -55,7 +57,7 @@ #include #include -static int *fd[MAX_NR_CPUS][MAX_COUNTERS]; +#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) static bool system_wide = false; @@ -100,6 +102,7 @@ struct sym_entry *sym_filter_entry = NULL; struct sym_entry *sym_filter_entry_sched = NULL; static int sym_pcnt_filter = 5; static int sym_counter = 0; +static struct perf_evsel *sym_evsel = NULL; static int display_weighted = -1; static const char *cpu_list; @@ -353,7 +356,7 @@ static void show_details(struct sym_entry *syme) return; symbol = sym_entry__symbol(syme); - printf("Showing %s for %s\n", event_name(sym_counter), symbol->name); + printf("Showing %s for %s\n", event_name(sym_evsel), symbol->name); printf(" Events Pcnt (>=%d%%)\n", sym_pcnt_filter); pthread_mutex_lock(&syme->src->lock); @@ -460,7 +463,8 @@ static void rb_insert_active_sym(struct rb_root *tree, struct sym_entry *se) static void print_sym_table(void) { int printed = 0, j; - int counter, snap = !display_weighted ? sym_counter : 0; + struct perf_evsel *counter; + int snap = !display_weighted ? sym_counter : 0; float samples_per_sec = samples/delay_secs; float ksamples_per_sec = kernel_samples/delay_secs; float us_samples_per_sec = (us_samples)/delay_secs; @@ -532,7 +536,9 @@ static void print_sym_table(void) } if (nr_counters == 1 || !display_weighted) { - printf("%Ld", (u64)attrs[0].sample_period); + struct perf_evsel *first; + first = list_entry(evsel_list.next, struct perf_evsel, node); + printf("%Ld", first->attr.sample_period); if (freq) printf("Hz "); else @@ -540,9 +546,9 @@ static void print_sym_table(void) } if (!display_weighted) - printf("%s", event_name(sym_counter)); - else for (counter = 0; counter < nr_counters; counter++) { - if (counter) + printf("%s", event_name(sym_evsel)); + else list_for_each_entry(counter, &evsel_list, node) { + if (counter->idx) printf("/"); printf("%s", event_name(counter)); @@ -739,7 +745,7 @@ static void print_mapped_keys(void) fprintf(stdout, "\t[e] display entries (lines). \t(%d)\n", print_entries); if (nr_counters > 1) - fprintf(stdout, "\t[E] active event counter. \t(%s)\n", event_name(sym_counter)); + fprintf(stdout, "\t[E] active event counter. \t(%s)\n", event_name(sym_evsel)); fprintf(stdout, "\t[f] profile display filter (count). \t(%d)\n", count_filter); @@ -826,19 +832,23 @@ static void handle_keypress(struct perf_session *session, int c) break; case 'E': if (nr_counters > 1) { - int i; - fprintf(stderr, "\nAvailable events:"); - for (i = 0; i < nr_counters; i++) - fprintf(stderr, "\n\t%d %s", i, event_name(i)); + + list_for_each_entry(sym_evsel, &evsel_list, node) + fprintf(stderr, "\n\t%d %s", sym_evsel->idx, event_name(sym_evsel)); prompt_integer(&sym_counter, "Enter details event counter"); if (sym_counter >= nr_counters) { - fprintf(stderr, "Sorry, no such event, using %s.\n", event_name(0)); + sym_evsel = list_entry(evsel_list.next, struct perf_evsel, node); sym_counter = 0; + fprintf(stderr, "Sorry, no such event, using %s.\n", event_name(sym_evsel)); sleep(1); + break; } + list_for_each_entry(sym_evsel, &evsel_list, node) + if (sym_evsel->idx == sym_counter) + break; } else sym_counter = 0; break; case 'f': @@ -978,7 +988,8 @@ static int symbol_filter(struct map *map, struct symbol *sym) static void event__process_sample(const event_t *self, struct sample_data *sample, - struct perf_session *session, int counter) + struct perf_session *session, + struct perf_evsel *evsel) { u64 ip = self->ip.ip; struct sym_entry *syme; @@ -1071,9 +1082,9 @@ static void event__process_sample(const event_t *self, syme = symbol__priv(al.sym); if (!syme->skip) { - syme->count[counter]++; + syme->count[evsel->idx]++; syme->origin = origin; - record_precise_ip(syme, counter, ip); + record_precise_ip(syme, evsel->idx, ip); pthread_mutex_lock(&active_symbols_lock); if (list_empty(&syme->node) || !syme->node.next) __list_insert_active_sym(syme); @@ -1082,12 +1093,24 @@ static void event__process_sample(const event_t *self, } struct mmap_data { - int counter; void *base; int mask; unsigned int prev; }; +static int perf_evsel__alloc_mmap_per_thread(struct perf_evsel *evsel, + int ncpus, int nthreads) +{ + evsel->priv = xyarray__new(ncpus, nthreads, sizeof(struct mmap_data)); + return evsel->priv != NULL ? 0 : -ENOMEM; +} + +static void perf_evsel__free_mmap(struct perf_evsel *evsel) +{ + xyarray__delete(evsel->priv); + evsel->priv = NULL; +} + static unsigned int mmap_read_head(struct mmap_data *md) { struct perf_event_mmap_page *pc = md->base; @@ -1100,8 +1123,11 @@ static unsigned int mmap_read_head(struct mmap_data *md) } static void perf_session__mmap_read_counter(struct perf_session *self, - struct mmap_data *md) + struct perf_evsel *evsel, + int cpu, int thread_idx) { + struct xyarray *mmap_array = evsel->priv; + struct mmap_data *md = xyarray__entry(mmap_array, cpu, thread_idx); unsigned int head = mmap_read_head(md); unsigned int old = md->prev; unsigned char *data = md->base + page_size; @@ -1155,7 +1181,7 @@ static void perf_session__mmap_read_counter(struct perf_session *self, event__parse_sample(event, self, &sample); if (event->header.type == PERF_RECORD_SAMPLE) - event__process_sample(event, &sample, self, md->counter); + event__process_sample(event, &sample, self, evsel); else event__process(event, &sample, self); old += size; @@ -1165,28 +1191,31 @@ static void perf_session__mmap_read_counter(struct perf_session *self, } static struct pollfd *event_array; -static struct mmap_data *mmap_array[MAX_NR_CPUS][MAX_COUNTERS]; static void perf_session__mmap_read(struct perf_session *self) { - int i, counter, thread_index; + struct perf_evsel *counter; + int i, thread_index; for (i = 0; i < nr_cpus; i++) { - for (counter = 0; counter < nr_counters; counter++) + list_for_each_entry(counter, &evsel_list, node) { for (thread_index = 0; thread_index < thread_num; thread_index++) { perf_session__mmap_read_counter(self, - &mmap_array[i][counter][thread_index]); + counter, i, thread_index); } + } } } int nr_poll; int group_fd; -static void start_counter(int i, int counter) +static void start_counter(int i, struct perf_evsel *evsel) { + struct xyarray *mmap_array = evsel->priv; + struct mmap_data *mm; struct perf_event_attr *attr; int cpu = -1; int thread_index; @@ -1194,7 +1223,7 @@ static void start_counter(int i, int counter) if (target_tid == -1) cpu = cpumap[i]; - attr = attrs + counter; + attr = &evsel->attr; attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID; @@ -1209,10 +1238,10 @@ static void start_counter(int i, int counter) for (thread_index = 0; thread_index < thread_num; thread_index++) { try_again: - fd[i][counter][thread_index] = sys_perf_event_open(attr, + FD(evsel, i, thread_index) = sys_perf_event_open(attr, all_tids[thread_index], cpu, group_fd, 0); - if (fd[i][counter][thread_index] < 0) { + if (FD(evsel, i, thread_index) < 0) { int err = errno; if (err == EPERM || err == EACCES) @@ -1236,29 +1265,29 @@ try_again: } printf("\n"); error("sys_perf_event_open() syscall returned with %d (%s). /bin/dmesg may provide additional information.\n", - fd[i][counter][thread_index], strerror(err)); + FD(evsel, i, thread_index), strerror(err)); die("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); exit(-1); } - assert(fd[i][counter][thread_index] >= 0); - fcntl(fd[i][counter][thread_index], F_SETFL, O_NONBLOCK); + assert(FD(evsel, i, thread_index) >= 0); + fcntl(FD(evsel, i, thread_index), F_SETFL, O_NONBLOCK); /* * First counter acts as the group leader: */ if (group && group_fd == -1) - group_fd = fd[i][counter][thread_index]; + group_fd = FD(evsel, i, thread_index); - event_array[nr_poll].fd = fd[i][counter][thread_index]; + event_array[nr_poll].fd = FD(evsel, i, thread_index); event_array[nr_poll].events = POLLIN; nr_poll++; - mmap_array[i][counter][thread_index].counter = counter; - mmap_array[i][counter][thread_index].prev = 0; - mmap_array[i][counter][thread_index].mask = mmap_pages*page_size - 1; - mmap_array[i][counter][thread_index].base = mmap(NULL, (mmap_pages+1)*page_size, - PROT_READ, MAP_SHARED, fd[i][counter][thread_index], 0); - if (mmap_array[i][counter][thread_index].base == MAP_FAILED) + mm = xyarray__entry(mmap_array, i, thread_index); + mm->prev = 0; + mm->mask = mmap_pages*page_size - 1; + mm->base = mmap(NULL, (mmap_pages+1)*page_size, + PROT_READ, MAP_SHARED, FD(evsel, i, thread_index), 0); + if (mm->base == MAP_FAILED) die("failed to mmap with %d (%s)\n", errno, strerror(errno)); } } @@ -1266,8 +1295,8 @@ try_again: static int __cmd_top(void) { pthread_t thread; - int i, counter; - int ret; + struct perf_evsel *counter; + int i, ret; /* * FIXME: perf_session__new should allow passing a O_MMAP, so that all this * mmap reading, etc is encapsulated in it. Use O_WRONLY for now. @@ -1283,7 +1312,7 @@ static int __cmd_top(void) for (i = 0; i < nr_cpus; i++) { group_fd = -1; - for (counter = 0; counter < nr_counters; counter++) + list_for_each_entry(counter, &evsel_list, node) start_counter(i, counter); } @@ -1372,8 +1401,8 @@ static const struct option options[] = { int cmd_top(int argc, const char **argv, const char *prefix __used) { - int counter; - int i,j; + struct perf_evsel *pos; + int status = -ENOMEM; page_size = sysconf(_SC_PAGE_SIZE); @@ -1398,15 +1427,6 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) thread_num = 1; } - for (i = 0; i < MAX_NR_CPUS; i++) { - for (j = 0; j < MAX_COUNTERS; j++) { - fd[i][j] = malloc(sizeof(int)*thread_num); - mmap_array[i][j] = zalloc( - sizeof(struct mmap_data)*thread_num); - if (!fd[i][j] || !mmap_array[i][j]) - return -ENOMEM; - } - } event_array = malloc( sizeof(struct pollfd)*MAX_NR_CPUS*MAX_COUNTERS*thread_num); if (!event_array) @@ -1419,15 +1439,10 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) cpu_list = NULL; } - if (!nr_counters) - nr_counters = 1; - - symbol_conf.priv_size = (sizeof(struct sym_entry) + - (nr_counters + 1) * sizeof(unsigned long)); - - symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL); - if (symbol__init() < 0) - return -1; + if (!nr_counters && perf_evsel_list__create_default() < 0) { + pr_err("Not enough memory for event selector list\n"); + return -ENOMEM; + } if (delay_secs < 1) delay_secs = 1; @@ -1444,16 +1459,6 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) exit(EXIT_FAILURE); } - /* - * Fill in the ones not specifically initialized via -c: - */ - for (counter = 0; counter < nr_counters; counter++) { - if (attrs[counter].sample_period) - continue; - - attrs[counter].sample_period = default_interval; - } - if (target_tid != -1) nr_cpus = 1; else @@ -1462,11 +1467,38 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) if (nr_cpus < 1) usage_with_options(top_usage, options); + list_for_each_entry(pos, &evsel_list, node) { + if (perf_evsel__alloc_mmap_per_thread(pos, nr_cpus, thread_num) < 0 || + perf_evsel__alloc_fd(pos, nr_cpus, thread_num) < 0) + goto out_free_fd; + /* + * Fill in the ones not specifically initialized via -c: + */ + if (pos->attr.sample_period) + continue; + + pos->attr.sample_period = default_interval; + } + + symbol_conf.priv_size = (sizeof(struct sym_entry) + + (nr_counters + 1) * sizeof(unsigned long)); + + symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL); + if (symbol__init() < 0) + return -1; + get_term_dimensions(&winsize); if (print_entries == 0) { update_print_entries(&winsize); signal(SIGWINCH, sig_winch_handler); } - return __cmd_top(); + status = __cmd_top(); +out_free_fd: + list_for_each_entry(pos, &evsel_list, node) { + perf_evsel__free_fd(pos); + perf_evsel__free_mmap(pos); + } + + return status; } -- cgit v1.2.2 From 70d544d0576775a2b3923a7e68cb49b0313d80c9 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 3 Jan 2011 16:51:39 -0200 Subject: perf evsel: Delete the event selectors at exit Freeing all the possibly allocated resources, reducing complexity on each tool exit path. Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Tom Zanussi LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-top.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'tools/perf/builtin-top.c') diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 13a836efa1e1..27b9c14a0a07 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -1495,10 +1495,8 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) status = __cmd_top(); out_free_fd: - list_for_each_entry(pos, &evsel_list, node) { - perf_evsel__free_fd(pos); + list_for_each_entry(pos, &evsel_list, node) perf_evsel__free_mmap(pos); - } return status; } -- cgit v1.2.2 From 60d567e2d9187379d642f6aba7c8a52b3fd5d261 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 3 Jan 2011 17:49:48 -0200 Subject: perf tools: Refactor cpumap to hold nr and the map So that later, we can pass the cpu_map instance instead of (nr_cpus, cpu_map) for things like perf_evsel__open and friends. Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Tom Zanussi LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-top.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'tools/perf/builtin-top.c') diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 27b9c14a0a07..0e426665716d 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -71,7 +71,7 @@ static int target_tid = -1; static pid_t *all_tids = NULL; static int thread_num = 0; static bool inherit = false; -static int nr_cpus = 0; +static struct cpu_map *cpus; static int realtime_prio = 0; static bool group = false; static unsigned int page_size; @@ -564,12 +564,12 @@ static void print_sym_table(void) printf(" (all"); if (cpu_list) - printf(", CPU%s: %s)\n", nr_cpus > 1 ? "s" : "", cpu_list); + printf(", CPU%s: %s)\n", cpus->nr > 1 ? "s" : "", cpu_list); else { if (target_tid != -1) printf(")\n"); else - printf(", %d CPU%s)\n", nr_cpus, nr_cpus > 1 ? "s" : ""); + printf(", %d CPU%s)\n", cpus->nr, cpus->nr > 1 ? "s" : ""); } printf("%-*.*s\n", win_width, win_width, graph_dotted_line); @@ -1197,7 +1197,7 @@ static void perf_session__mmap_read(struct perf_session *self) struct perf_evsel *counter; int i, thread_index; - for (i = 0; i < nr_cpus; i++) { + for (i = 0; i < cpus->nr; i++) { list_for_each_entry(counter, &evsel_list, node) { for (thread_index = 0; thread_index < thread_num; @@ -1221,7 +1221,7 @@ static void start_counter(int i, struct perf_evsel *evsel) int thread_index; if (target_tid == -1) - cpu = cpumap[i]; + cpu = cpus->map[i]; attr = &evsel->attr; @@ -1310,7 +1310,7 @@ static int __cmd_top(void) else event__synthesize_threads(event__process, session); - for (i = 0; i < nr_cpus; i++) { + for (i = 0; i < cpus->nr; i++) { group_fd = -1; list_for_each_entry(counter, &evsel_list, node) start_counter(i, counter); @@ -1460,16 +1460,16 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) } if (target_tid != -1) - nr_cpus = 1; + cpus = cpu_map__dummy_new(); else - nr_cpus = read_cpu_map(cpu_list); + cpus = cpu_map__new(cpu_list); - if (nr_cpus < 1) + if (cpus == NULL) usage_with_options(top_usage, options); list_for_each_entry(pos, &evsel_list, node) { - if (perf_evsel__alloc_mmap_per_thread(pos, nr_cpus, thread_num) < 0 || - perf_evsel__alloc_fd(pos, nr_cpus, thread_num) < 0) + if (perf_evsel__alloc_mmap_per_thread(pos, cpus->nr, thread_num) < 0 || + perf_evsel__alloc_fd(pos, cpus->nr, thread_num) < 0) goto out_free_fd; /* * Fill in the ones not specifically initialized via -c: -- cgit v1.2.2 From 5c98d466e49267a9221f30958d45cd06f794269a Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 3 Jan 2011 17:53:33 -0200 Subject: perf tools: Refactor all_tids to hold nr and the map So that later, we can pass the thread_map instance instead of (thread_num, thread_map) for things like perf_evsel__open and friends, just like was done with cpu_map. Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Tom Zanussi LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-top.c | 35 +++++++++++++---------------------- 1 file changed, 13 insertions(+), 22 deletions(-) (limited to 'tools/perf/builtin-top.c') diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 0e426665716d..1e67ab9c7ebc 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -68,8 +68,7 @@ static int print_entries; static int target_pid = -1; static int target_tid = -1; -static pid_t *all_tids = NULL; -static int thread_num = 0; +static struct thread_map *threads; static bool inherit = false; static struct cpu_map *cpus; static int realtime_prio = 0; @@ -1200,7 +1199,7 @@ static void perf_session__mmap_read(struct perf_session *self) for (i = 0; i < cpus->nr; i++) { list_for_each_entry(counter, &evsel_list, node) { for (thread_index = 0; - thread_index < thread_num; + thread_index < threads->nr; thread_index++) { perf_session__mmap_read_counter(self, counter, i, thread_index); @@ -1236,10 +1235,10 @@ static void start_counter(int i, struct perf_evsel *evsel) attr->inherit = (cpu < 0) && inherit; attr->mmap = 1; - for (thread_index = 0; thread_index < thread_num; thread_index++) { + for (thread_index = 0; thread_index < threads->nr; thread_index++) { try_again: FD(evsel, i, thread_index) = sys_perf_event_open(attr, - all_tids[thread_index], cpu, group_fd, 0); + threads->map[thread_index], cpu, group_fd, 0); if (FD(evsel, i, thread_index) < 0) { int err = errno; @@ -1410,25 +1409,17 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) if (argc) usage_with_options(top_usage, options); - if (target_pid != -1) { + if (target_pid != -1) target_tid = target_pid; - thread_num = find_all_tid(target_pid, &all_tids); - if (thread_num <= 0) { - fprintf(stderr, "Can't find all threads of pid %d\n", - target_pid); - usage_with_options(top_usage, options); - } - } else { - all_tids=malloc(sizeof(pid_t)); - if (!all_tids) - return -ENOMEM; - all_tids[0] = target_tid; - thread_num = 1; + threads = thread_map__new(target_pid, target_tid); + if (threads == NULL) { + pr_err("Problems finding threads of monitor\n"); + usage_with_options(top_usage, options); } - event_array = malloc( - sizeof(struct pollfd)*MAX_NR_CPUS*MAX_COUNTERS*thread_num); + event_array = malloc((sizeof(struct pollfd) * + MAX_NR_CPUS * MAX_COUNTERS * threads->nr)); if (!event_array) return -ENOMEM; @@ -1468,8 +1459,8 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) usage_with_options(top_usage, options); list_for_each_entry(pos, &evsel_list, node) { - if (perf_evsel__alloc_mmap_per_thread(pos, cpus->nr, thread_num) < 0 || - perf_evsel__alloc_fd(pos, cpus->nr, thread_num) < 0) + if (perf_evsel__alloc_mmap_per_thread(pos, cpus->nr, threads->nr) < 0 || + perf_evsel__alloc_fd(pos, cpus->nr, threads->nr) < 0) goto out_free_fd; /* * Fill in the ones not specifically initialized via -c: -- cgit v1.2.2 From aa7bc7ef73efc46d7c3a0e185eefaf85744aec98 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 10 Jan 2011 13:36:24 -0200 Subject: perf tools: Emit clearer message for sys_perf_event_open ENOENT return Improve sys_perf_event_open ENOENT return handling in top and record, just like 5a3446b does for stat. Cc: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Tom Zanussi LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-top.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'tools/perf/builtin-top.c') diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 1e67ab9c7ebc..6ce4042421bd 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -1247,6 +1247,8 @@ try_again: die("Permission error - are you root?\n" "\t Consider tweaking" " /proc/sys/kernel/perf_event_paranoid.\n"); + if (err == ENOENT) + die("%s event is not supported. ", event_name(evsel)); /* * If it's cycles then fall back to hrtimer * based cpu-clock-tick sw counter, which -- cgit v1.2.2 From bd3bfe9eda94d3c050830217c1e1c338808de5b2 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 11 Jan 2011 12:42:00 -0200 Subject: perf evsel: Fix order of event list deletion We need to defer calling perf_evsel_list__delete() till after atexit registered routines, because we need to traverse the events being recorded at that time at least on 'perf record'. This fixes the problem reported by Thomas Renninger where cmd_record called by cmd_timechart would not write the tracing data to the perf.data file header because the evsel_list at atexit (control+C on 'perf timechart record') time would be empty, being already deleted by run_builtin(), and thus 'perf timechart' when trying to process such perf.data file would die with: "no trace data in the file" Problem introduced in 70d544d. Reported-by: Thomas Renninger Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Thomas Renninger Cc: Tom Zanussi LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-top.c | 1 + 1 file changed, 1 insertion(+) (limited to 'tools/perf/builtin-top.c') diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 6ce4042421bd..4b995ee099cf 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -1490,6 +1490,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) out_free_fd: list_for_each_entry(pos, &evsel_list, node) perf_evsel__free_mmap(pos); + perf_evsel_list__delete(); return status; } -- cgit v1.2.2 From cc841580aa58ad7498b23e282859d07f8b721e24 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 11 Jan 2011 15:16:52 -0200 Subject: perf top: Fix annotate segv Before we had sym_counter, it was initialized to zero and we used that as an index in the global attrs variable, now we have a list of evsel entries, and sym_counter became sym_evsel, that remained initialized to zero (NULL): b00m. Fix it by initializing it to the first entry in the evsel list. Bug-introduced: 69aad6f Reported-by: Kirill Smelkov Tested-by: Kirill Smelkov Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Kirill Smelkov Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Tom Zanussi LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-top.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'tools/perf/builtin-top.c') diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 4b995ee099cf..568b1950e632 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -1473,6 +1473,8 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) pos->attr.sample_period = default_interval; } + sym_evsel = list_entry(evsel_list.next, struct perf_evsel, node); + symbol_conf.priv_size = (sizeof(struct sym_entry) + (nr_counters + 1) * sizeof(unsigned long)); -- cgit v1.2.2 From 4ad9f594d7199c99f6b1b3ef88c64bd5920a4592 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 11 Jan 2011 16:58:54 -0200 Subject: Revert "perf tools: Emit clearer message for sys_perf_event_open ENOENT return" This reverts commit aa7bc7ef73efc46d7c3a0e185eefaf85744aec98. It removed the fallback from hardware profiling to software profiling. .e.g., in a VM with no PMU. Reported-by: David Ahern Cc: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Tom Zanussi LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-top.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'tools/perf/builtin-top.c') diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 568b1950e632..05344c6210ac 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -1247,8 +1247,6 @@ try_again: die("Permission error - are you root?\n" "\t Consider tweaking" " /proc/sys/kernel/perf_event_paranoid.\n"); - if (err == ENOENT) - die("%s event is not supported. ", event_name(evsel)); /* * If it's cycles then fall back to hrtimer * based cpu-clock-tick sw counter, which -- cgit v1.2.2 From 9486aa38771661e96fbb51c549b9901b5df609d8 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sat, 22 Jan 2011 20:37:02 -0200 Subject: perf tools: Fix 64 bit integer format strings Using %L[uxd] has issues in some architectures, like on ppc64. Fix it by making our 64 bit integers typedefs of stdint.h types and using PRI[ux]64 like, for instance, git does. Reported by Denis Kirjanov that provided a patch for one case, I went and changed all cases. Reported-by: Denis Kirjanov Tested-by: Denis Kirjanov LKML-Reference: <20110120093246.GA8031@hera.kernel.org> Cc: Denis Kirjanov Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Pingtian Han Cc: Stephane Eranian Cc: Tom Zanussi Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-top.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'tools/perf/builtin-top.c') diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 05344c6210ac..b6998e055767 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include @@ -214,7 +215,7 @@ static int parse_source(struct sym_entry *syme) len = sym->end - sym->start; sprintf(command, - "objdump --start-address=%#0*Lx --stop-address=%#0*Lx -dS %s", + "objdump --start-address=%#0*" PRIx64 " --stop-address=%#0*" PRIx64 " -dS %s", BITS_PER_LONG / 4, map__rip_2objdump(map, sym->start), BITS_PER_LONG / 4, map__rip_2objdump(map, sym->end), path); @@ -308,7 +309,7 @@ static void lookup_sym_source(struct sym_entry *syme) struct source_line *line; char pattern[PATTERN_LEN + 1]; - sprintf(pattern, "%0*Lx <", BITS_PER_LONG / 4, + sprintf(pattern, "%0*" PRIx64 " <", BITS_PER_LONG / 4, map__rip_2objdump(syme->map, symbol->start)); pthread_mutex_lock(&syme->src->lock); @@ -537,7 +538,7 @@ static void print_sym_table(void) if (nr_counters == 1 || !display_weighted) { struct perf_evsel *first; first = list_entry(evsel_list.next, struct perf_evsel, node); - printf("%Ld", first->attr.sample_period); + printf("%" PRIu64, (uint64_t)first->attr.sample_period); if (freq) printf("Hz "); else @@ -640,7 +641,7 @@ static void print_sym_table(void) percent_color_fprintf(stdout, "%4.1f%%", pcnt); if (verbose) - printf(" %016llx", sym->start); + printf(" %016" PRIx64, sym->start); printf(" %-*.*s", sym_width, sym_width, sym->name); printf(" %-*.*s\n", dso_width, dso_width, dso_width >= syme->map->dso->long_name_len ? -- cgit v1.2.2 From 361c99a661a78ed22264649440e87fe4fe8da1f2 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 11 Jan 2011 20:56:53 -0200 Subject: perf evsel: Introduce perf_evlist Killing two more perf wide global variables: nr_counters and evsel_list as a list_head. There are more operations that will need more fields in perf_evlist, like the pollfd for polling all the fds in a list of evsel instances. Use option->value to pass the evsel_list to parse_{events,filters}. LKML-Reference: Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Tom Zanussi Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-top.c | 60 +++++++++++++++++++++++++++--------------------- 1 file changed, 34 insertions(+), 26 deletions(-) (limited to 'tools/perf/builtin-top.c') diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index b6998e055767..216b62ed4b89 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -21,6 +21,7 @@ #include "perf.h" #include "util/color.h" +#include "util/evlist.h" #include "util/evsel.h" #include "util/session.h" #include "util/symbol.h" @@ -60,6 +61,8 @@ #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) +struct perf_evlist *evsel_list; + static bool system_wide = false; static int default_interval = 0; @@ -267,7 +270,7 @@ static void __zero_source_counters(struct sym_entry *syme) line = syme->src->lines; while (line) { - for (i = 0; i < nr_counters; i++) + for (i = 0; i < evsel_list->nr_entries; i++) line->count[i] = 0; line = line->next; } @@ -414,7 +417,7 @@ static double sym_weight(const struct sym_entry *sym) if (!display_weighted) return weight; - for (counter = 1; counter < nr_counters-1; counter++) + for (counter = 1; counter < evsel_list->nr_entries - 1; counter++) weight *= sym->count[counter]; weight /= (sym->count[counter] + 1); @@ -501,7 +504,7 @@ static void print_sym_table(void) rb_insert_active_sym(&tmp, syme); sum_ksamples += syme->snap_count; - for (j = 0; j < nr_counters; j++) + for (j = 0; j < evsel_list->nr_entries; j++) syme->count[j] = zero ? 0 : syme->count[j] * 7 / 8; } else list_remove_active_sym(syme); @@ -535,9 +538,9 @@ static void print_sym_table(void) esamples_percent); } - if (nr_counters == 1 || !display_weighted) { + if (evsel_list->nr_entries == 1 || !display_weighted) { struct perf_evsel *first; - first = list_entry(evsel_list.next, struct perf_evsel, node); + first = list_entry(evsel_list->entries.next, struct perf_evsel, node); printf("%" PRIu64, (uint64_t)first->attr.sample_period); if (freq) printf("Hz "); @@ -547,7 +550,7 @@ static void print_sym_table(void) if (!display_weighted) printf("%s", event_name(sym_evsel)); - else list_for_each_entry(counter, &evsel_list, node) { + else list_for_each_entry(counter, &evsel_list->entries, node) { if (counter->idx) printf("/"); @@ -606,7 +609,7 @@ static void print_sym_table(void) sym_width = winsize.ws_col - dso_width - 29; } putchar('\n'); - if (nr_counters == 1) + if (evsel_list->nr_entries == 1) printf(" samples pcnt"); else printf(" weight samples pcnt"); @@ -615,7 +618,7 @@ static void print_sym_table(void) printf(" RIP "); printf(" %-*.*s DSO\n", sym_width, sym_width, "function"); printf(" %s _______ _____", - nr_counters == 1 ? " " : "______"); + evsel_list->nr_entries == 1 ? " " : "______"); if (verbose) printf(" ________________"); printf(" %-*.*s", sym_width, sym_width, graph_line); @@ -634,7 +637,7 @@ static void print_sym_table(void) pcnt = 100.0 - (100.0 * ((sum_ksamples - syme->snap_count) / sum_ksamples)); - if (nr_counters == 1 || !display_weighted) + if (evsel_list->nr_entries == 1 || !display_weighted) printf("%20.2f ", syme->weight); else printf("%9.1f %10ld ", syme->weight, syme->snap_count); @@ -744,7 +747,7 @@ static void print_mapped_keys(void) fprintf(stdout, "\t[d] display refresh delay. \t(%d)\n", delay_secs); fprintf(stdout, "\t[e] display entries (lines). \t(%d)\n", print_entries); - if (nr_counters > 1) + if (evsel_list->nr_entries > 1) fprintf(stdout, "\t[E] active event counter. \t(%s)\n", event_name(sym_evsel)); fprintf(stdout, "\t[f] profile display filter (count). \t(%d)\n", count_filter); @@ -753,7 +756,7 @@ static void print_mapped_keys(void) fprintf(stdout, "\t[s] annotate symbol. \t(%s)\n", name?: "NULL"); fprintf(stdout, "\t[S] stop annotation.\n"); - if (nr_counters > 1) + if (evsel_list->nr_entries > 1) fprintf(stdout, "\t[w] toggle display weighted/count[E]r. \t(%d)\n", display_weighted ? 1 : 0); fprintf(stdout, @@ -783,7 +786,7 @@ static int key_mapped(int c) return 1; case 'E': case 'w': - return nr_counters > 1 ? 1 : 0; + return evsel_list->nr_entries > 1 ? 1 : 0; default: break; } @@ -831,22 +834,22 @@ static void handle_keypress(struct perf_session *session, int c) signal(SIGWINCH, SIG_DFL); break; case 'E': - if (nr_counters > 1) { + if (evsel_list->nr_entries > 1) { fprintf(stderr, "\nAvailable events:"); - list_for_each_entry(sym_evsel, &evsel_list, node) + list_for_each_entry(sym_evsel, &evsel_list->entries, node) fprintf(stderr, "\n\t%d %s", sym_evsel->idx, event_name(sym_evsel)); prompt_integer(&sym_counter, "Enter details event counter"); - if (sym_counter >= nr_counters) { - sym_evsel = list_entry(evsel_list.next, struct perf_evsel, node); + if (sym_counter >= evsel_list->nr_entries) { + sym_evsel = list_entry(evsel_list->entries.next, struct perf_evsel, node); sym_counter = 0; fprintf(stderr, "Sorry, no such event, using %s.\n", event_name(sym_evsel)); sleep(1); break; } - list_for_each_entry(sym_evsel, &evsel_list, node) + list_for_each_entry(sym_evsel, &evsel_list->entries, node) if (sym_evsel->idx == sym_counter) break; } else sym_counter = 0; @@ -1198,7 +1201,7 @@ static void perf_session__mmap_read(struct perf_session *self) int i, thread_index; for (i = 0; i < cpus->nr; i++) { - list_for_each_entry(counter, &evsel_list, node) { + list_for_each_entry(counter, &evsel_list->entries, node) { for (thread_index = 0; thread_index < threads->nr; thread_index++) { @@ -1312,7 +1315,7 @@ static int __cmd_top(void) for (i = 0; i < cpus->nr; i++) { group_fd = -1; - list_for_each_entry(counter, &evsel_list, node) + list_for_each_entry(counter, &evsel_list->entries, node) start_counter(i, counter); } @@ -1354,7 +1357,7 @@ static const char * const top_usage[] = { }; static const struct option options[] = { - OPT_CALLBACK('e', "event", NULL, "event", + OPT_CALLBACK('e', "event", &evsel_list, "event", "event selector. use 'perf list' to list available events", parse_events), OPT_INTEGER('c', "count", &default_interval, @@ -1404,6 +1407,10 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) struct perf_evsel *pos; int status = -ENOMEM; + evsel_list = perf_evlist__new(); + if (evsel_list == NULL) + return -ENOMEM; + page_size = sysconf(_SC_PAGE_SIZE); argc = parse_options(argc, argv, options, top_usage, 0); @@ -1431,7 +1438,8 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) cpu_list = NULL; } - if (!nr_counters && perf_evsel_list__create_default() < 0) { + if (!evsel_list->nr_entries && + perf_evlist__add_default(evsel_list) < 0) { pr_err("Not enough memory for event selector list\n"); return -ENOMEM; } @@ -1459,7 +1467,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) if (cpus == NULL) usage_with_options(top_usage, options); - list_for_each_entry(pos, &evsel_list, node) { + list_for_each_entry(pos, &evsel_list->entries, node) { if (perf_evsel__alloc_mmap_per_thread(pos, cpus->nr, threads->nr) < 0 || perf_evsel__alloc_fd(pos, cpus->nr, threads->nr) < 0) goto out_free_fd; @@ -1472,10 +1480,10 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) pos->attr.sample_period = default_interval; } - sym_evsel = list_entry(evsel_list.next, struct perf_evsel, node); + sym_evsel = list_entry(evsel_list->entries.next, struct perf_evsel, node); symbol_conf.priv_size = (sizeof(struct sym_entry) + - (nr_counters + 1) * sizeof(unsigned long)); + (evsel_list->nr_entries + 1) * sizeof(unsigned long)); symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL); if (symbol__init() < 0) @@ -1489,9 +1497,9 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) status = __cmd_top(); out_free_fd: - list_for_each_entry(pos, &evsel_list, node) + list_for_each_entry(pos, &evsel_list->entries, node) perf_evsel__free_mmap(pos); - perf_evsel_list__delete(); + perf_evlist__delete(evsel_list); return status; } -- cgit v1.2.2 From 5c581041cf97aa7980b442de81ddea8273d6dcde Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 11 Jan 2011 22:30:02 -0200 Subject: perf evlist: Adopt the pollfd array Allocating just the space needed for nr_cpus * nr_threads * nr_evsels, not the MAX_NR_CPUS and counters. LKML-Reference: Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Tom Zanussi Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-top.c | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) (limited to 'tools/perf/builtin-top.c') diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 216b62ed4b89..1bc465215fc6 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -1193,8 +1193,6 @@ static void perf_session__mmap_read_counter(struct perf_session *self, md->prev = old; } -static struct pollfd *event_array; - static void perf_session__mmap_read(struct perf_session *self) { struct perf_evsel *counter; @@ -1212,10 +1210,10 @@ static void perf_session__mmap_read(struct perf_session *self) } } -int nr_poll; int group_fd; -static void start_counter(int i, struct perf_evsel *evsel) +static void start_counter(int i, struct perf_evlist *evlist, + struct perf_evsel *evsel) { struct xyarray *mmap_array = evsel->priv; struct mmap_data *mm; @@ -1281,9 +1279,9 @@ try_again: if (group && group_fd == -1) group_fd = FD(evsel, i, thread_index); - event_array[nr_poll].fd = FD(evsel, i, thread_index); - event_array[nr_poll].events = POLLIN; - nr_poll++; + evlist->pollfd[evlist->nr_fds].fd = FD(evsel, i, thread_index); + evlist->pollfd[evlist->nr_fds].events = POLLIN; + evlist->nr_fds++; mm = xyarray__entry(mmap_array, i, thread_index); mm->prev = 0; @@ -1316,11 +1314,11 @@ static int __cmd_top(void) for (i = 0; i < cpus->nr; i++) { group_fd = -1; list_for_each_entry(counter, &evsel_list->entries, node) - start_counter(i, counter); + start_counter(i, evsel_list, counter); } /* Wait for a minimal set of events before starting the snapshot */ - poll(&event_array[0], nr_poll, 100); + poll(evsel_list->pollfd, evsel_list->nr_fds, 100); perf_session__mmap_read(session); @@ -1345,7 +1343,7 @@ static int __cmd_top(void) perf_session__mmap_read(session); if (hits == samples) - ret = poll(event_array, nr_poll, 100); + ret = poll(evsel_list->pollfd, evsel_list->nr_fds, 100); } return 0; @@ -1426,11 +1424,6 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) usage_with_options(top_usage, options); } - event_array = malloc((sizeof(struct pollfd) * - MAX_NR_CPUS * MAX_COUNTERS * threads->nr)); - if (!event_array) - return -ENOMEM; - /* CPU and PID are mutually exclusive */ if (target_tid > 0 && cpu_list) { printf("WARNING: PID switch overriding CPU\n"); @@ -1480,6 +1473,9 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) pos->attr.sample_period = default_interval; } + if (perf_evlist__alloc_pollfd(evsel_list, cpus->nr, threads->nr) < 0) + goto out_free_fd; + sym_evsel = list_entry(evsel_list->entries.next, struct perf_evsel, node); symbol_conf.priv_size = (sizeof(struct sym_entry) + -- cgit v1.2.2 From 72cb7013e08dec29631e0447f9496b7bacd3e14b Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 12 Jan 2011 10:52:47 -0200 Subject: perf top: Use perf_evsel__open Now that it handles group_fd and inherit we can use it, sharing it with stat. Next step: 'perf record' should use, then move the mmap_array out of ->priv and into perf_evsel, with top and record sharing this, and at the same time, write a 'perf test' stress test. Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Tom Zanussi LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-top.c | 92 ++++++++++++++++++++++-------------------------- 1 file changed, 42 insertions(+), 50 deletions(-) (limited to 'tools/perf/builtin-top.c') diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 1bc465215fc6..15d89bede2fb 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -1210,39 +1210,50 @@ static void perf_session__mmap_read(struct perf_session *self) } } -int group_fd; - static void start_counter(int i, struct perf_evlist *evlist, struct perf_evsel *evsel) { struct xyarray *mmap_array = evsel->priv; struct mmap_data *mm; - struct perf_event_attr *attr; - int cpu = -1; int thread_index; - if (target_tid == -1) - cpu = cpus->map[i]; - - attr = &evsel->attr; + for (thread_index = 0; thread_index < threads->nr; thread_index++) { + assert(FD(evsel, i, thread_index) >= 0); + fcntl(FD(evsel, i, thread_index), F_SETFL, O_NONBLOCK); - attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID; + evlist->pollfd[evlist->nr_fds].fd = FD(evsel, i, thread_index); + evlist->pollfd[evlist->nr_fds].events = POLLIN; + evlist->nr_fds++; - if (freq) { - attr->sample_type |= PERF_SAMPLE_PERIOD; - attr->freq = 1; - attr->sample_freq = freq; + mm = xyarray__entry(mmap_array, i, thread_index); + mm->prev = 0; + mm->mask = mmap_pages*page_size - 1; + mm->base = mmap(NULL, (mmap_pages+1)*page_size, + PROT_READ, MAP_SHARED, FD(evsel, i, thread_index), 0); + if (mm->base == MAP_FAILED) + die("failed to mmap with %d (%s)\n", errno, strerror(errno)); } +} + +static void start_counters(struct perf_evlist *evlist) +{ + struct perf_evsel *counter; + int i; - attr->inherit = (cpu < 0) && inherit; - attr->mmap = 1; + list_for_each_entry(counter, &evlist->entries, node) { + struct perf_event_attr *attr = &counter->attr; - for (thread_index = 0; thread_index < threads->nr; thread_index++) { -try_again: - FD(evsel, i, thread_index) = sys_perf_event_open(attr, - threads->map[thread_index], cpu, group_fd, 0); + attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID; + + if (freq) { + attr->sample_type |= PERF_SAMPLE_PERIOD; + attr->freq = 1; + attr->sample_freq = freq; + } - if (FD(evsel, i, thread_index) < 0) { + attr->mmap = 1; +try_again: + if (perf_evsel__open(counter, cpus, threads, group, inherit) < 0) { int err = errno; if (err == EPERM || err == EACCES) @@ -1254,8 +1265,8 @@ try_again: * based cpu-clock-tick sw counter, which * is always available even if no PMU support: */ - if (attr->type == PERF_TYPE_HARDWARE - && attr->config == PERF_COUNT_HW_CPU_CYCLES) { + if (attr->type == PERF_TYPE_HARDWARE && + attr->config == PERF_COUNT_HW_CPU_CYCLES) { if (verbose) warning(" ... trying to fall back to cpu-clock-ticks\n"); @@ -1265,39 +1276,24 @@ try_again: goto try_again; } printf("\n"); - error("sys_perf_event_open() syscall returned with %d (%s). /bin/dmesg may provide additional information.\n", - FD(evsel, i, thread_index), strerror(err)); + error("sys_perf_event_open() syscall returned with %d " + "(%s). /bin/dmesg may provide additional information.\n", + err, strerror(err)); die("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); exit(-1); } - assert(FD(evsel, i, thread_index) >= 0); - fcntl(FD(evsel, i, thread_index), F_SETFL, O_NONBLOCK); - - /* - * First counter acts as the group leader: - */ - if (group && group_fd == -1) - group_fd = FD(evsel, i, thread_index); - - evlist->pollfd[evlist->nr_fds].fd = FD(evsel, i, thread_index); - evlist->pollfd[evlist->nr_fds].events = POLLIN; - evlist->nr_fds++; + } - mm = xyarray__entry(mmap_array, i, thread_index); - mm->prev = 0; - mm->mask = mmap_pages*page_size - 1; - mm->base = mmap(NULL, (mmap_pages+1)*page_size, - PROT_READ, MAP_SHARED, FD(evsel, i, thread_index), 0); - if (mm->base == MAP_FAILED) - die("failed to mmap with %d (%s)\n", errno, strerror(errno)); + for (i = 0; i < cpus->nr; i++) { + list_for_each_entry(counter, &evlist->entries, node) + start_counter(i, evsel_list, counter); } } static int __cmd_top(void) { pthread_t thread; - struct perf_evsel *counter; - int i, ret; + int ret; /* * FIXME: perf_session__new should allow passing a O_MMAP, so that all this * mmap reading, etc is encapsulated in it. Use O_WRONLY for now. @@ -1311,11 +1307,7 @@ static int __cmd_top(void) else event__synthesize_threads(event__process, session); - for (i = 0; i < cpus->nr; i++) { - group_fd = -1; - list_for_each_entry(counter, &evsel_list->entries, node) - start_counter(i, evsel_list, counter); - } + start_counters(evsel_list); /* Wait for a minimal set of events before starting the snapshot */ poll(evsel_list->pollfd, evsel_list->nr_fds, 100); -- cgit v1.2.2 From 70082dd92c4b288bd723a77897e2b555f0e63113 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 12 Jan 2011 17:03:24 -0200 Subject: perf evsel: Introduce mmap support Out of the code in 'perf top'. Record is next in line. Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Tom Zanussi LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-top.c | 71 ++++-------------------------------------------- 1 file changed, 5 insertions(+), 66 deletions(-) (limited to 'tools/perf/builtin-top.c') diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 15d89bede2fb..7d723ad0bfa9 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -1095,43 +1095,12 @@ static void event__process_sample(const event_t *self, } } -struct mmap_data { - void *base; - int mask; - unsigned int prev; -}; - -static int perf_evsel__alloc_mmap_per_thread(struct perf_evsel *evsel, - int ncpus, int nthreads) -{ - evsel->priv = xyarray__new(ncpus, nthreads, sizeof(struct mmap_data)); - return evsel->priv != NULL ? 0 : -ENOMEM; -} - -static void perf_evsel__free_mmap(struct perf_evsel *evsel) -{ - xyarray__delete(evsel->priv); - evsel->priv = NULL; -} - -static unsigned int mmap_read_head(struct mmap_data *md) -{ - struct perf_event_mmap_page *pc = md->base; - int head; - - head = pc->data_head; - rmb(); - - return head; -} - static void perf_session__mmap_read_counter(struct perf_session *self, struct perf_evsel *evsel, int cpu, int thread_idx) { - struct xyarray *mmap_array = evsel->priv; - struct mmap_data *md = xyarray__entry(mmap_array, cpu, thread_idx); - unsigned int head = mmap_read_head(md); + struct perf_mmap *md = xyarray__entry(evsel->mmap, cpu, thread_idx); + unsigned int head = perf_mmap__read_head(md); unsigned int old = md->prev; unsigned char *data = md->base + page_size; struct sample_data sample; @@ -1210,35 +1179,9 @@ static void perf_session__mmap_read(struct perf_session *self) } } -static void start_counter(int i, struct perf_evlist *evlist, - struct perf_evsel *evsel) -{ - struct xyarray *mmap_array = evsel->priv; - struct mmap_data *mm; - int thread_index; - - for (thread_index = 0; thread_index < threads->nr; thread_index++) { - assert(FD(evsel, i, thread_index) >= 0); - fcntl(FD(evsel, i, thread_index), F_SETFL, O_NONBLOCK); - - evlist->pollfd[evlist->nr_fds].fd = FD(evsel, i, thread_index); - evlist->pollfd[evlist->nr_fds].events = POLLIN; - evlist->nr_fds++; - - mm = xyarray__entry(mmap_array, i, thread_index); - mm->prev = 0; - mm->mask = mmap_pages*page_size - 1; - mm->base = mmap(NULL, (mmap_pages+1)*page_size, - PROT_READ, MAP_SHARED, FD(evsel, i, thread_index), 0); - if (mm->base == MAP_FAILED) - die("failed to mmap with %d (%s)\n", errno, strerror(errno)); - } -} - static void start_counters(struct perf_evlist *evlist) { struct perf_evsel *counter; - int i; list_for_each_entry(counter, &evlist->entries, node) { struct perf_event_attr *attr = &counter->attr; @@ -1282,11 +1225,9 @@ try_again: die("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); exit(-1); } - } - for (i = 0; i < cpus->nr; i++) { - list_for_each_entry(counter, &evlist->entries, node) - start_counter(i, evsel_list, counter); + if (perf_evsel__mmap(counter, cpus, threads, mmap_pages, evlist) < 0) + die("failed to mmap with %d (%s)\n", errno, strerror(errno)); } } @@ -1453,7 +1394,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) usage_with_options(top_usage, options); list_for_each_entry(pos, &evsel_list->entries, node) { - if (perf_evsel__alloc_mmap_per_thread(pos, cpus->nr, threads->nr) < 0 || + if (perf_evsel__alloc_mmap(pos, cpus->nr, threads->nr) < 0 || perf_evsel__alloc_fd(pos, cpus->nr, threads->nr) < 0) goto out_free_fd; /* @@ -1485,8 +1426,6 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) status = __cmd_top(); out_free_fd: - list_for_each_entry(pos, &evsel_list->entries, node) - perf_evsel__free_mmap(pos); perf_evlist__delete(evsel_list); return status; -- cgit v1.2.2 From 70db7533caef02350ec8d6852e589491bca3a951 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 12 Jan 2011 22:39:13 -0200 Subject: perf evlist: Move the mmap array from perf_evsel Adopting the new model used in 'perf record', where we don't have a map per thread per cpu, instead we have an mmap per cpu, established on the first fd for that cpu and ask the kernel using the PERF_EVENT_IOC_SET_OUTPUT ioctl to send events for the other fds on that cpu for the one with the mmap. The methods moved from perf_evsel to perf_evlist, but for easing review they were modified in place, in evsel.c, the next patch will move the migrated methods to evlist.c. With this 'perf top' now uses the same mmap model used by 'perf record' and the next patches will make 'perf record' use these new routines, establishing a common codebase for both tools. Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Tom Zanussi LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-top.c | 56 ++++++++++++++++++++++++------------------------ 1 file changed, 28 insertions(+), 28 deletions(-) (limited to 'tools/perf/builtin-top.c') diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 7d723ad0bfa9..df85c1f9417b 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -78,7 +78,7 @@ static struct cpu_map *cpus; static int realtime_prio = 0; static bool group = false; static unsigned int page_size; -static unsigned int mmap_pages = 16; +static unsigned int mmap_pages = 128; static int freq = 1000; /* 1 KHz */ static int delay_secs = 2; @@ -991,8 +991,7 @@ static int symbol_filter(struct map *map, struct symbol *sym) static void event__process_sample(const event_t *self, struct sample_data *sample, - struct perf_session *session, - struct perf_evsel *evsel) + struct perf_session *session) { u64 ip = self->ip.ip; struct sym_entry *syme; @@ -1085,8 +1084,12 @@ static void event__process_sample(const event_t *self, syme = symbol__priv(al.sym); if (!syme->skip) { - syme->count[evsel->idx]++; + struct perf_evsel *evsel; + syme->origin = origin; + evsel = perf_evlist__id2evsel(evsel_list, sample->id); + assert(evsel != NULL); + syme->count[evsel->idx]++; record_precise_ip(syme, evsel->idx, ip); pthread_mutex_lock(&active_symbols_lock); if (list_empty(&syme->node) || !syme->node.next) @@ -1095,11 +1098,9 @@ static void event__process_sample(const event_t *self, } } -static void perf_session__mmap_read_counter(struct perf_session *self, - struct perf_evsel *evsel, - int cpu, int thread_idx) +static void perf_session__mmap_read_cpu(struct perf_session *self, int cpu) { - struct perf_mmap *md = xyarray__entry(evsel->mmap, cpu, thread_idx); + struct perf_mmap *md = &evsel_list->mmap[cpu]; unsigned int head = perf_mmap__read_head(md); unsigned int old = md->prev; unsigned char *data = md->base + page_size; @@ -1153,7 +1154,7 @@ static void perf_session__mmap_read_counter(struct perf_session *self, event__parse_sample(event, self, &sample); if (event->header.type == PERF_RECORD_SAMPLE) - event__process_sample(event, &sample, self, evsel); + event__process_sample(event, &sample, self); else event__process(event, &sample, self); old += size; @@ -1164,19 +1165,10 @@ static void perf_session__mmap_read_counter(struct perf_session *self, static void perf_session__mmap_read(struct perf_session *self) { - struct perf_evsel *counter; - int i, thread_index; - - for (i = 0; i < cpus->nr; i++) { - list_for_each_entry(counter, &evsel_list->entries, node) { - for (thread_index = 0; - thread_index < threads->nr; - thread_index++) { - perf_session__mmap_read_counter(self, - counter, i, thread_index); - } - } - } + int i; + + for (i = 0; i < cpus->nr; i++) + perf_session__mmap_read_cpu(self, i); } static void start_counters(struct perf_evlist *evlist) @@ -1194,6 +1186,11 @@ static void start_counters(struct perf_evlist *evlist) attr->sample_freq = freq; } + if (evlist->nr_entries > 1) { + attr->sample_type |= PERF_SAMPLE_ID; + attr->read_format |= PERF_FORMAT_ID; + } + attr->mmap = 1; try_again: if (perf_evsel__open(counter, cpus, threads, group, inherit) < 0) { @@ -1225,15 +1222,16 @@ try_again: die("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); exit(-1); } - - if (perf_evsel__mmap(counter, cpus, threads, mmap_pages, evlist) < 0) - die("failed to mmap with %d (%s)\n", errno, strerror(errno)); } + + if (perf_evlist__mmap(evlist, cpus, threads, mmap_pages, true) < 0) + die("failed to mmap with %d (%s)\n", errno, strerror(errno)); } static int __cmd_top(void) { pthread_t thread; + struct perf_evsel *first; int ret; /* * FIXME: perf_session__new should allow passing a O_MMAP, so that all this @@ -1249,6 +1247,8 @@ static int __cmd_top(void) event__synthesize_threads(event__process, session); start_counters(evsel_list); + first = list_entry(evsel_list->entries.next, struct perf_evsel, node); + perf_session__set_sample_type(session, first->attr.sample_type); /* Wait for a minimal set of events before starting the snapshot */ poll(evsel_list->pollfd, evsel_list->nr_fds, 100); @@ -1394,8 +1394,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) usage_with_options(top_usage, options); list_for_each_entry(pos, &evsel_list->entries, node) { - if (perf_evsel__alloc_mmap(pos, cpus->nr, threads->nr) < 0 || - perf_evsel__alloc_fd(pos, cpus->nr, threads->nr) < 0) + if (perf_evsel__alloc_fd(pos, cpus->nr, threads->nr) < 0) goto out_free_fd; /* * Fill in the ones not specifically initialized via -c: @@ -1406,7 +1405,8 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) pos->attr.sample_period = default_interval; } - if (perf_evlist__alloc_pollfd(evsel_list, cpus->nr, threads->nr) < 0) + if (perf_evlist__alloc_pollfd(evsel_list, cpus->nr, threads->nr) < 0 || + perf_evlist__alloc_mmap(evsel_list, cpus->nr) < 0) goto out_free_fd; sym_evsel = list_entry(evsel_list->entries.next, struct perf_evsel, node); -- cgit v1.2.2 From 04391debc3e1195222a4dbb162ace6542dd89c1c Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sat, 15 Jan 2011 10:40:59 -0200 Subject: perf evlist: Steal mmap reading routine from 'perf top' Will be used in the upcoming 'perf test' entry for the evlist mmap routines. Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Tom Zanussi LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-top.c | 56 +++--------------------------------------------- 1 file changed, 3 insertions(+), 53 deletions(-) (limited to 'tools/perf/builtin-top.c') diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index df85c1f9417b..58352ad807c7 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -1100,67 +1100,17 @@ static void event__process_sample(const event_t *self, static void perf_session__mmap_read_cpu(struct perf_session *self, int cpu) { - struct perf_mmap *md = &evsel_list->mmap[cpu]; - unsigned int head = perf_mmap__read_head(md); - unsigned int old = md->prev; - unsigned char *data = md->base + page_size; struct sample_data sample; - int diff; - - /* - * If we're further behind than half the buffer, there's a chance - * the writer will bite our tail and mess up the samples under us. - * - * If we somehow ended up ahead of the head, we got messed up. - * - * In either case, truncate and restart at head. - */ - diff = head - old; - if (diff > md->mask / 2 || diff < 0) { - fprintf(stderr, "WARNING: failed to keep up with mmap data.\n"); - - /* - * head points to a known good entry, start there. - */ - old = head; - } - - for (; old != head;) { - event_t *event = (event_t *)&data[old & md->mask]; - - event_t event_copy; - - size_t size = event->header.size; - - /* - * Event straddles the mmap boundary -- header should always - * be inside due to u64 alignment of output. - */ - if ((old & md->mask) + size != ((old + size) & md->mask)) { - unsigned int offset = old; - unsigned int len = min(sizeof(*event), size), cpy; - void *dst = &event_copy; - - do { - cpy = min(md->mask + 1 - (offset & md->mask), len); - memcpy(dst, &data[offset & md->mask], cpy); - offset += cpy; - dst += cpy; - len -= cpy; - } while (len); - - event = &event_copy; - } + event_t *event; + while ((event = perf_evlist__read_on_cpu(evsel_list, cpu)) != NULL) { event__parse_sample(event, self, &sample); + if (event->header.type == PERF_RECORD_SAMPLE) event__process_sample(event, &sample, self); else event__process(event, &sample, self); - old += size; } - - md->prev = old; } static void perf_session__mmap_read(struct perf_session *self) -- cgit v1.2.2 From b0e8572f3b29c0760b66ba5627a6d5426c88c97d Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sun, 16 Jan 2011 17:39:15 -0200 Subject: perf top: Add native_safe_halt to skip symbols Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Tom Zanussi LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-top.c | 1 + 1 file changed, 1 insertion(+) (limited to 'tools/perf/builtin-top.c') diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 58352ad807c7..31fbaf38d9c1 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -933,6 +933,7 @@ repeat: /* Tag samples to be skipped. */ static const char *skip_symbols[] = { "default_idle", + "native_safe_halt", "cpu_idle", "enter_idle", "exit_idle", -- cgit v1.2.2 From fd78260b5376173faeb17127bd63b3c99a8e8bfb Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 18 Jan 2011 15:15:24 -0200 Subject: perf threads: Move thread_map to separate file To untangle it from struct thread handling, that is tied to symbols, etc. Right now in the python bindings I'm working on I need just a subset of the util/ files, untangling it allows me to do that. Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Tom Zanussi LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-top.c | 1 + 1 file changed, 1 insertion(+) (limited to 'tools/perf/builtin-top.c') diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 31fbaf38d9c1..d0b16d905405 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -26,6 +26,7 @@ #include "util/session.h" #include "util/symbol.h" #include "util/thread.h" +#include "util/thread_map.h" #include "util/util.h" #include #include "util/parse-options.h" -- cgit v1.2.2 From d0dd74e853a0a6f37e8061d6d50be41c7034c54c Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 21 Jan 2011 13:46:41 -0200 Subject: perf tools: Move event__parse_sample to evsel.c To avoid linking more stuff in the python binding I'm working on, future csets will make the sample type be taken from the evsel itself, but for that we need to first have one file per cpu and per sample_type, not a single perf.data file. Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Tom Zanussi LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-top.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools/perf/builtin-top.c') diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index d0b16d905405..ce2e50c891c7 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -1106,7 +1106,7 @@ static void perf_session__mmap_read_cpu(struct perf_session *self, int cpu) event_t *event; while ((event = perf_evlist__read_on_cpu(evsel_list, cpu)) != NULL) { - event__parse_sample(event, self, &sample); + perf_session__parse_sample(self, event, &sample); if (event->header.type == PERF_RECORD_SAMPLE) event__process_sample(event, &sample, self); -- cgit v1.2.2 From 93fc64f14472ae24fd640bf3834a178f59142842 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sat, 29 Jan 2011 12:08:00 -0200 Subject: perf top: Switch to non overwrite mode Just like 'perf record'. Warn the user when PERF_RECORD_LOST events happen. Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Tom Zanussi LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-top.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'tools/perf/builtin-top.c') diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index ce2e50c891c7..7f92ab7696f7 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -464,7 +464,7 @@ static void rb_insert_active_sym(struct rb_root *tree, struct sym_entry *se) rb_insert_color(&se->rb_node, tree); } -static void print_sym_table(void) +static void print_sym_table(struct perf_session *session) { int printed = 0, j; struct perf_evsel *counter; @@ -513,7 +513,6 @@ static void print_sym_table(void) puts(CONSOLE_CLEAR); - printf("%-*.*s\n", win_width, win_width, graph_dotted_line); if (!perf_guest) { printf(" PerfTop:%8.0f irqs/sec kernel:%4.1f%%" " exact: %4.1f%% [", @@ -578,6 +577,12 @@ static void print_sym_table(void) printf("%-*.*s\n", win_width, win_width, graph_dotted_line); + if (session->hists.stats.total_lost != 0) { + color_fprintf(stdout, PERF_COLOR_RED, "WARNING:"); + printf(" LOST %" PRIu64 " events, Check IO/CPU overload\n", + session->hists.stats.total_lost); + } + if (sym_filter_entry) { show_details(sym_filter_entry); return; @@ -919,7 +924,7 @@ repeat: getc(stdin); do { - print_sym_table(); + print_sym_table(session); } while (!poll(&stdin_poll, 1, delay_msecs) == 1); c = getc(stdin); @@ -1176,7 +1181,7 @@ try_again: } } - if (perf_evlist__mmap(evlist, cpus, threads, mmap_pages, true) < 0) + if (perf_evlist__mmap(evlist, cpus, threads, mmap_pages, false) < 0) die("failed to mmap with %d (%s)\n", errno, strerror(errno)); } -- cgit v1.2.2 From 8d50e5b4171a69cf48ca94a1e7c14033d0b4771d Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sat, 29 Jan 2011 13:02:00 -0200 Subject: perf tools: Rename 'struct sample_data' to 'struct perf_sample' Making the namespace more uniform. Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Tom Zanussi LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-top.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'tools/perf/builtin-top.c') diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 7f92ab7696f7..d923127b41b6 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -997,7 +997,7 @@ static int symbol_filter(struct map *map, struct symbol *sym) } static void event__process_sample(const event_t *self, - struct sample_data *sample, + struct perf_sample *sample, struct perf_session *session) { u64 ip = self->ip.ip; @@ -1107,7 +1107,7 @@ static void event__process_sample(const event_t *self, static void perf_session__mmap_read_cpu(struct perf_session *self, int cpu) { - struct sample_data sample; + struct perf_sample sample; event_t *event; while ((event = perf_evlist__read_on_cpu(evsel_list, cpu)) != NULL) { -- cgit v1.2.2 From 8115d60c323dd9931b95221c0a392aeddc1d6ef3 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sat, 29 Jan 2011 14:01:45 -0200 Subject: perf tools: Kill event_t typedef, use 'union perf_event' instead And move the event_t methods to the perf_event__ too. No code changes, just namespace consistency. Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Tom Zanussi LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-top.c | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) (limited to 'tools/perf/builtin-top.c') diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index d923127b41b6..2f4d1f244be1 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -401,7 +401,7 @@ static void show_details(struct sym_entry *syme) } /* - * Symbols will be added here in event__process_sample and will get out + * Symbols will be added here in perf_event__process_sample and will get out * after decayed. */ static LIST_HEAD(active_symbols); @@ -996,15 +996,15 @@ static int symbol_filter(struct map *map, struct symbol *sym) return 0; } -static void event__process_sample(const event_t *self, - struct perf_sample *sample, - struct perf_session *session) +static void perf_event__process_sample(const union perf_event *event, + struct perf_sample *sample, + struct perf_session *session) { - u64 ip = self->ip.ip; + u64 ip = event->ip.ip; struct sym_entry *syme; struct addr_location al; struct machine *machine; - u8 origin = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; + u8 origin = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; ++samples; @@ -1023,7 +1023,7 @@ static void event__process_sample(const event_t *self, break; case PERF_RECORD_MISC_GUEST_KERNEL: ++guest_kernel_samples; - machine = perf_session__find_machine(session, self->ip.pid); + machine = perf_session__find_machine(session, event->ip.pid); break; case PERF_RECORD_MISC_GUEST_USER: ++guest_us_samples; @@ -1038,15 +1038,15 @@ static void event__process_sample(const event_t *self, if (!machine && perf_guest) { pr_err("Can't find guest [%d]'s kernel information\n", - self->ip.pid); + event->ip.pid); return; } - if (self->header.misc & PERF_RECORD_MISC_EXACT_IP) + if (event->header.misc & PERF_RECORD_MISC_EXACT_IP) exact_samples++; - if (event__preprocess_sample(self, session, &al, sample, - symbol_filter) < 0 || + if (perf_event__preprocess_sample(event, session, &al, sample, + symbol_filter) < 0 || al.filtered) return; @@ -1108,15 +1108,15 @@ static void event__process_sample(const event_t *self, static void perf_session__mmap_read_cpu(struct perf_session *self, int cpu) { struct perf_sample sample; - event_t *event; + union perf_event *event; while ((event = perf_evlist__read_on_cpu(evsel_list, cpu)) != NULL) { perf_session__parse_sample(self, event, &sample); if (event->header.type == PERF_RECORD_SAMPLE) - event__process_sample(event, &sample, self); + perf_event__process_sample(event, &sample, self); else - event__process(event, &sample, self); + perf_event__process(event, &sample, self); } } @@ -1199,9 +1199,10 @@ static int __cmd_top(void) return -ENOMEM; if (target_tid != -1) - event__synthesize_thread(target_tid, event__process, session); + perf_event__synthesize_thread(target_tid, perf_event__process, + session); else - event__synthesize_threads(event__process, session); + perf_event__synthesize_threads(perf_event__process, session); start_counters(evsel_list); first = list_entry(evsel_list->entries.next, struct perf_evsel, node); -- cgit v1.2.2 From 7e2ed097538c57ff5268e9a6bced7c0b885809c8 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sun, 30 Jan 2011 11:59:43 -0200 Subject: perf evlist: Store pointer to the cpu and thread maps So that we don't have to pass it around to the several methods that needs it, simplifying usage. There is one case where we don't have the thread/cpu map in advance, which is in the parsing routines used by top, stat, record, that we have to wait till all options are parsed to know if a cpu or thread list was passed to then create those maps. For that case consolidate the cpu and thread map creation via perf_evlist__create_maps() out of the code in top and record, while also providing a perf_evlist__set_maps() for cases where multiple evlists share maps or for when maps that represent CPU sockets, for instance, get crafted out of topology information or subsets of threads in a particular application are to be monitored, providing more granularity in specifying which cpus and threads to monitor. Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Tom Zanussi LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-top.c | 47 +++++++++++++++++++---------------------------- 1 file changed, 19 insertions(+), 28 deletions(-) (limited to 'tools/perf/builtin-top.c') diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 2f4d1f244be1..599036b06730 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -73,9 +73,7 @@ static int print_entries; static int target_pid = -1; static int target_tid = -1; -static struct thread_map *threads; static bool inherit = false; -static struct cpu_map *cpus; static int realtime_prio = 0; static bool group = false; static unsigned int page_size; @@ -567,12 +565,13 @@ static void print_sym_table(struct perf_session *session) printf(" (all"); if (cpu_list) - printf(", CPU%s: %s)\n", cpus->nr > 1 ? "s" : "", cpu_list); + printf(", CPU%s: %s)\n", evsel_list->cpus->nr > 1 ? "s" : "", cpu_list); else { if (target_tid != -1) printf(")\n"); else - printf(", %d CPU%s)\n", cpus->nr, cpus->nr > 1 ? "s" : ""); + printf(", %d CPU%s)\n", evsel_list->cpus->nr, + evsel_list->cpus->nr > 1 ? "s" : ""); } printf("%-*.*s\n", win_width, win_width, graph_dotted_line); @@ -1124,7 +1123,7 @@ static void perf_session__mmap_read(struct perf_session *self) { int i; - for (i = 0; i < cpus->nr; i++) + for (i = 0; i < evsel_list->cpus->nr; i++) perf_session__mmap_read_cpu(self, i); } @@ -1150,7 +1149,8 @@ static void start_counters(struct perf_evlist *evlist) attr->mmap = 1; try_again: - if (perf_evsel__open(counter, cpus, threads, group, inherit) < 0) { + if (perf_evsel__open(counter, evsel_list->cpus, + evsel_list->threads, group, inherit) < 0) { int err = errno; if (err == EPERM || err == EACCES) @@ -1181,7 +1181,7 @@ try_again: } } - if (perf_evlist__mmap(evlist, cpus, threads, mmap_pages, false) < 0) + if (perf_evlist__mmap(evlist, mmap_pages, false) < 0) die("failed to mmap with %d (%s)\n", errno, strerror(errno)); } @@ -1296,7 +1296,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) struct perf_evsel *pos; int status = -ENOMEM; - evsel_list = perf_evlist__new(); + evsel_list = perf_evlist__new(NULL, NULL); if (evsel_list == NULL) return -ENOMEM; @@ -1306,15 +1306,6 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) if (argc) usage_with_options(top_usage, options); - if (target_pid != -1) - target_tid = target_pid; - - threads = thread_map__new(target_pid, target_tid); - if (threads == NULL) { - pr_err("Problems finding threads of monitor\n"); - usage_with_options(top_usage, options); - } - /* CPU and PID are mutually exclusive */ if (target_tid > 0 && cpu_list) { printf("WARNING: PID switch overriding CPU\n"); @@ -1322,6 +1313,13 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) cpu_list = NULL; } + if (target_pid != -1) + target_tid = target_pid; + + if (perf_evlist__create_maps(evsel_list, target_pid, + target_tid, cpu_list) < 0) + usage_with_options(top_usage, options); + if (!evsel_list->nr_entries && perf_evlist__add_default(evsel_list) < 0) { pr_err("Not enough memory for event selector list\n"); @@ -1343,16 +1341,9 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) exit(EXIT_FAILURE); } - if (target_tid != -1) - cpus = cpu_map__dummy_new(); - else - cpus = cpu_map__new(cpu_list); - - if (cpus == NULL) - usage_with_options(top_usage, options); - list_for_each_entry(pos, &evsel_list->entries, node) { - if (perf_evsel__alloc_fd(pos, cpus->nr, threads->nr) < 0) + if (perf_evsel__alloc_fd(pos, evsel_list->cpus->nr, + evsel_list->threads->nr) < 0) goto out_free_fd; /* * Fill in the ones not specifically initialized via -c: @@ -1363,8 +1354,8 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) pos->attr.sample_period = default_interval; } - if (perf_evlist__alloc_pollfd(evsel_list, cpus->nr, threads->nr) < 0 || - perf_evlist__alloc_mmap(evsel_list, cpus->nr) < 0) + if (perf_evlist__alloc_pollfd(evsel_list) < 0 || + perf_evlist__alloc_mmap(evsel_list) < 0) goto out_free_fd; sym_evsel = list_entry(evsel_list->entries.next, struct perf_evsel, node); -- cgit v1.2.2 From 8c3e10eb1968877d6a1957b7e790c6ce01bd56fc Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 31 Jan 2011 14:50:39 -0200 Subject: perf top: Move display agnostic routines to util/top.[ch] Paving the way for a slang browser a la 'perf report --tui'. Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Tom Zanussi LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-top.c | 482 ++++++++++++++--------------------------------- 1 file changed, 137 insertions(+), 345 deletions(-) (limited to 'tools/perf/builtin-top.c') diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 599036b06730..3c9ba943aa48 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -27,6 +27,7 @@ #include "util/symbol.h" #include "util/thread.h" #include "util/thread_map.h" +#include "util/top.h" #include "util/util.h" #include #include "util/parse-options.h" @@ -47,7 +48,6 @@ #include #include #include -#include #include #include @@ -62,75 +62,35 @@ #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) -struct perf_evlist *evsel_list; +static struct perf_top top = { + .count_filter = 5, + .delay_secs = 2, + .display_weighted = -1, + .target_pid = -1, + .target_tid = -1, + .active_symbols = LIST_HEAD_INIT(top.active_symbols), + .active_symbols_lock = PTHREAD_MUTEX_INITIALIZER, + .freq = 1000, /* 1 KHz */ +}; static bool system_wide = false; static int default_interval = 0; -static int count_filter = 5; -static int print_entries; - -static int target_pid = -1; -static int target_tid = -1; static bool inherit = false; static int realtime_prio = 0; static bool group = false; static unsigned int page_size; static unsigned int mmap_pages = 128; -static int freq = 1000; /* 1 KHz */ -static int delay_secs = 2; -static bool zero = false; static bool dump_symtab = false; -static bool hide_kernel_symbols = false; -static bool hide_user_symbols = false; static struct winsize winsize; -/* - * Source - */ - -struct source_line { - u64 eip; - unsigned long count[MAX_COUNTERS]; - char *line; - struct source_line *next; -}; - static const char *sym_filter = NULL; struct sym_entry *sym_filter_entry = NULL; struct sym_entry *sym_filter_entry_sched = NULL; static int sym_pcnt_filter = 5; -static int sym_counter = 0; -static struct perf_evsel *sym_evsel = NULL; -static int display_weighted = -1; -static const char *cpu_list; - -/* - * Symbols - */ - -struct sym_entry_source { - struct source_line *source; - struct source_line *lines; - struct source_line **lines_tail; - pthread_mutex_t lock; -}; - -struct sym_entry { - struct rb_node rb_node; - struct list_head node; - unsigned long snap_count; - double weight; - int skip; - u16 name_len; - u8 origin; - struct map *map; - struct sym_entry_source *src; - unsigned long count[0]; -}; /* * Source functions @@ -165,10 +125,10 @@ void get_term_dimensions(struct winsize *ws) static void update_print_entries(struct winsize *ws) { - print_entries = ws->ws_row; + top.print_entries = ws->ws_row; - if (print_entries > 9) - print_entries -= 9; + if (top.print_entries > 9) + top.print_entries -= 9; } static void sig_winch_handler(int sig __used) @@ -269,7 +229,7 @@ static void __zero_source_counters(struct sym_entry *syme) line = syme->src->lines; while (line) { - for (i = 0; i < evsel_list->nr_entries; i++) + for (i = 0; i < top.evlist->nr_entries; i++) line->count[i] = 0; line = line->next; } @@ -331,9 +291,9 @@ static void show_lines(struct source_line *queue, int count, int total) line = queue; for (i = 0; i < count; i++) { - float pcnt = 100.0*(float)line->count[sym_counter]/(float)total; + float pcnt = 100.0*(float)line->count[top.sym_counter]/(float)total; - printf("%8li %4.1f%%\t%s\n", line->count[sym_counter], pcnt, line->line); + printf("%8li %4.1f%%\t%s\n", line->count[top.sym_counter], pcnt, line->line); line = line->next; } } @@ -358,13 +318,13 @@ static void show_details(struct sym_entry *syme) return; symbol = sym_entry__symbol(syme); - printf("Showing %s for %s\n", event_name(sym_evsel), symbol->name); + printf("Showing %s for %s\n", event_name(top.sym_evsel), symbol->name); printf(" Events Pcnt (>=%d%%)\n", sym_pcnt_filter); pthread_mutex_lock(&syme->src->lock); line = syme->src->source; while (line) { - total += line->count[sym_counter]; + total += line->count[top.sym_counter]; line = line->next; } @@ -376,10 +336,10 @@ static void show_details(struct sym_entry *syme) line_queue = line; line_queue_count++; - if (line->count[sym_counter]) - pcnt = 100.0 * line->count[sym_counter] / (float)total; + if (line->count[top.sym_counter]) + pcnt = 100.0 * line->count[top.sym_counter] / (float)total; if (pcnt >= (float)sym_pcnt_filter) { - if (displayed <= print_entries) + if (displayed <= top.print_entries) show_lines(line_queue, line_queue_count, total); else more++; displayed += line_queue_count; @@ -390,7 +350,7 @@ static void show_details(struct sym_entry *syme) line_queue_count--; } - line->count[sym_counter] = zero ? 0 : line->count[sym_counter] * 7 / 8; + line->count[top.sym_counter] = top.zero ? 0 : line->count[top.sym_counter] * 7 / 8; line = line->next; } pthread_mutex_unlock(&syme->src->lock); @@ -398,181 +358,30 @@ static void show_details(struct sym_entry *syme) printf("%d lines not displayed, maybe increase display entries [e]\n", more); } -/* - * Symbols will be added here in perf_event__process_sample and will get out - * after decayed. - */ -static LIST_HEAD(active_symbols); -static pthread_mutex_t active_symbols_lock = PTHREAD_MUTEX_INITIALIZER; - -/* - * Ordering weight: count-1 * count-2 * ... / count-n - */ -static double sym_weight(const struct sym_entry *sym) -{ - double weight = sym->snap_count; - int counter; - - if (!display_weighted) - return weight; - - for (counter = 1; counter < evsel_list->nr_entries - 1; counter++) - weight *= sym->count[counter]; - - weight /= (sym->count[counter] + 1); - - return weight; -} - -static long samples; -static long kernel_samples, us_samples; -static long exact_samples; -static long guest_us_samples, guest_kernel_samples; static const char CONSOLE_CLEAR[] = ""; static void __list_insert_active_sym(struct sym_entry *syme) { - list_add(&syme->node, &active_symbols); -} - -static void list_remove_active_sym(struct sym_entry *syme) -{ - pthread_mutex_lock(&active_symbols_lock); - list_del_init(&syme->node); - pthread_mutex_unlock(&active_symbols_lock); -} - -static void rb_insert_active_sym(struct rb_root *tree, struct sym_entry *se) -{ - struct rb_node **p = &tree->rb_node; - struct rb_node *parent = NULL; - struct sym_entry *iter; - - while (*p != NULL) { - parent = *p; - iter = rb_entry(parent, struct sym_entry, rb_node); - - if (se->weight > iter->weight) - p = &(*p)->rb_left; - else - p = &(*p)->rb_right; - } - - rb_link_node(&se->rb_node, parent, p); - rb_insert_color(&se->rb_node, tree); + list_add(&syme->node, &top.active_symbols); } static void print_sym_table(struct perf_session *session) { - int printed = 0, j; - struct perf_evsel *counter; - int snap = !display_weighted ? sym_counter : 0; - float samples_per_sec = samples/delay_secs; - float ksamples_per_sec = kernel_samples/delay_secs; - float us_samples_per_sec = (us_samples)/delay_secs; - float guest_kernel_samples_per_sec = (guest_kernel_samples)/delay_secs; - float guest_us_samples_per_sec = (guest_us_samples)/delay_secs; - float esamples_percent = (100.0*exact_samples)/samples; - float sum_ksamples = 0.0; - struct sym_entry *syme, *n; - struct rb_root tmp = RB_ROOT; + char bf[160]; + int printed = 0; struct rb_node *nd; - int sym_width = 0, dso_width = 0, dso_short_width = 0; + struct sym_entry *syme; + struct rb_root tmp = RB_ROOT; const int win_width = winsize.ws_col - 1; - - samples = us_samples = kernel_samples = exact_samples = 0; - guest_kernel_samples = guest_us_samples = 0; - - /* Sort the active symbols */ - pthread_mutex_lock(&active_symbols_lock); - syme = list_entry(active_symbols.next, struct sym_entry, node); - pthread_mutex_unlock(&active_symbols_lock); - - list_for_each_entry_safe_from(syme, n, &active_symbols, node) { - syme->snap_count = syme->count[snap]; - if (syme->snap_count != 0) { - - if ((hide_user_symbols && - syme->origin == PERF_RECORD_MISC_USER) || - (hide_kernel_symbols && - syme->origin == PERF_RECORD_MISC_KERNEL)) { - list_remove_active_sym(syme); - continue; - } - syme->weight = sym_weight(syme); - rb_insert_active_sym(&tmp, syme); - sum_ksamples += syme->snap_count; - - for (j = 0; j < evsel_list->nr_entries; j++) - syme->count[j] = zero ? 0 : syme->count[j] * 7 / 8; - } else - list_remove_active_sym(syme); - } + int sym_width, dso_width, dso_short_width; + float sum_ksamples = perf_top__decay_samples(&top, &tmp); puts(CONSOLE_CLEAR); - if (!perf_guest) { - printf(" PerfTop:%8.0f irqs/sec kernel:%4.1f%%" - " exact: %4.1f%% [", - samples_per_sec, - 100.0 - (100.0 * ((samples_per_sec - ksamples_per_sec) / - samples_per_sec)), - esamples_percent); - } else { - printf(" PerfTop:%8.0f irqs/sec kernel:%4.1f%% us:%4.1f%%" - " guest kernel:%4.1f%% guest us:%4.1f%%" - " exact: %4.1f%% [", - samples_per_sec, - 100.0 - (100.0 * ((samples_per_sec-ksamples_per_sec) / - samples_per_sec)), - 100.0 - (100.0 * ((samples_per_sec-us_samples_per_sec) / - samples_per_sec)), - 100.0 - (100.0 * ((samples_per_sec - - guest_kernel_samples_per_sec) / - samples_per_sec)), - 100.0 - (100.0 * ((samples_per_sec - - guest_us_samples_per_sec) / - samples_per_sec)), - esamples_percent); - } + perf_top__header_snprintf(&top, bf, sizeof(bf)); + printf("%s\n", bf); - if (evsel_list->nr_entries == 1 || !display_weighted) { - struct perf_evsel *first; - first = list_entry(evsel_list->entries.next, struct perf_evsel, node); - printf("%" PRIu64, (uint64_t)first->attr.sample_period); - if (freq) - printf("Hz "); - else - printf(" "); - } - - if (!display_weighted) - printf("%s", event_name(sym_evsel)); - else list_for_each_entry(counter, &evsel_list->entries, node) { - if (counter->idx) - printf("/"); - - printf("%s", event_name(counter)); - } - - printf( "], "); - - if (target_pid != -1) - printf(" (target_pid: %d", target_pid); - else if (target_tid != -1) - printf(" (target_tid: %d", target_tid); - else - printf(" (all"); - - if (cpu_list) - printf(", CPU%s: %s)\n", evsel_list->cpus->nr > 1 ? "s" : "", cpu_list); - else { - if (target_tid != -1) - printf(")\n"); - else - printf(", %d CPU%s)\n", evsel_list->cpus->nr, - evsel_list->cpus->nr > 1 ? "s" : ""); - } + perf_top__reset_sample_counters(&top); printf("%-*.*s\n", win_width, win_width, graph_dotted_line); @@ -587,26 +396,8 @@ static void print_sym_table(struct perf_session *session) return; } - /* - * Find the longest symbol name that will be displayed - */ - for (nd = rb_first(&tmp); nd; nd = rb_next(nd)) { - syme = rb_entry(nd, struct sym_entry, rb_node); - if (++printed > print_entries || - (int)syme->snap_count < count_filter) - continue; - - if (syme->map->dso->long_name_len > dso_width) - dso_width = syme->map->dso->long_name_len; - - if (syme->map->dso->short_name_len > dso_short_width) - dso_short_width = syme->map->dso->short_name_len; - - if (syme->name_len > sym_width) - sym_width = syme->name_len; - } - - printed = 0; + perf_top__find_widths(&top, &tmp, &dso_width, &dso_short_width, + &sym_width); if (sym_width + dso_width > winsize.ws_col - 29) { dso_width = dso_short_width; @@ -614,7 +405,7 @@ static void print_sym_table(struct perf_session *session) sym_width = winsize.ws_col - dso_width - 29; } putchar('\n'); - if (evsel_list->nr_entries == 1) + if (top.evlist->nr_entries == 1) printf(" samples pcnt"); else printf(" weight samples pcnt"); @@ -623,7 +414,7 @@ static void print_sym_table(struct perf_session *session) printf(" RIP "); printf(" %-*.*s DSO\n", sym_width, sym_width, "function"); printf(" %s _______ _____", - evsel_list->nr_entries == 1 ? " " : "______"); + top.evlist->nr_entries == 1 ? " " : "______"); if (verbose) printf(" ________________"); printf(" %-*.*s", sym_width, sym_width, graph_line); @@ -636,13 +427,14 @@ static void print_sym_table(struct perf_session *session) syme = rb_entry(nd, struct sym_entry, rb_node); sym = sym_entry__symbol(syme); - if (++printed > print_entries || (int)syme->snap_count < count_filter) + if (++printed > top.print_entries || + (int)syme->snap_count < top.count_filter) continue; pcnt = 100.0 - (100.0 * ((sum_ksamples - syme->snap_count) / sum_ksamples)); - if (evsel_list->nr_entries == 1 || !display_weighted) + if (top.evlist->nr_entries == 1 || !top.display_weighted) printf("%20.2f ", syme->weight); else printf("%9.1f %10ld ", syme->weight, syme->snap_count); @@ -715,11 +507,11 @@ static void prompt_symbol(struct sym_entry **target, const char *msg) if (p) *p = 0; - pthread_mutex_lock(&active_symbols_lock); - syme = list_entry(active_symbols.next, struct sym_entry, node); - pthread_mutex_unlock(&active_symbols_lock); + pthread_mutex_lock(&top.active_symbols_lock); + syme = list_entry(top.active_symbols.next, struct sym_entry, node); + pthread_mutex_unlock(&top.active_symbols_lock); - list_for_each_entry_safe_from(syme, n, &active_symbols, node) { + list_for_each_entry_safe_from(syme, n, &top.active_symbols, node) { struct symbol *sym = sym_entry__symbol(syme); if (!strcmp(buf, sym->name)) { @@ -749,28 +541,28 @@ static void print_mapped_keys(void) } fprintf(stdout, "\nMapped keys:\n"); - fprintf(stdout, "\t[d] display refresh delay. \t(%d)\n", delay_secs); - fprintf(stdout, "\t[e] display entries (lines). \t(%d)\n", print_entries); + fprintf(stdout, "\t[d] display refresh delay. \t(%d)\n", top.delay_secs); + fprintf(stdout, "\t[e] display entries (lines). \t(%d)\n", top.print_entries); - if (evsel_list->nr_entries > 1) - fprintf(stdout, "\t[E] active event counter. \t(%s)\n", event_name(sym_evsel)); + if (top.evlist->nr_entries > 1) + fprintf(stdout, "\t[E] active event counter. \t(%s)\n", event_name(top.sym_evsel)); - fprintf(stdout, "\t[f] profile display filter (count). \t(%d)\n", count_filter); + fprintf(stdout, "\t[f] profile display filter (count). \t(%d)\n", top.count_filter); fprintf(stdout, "\t[F] annotate display filter (percent). \t(%d%%)\n", sym_pcnt_filter); fprintf(stdout, "\t[s] annotate symbol. \t(%s)\n", name?: "NULL"); fprintf(stdout, "\t[S] stop annotation.\n"); - if (evsel_list->nr_entries > 1) - fprintf(stdout, "\t[w] toggle display weighted/count[E]r. \t(%d)\n", display_weighted ? 1 : 0); + if (top.evlist->nr_entries > 1) + fprintf(stdout, "\t[w] toggle display weighted/count[E]r. \t(%d)\n", top.display_weighted ? 1 : 0); fprintf(stdout, "\t[K] hide kernel_symbols symbols. \t(%s)\n", - hide_kernel_symbols ? "yes" : "no"); + top.hide_kernel_symbols ? "yes" : "no"); fprintf(stdout, "\t[U] hide user symbols. \t(%s)\n", - hide_user_symbols ? "yes" : "no"); - fprintf(stdout, "\t[z] toggle sample zeroing. \t(%d)\n", zero ? 1 : 0); + top.hide_user_symbols ? "yes" : "no"); + fprintf(stdout, "\t[z] toggle sample zeroing. \t(%d)\n", top.zero ? 1 : 0); fprintf(stdout, "\t[qQ] quit.\n"); } @@ -791,7 +583,7 @@ static int key_mapped(int c) return 1; case 'E': case 'w': - return evsel_list->nr_entries > 1 ? 1 : 0; + return top.evlist->nr_entries > 1 ? 1 : 0; default: break; } @@ -826,47 +618,47 @@ static void handle_keypress(struct perf_session *session, int c) switch (c) { case 'd': - prompt_integer(&delay_secs, "Enter display delay"); - if (delay_secs < 1) - delay_secs = 1; + prompt_integer(&top.delay_secs, "Enter display delay"); + if (top.delay_secs < 1) + top.delay_secs = 1; break; case 'e': - prompt_integer(&print_entries, "Enter display entries (lines)"); - if (print_entries == 0) { + prompt_integer(&top.print_entries, "Enter display entries (lines)"); + if (top.print_entries == 0) { sig_winch_handler(SIGWINCH); signal(SIGWINCH, sig_winch_handler); } else signal(SIGWINCH, SIG_DFL); break; case 'E': - if (evsel_list->nr_entries > 1) { + if (top.evlist->nr_entries > 1) { fprintf(stderr, "\nAvailable events:"); - list_for_each_entry(sym_evsel, &evsel_list->entries, node) - fprintf(stderr, "\n\t%d %s", sym_evsel->idx, event_name(sym_evsel)); + list_for_each_entry(top.sym_evsel, &top.evlist->entries, node) + fprintf(stderr, "\n\t%d %s", top.sym_evsel->idx, event_name(top.sym_evsel)); - prompt_integer(&sym_counter, "Enter details event counter"); + prompt_integer(&top.sym_counter, "Enter details event counter"); - if (sym_counter >= evsel_list->nr_entries) { - sym_evsel = list_entry(evsel_list->entries.next, struct perf_evsel, node); - sym_counter = 0; - fprintf(stderr, "Sorry, no such event, using %s.\n", event_name(sym_evsel)); + if (top.sym_counter >= top.evlist->nr_entries) { + top.sym_evsel = list_entry(top.evlist->entries.next, struct perf_evsel, node); + top.sym_counter = 0; + fprintf(stderr, "Sorry, no such event, using %s.\n", event_name(top.sym_evsel)); sleep(1); break; } - list_for_each_entry(sym_evsel, &evsel_list->entries, node) - if (sym_evsel->idx == sym_counter) + list_for_each_entry(top.sym_evsel, &top.evlist->entries, node) + if (top.sym_evsel->idx == top.sym_counter) break; - } else sym_counter = 0; + } else top.sym_counter = 0; break; case 'f': - prompt_integer(&count_filter, "Enter display event count filter"); + prompt_integer(&top.count_filter, "Enter display event count filter"); break; case 'F': prompt_percent(&sym_pcnt_filter, "Enter details display event filter (percent)"); break; case 'K': - hide_kernel_symbols = !hide_kernel_symbols; + top.hide_kernel_symbols = !top.hide_kernel_symbols; break; case 'q': case 'Q': @@ -890,13 +682,13 @@ static void handle_keypress(struct perf_session *session, int c) } break; case 'U': - hide_user_symbols = !hide_user_symbols; + top.hide_user_symbols = !top.hide_user_symbols; break; case 'w': - display_weighted = ~display_weighted; + top.display_weighted = ~top.display_weighted; break; case 'z': - zero = !zero; + top.zero = !top.zero; break; default: break; @@ -917,7 +709,7 @@ static void *display_thread(void *arg __used) tc.c_cc[VTIME] = 0; repeat: - delay_msecs = delay_secs * 1000; + delay_msecs = top.delay_secs * 1000; tcsetattr(0, TCSANOW, &tc); /* trash return*/ getc(stdin); @@ -1005,27 +797,27 @@ static void perf_event__process_sample(const union perf_event *event, struct machine *machine; u8 origin = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; - ++samples; + ++top.samples; switch (origin) { case PERF_RECORD_MISC_USER: - ++us_samples; - if (hide_user_symbols) + ++top.us_samples; + if (top.hide_user_symbols) return; machine = perf_session__find_host_machine(session); break; case PERF_RECORD_MISC_KERNEL: - ++kernel_samples; - if (hide_kernel_symbols) + ++top.kernel_samples; + if (top.hide_kernel_symbols) return; machine = perf_session__find_host_machine(session); break; case PERF_RECORD_MISC_GUEST_KERNEL: - ++guest_kernel_samples; + ++top.guest_kernel_samples; machine = perf_session__find_machine(session, event->ip.pid); break; case PERF_RECORD_MISC_GUEST_USER: - ++guest_us_samples; + ++top.guest_us_samples; /* * TODO: we don't process guest user from host side * except simple counting. @@ -1042,7 +834,7 @@ static void perf_event__process_sample(const union perf_event *event, } if (event->header.misc & PERF_RECORD_MISC_EXACT_IP) - exact_samples++; + top.exact_samples++; if (perf_event__preprocess_sample(event, session, &al, sample, symbol_filter) < 0 || @@ -1093,14 +885,14 @@ static void perf_event__process_sample(const union perf_event *event, struct perf_evsel *evsel; syme->origin = origin; - evsel = perf_evlist__id2evsel(evsel_list, sample->id); + evsel = perf_evlist__id2evsel(top.evlist, sample->id); assert(evsel != NULL); syme->count[evsel->idx]++; record_precise_ip(syme, evsel->idx, ip); - pthread_mutex_lock(&active_symbols_lock); + pthread_mutex_lock(&top.active_symbols_lock); if (list_empty(&syme->node) || !syme->node.next) __list_insert_active_sym(syme); - pthread_mutex_unlock(&active_symbols_lock); + pthread_mutex_unlock(&top.active_symbols_lock); } } @@ -1109,7 +901,7 @@ static void perf_session__mmap_read_cpu(struct perf_session *self, int cpu) struct perf_sample sample; union perf_event *event; - while ((event = perf_evlist__read_on_cpu(evsel_list, cpu)) != NULL) { + while ((event = perf_evlist__read_on_cpu(top.evlist, cpu)) != NULL) { perf_session__parse_sample(self, event, &sample); if (event->header.type == PERF_RECORD_SAMPLE) @@ -1123,7 +915,7 @@ static void perf_session__mmap_read(struct perf_session *self) { int i; - for (i = 0; i < evsel_list->cpus->nr; i++) + for (i = 0; i < top.evlist->cpus->nr; i++) perf_session__mmap_read_cpu(self, i); } @@ -1136,10 +928,10 @@ static void start_counters(struct perf_evlist *evlist) attr->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID; - if (freq) { + if (top.freq) { attr->sample_type |= PERF_SAMPLE_PERIOD; attr->freq = 1; - attr->sample_freq = freq; + attr->sample_freq = top.freq; } if (evlist->nr_entries > 1) { @@ -1149,8 +941,8 @@ static void start_counters(struct perf_evlist *evlist) attr->mmap = 1; try_again: - if (perf_evsel__open(counter, evsel_list->cpus, - evsel_list->threads, group, inherit) < 0) { + if (perf_evsel__open(counter, top.evlist->cpus, + top.evlist->threads, group, inherit) < 0) { int err = errno; if (err == EPERM || err == EACCES) @@ -1198,18 +990,18 @@ static int __cmd_top(void) if (session == NULL) return -ENOMEM; - if (target_tid != -1) - perf_event__synthesize_thread(target_tid, perf_event__process, + if (top.target_tid != -1) + perf_event__synthesize_thread(top.target_tid, perf_event__process, session); else perf_event__synthesize_threads(perf_event__process, session); - start_counters(evsel_list); - first = list_entry(evsel_list->entries.next, struct perf_evsel, node); + start_counters(top.evlist); + first = list_entry(top.evlist->entries.next, struct perf_evsel, node); perf_session__set_sample_type(session, first->attr.sample_type); /* Wait for a minimal set of events before starting the snapshot */ - poll(evsel_list->pollfd, evsel_list->nr_fds, 100); + poll(top.evlist->pollfd, top.evlist->nr_fds, 100); perf_session__mmap_read(session); @@ -1229,12 +1021,12 @@ static int __cmd_top(void) } while (1) { - int hits = samples; + u64 hits = top.samples; perf_session__mmap_read(session); - if (hits == samples) - ret = poll(evsel_list->pollfd, evsel_list->nr_fds, 100); + if (hits == top.samples) + ret = poll(top.evlist->pollfd, top.evlist->nr_fds, 100); } return 0; @@ -1246,31 +1038,31 @@ static const char * const top_usage[] = { }; static const struct option options[] = { - OPT_CALLBACK('e', "event", &evsel_list, "event", + OPT_CALLBACK('e', "event", &top.evlist, "event", "event selector. use 'perf list' to list available events", parse_events), OPT_INTEGER('c', "count", &default_interval, "event period to sample"), - OPT_INTEGER('p', "pid", &target_pid, + OPT_INTEGER('p', "pid", &top.target_pid, "profile events on existing process id"), - OPT_INTEGER('t', "tid", &target_tid, + OPT_INTEGER('t', "tid", &top.target_tid, "profile events on existing thread id"), OPT_BOOLEAN('a', "all-cpus", &system_wide, "system-wide collection from all CPUs"), - OPT_STRING('C', "cpu", &cpu_list, "cpu", + OPT_STRING('C', "cpu", &top.cpu_list, "cpu", "list of cpus to monitor"), OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, "file", "vmlinux pathname"), - OPT_BOOLEAN('K', "hide_kernel_symbols", &hide_kernel_symbols, + OPT_BOOLEAN('K', "hide_kernel_symbols", &top.hide_kernel_symbols, "hide kernel symbols"), OPT_UINTEGER('m', "mmap-pages", &mmap_pages, "number of mmap data pages"), OPT_INTEGER('r', "realtime", &realtime_prio, "collect data with this RT SCHED_FIFO priority"), - OPT_INTEGER('d', "delay", &delay_secs, + OPT_INTEGER('d', "delay", &top.delay_secs, "number of seconds to delay between refreshes"), OPT_BOOLEAN('D', "dump-symtab", &dump_symtab, "dump the symbol table used for profiling"), - OPT_INTEGER('f', "count-filter", &count_filter, + OPT_INTEGER('f', "count-filter", &top.count_filter, "only display functions with more events than this"), OPT_BOOLEAN('g', "group", &group, "put the counters into a counter group"), @@ -1278,13 +1070,13 @@ static const struct option options[] = { "child tasks inherit counters"), OPT_STRING('s', "sym-annotate", &sym_filter, "symbol name", "symbol to annotate"), - OPT_BOOLEAN('z', "zero", &zero, + OPT_BOOLEAN('z', "zero", &top.zero, "zero history across updates"), - OPT_INTEGER('F', "freq", &freq, + OPT_INTEGER('F', "freq", &top.freq, "profile at this frequency"), - OPT_INTEGER('E', "entries", &print_entries, + OPT_INTEGER('E', "entries", &top.print_entries, "display this many functions"), - OPT_BOOLEAN('U', "hide_user_symbols", &hide_user_symbols, + OPT_BOOLEAN('U', "hide_user_symbols", &top.hide_user_symbols, "hide user symbols"), OPT_INCR('v', "verbose", &verbose, "be more verbose (show counter open errors, etc)"), @@ -1296,8 +1088,8 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) struct perf_evsel *pos; int status = -ENOMEM; - evsel_list = perf_evlist__new(NULL, NULL); - if (evsel_list == NULL) + top.evlist = perf_evlist__new(NULL, NULL); + if (top.evlist == NULL) return -ENOMEM; page_size = sysconf(_SC_PAGE_SIZE); @@ -1307,43 +1099,43 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) usage_with_options(top_usage, options); /* CPU and PID are mutually exclusive */ - if (target_tid > 0 && cpu_list) { + if (top.target_tid > 0 && top.cpu_list) { printf("WARNING: PID switch overriding CPU\n"); sleep(1); - cpu_list = NULL; + top.cpu_list = NULL; } - if (target_pid != -1) - target_tid = target_pid; + if (top.target_pid != -1) + top.target_tid = top.target_pid; - if (perf_evlist__create_maps(evsel_list, target_pid, - target_tid, cpu_list) < 0) + if (perf_evlist__create_maps(top.evlist, top.target_pid, + top.target_tid, top.cpu_list) < 0) usage_with_options(top_usage, options); - if (!evsel_list->nr_entries && - perf_evlist__add_default(evsel_list) < 0) { + if (!top.evlist->nr_entries && + perf_evlist__add_default(top.evlist) < 0) { pr_err("Not enough memory for event selector list\n"); return -ENOMEM; } - if (delay_secs < 1) - delay_secs = 1; + if (top.delay_secs < 1) + top.delay_secs = 1; /* * User specified count overrides default frequency. */ if (default_interval) - freq = 0; - else if (freq) { - default_interval = freq; + top.freq = 0; + else if (top.freq) { + default_interval = top.freq; } else { fprintf(stderr, "frequency and count are zero, aborting\n"); exit(EXIT_FAILURE); } - list_for_each_entry(pos, &evsel_list->entries, node) { - if (perf_evsel__alloc_fd(pos, evsel_list->cpus->nr, - evsel_list->threads->nr) < 0) + list_for_each_entry(pos, &top.evlist->entries, node) { + if (perf_evsel__alloc_fd(pos, top.evlist->cpus->nr, + top.evlist->threads->nr) < 0) goto out_free_fd; /* * Fill in the ones not specifically initialized via -c: @@ -1354,28 +1146,28 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) pos->attr.sample_period = default_interval; } - if (perf_evlist__alloc_pollfd(evsel_list) < 0 || - perf_evlist__alloc_mmap(evsel_list) < 0) + if (perf_evlist__alloc_pollfd(top.evlist) < 0 || + perf_evlist__alloc_mmap(top.evlist) < 0) goto out_free_fd; - sym_evsel = list_entry(evsel_list->entries.next, struct perf_evsel, node); + top.sym_evsel = list_entry(top.evlist->entries.next, struct perf_evsel, node); symbol_conf.priv_size = (sizeof(struct sym_entry) + - (evsel_list->nr_entries + 1) * sizeof(unsigned long)); + (top.evlist->nr_entries + 1) * sizeof(unsigned long)); symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL); if (symbol__init() < 0) return -1; get_term_dimensions(&winsize); - if (print_entries == 0) { + if (top.print_entries == 0) { update_print_entries(&winsize); signal(SIGWINCH, sig_winch_handler); } status = __cmd_top(); out_free_fd: - perf_evlist__delete(evsel_list); + perf_evlist__delete(top.evlist); return status; } -- cgit v1.2.2 From c0443df1b69b59675fc6790e0ddce87c8ca00abf Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 31 Jan 2011 18:19:33 -0200 Subject: perf top: Introduce slang based TUI Disabled by default as there are features found in the stdio based one that aren't implemented, like live annotation, filtering knobs data entry. Annotation hopefully will get somehow merged with the 'perf annotate' code. To use it: perf top --tui Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Tom Zanussi LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-top.c | 35 +++++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) (limited to 'tools/perf/builtin-top.c') diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 3c9ba943aa48..104de9ab314c 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -20,6 +20,7 @@ #include "perf.h" +#include "util/cache.h" #include "util/color.h" #include "util/evlist.h" #include "util/evsel.h" @@ -75,6 +76,8 @@ static struct perf_top top = { static bool system_wide = false; +static bool use_tui, use_stdio; + static int default_interval = 0; static bool inherit = false; @@ -96,11 +99,6 @@ static int sym_pcnt_filter = 5; * Source functions */ -static inline struct symbol *sym_entry__symbol(struct sym_entry *self) -{ - return ((void *)self) + symbol_conf.priv_size; -} - void get_term_dimensions(struct winsize *ws) { char *s = getenv("LINES"); @@ -695,6 +693,14 @@ static void handle_keypress(struct perf_session *session, int c) } } +static void *display_thread_tui(void *arg __used) +{ + perf_top__tui_browser(&top); + exit_browser(0); + exit(0); + return NULL; +} + static void *display_thread(void *arg __used) { struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; @@ -1005,7 +1011,8 @@ static int __cmd_top(void) perf_session__mmap_read(session); - if (pthread_create(&thread, NULL, display_thread, session)) { + if (pthread_create(&thread, NULL, (use_browser > 0 ? display_thread_tui : + display_thread), session)) { printf("Could not create display thread.\n"); exit(-1); } @@ -1078,6 +1085,8 @@ static const struct option options[] = { "display this many functions"), OPT_BOOLEAN('U', "hide_user_symbols", &top.hide_user_symbols, "hide user symbols"), + OPT_BOOLEAN(0, "tui", &use_tui, "Use the TUI interface"), + OPT_BOOLEAN(0, "stdio", &use_stdio, "Use the stdio interface"), OPT_INCR('v', "verbose", &verbose, "be more verbose (show counter open errors, etc)"), OPT_END() @@ -1098,6 +1107,20 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) if (argc) usage_with_options(top_usage, options); + /* + * XXX For now start disabled, only using TUI if explicitely asked for. + * Change that when handle_keys equivalent gets written, live annotation + * done, etc. + */ + use_browser = 0; + + if (use_stdio) + use_browser = 0; + else if (use_tui) + use_browser = 1; + + setup_browser(false); + /* CPU and PID are mutually exclusive */ if (top.target_tid > 0 && top.cpu_list) { printf("WARNING: PID switch overriding CPU\n"); -- cgit v1.2.2 From 764328d3209dd81b02a55722556b07b6f35e3ca0 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 4 Feb 2011 07:33:24 -0200 Subject: perf top: Remove superfluous name_len field From the sym_entry struct, struct symbol already has this field. Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Tom Zanussi LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-top.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'tools/perf/builtin-top.c') diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 104de9ab314c..154e088588bc 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -787,9 +787,6 @@ static int symbol_filter(struct map *map, struct symbol *sym) } } - if (!syme->skip) - syme->name_len = strlen(sym->name); - return 0; } -- cgit v1.2.2 From 36532461a0f60bb36c5470a0326f7394f19db23c Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sun, 6 Feb 2011 14:54:44 -0200 Subject: perf top: Ditch private annotation code, share perf annotate's Next step: Live TUI annotation in perf top, just press enter on a symbol line. Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Tom Zanussi LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-top.c | 181 ++++++++--------------------------------------- 1 file changed, 31 insertions(+), 150 deletions(-) (limited to 'tools/perf/builtin-top.c') diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 154e088588bc..716118a3b3e4 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -20,6 +20,7 @@ #include "perf.h" +#include "util/annotate.h" #include "util/cache.h" #include "util/color.h" #include "util/evlist.h" @@ -140,10 +141,7 @@ static int parse_source(struct sym_entry *syme) struct symbol *sym; struct sym_entry_source *source; struct map *map; - FILE *file; - char command[PATH_MAX*2]; - const char *path; - u64 len; + int err = -1; if (!syme) return -1; @@ -162,197 +160,80 @@ static int parse_source(struct sym_entry *syme) if (syme->src == NULL) return -1; pthread_mutex_init(&syme->src->lock, NULL); + INIT_LIST_HEAD(&syme->src->head); } source = syme->src; - if (source->lines) { + if (symbol__annotation(sym)->histograms != NULL) { pthread_mutex_lock(&source->lock); goto out_assign; } - path = map->dso->long_name; - - len = sym->end - sym->start; - - sprintf(command, - "objdump --start-address=%#0*" PRIx64 " --stop-address=%#0*" PRIx64 " -dS %s", - BITS_PER_LONG / 4, map__rip_2objdump(map, sym->start), - BITS_PER_LONG / 4, map__rip_2objdump(map, sym->end), path); - - file = popen(command, "r"); - if (!file) - return -1; pthread_mutex_lock(&source->lock); - source->lines_tail = &source->lines; - while (!feof(file)) { - struct source_line *src; - size_t dummy = 0; - char *c, *sep; - - src = malloc(sizeof(struct source_line)); - assert(src != NULL); - memset(src, 0, sizeof(struct source_line)); - - if (getline(&src->line, &dummy, file) < 0) - break; - if (!src->line) - break; - - c = strchr(src->line, '\n'); - if (c) - *c = 0; - src->next = NULL; - *source->lines_tail = src; - source->lines_tail = &src->next; - - src->eip = strtoull(src->line, &sep, 16); - if (*sep == ':') - src->eip = map__objdump_2ip(map, src->eip); - else /* this line has no ip info (e.g. source line) */ - src->eip = 0; + if (symbol__alloc_hist(sym, top.evlist->nr_entries) < 0) { + pr_err("Not enough memory for annotating '%s' symbol!\n", + sym->name); + goto out_unlock; } - pclose(file); + + err = symbol__annotate(sym, syme->map, &source->head, 0); + if (err == 0) { out_assign: sym_filter_entry = syme; + } +out_unlock: pthread_mutex_unlock(&source->lock); - return 0; + return err; } static void __zero_source_counters(struct sym_entry *syme) { - int i; - struct source_line *line; - - line = syme->src->lines; - while (line) { - for (i = 0; i < top.evlist->nr_entries; i++) - line->count[i] = 0; - line = line->next; - } + struct symbol *sym = sym_entry__symbol(syme); + symbol__annotate_zero_histograms(sym); } static void record_precise_ip(struct sym_entry *syme, int counter, u64 ip) { - struct source_line *line; - if (syme != sym_filter_entry) return; if (pthread_mutex_trylock(&syme->src->lock)) return; - if (syme->src == NULL || syme->src->source == NULL) - goto out_unlock; - - for (line = syme->src->lines; line; line = line->next) { - /* skip lines without IP info */ - if (line->eip == 0) - continue; - if (line->eip == ip) { - line->count[counter]++; - break; - } - if (line->eip > ip) - break; - } -out_unlock: - pthread_mutex_unlock(&syme->src->lock); -} - -#define PATTERN_LEN (BITS_PER_LONG / 4 + 2) + ip = syme->map->map_ip(syme->map, ip); + symbol__inc_addr_samples(sym_entry__symbol(syme), syme->map, counter, ip); -static void lookup_sym_source(struct sym_entry *syme) -{ - struct symbol *symbol = sym_entry__symbol(syme); - struct source_line *line; - char pattern[PATTERN_LEN + 1]; - - sprintf(pattern, "%0*" PRIx64 " <", BITS_PER_LONG / 4, - map__rip_2objdump(syme->map, symbol->start)); - - pthread_mutex_lock(&syme->src->lock); - for (line = syme->src->lines; line; line = line->next) { - if (memcmp(line->line, pattern, PATTERN_LEN) == 0) { - syme->src->source = line; - break; - } - } pthread_mutex_unlock(&syme->src->lock); } -static void show_lines(struct source_line *queue, int count, int total) -{ - int i; - struct source_line *line; - - line = queue; - for (i = 0; i < count; i++) { - float pcnt = 100.0*(float)line->count[top.sym_counter]/(float)total; - - printf("%8li %4.1f%%\t%s\n", line->count[top.sym_counter], pcnt, line->line); - line = line->next; - } -} - -#define TRACE_COUNT 3 - static void show_details(struct sym_entry *syme) { struct symbol *symbol; - struct source_line *line; - struct source_line *line_queue = NULL; - int displayed = 0; - int line_queue_count = 0, total = 0, more = 0; + int more; if (!syme) return; - if (!syme->src->source) - lookup_sym_source(syme); - - if (!syme->src->source) + symbol = sym_entry__symbol(syme); + if (!syme->src || symbol__annotation(symbol)->histograms == NULL) return; - symbol = sym_entry__symbol(syme); printf("Showing %s for %s\n", event_name(top.sym_evsel), symbol->name); printf(" Events Pcnt (>=%d%%)\n", sym_pcnt_filter); pthread_mutex_lock(&syme->src->lock); - line = syme->src->source; - while (line) { - total += line->count[top.sym_counter]; - line = line->next; - } - - line = syme->src->source; - while (line) { - float pcnt = 0.0; - - if (!line_queue_count) - line_queue = line; - line_queue_count++; - - if (line->count[top.sym_counter]) - pcnt = 100.0 * line->count[top.sym_counter] / (float)total; - if (pcnt >= (float)sym_pcnt_filter) { - if (displayed <= top.print_entries) - show_lines(line_queue, line_queue_count, total); - else more++; - displayed += line_queue_count; - line_queue_count = 0; - line_queue = NULL; - } else if (line_queue_count > TRACE_COUNT) { - line_queue = line_queue->next; - line_queue_count--; - } - - line->count[top.sym_counter] = top.zero ? 0 : line->count[top.sym_counter] * 7 / 8; - line = line->next; - } + more = symbol__annotate_printf(symbol, syme->map, &syme->src->head, + top.sym_evsel->idx, 0, sym_pcnt_filter, + top.print_entries); + if (top.zero) + symbol__annotate_zero_histogram(symbol, top.sym_evsel->idx); + else + symbol__annotate_decay_histogram(symbol, &syme->src->head, + top.sym_evsel->idx); pthread_mutex_unlock(&syme->src->lock); - if (more) + if (more != 0) printf("%d lines not displayed, maybe increase display entries [e]\n", more); } @@ -1172,7 +1053,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) top.sym_evsel = list_entry(top.evlist->entries.next, struct perf_evsel, node); - symbol_conf.priv_size = (sizeof(struct sym_entry) + + symbol_conf.priv_size = (sizeof(struct sym_entry) + sizeof(struct annotation) + (top.evlist->nr_entries + 1) * sizeof(unsigned long)); symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL); -- cgit v1.2.2 From fb7d0b3cefb80a105f7fd26bbc62e0cbf9192822 Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Mon, 24 Jan 2011 11:13:04 -0500 Subject: perf tool: Fix gcc 4.6.0 issues GCC 4.6.0 in Fedora rawhide turned up some compile errors in tools/perf due to the -Werror=unused-but-set-variable flag. I've gone through and annotated some of the assignments that had side effects (ie: return value from a function) with the __used annotation, and in some cases, just removed unused code. In a few cases, we were assigning something useful, but not using it in later parts of the function. kyle@dreadnought:~/src% gcc --version gcc (GCC) 4.6.0 20110122 (Red Hat 4.6.0-0.3) Cc: Ingo Molnar LKML-Reference: <20110124161304.GK27353@bombadil.infradead.org> Signed-off-by: Kyle McMartin [ committer note: Fixed up the annotation fixes, as that code moved recently ] Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-top.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools/perf/builtin-top.c') diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 716118a3b3e4..b790673cb0aa 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -865,7 +865,7 @@ static int __cmd_top(void) { pthread_t thread; struct perf_evsel *first; - int ret; + int ret __used; /* * FIXME: perf_session__new should allow passing a O_MMAP, so that all this * mmap reading, etc is encapsulated in it. Use O_WRONLY for now. -- cgit v1.2.2 From ce6f4fab4059cd72638a0cfa596a8ee2c79c1c8e Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 8 Feb 2011 13:27:39 -0200 Subject: perf annotate: Move locking to struct annotation Since we'll need it when implementing the live annotate TUI browser. This also simplifies things a bit by having the list head for the source code to be in the dynamicly allocated part of struct annotation, that way we don't have to pass it around, it can be found from the struct symbol that is passed everywhere. Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Tom Zanussi LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-top.c | 67 ++++++++++++++++++++++++------------------------ 1 file changed, 34 insertions(+), 33 deletions(-) (limited to 'tools/perf/builtin-top.c') diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index b790673cb0aa..7dbf22d096b8 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -139,7 +139,7 @@ static void sig_winch_handler(int sig __used) static int parse_source(struct sym_entry *syme) { struct symbol *sym; - struct sym_entry_source *source; + struct annotation *notes; struct map *map; int err = -1; @@ -152,39 +152,35 @@ static int parse_source(struct sym_entry *syme) /* * We can't annotate with just /proc/kallsyms */ - if (map->dso->origin == DSO__ORIG_KERNEL) + if (map->dso->origin == DSO__ORIG_KERNEL) { + pr_err("Can't annotate %s: No vmlinux file was found in the " + "path\n", sym->name); + sleep(1); return -1; - - if (syme->src == NULL) { - syme->src = zalloc(sizeof(*source)); - if (syme->src == NULL) - return -1; - pthread_mutex_init(&syme->src->lock, NULL); - INIT_LIST_HEAD(&syme->src->head); } - source = syme->src; - - if (symbol__annotation(sym)->histograms != NULL) { - pthread_mutex_lock(&source->lock); + notes = symbol__annotation(sym); + if (notes->src != NULL) { + pthread_mutex_lock(¬es->lock); goto out_assign; } - pthread_mutex_lock(&source->lock); + pthread_mutex_lock(¬es->lock); if (symbol__alloc_hist(sym, top.evlist->nr_entries) < 0) { pr_err("Not enough memory for annotating '%s' symbol!\n", sym->name); + sleep(1); goto out_unlock; } - err = symbol__annotate(sym, syme->map, &source->head, 0); + err = symbol__annotate(sym, syme->map, 0); if (err == 0) { out_assign: sym_filter_entry = syme; } out_unlock: - pthread_mutex_unlock(&source->lock); + pthread_mutex_unlock(¬es->lock); return err; } @@ -196,20 +192,27 @@ static void __zero_source_counters(struct sym_entry *syme) static void record_precise_ip(struct sym_entry *syme, int counter, u64 ip) { + struct annotation *notes; + struct symbol *sym; + if (syme != sym_filter_entry) return; - if (pthread_mutex_trylock(&syme->src->lock)) + sym = sym_entry__symbol(syme); + notes = symbol__annotation(sym); + + if (pthread_mutex_trylock(¬es->lock)) return; ip = syme->map->map_ip(syme->map, ip); - symbol__inc_addr_samples(sym_entry__symbol(syme), syme->map, counter, ip); + symbol__inc_addr_samples(sym, syme->map, counter, ip); - pthread_mutex_unlock(&syme->src->lock); + pthread_mutex_unlock(¬es->lock); } static void show_details(struct sym_entry *syme) { + struct annotation *notes; struct symbol *symbol; int more; @@ -217,24 +220,26 @@ static void show_details(struct sym_entry *syme) return; symbol = sym_entry__symbol(syme); - if (!syme->src || symbol__annotation(symbol)->histograms == NULL) - return; + notes = symbol__annotation(symbol); + + pthread_mutex_lock(¬es->lock); + + if (notes->src == NULL) + goto out_unlock; printf("Showing %s for %s\n", event_name(top.sym_evsel), symbol->name); printf(" Events Pcnt (>=%d%%)\n", sym_pcnt_filter); - pthread_mutex_lock(&syme->src->lock); - more = symbol__annotate_printf(symbol, syme->map, &syme->src->head, - top.sym_evsel->idx, 0, sym_pcnt_filter, - top.print_entries); + more = symbol__annotate_printf(symbol, syme->map, top.sym_evsel->idx, + 0, sym_pcnt_filter, top.print_entries); if (top.zero) symbol__annotate_zero_histogram(symbol, top.sym_evsel->idx); else - symbol__annotate_decay_histogram(symbol, &syme->src->head, - top.sym_evsel->idx); - pthread_mutex_unlock(&syme->src->lock); + symbol__annotate_decay_histogram(symbol, top.sym_evsel->idx); if (more != 0) printf("%d lines not displayed, maybe increase display entries [e]\n", more); +out_unlock: + pthread_mutex_unlock(¬es->lock); } static const char CONSOLE_CLEAR[] = ""; @@ -372,10 +377,8 @@ static void prompt_symbol(struct sym_entry **target, const char *msg) /* zero counters of active symbol */ if (syme) { - pthread_mutex_lock(&syme->src->lock); __zero_source_counters(syme); *target = NULL; - pthread_mutex_unlock(&syme->src->lock); } fprintf(stdout, "\n%s: ", msg); @@ -554,10 +557,8 @@ static void handle_keypress(struct perf_session *session, int c) else { struct sym_entry *syme = sym_filter_entry; - pthread_mutex_lock(&syme->src->lock); sym_filter_entry = NULL; __zero_source_counters(syme); - pthread_mutex_unlock(&syme->src->lock); } break; case 'U': @@ -653,7 +654,7 @@ static int symbol_filter(struct map *map, struct symbol *sym) syme = symbol__priv(sym); syme->map = map; - syme->src = NULL; + symbol__annotate_init(map, sym); if (!sym_filter_entry && sym_filter && !strcmp(name, sym_filter)) { /* schedule initial sym_filter_entry setup */ -- cgit v1.2.2 From d5e3d747007fdb541e57ed72e020ff0b94db3470 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 8 Feb 2011 15:29:25 -0200 Subject: perf annotate: Fix annotate context lines regression The live annotation done in 'perf top' needs to limit the context before lines that aren't filtered out by the min percent filter, if we don't do that, the screen in a tty often is not enough for showing what is interesting: lines with hits and a few source code lines before it. Reported-by: Mike Galbraith Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Tom Zanussi LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-top.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools/perf/builtin-top.c') diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 7dbf22d096b8..210c736e6db4 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -231,7 +231,7 @@ static void show_details(struct sym_entry *syme) printf(" Events Pcnt (>=%d%%)\n", sym_pcnt_filter); more = symbol__annotate_printf(symbol, syme->map, top.sym_evsel->idx, - 0, sym_pcnt_filter, top.print_entries); + 0, sym_pcnt_filter, top.print_entries, 4); if (top.zero) symbol__annotate_zero_histogram(symbol, top.sym_evsel->idx); else -- cgit v1.2.2 From 401b8e1317d288f28d6e1afd13271dcb08fd9869 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 10 Feb 2011 12:52:47 -0200 Subject: perf tools: Fix thread_map event synthesizing in top and record Jeff Moyer reported these messages: Warning: ... trying to fall back to cpu-clock-ticks couldn't open /proc/-1/status couldn't open /proc/-1/maps [ls output] [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.008 MB perf.data (~363 samples) ] That lead me and David Ahern to see that something was fishy on the thread synthesizing routines, at least for the case where the workload is started from 'perf record', as -1 is the default for target_tid in 'perf record --tid' parameter, so somehow we were trying to synthesize the PERF_RECORD_MMAP and PERF_RECORD_COMM events for the thread -1, a bug. So I investigated this and noticed that when we introduced support for recording a process and its threads using --pid some bugs were introduced and that the way to fix it was to instead of passing the target_tid to the event synthesizing routines we should better pass the thread_map that has the list of threads for a --pid or just the single thread for a --tid. Checked in the following ways: On a 8-way machine run cyclictest: [root@emilia ~]# perf record cyclictest -a -t -n -p99 -i100 -d50 policy: fifo: loadavg: 0.00 0.13 0.31 2/139 28798 T: 0 (28791) P:99 I:100 C: 25072 Min: 4 Act: 5 Avg: 6 Max: 122 T: 1 (28792) P:98 I:150 C: 16715 Min: 4 Act: 6 Avg: 5 Max: 27 T: 2 (28793) P:97 I:200 C: 12534 Min: 4 Act: 5 Avg: 4 Max: 8 T: 3 (28794) P:96 I:250 C: 10028 Min: 4 Act: 5 Avg: 5 Max: 96 T: 4 (28795) P:95 I:300 C: 8357 Min: 5 Act: 6 Avg: 5 Max: 12 T: 5 (28796) P:94 I:350 C: 7163 Min: 5 Act: 6 Avg: 5 Max: 12 T: 6 (28797) P:93 I:400 C: 6267 Min: 4 Act: 5 Avg: 5 Max: 9 T: 7 (28798) P:92 I:450 C: 5571 Min: 4 Act: 5 Avg: 5 Max: 9 ^C[ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.108 MB perf.data (~4719 samples) ] [root@emilia ~]# This will create one extra thread per CPU: [root@emilia ~]# tuna -t cyclictest -CP thread ctxt_switches pid SCHED_ rtpri affinity voluntary nonvoluntary cmd 28825 OTHER 0 0xff 2169 671 cyclictest 28832 FIFO 93 6 52338 1 cyclictest 28833 FIFO 92 7 46524 1 cyclictest 28826 FIFO 99 0 209360 1 cyclictest 28827 FIFO 98 1 139577 1 cyclictest 28828 FIFO 97 2 104686 0 cyclictest 28829 FIFO 96 3 83751 1 cyclictest 28830 FIFO 95 4 69794 1 cyclictest 28831 FIFO 94 5 59825 1 cyclictest [root@emilia ~]# So we should expect only samples for the above 9 threads when using the --dump-raw-trace|-D perf report switch to look at the column with the tid: [root@emilia ~]# perf report -D | grep RECORD_SAMPLE | cut -d/ -f2 | cut -d: -f1 | sort | uniq -c 629 28825 110 28826 491 28827 308 28828 198 28829 621 28830 225 28831 203 28832 89 28833 [root@emilia ~]# So for workloads started by 'perf record' seems to work, now for existing workloads, just run cyclictest first, without 'perf record': [root@emilia ~]# tuna -t cyclictest -CP thread ctxt_switches pid SCHED_ rtpri affinity voluntary nonvoluntary cmd 28859 OTHER 0 0xff 594 200 cyclictest 28864 FIFO 95 4 16587 1 cyclictest 28865 FIFO 94 5 14219 1 cyclictest 28866 FIFO 93 6 12443 0 cyclictest 28867 FIFO 92 7 11062 1 cyclictest 28860 FIFO 99 0 49779 1 cyclictest 28861 FIFO 98 1 33190 1 cyclictest 28862 FIFO 97 2 24895 1 cyclictest 28863 FIFO 96 3 19918 1 cyclictest [root@emilia ~]# and then later did: [root@emilia ~]# perf record --pid 28859 sleep 3 [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.027 MB perf.data (~1195 samples) ] [root@emilia ~]# To collect 3 seconds worth of samples for pid 28859 and its children: [root@emilia ~]# perf report -D | grep RECORD_SAMPLE | cut -d/ -f2 | cut -d: -f1 | sort | uniq -c 15 28859 33 28860 19 28861 13 28862 13 28863 10 28864 11 28865 9 28866 255 28867 [root@emilia ~]# Works, last thing is to check if looking at just one of those threads also works: [root@emilia ~]# perf record --tid 28866 sleep 3 [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.006 MB perf.data (~242 samples) ] [root@emilia ~]# perf report -D | grep RECORD_SAMPLE | cut -d/ -f2 | cut -d: -f1 | sort | uniq -c 3 28866 [root@emilia ~]# Works too. Reported-by: Jeff Moyer Cc: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Jeff Moyer Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Tom Zanussi LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-top.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools/perf/builtin-top.c') diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index b6998e055767..5a29d9cd9486 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -1306,7 +1306,7 @@ static int __cmd_top(void) return -ENOMEM; if (target_tid != -1) - event__synthesize_thread(target_tid, event__process, session); + event__synthesize_thread_map(threads, event__process, session); else event__synthesize_threads(event__process, session); -- cgit v1.2.2 From c97cf42219b7b6037d2f96c27a5f114f2383f828 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 22 Feb 2011 12:02:07 -0300 Subject: perf top: Live TUI Annotation Now one has just to press the right key, 'a' or Enter on the main 'perf top --tui' screen to live annotate the symbol under the cursor. The annotate window starts centered on the hottest line (the one with most samples so far) then TAB and shift+TAB can be used to go to the prev/next hot line. Pressing 'H' at any point will center again the screen on the hottest line. Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Tom Zanussi LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-top.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) (limited to 'tools/perf/builtin-top.c') diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index c9fd66d4a082..f88a2630e1fc 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -92,7 +92,6 @@ static bool dump_symtab = false; static struct winsize winsize; static const char *sym_filter = NULL; -struct sym_entry *sym_filter_entry = NULL; struct sym_entry *sym_filter_entry_sched = NULL; static int sym_pcnt_filter = 5; @@ -168,18 +167,19 @@ static int parse_source(struct sym_entry *syme) pthread_mutex_lock(¬es->lock); if (symbol__alloc_hist(sym, top.evlist->nr_entries) < 0) { + pthread_mutex_unlock(¬es->lock); pr_err("Not enough memory for annotating '%s' symbol!\n", sym->name); sleep(1); - goto out_unlock; + return err; } err = symbol__annotate(sym, syme->map, 0); if (err == 0) { out_assign: - sym_filter_entry = syme; + top.sym_filter_entry = syme; } -out_unlock: + pthread_mutex_unlock(¬es->lock); return err; } @@ -195,7 +195,7 @@ static void record_precise_ip(struct sym_entry *syme, int counter, u64 ip) struct annotation *notes; struct symbol *sym; - if (syme != sym_filter_entry) + if (syme != top.sym_filter_entry) return; sym = sym_entry__symbol(syme); @@ -275,8 +275,8 @@ static void print_sym_table(struct perf_session *session) session->hists.stats.total_lost); } - if (sym_filter_entry) { - show_details(sym_filter_entry); + if (top.sym_filter_entry) { + show_details(top.sym_filter_entry); return; } @@ -417,8 +417,8 @@ static void print_mapped_keys(void) { char *name = NULL; - if (sym_filter_entry) { - struct symbol *sym = sym_entry__symbol(sym_filter_entry); + if (top.sym_filter_entry) { + struct symbol *sym = sym_entry__symbol(top.sym_filter_entry); name = sym->name; } @@ -549,15 +549,15 @@ static void handle_keypress(struct perf_session *session, int c) perf_session__fprintf_dsos(session, stderr); exit(0); case 's': - prompt_symbol(&sym_filter_entry, "Enter details symbol"); + prompt_symbol(&top.sym_filter_entry, "Enter details symbol"); break; case 'S': - if (!sym_filter_entry) + if (!top.sym_filter_entry) break; else { - struct sym_entry *syme = sym_filter_entry; + struct sym_entry *syme = top.sym_filter_entry; - sym_filter_entry = NULL; + top.sym_filter_entry = NULL; __zero_source_counters(syme); } break; @@ -656,7 +656,7 @@ static int symbol_filter(struct map *map, struct symbol *sym) syme->map = map; symbol__annotate_init(map, sym); - if (!sym_filter_entry && sym_filter && !strcmp(name, sym_filter)) { + if (!top.sym_filter_entry && sym_filter && !strcmp(name, sym_filter)) { /* schedule initial sym_filter_entry setup */ sym_filter_entry_sched = syme; sym_filter = NULL; @@ -750,13 +750,13 @@ static void perf_event__process_sample(const union perf_event *event, /* let's see, whether we need to install initial sym_filter_entry */ if (sym_filter_entry_sched) { - sym_filter_entry = sym_filter_entry_sched; + top.sym_filter_entry = sym_filter_entry_sched; sym_filter_entry_sched = NULL; - if (parse_source(sym_filter_entry) < 0) { - struct symbol *sym = sym_entry__symbol(sym_filter_entry); + if (parse_source(top.sym_filter_entry) < 0) { + struct symbol *sym = sym_entry__symbol(top.sym_filter_entry); pr_err("Can't annotate %s", sym->name); - if (sym_filter_entry->map->dso->origin == DSO__ORIG_KERNEL) { + if (top.sym_filter_entry->map->dso->origin == DSO__ORIG_KERNEL) { pr_err(": No vmlinux file was found in the path:\n"); machine__fprintf_vmlinux_path(machine, stderr); } else -- cgit v1.2.2 From 374cfe56892701f062586d6a6de6cb71777a4184 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 1 Mar 2011 10:27:27 -0300 Subject: perf top: Fix reporting of invalid --vmlinux Using ui__warning, that will, in --tui, show a window with the message, waiting for the user to press Ok. Also run exit_browser() to let newt do its final cleaning of the screen. Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Tom Zanussi LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-top.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'tools/perf/builtin-top.c') diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index f88a2630e1fc..0b07cc30b669 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -740,8 +740,9 @@ static void perf_event__process_sample(const union perf_event *event, */ if (al.map == machine->vmlinux_maps[MAP__FUNCTION] && RB_EMPTY_ROOT(&al.map->dso->symbols[MAP__FUNCTION])) { - pr_err("The %s file can't be used\n", - symbol_conf.vmlinux_name); + ui__warning("The %s file can't be used\n", + symbol_conf.vmlinux_name); + exit_browser(0); exit(1); } -- cgit v1.2.2 From 5807806a92450fd57f8063868efae9d4af74db02 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 1 Mar 2011 10:43:03 -0300 Subject: perf top tui: Wait till the first sample to refresh the screen. Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Tom Zanussi LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-top.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) (limited to 'tools/perf/builtin-top.c') diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 0b07cc30b669..417f757e3cbe 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -72,6 +72,7 @@ static struct perf_top top = { .target_tid = -1, .active_symbols = LIST_HEAD_INIT(top.active_symbols), .active_symbols_lock = PTHREAD_MUTEX_INITIALIZER, + .active_symbols_cond = PTHREAD_COND_INITIALIZER, .freq = 1000, /* 1 KHz */ }; @@ -577,7 +578,17 @@ static void handle_keypress(struct perf_session *session, int c) static void *display_thread_tui(void *arg __used) { - perf_top__tui_browser(&top); + int err = 0; + pthread_mutex_lock(&top.active_symbols_lock); + while (list_empty(&top.active_symbols)) { + err = pthread_cond_wait(&top.active_symbols_cond, + &top.active_symbols_lock); + if (err) + break; + } + pthread_mutex_unlock(&top.active_symbols_lock); + if (!err) + perf_top__tui_browser(&top); exit_browser(0); exit(0); return NULL; @@ -776,8 +787,14 @@ static void perf_event__process_sample(const union perf_event *event, syme->count[evsel->idx]++; record_precise_ip(syme, evsel->idx, ip); pthread_mutex_lock(&top.active_symbols_lock); - if (list_empty(&syme->node) || !syme->node.next) + if (list_empty(&syme->node) || !syme->node.next) { + static bool first = true; __list_insert_active_sym(syme); + if (first) { + pthread_cond_broadcast(&top.active_symbols_cond); + first = false; + } + } pthread_mutex_unlock(&top.active_symbols_lock); } } -- cgit v1.2.2 From a91e5431d54f5359fccb5ec2512f252eb217707e Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 10 Mar 2011 11:15:54 -0300 Subject: perf session: Use evlist/evsel for managing perf.data attributes So that we can reuse things like the id to attr lookup routine (perf_evlist__id2evsel) that uses a hash table instead of the linear lookup done in the older perf_header_attr routines, etc. Also to make evsels/evlist more pervasive an API, simplyfing using the emerging perf lib. cc: Arun Sharma Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Tom Zanussi LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-top.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'tools/perf/builtin-top.c') diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 417f757e3cbe..80c9e062bd5b 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -883,7 +883,6 @@ try_again: static int __cmd_top(void) { pthread_t thread; - struct perf_evsel *first; int ret __used; /* * FIXME: perf_session__new should allow passing a O_MMAP, so that all this @@ -900,8 +899,8 @@ static int __cmd_top(void) perf_event__synthesize_threads(perf_event__process, session); start_counters(top.evlist); - first = list_entry(top.evlist->entries.next, struct perf_evsel, node); - perf_session__set_sample_type(session, first->attr.sample_type); + session->evlist = top.evlist; + perf_session__update_sample_type(session); /* Wait for a minimal set of events before starting the snapshot */ poll(top.evlist->pollfd, top.evlist->nr_fds, 100); -- cgit v1.2.2 From ec52d9765a0f3603c62b4238482bf38897e4d42f Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 11 Mar 2011 10:11:48 -0300 Subject: perf top: Remove redundant perf_top->sym_counter We can get that counter index from perf_top->sym_evsel->idx instead. Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Tom Zanussi LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-top.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'tools/perf/builtin-top.c') diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 80c9e062bd5b..4bf6e02c2b2a 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -515,24 +515,25 @@ static void handle_keypress(struct perf_session *session, int c) break; case 'E': if (top.evlist->nr_entries > 1) { + int counter; fprintf(stderr, "\nAvailable events:"); list_for_each_entry(top.sym_evsel, &top.evlist->entries, node) fprintf(stderr, "\n\t%d %s", top.sym_evsel->idx, event_name(top.sym_evsel)); - prompt_integer(&top.sym_counter, "Enter details event counter"); + prompt_integer(&counter, "Enter details event counter"); - if (top.sym_counter >= top.evlist->nr_entries) { + if (counter >= top.evlist->nr_entries) { top.sym_evsel = list_entry(top.evlist->entries.next, struct perf_evsel, node); - top.sym_counter = 0; fprintf(stderr, "Sorry, no such event, using %s.\n", event_name(top.sym_evsel)); sleep(1); break; } list_for_each_entry(top.sym_evsel, &top.evlist->entries, node) - if (top.sym_evsel->idx == top.sym_counter) + if (top.sym_evsel->idx == counter) break; - } else top.sym_counter = 0; + } else + top.sym_evsel = list_entry(top.evlist->entries.next, struct perf_evsel, node); break; case 'f': prompt_integer(&top.count_filter, "Enter display event count filter"); -- cgit v1.2.2 From 8b8ba4a9a5b04916858f79cee71873f973931649 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 11 Mar 2011 12:38:48 -0300 Subject: perf top: Remove redundant syme->origin field We can get it from syme->map->dso->kernel (that should be renamed to origin, but leave this for another patch). Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Tom Zanussi LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-top.c | 1 - 1 file changed, 1 deletion(-) (limited to 'tools/perf/builtin-top.c') diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 4bf6e02c2b2a..4976400a1438 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -782,7 +782,6 @@ static void perf_event__process_sample(const union perf_event *event, if (!syme->skip) { struct perf_evsel *evsel; - syme->origin = origin; evsel = perf_evlist__id2evsel(top.evlist, sample->id); assert(evsel != NULL); syme->count[evsel->idx]++; -- cgit v1.2.2 From 878b439dccd064d6908800fab0b47bd3c3a87ebb Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 11 Mar 2011 13:13:36 -0300 Subject: perf symbols: Rename dso->origin to dso->symtab_type And the DSO__ORIG_ enum to SYMTAB__, to clarify that this is about from where the symtab was obtained. Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Tom Zanussi LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-top.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'tools/perf/builtin-top.c') diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 4976400a1438..31ea7a68baa4 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -152,7 +152,7 @@ static int parse_source(struct sym_entry *syme) /* * We can't annotate with just /proc/kallsyms */ - if (map->dso->origin == DSO__ORIG_KERNEL) { + if (map->dso->symtab_type == SYMTAB__KALLSYMS) { pr_err("Can't annotate %s: No vmlinux file was found in the " "path\n", sym->name); sleep(1); @@ -769,7 +769,7 @@ static void perf_event__process_sample(const union perf_event *event, struct symbol *sym = sym_entry__symbol(top.sym_filter_entry); pr_err("Can't annotate %s", sym->name); - if (top.sym_filter_entry->map->dso->origin == DSO__ORIG_KERNEL) { + if (top.sym_filter_entry->map->dso->symtab_type == SYMTAB__KALLSYMS) { pr_err(": No vmlinux file was found in the path:\n"); machine__fprintf_vmlinux_path(machine, stderr); } else -- cgit v1.2.2 From 171b3be9c42e97cd4530706654242f6a3efb6ac3 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 11 Mar 2011 13:36:01 -0300 Subject: perf symbol: Move sym_entry->skip to symbol->ignore While going thru each of the sym_entry fields looking to reduce it to the set of entries needed when in an active symbols list, 'skip' should really be in symbol, as we set it when loading the symtab. And the space used by the basic symbol allocation remains the same as we had 5 bytes of padding. Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Tom Zanussi LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-top.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'tools/perf/builtin-top.c') diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 31ea7a68baa4..70f1075cc5b0 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -676,7 +676,7 @@ static int symbol_filter(struct map *map, struct symbol *sym) for (i = 0; skip_symbols[i]; i++) { if (!strcmp(skip_symbols[i], name)) { - syme->skip = 1; + sym->ignore = true; break; } } @@ -779,7 +779,7 @@ static void perf_event__process_sample(const union perf_event *event, } syme = symbol__priv(al.sym); - if (!syme->skip) { + if (!al.sym->ignore) { struct perf_evsel *evsel; evsel = perf_evlist__id2evsel(top.evlist, sample->id); -- cgit v1.2.2 From ce2d17ca7f85dcade62cd608601a0d52ccdaf0e6 Mon Sep 17 00:00:00 2001 From: Akihiro Nagai Date: Wed, 23 Mar 2011 16:29:39 +0900 Subject: perf top: Fix uninitialized 'counter' variable builtin-top.c has an uninitialized variable. gcc(version 4.5.1) warns about it and it results in build failure: builtin-top.c: In function 'display_thread': builtin-top.c:518:9: error: 'counter' may be used uninitialized This situation can indeed trigger, if the getline() call in prompt_integer() fails. Signed-off-by: Akihiro Nagai Cc: Arnaldo Carvalho de Melo Cc: Masami Hiramatsu Cc: Paul Mackerras Cc: Peter Zijlstra LKML-Reference: <20110323072939.11638.50173.stgit@localhost6.localdomain6> Signed-off-by: Ingo Molnar --- tools/perf/builtin-top.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'tools/perf/builtin-top.c') diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 70f1075cc5b0..676b4fb0070f 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -515,7 +515,9 @@ static void handle_keypress(struct perf_session *session, int c) break; case 'E': if (top.evlist->nr_entries > 1) { - int counter; + /* Select 0 as the default event: */ + int counter = 0; + fprintf(stderr, "\nAvailable events:"); list_for_each_entry(top.sym_evsel, &top.evlist->entries, node) -- cgit v1.2.2 From c286c419c784c238cd699be37fec7a9acc30d89f Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 28 Mar 2011 09:50:11 -0300 Subject: perf tools: Fixup exit path when not able to open events We have to deal with the TUI mode in perf top, so that we don't end up with a garbled screen when, say, a non root user on a machine with a paranoid setting (the default) tries to use 'perf top'. Introduce a ui__warning_paranoid() routine shared by top and record that tells the user the valid values for /proc/sys/kernel/perf_event_paranoid. Cc: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Tom Zanussi LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-top.c | 38 ++++++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 14 deletions(-) (limited to 'tools/perf/builtin-top.c') diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 676b4fb0070f..935fc4fd878e 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -850,10 +850,10 @@ try_again: top.evlist->threads, group, inherit) < 0) { int err = errno; - if (err == EPERM || err == EACCES) - die("Permission error - are you root?\n" - "\t Consider tweaking" - " /proc/sys/kernel/perf_event_paranoid.\n"); + if (err == EPERM || err == EACCES) { + ui__warning_paranoid(); + goto out_err; + } /* * If it's cycles then fall back to hrtimer * based cpu-clock-tick sw counter, which @@ -861,25 +861,35 @@ try_again: */ if (attr->type == PERF_TYPE_HARDWARE && attr->config == PERF_COUNT_HW_CPU_CYCLES) { - if (verbose) - warning(" ... trying to fall back to cpu-clock-ticks\n"); + ui__warning("Cycles event not supported,\n" + "trying to fall back to cpu-clock-ticks\n"); attr->type = PERF_TYPE_SOFTWARE; attr->config = PERF_COUNT_SW_CPU_CLOCK; goto try_again; } - printf("\n"); - error("sys_perf_event_open() syscall returned with %d " - "(%s). /bin/dmesg may provide additional information.\n", - err, strerror(err)); - die("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); - exit(-1); + + ui__warning("The sys_perf_event_open() syscall " + "returned with %d (%s). /bin/dmesg " + "may provide additional information.\n" + "No CONFIG_PERF_EVENTS=y kernel support " + "configured?\n", err, strerror(err)); + goto out_err; } } - if (perf_evlist__mmap(evlist, mmap_pages, false) < 0) - die("failed to mmap with %d (%s)\n", errno, strerror(errno)); + if (perf_evlist__mmap(evlist, mmap_pages, false) < 0) { + ui__warning("Failed to mmap with %d (%s)\n", + errno, strerror(errno)); + goto out_err; + } + + return; + +out_err: + exit_browser(0); + exit(0); } static int __cmd_top(void) -- cgit v1.2.2 From ca6a42586fae639ff9e5285d9bdc550fcb1b8d41 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Fri, 25 Mar 2011 13:11:11 -0600 Subject: perf tools: Emit clearer message for sys_perf_event_open ENOENT return Resend of patch sent back in January 2011 in light of recent confusion around unsupported events for a given platform. Improve sys_perf_event_open ENOENT return handling in top and record, just like 5a3446b does for stat. Retry of Arnaldo's patch using ui_warning instead of die which allows the fallback from hardware cycles to software clock. Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-kernel@vger.kernel.org LKML-Reference: <1301080271-20945-1-git-send-email-daahern@cisco.com> Signed-off-by: David Ahern [ committer note: Some adjustments to make it apply to newer codebase ] Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-top.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'tools/perf/builtin-top.c') diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 935fc4fd878e..fc1273e976c5 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -870,6 +870,12 @@ try_again: goto try_again; } + if (err == ENOENT) { + ui__warning("The %s event is not supported.\n", + event_name(counter)); + goto out_err; + } + ui__warning("The sys_perf_event_open() syscall " "returned with %d (%s). /bin/dmesg " "may provide additional information.\n" -- cgit v1.2.2 From 5d2cd90922c778908bd0cd669e572a5b5eafd737 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 14 Apr 2011 11:20:14 -0300 Subject: perf evsel: Fix use of inherit perf stat doesn't mmap and its perfectly fine for it to use task-bound counters with inheritance. So set the attr.inherit on the caller and leave the syscall itself to validate it. When the mmap fails perf_evlist__mmap will just emit a warning if this is the failure reason. Reported-by: Peter Zijlstra Acked-by: Peter Zijlstra Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Tom Zanussi Link: http://lkml.kernel.org/r/20110414170121.GC3229@ghostprotocols.net Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-top.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'tools/perf/builtin-top.c') diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index fc1273e976c5..7e3d6e310bf8 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -845,9 +845,10 @@ static void start_counters(struct perf_evlist *evlist) } attr->mmap = 1; + attr->inherit = inherit; try_again: if (perf_evsel__open(counter, top.evlist->cpus, - top.evlist->threads, group, inherit) < 0) { + top.evlist->threads, group) < 0) { int err = errno; if (err == EPERM || err == EACCES) { -- cgit v1.2.2 From aece948f5ddd70d70df2f35855c706ef9a4f62e2 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sun, 15 May 2011 09:39:00 -0300 Subject: perf evlist: Fix per thread mmap setup The PERF_EVENT_IOC_SET_OUTPUT ioctl was returning -EINVAL when using --pid when monitoring multithreaded apps, as we can only share a ring buffer for events on the same thread if not doing per cpu. Fix it by using per thread ring buffers. Tested with: [root@felicio ~]# tuna -t 26131 -CP | nl 1 thread ctxt_switches 2 pid SCHED_ rtpri affinity voluntary nonvoluntary cmd 3 26131 OTHER 0 0,1 10814276 2397830 chromium-browse 4 642 OTHER 0 0,1 14688 0 chromium-browse 5 26148 OTHER 0 0,1 713602 115479 chromium-browse 6 26149 OTHER 0 0,1 801958 2262 chromium-browse 7 26150 OTHER 0 0,1 1271128 248 chromium-browse 8 26151 OTHER 0 0,1 3 0 chromium-browse 9 27049 OTHER 0 0,1 36796 9 chromium-browse 10 618 OTHER 0 0,1 14711 0 chromium-browse 11 661 OTHER 0 0,1 14593 0 chromium-browse 12 29048 OTHER 0 0,1 28125 0 chromium-browse 13 26143 OTHER 0 0,1 2202789 781 chromium-browse [root@felicio ~]# So 11 threads under pid 26131, then: [root@felicio ~]# perf record -F 50000 --pid 26131 [root@felicio ~]# grep perf_event /proc/`pidof perf`/maps | nl 1 7fa4a2538000-7fa4a25b9000 rwxs 00000000 00:09 4064 anon_inode:[perf_event] 2 7fa4a25b9000-7fa4a263a000 rwxs 00000000 00:09 4064 anon_inode:[perf_event] 3 7fa4a263a000-7fa4a26bb000 rwxs 00000000 00:09 4064 anon_inode:[perf_event] 4 7fa4a26bb000-7fa4a273c000 rwxs 00000000 00:09 4064 anon_inode:[perf_event] 5 7fa4a273c000-7fa4a27bd000 rwxs 00000000 00:09 4064 anon_inode:[perf_event] 6 7fa4a27bd000-7fa4a283e000 rwxs 00000000 00:09 4064 anon_inode:[perf_event] 7 7fa4a283e000-7fa4a28bf000 rwxs 00000000 00:09 4064 anon_inode:[perf_event] 8 7fa4a28bf000-7fa4a2940000 rwxs 00000000 00:09 4064 anon_inode:[perf_event] 9 7fa4a2940000-7fa4a29c1000 rwxs 00000000 00:09 4064 anon_inode:[perf_event] 10 7fa4a29c1000-7fa4a2a42000 rwxs 00000000 00:09 4064 anon_inode:[perf_event] 11 7fa4a2a42000-7fa4a2ac3000 rwxs 00000000 00:09 4064 anon_inode:[perf_event] [root@felicio ~]# 11 mmaps, one per thread since we didn't specify any CPU list, so we need one mmap per thread and: [root@felicio ~]# perf record -F 50000 --pid 26131 ^M ^C[ perf record: Woken up 79 times to write data ] [ perf record: Captured and wrote 20.614 MB perf.data (~900639 samples) ] [root@felicio ~]# perf report -D | grep PERF_RECORD_SAMPLE | cut -d/ -f2 | cut -d: -f1 | sort -n | uniq -c | sort -nr | nl 1 371310 26131 2 96516 26148 3 95694 26149 4 95203 26150 5 7291 26143 6 87 27049 7 76 661 8 60 29048 9 47 618 10 43 642 [root@felicio ~]# Ok, one of the threads, 26151 was quiescent, so no samples there, but all the others are there. Then, if I specify one CPU: [root@felicio ~]# perf record -F 50000 --pid 26131 --cpu 1 ^C[ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.680 MB perf.data (~29730 samples) ] [root@felicio ~]# perf report -D | grep PERF_RECORD_SAMPLE | cut -d/ -f2 | cut -d: -f1 | sort -n | uniq -c | sort -nr | nl 1 8444 26131 2 2584 26149 3 2518 26148 4 2324 26150 5 123 26143 6 9 661 7 9 29048 [root@felicio ~]# This machine has two cores, so fewer threads appeared on the radar, and: [root@felicio ~]# grep perf_event /proc/`pidof perf`/maps | nl 1 7f484b922000-7f484b9a3000 rwxs 00000000 00:09 4064 anon_inode:[perf_event] [root@felicio ~]# Just one mmap, as now we can use just one per-cpu buffer instead of the per-thread needed in the previous case. For global profiling: [root@felicio ~]# perf record -F 50000 -a ^C[ perf record: Woken up 26 times to write data ] [ perf record: Captured and wrote 7.128 MB perf.data (~311412 samples) ] [root@felicio ~]# grep perf_event /proc/`pidof perf`/maps | nl 1 7fb49b435000-7fb49b4b6000 rwxs 00000000 00:09 4064 anon_inode:[perf_event] 2 7fb49b4b6000-7fb49b537000 rwxs 00000000 00:09 4064 anon_inode:[perf_event] [root@felicio ~]# It uses per-cpu buffers. For just one thread: [root@felicio ~]# perf record -F 50000 --tid 26148 ^C[ perf record: Woken up 2 times to write data ] [ perf record: Captured and wrote 0.330 MB perf.data (~14426 samples) ] [root@felicio ~]# perf report -D | grep PERF_RECORD_SAMPLE | cut -d/ -f2 | cut -d: -f1 | sort -n | uniq -c | sort -nr | nl 1 9969 26148 [root@felicio ~]# [root@felicio ~]# grep perf_event /proc/`pidof perf`/maps | nl 1 7f286a51b000-7f286a59c000 rwxs 00000000 00:09 4064 anon_inode:[perf_event] [root@felicio ~]# Tested-by: David Ahern Tested-by: Lin Ming Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Tom Zanussi Link: http://lkml.kernel.org/r/20110426204401.GB1746@ghostprotocols.net Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-top.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'tools/perf/builtin-top.c') diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 7e3d6e310bf8..ebfc7cf5f63b 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -801,12 +801,12 @@ static void perf_event__process_sample(const union perf_event *event, } } -static void perf_session__mmap_read_cpu(struct perf_session *self, int cpu) +static void perf_session__mmap_read_idx(struct perf_session *self, int idx) { struct perf_sample sample; union perf_event *event; - while ((event = perf_evlist__read_on_cpu(top.evlist, cpu)) != NULL) { + while ((event = perf_evlist__mmap_read(top.evlist, idx)) != NULL) { perf_session__parse_sample(self, event, &sample); if (event->header.type == PERF_RECORD_SAMPLE) @@ -820,8 +820,8 @@ static void perf_session__mmap_read(struct perf_session *self) { int i; - for (i = 0; i < top.evlist->cpus->nr; i++) - perf_session__mmap_read_cpu(self, i); + for (i = 0; i < top.evlist->nr_mmaps; i++) + perf_session__mmap_read_idx(self, i); } static void start_counters(struct perf_evlist *evlist) -- cgit v1.2.2 From 5538becaec9ca2ff21e7826372941dc46f498487 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Sun, 22 May 2011 02:17:22 +0200 Subject: perf tools: Propagate event parse error handling Better handle event parsing error by propagating the details in upper layers or by dumping some failure message. So that the user knows he has some crazy events in the batch. Signed-off-by: Frederic Weisbecker Cc: Ingo Molnar Cc: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Stephane Eranian --- tools/perf/builtin-top.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'tools/perf/builtin-top.c') diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 7e3d6e310bf8..74f533cbf6ca 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -805,9 +805,14 @@ static void perf_session__mmap_read_cpu(struct perf_session *self, int cpu) { struct perf_sample sample; union perf_event *event; + int ret; while ((event = perf_evlist__read_on_cpu(top.evlist, cpu)) != NULL) { - perf_session__parse_sample(self, event, &sample); + ret = perf_session__parse_sample(self, event, &sample); + if (ret) { + pr_err("Can't parse sample, err = %d\n", ret); + continue; + } if (event->header.type == PERF_RECORD_SAMPLE) perf_event__process_sample(event, &sample, self); -- cgit v1.2.2 From 59fb1ee95e74e8e0777289c44300cbe812aca836 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 27 May 2011 11:14:00 -0300 Subject: perf top: Remove unused macro Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Tom Zanussi Link: http://lkml.kernel.org/n/tip-weqbs0tkk2u0qp1xxdxxosfg@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-top.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'tools/perf/builtin-top.c') diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 2d7934e9de38..375ed160d936 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -62,8 +62,6 @@ #include #include -#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) - static struct perf_top top = { .count_filter = 5, .delay_secs = 2, -- cgit v1.2.2 From 5f6f55809758e106eca72c6e01402c8080a88ee8 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 27 May 2011 11:53:28 -0300 Subject: perf top: Handle kptr_restrict Reported-by: Ingo Molnar Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Tom Zanussi Link: http://lkml.kernel.org/n/tip-cyl5zmi1nu35vyu7l5im2pyv@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-top.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'tools/perf/builtin-top.c') diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 375ed160d936..472f62790022 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -80,6 +80,7 @@ static bool use_tui, use_stdio; static int default_interval = 0; +static bool kptr_restrict_warned; static bool inherit = false; static int realtime_prio = 0; static bool group = false; @@ -738,6 +739,20 @@ static void perf_event__process_sample(const union perf_event *event, al.filtered) return; + if (!kptr_restrict_warned && + symbol_conf.kptr_restrict && + al.cpumode == PERF_RECORD_MISC_KERNEL) { + ui__warning( +"Kernel address maps (/proc/{kallsyms,modules}) are restricted.\n\n" +"Check /proc/sys/kernel/kptr_restrict.\n\n" +"Kernel%s samples will not be resolved.\n", + !RB_EMPTY_ROOT(&al.map->dso->symbols[MAP__FUNCTION]) ? + " modules" : ""); + if (use_browser <= 0) + sleep(5); + kptr_restrict_warned = true; + } + if (al.sym == NULL) { /* * As we do lazy loading of symtabs we only will know if the -- cgit v1.2.2 From e4a338d05df93ab1ebf291aca1e753064319d301 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 27 May 2011 13:42:16 -0300 Subject: perf top: Don't stop if no kernel symtab is found We now just warn the user about the fact and go on providing just userspace samples. This fixes a problem when no vmlinux is explicetely passed by the user, thus symbol_conf.vmlinux_name is NULL, no suitable vmlinux is found, and then we get: aldebaran:~> perf top -p 7557 [kernel.kallsyms] with build id 44d9a989eabbd79e486bc079d6b743d397c204e0 not found, continuing without symbols The (null) file can't be used Reported-by: Ingo Molnar Cc: Frederic Weisbecker Cc: Mike Galbraith Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Tom Zanussi Link: http://lkml.kernel.org/n/tip-cj2g81hn64wv2bipmqk4fy2m@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-top.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) (limited to 'tools/perf/builtin-top.c') diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 472f62790022..f2f3f4937aa2 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -81,6 +81,7 @@ static bool use_tui, use_stdio; static int default_interval = 0; static bool kptr_restrict_warned; +static bool vmlinux_warned; static bool inherit = false; static int realtime_prio = 0; static bool group = false; @@ -754,6 +755,7 @@ static void perf_event__process_sample(const union perf_event *event, } if (al.sym == NULL) { + const char *msg = "Kernel samples will not be resolved.\n"; /* * As we do lazy loading of symtabs we only will know if the * specified vmlinux file is invalid when we actually have a @@ -765,12 +767,20 @@ static void perf_event__process_sample(const union perf_event *event, * --hide-kernel-symbols, even if the user specifies an * invalid --vmlinux ;-) */ - if (al.map == machine->vmlinux_maps[MAP__FUNCTION] && + if (!kptr_restrict_warned && !vmlinux_warned && + al.map == machine->vmlinux_maps[MAP__FUNCTION] && RB_EMPTY_ROOT(&al.map->dso->symbols[MAP__FUNCTION])) { - ui__warning("The %s file can't be used\n", - symbol_conf.vmlinux_name); - exit_browser(0); - exit(1); + if (symbol_conf.vmlinux_name) { + ui__warning("The %s file can't be used.\n%s", + symbol_conf.vmlinux_name, msg); + } else { + ui__warning("A vmlinux file was not found.\n%s", + msg); + } + + if (use_browser <= 0) + sleep(5); + vmlinux_warned = true; } return; -- cgit v1.2.2