From f006d25a15216a483cec71e886786874f66f9452 Mon Sep 17 00:00:00 2001 From: Han Pingtian Date: Thu, 6 Jan 2011 17:39:22 +0800 Subject: perf tools: Fix buffer overflow error when specifying all tracepoints I found when specifying all tracepoints with -e to one of subcommand, such as 'stat', the program will trigger a buffer overflow error, like this: *** buffer overflow detected ***: ./perf terminated ======= Backtrace: ========= /lib64/libc.so.6(__fortify_fail+0x37)[0x382cefb2c7] .... The tracepoints are separated by comma, something like this: $ perf stat -a -e `perf list |grep Tracepoint|awk -F'[' '{gsub(/[[:space:]]+/,"",$1);array[FNR]=$1}END{outputs=array[1];for (i=2;i<=FNR;i++){ outputs=outputs "," array[i];};print outputs}'` The root reason of this problem is that store_event_type() is called for all events, and will overflow the 'filename' at: strncat(filename, orgname, strlen(orgname)); This patch fixes it by calling store_event_type() only when the event name has been found. LKML-Reference: <20110106093922.GB6713@hpt.nay.redhat.com> Signed-off-by: Han Pingtian Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/parse-events.c | 61 +++++++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 31 deletions(-) (limited to 'tools') diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 649083f27e08..917a0ca521c1 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -490,6 +490,31 @@ parse_multiple_tracepoint_event(char *sys_name, const char *evt_exp, return EVT_HANDLED_ALL; } +static int store_event_type(const char *orgname) +{ + char filename[PATH_MAX], *c; + FILE *file; + int id, n; + + sprintf(filename, "%s/", debugfs_path); + strncat(filename, orgname, strlen(orgname)); + strcat(filename, "/id"); + + c = strchr(filename, ':'); + if (c) + *c = '/'; + + file = fopen(filename, "r"); + if (!file) + return 0; + n = fscanf(file, "%i", &id); + fclose(file); + if (n < 1) { + pr_err("cannot store event ID\n"); + return -EINVAL; + } + return perf_header__push_event(id, orgname); +} static enum event_result parse_tracepoint_event(const char **strp, struct perf_event_attr *attr) @@ -533,9 +558,13 @@ static enum event_result parse_tracepoint_event(const char **strp, *strp += strlen(sys_name) + evt_length; return parse_multiple_tracepoint_event(sys_name, evt_name, flags); - } else + } else { + if (store_event_type(evt_name) < 0) + return EVT_FAILED; + return parse_single_tracepoint_event(sys_name, evt_name, evt_length, attr, strp); + } } static enum event_result @@ -778,41 +807,11 @@ modifier: return ret; } -static int store_event_type(const char *orgname) -{ - char filename[PATH_MAX], *c; - FILE *file; - int id, n; - - sprintf(filename, "%s/", debugfs_path); - strncat(filename, orgname, strlen(orgname)); - strcat(filename, "/id"); - - c = strchr(filename, ':'); - if (c) - *c = '/'; - - file = fopen(filename, "r"); - if (!file) - return 0; - n = fscanf(file, "%i", &id); - fclose(file); - if (n < 1) { - pr_err("cannot store event ID\n"); - return -EINVAL; - } - return perf_header__push_event(id, orgname); -} - int parse_events(const struct option *opt __used, const char *str, int unset __used) { struct perf_event_attr attr; enum event_result ret; - if (strchr(str, ':')) - if (store_event_type(str) < 0) - return -1; - for (;;) { memset(&attr, 0, sizeof(attr)); ret = parse_event_symbols(&str, &attr); -- cgit v1.2.3 From 6b01f2c4f6188da50d8fe094e369a9c0390424ab Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Thu, 6 Jan 2011 15:51:53 +0100 Subject: perf tools: Build with frame pointer It seems that some gcc versions build by default with frame pointers and some others omit them. Just build the tools with frame pointers as the callchains can be an important part of the perf workflow. Cc: Ingo Molnar Cc: Peter Zijlstra Cc: Stephane Eranian LKML-Reference: <1294325513-14276-3-git-send-email-fweisbec@gmail.com> Signed-off-by: Frederic Weisbecker Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 1b9b13ee2a72..2b5387d53ba5 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile @@ -227,7 +227,7 @@ ifndef PERF_DEBUG CFLAGS_OPTIMIZE = -O6 endif -CFLAGS = -ggdb3 -Wall -Wextra -std=gnu99 -Werror $(CFLAGS_OPTIMIZE) -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS) +CFLAGS = -fno-omit-frame-pointer -ggdb3 -Wall -Wextra -std=gnu99 -Werror $(CFLAGS_OPTIMIZE) -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS) EXTLIBS = -lpthread -lrt -lelf -lm ALL_CFLAGS = $(CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 ALL_LDFLAGS = $(LDFLAGS) -- cgit v1.2.3 From 23a2f3ab46596d9fd0b0e592d2101bea90970594 Mon Sep 17 00:00:00 2001 From: Lin Ming Date: Fri, 7 Jan 2011 11:11:09 +0800 Subject: perf tools: Pass whole attr to event selectors Since commit 69aad6f1(perf tools: Introduce event selectors), only perf_event_attr::type and ::config are passed to event selector, which makes perf tool not work correctly. For example, PEBS does not work because perf_event_attr::precise_ip is not passed to the syscall. Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Peter Zijlstra LKML-Reference: <1294369869.20563.19.camel@minggr.sh.intel.com> Signed-off-by: Lin Ming Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-stat.c | 3 +-- tools/perf/builtin-test.c | 6 +++++- tools/perf/util/evsel.c | 5 ++--- tools/perf/util/evsel.h | 2 +- tools/perf/util/parse-events.c | 13 ++++++++++--- 5 files changed, 19 insertions(+), 10 deletions(-) (limited to 'tools') diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 02b2d8013a61..2dfcb613e66b 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -683,8 +683,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used) nr_counters = ARRAY_SIZE(default_attrs); for (c = 0; c < ARRAY_SIZE(default_attrs); ++c) { - pos = perf_evsel__new(default_attrs[c].type, - default_attrs[c].config, + pos = perf_evsel__new(&default_attrs[c], nr_counters); if (pos == NULL) goto out; diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c index 1c984342a579..e12753f976a1 100644 --- a/tools/perf/builtin-test.c +++ b/tools/perf/builtin-test.c @@ -264,6 +264,7 @@ static int test__open_syscall_event(void) int err = -1, fd; struct thread_map *threads; struct perf_evsel *evsel; + struct perf_event_attr attr; unsigned int nr_open_calls = 111, i; int id = trace_event__id("sys_enter_open"); @@ -278,7 +279,10 @@ static int test__open_syscall_event(void) return -1; } - evsel = perf_evsel__new(PERF_TYPE_TRACEPOINT, id, 0); + memset(&attr, 0, sizeof(attr)); + attr.type = PERF_TYPE_TRACEPOINT; + attr.config = id; + evsel = perf_evsel__new(&attr, 0); if (evsel == NULL) { pr_debug("perf_evsel__new\n"); goto out_thread_map_delete; diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index c95267e63c5b..1a5591d7a245 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -6,14 +6,13 @@ #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) -struct perf_evsel *perf_evsel__new(u32 type, u64 config, int idx) +struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx) { struct perf_evsel *evsel = zalloc(sizeof(*evsel)); if (evsel != NULL) { evsel->idx = idx; - evsel->attr.type = type; - evsel->attr.config = config; + evsel->attr = *attr; INIT_LIST_HEAD(&evsel->node); } diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index a0ccd69c3fc2..b2d755fe88a5 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h @@ -37,7 +37,7 @@ struct perf_evsel { struct cpu_map; struct thread_map; -struct perf_evsel *perf_evsel__new(u32 type, u64 config, int idx); +struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx); void perf_evsel__delete(struct perf_evsel *evsel); int perf_evsel__alloc_fd(struct perf_evsel *evsel, int ncpus, int nthreads); diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 917a0ca521c1..5cb6f4bde905 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -823,7 +823,7 @@ int parse_events(const struct option *opt __used, const char *str, int unset __u if (ret != EVT_HANDLED_ALL) { struct perf_evsel *evsel; - evsel = perf_evsel__new(attr.type, attr.config, + evsel = perf_evsel__new(&attr, nr_counters); if (evsel == NULL) return -1; @@ -1013,8 +1013,15 @@ void print_events(void) int perf_evsel_list__create_default(void) { - struct perf_evsel *evsel = perf_evsel__new(PERF_TYPE_HARDWARE, - PERF_COUNT_HW_CPU_CYCLES, 0); + struct perf_evsel *evsel; + struct perf_event_attr attr; + + memset(&attr, 0, sizeof(attr)); + attr.type = PERF_TYPE_HARDWARE; + attr.config = PERF_COUNT_HW_CPU_CYCLES; + + evsel = perf_evsel__new(&attr, 0); + if (evsel == NULL) return -ENOMEM; -- cgit v1.2.3 From e462dc553ea5e09d4713e7c35a11ed331dc6f369 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 10 Jan 2011 10:48:47 -0200 Subject: perf sched: Fix allocation result check Bug introduced in ce47dc56. Reported-by: Mike Galbraith Cc: Chris Samuel 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-sched.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index 7a4ebeb8b016..54024d2a017e 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c @@ -1861,7 +1861,7 @@ static int __cmd_record(int argc, const char **argv) rec_argc = ARRAY_SIZE(record_args) + argc - 1; rec_argv = calloc(rec_argc + 1, sizeof(char *)); - if (rec_argv) + if (rec_argv == NULL) return -ENOMEM; for (i = 0; i < ARRAY_SIZE(record_args); i++) -- cgit v1.2.3 From 5a3446bc648d86a99a895e93d28d7df00bbbfb3c Mon Sep 17 00:00:00 2001 From: David Ahern Date: Sun, 9 Jan 2011 11:21:12 -0700 Subject: perf stat: better error message for unsupported events For unsupported events (e.g., H/W events when running in a VM) perf stat currently fails with the error message: Error: open_counter returned with 2 (No such file or directory). /bin/dmesg may provide additional information. Fatal: Not all events could be opened. dmesg is of no help and it is not clear as to why it fails to open the counter. This patch changes the error message to Error: cache-misses event is not supported. Fatal: Not all events could be opened. Cc: Ingo Molnar Cc: Paul Mackerras Cc: a.p.zijlstra@chello.nl LPU-Reference: <1294597272-17335-1-git-send-email-daahern@cisco.com> Signed-off-by: David Ahern Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-stat.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'tools') diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 2dfcb613e66b..c385a63ebfd1 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -316,6 +316,8 @@ static int run_perf_stat(int argc __used, const char **argv) "\t Consider tweaking" " /proc/sys/kernel/perf_event_paranoid or running as root.", system_wide ? "system-wide " : ""); + } else if (errno == ENOENT) { + error("%s event is not supported. ", event_name(counter)); } else { error("open_counter returned with %d (%s). " "/bin/dmesg may provide additional information.\n", -- cgit v1.2.3 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-record.c | 3 +++ tools/perf/builtin-top.c | 2 ++ 2 files changed, 5 insertions(+) (limited to 'tools') diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 7bc049035484..7069bd3e90b3 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -331,6 +331,9 @@ try_again: else if (err == ENODEV && cpu_list) { die("No such device - did you specify" " an out-of-range profile CPU?\n"); + } else if (err == ENOENT) { + die("%s event is not supported. ", + event_name(evsel)); } else if (err == EINVAL && sample_id_all_avail) { /* * Old kernel, no attr->sample_id_type_all field 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.3 From 12f7e0364375ba1ba55abcc5ac082b68fb526c80 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Mon, 10 Jan 2011 14:14:23 -0200 Subject: perf sched: Use PTHREAD_STACK_MIN to avoid pthread_attr_setstacksize() fail on ppc64: /usr/include/bits/local_lim.h:#define PTHREAD_STACK_MIN 131072 therefore following set of commands: gives: perf.2.6.37test: builtin-sched.c:493: create_tasks: Assertion `!(err)' failed. So make sure we do not set stack size lower than PTHREAD_STACK_MIN. Cc: Ingo Molnar Cc: Paul Mackerras Cc: Peter Zijlstra LKML-Reference: <20110110160417.GB2685@psychotron.brq.redhat.com> Signed-off-by: Jiri Pirko Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-sched.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index 54024d2a017e..abd4b8497bc4 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c @@ -489,7 +489,8 @@ static void create_tasks(void) err = pthread_attr_init(&attr); BUG_ON(err); - err = pthread_attr_setstacksize(&attr, (size_t)(16*1024)); + err = pthread_attr_setstacksize(&attr, + (size_t) max(16 * 1024, PTHREAD_STACK_MIN)); BUG_ON(err); err = pthread_mutex_lock(&start_work_mutex); BUG_ON(err); -- cgit v1.2.3 From 0252208eb52f6fe8731a47804eddc7ba93f60a87 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 4 Jan 2011 11:55:27 -0200 Subject: perf evsel: Support perf_evsel__open(cpus > 1 && threads > 1) And a test for it: [acme@felicio linux]$ perf test 1: vmlinux symtab matches kallsyms: Ok 2: detect open syscall event: Ok 3: detect open syscall event on all cpus: Ok [acme@felicio linux]$ Translating C the test does: 1. generates different number of open syscalls on each CPU by using sched_setaffinity 2. Verifies that the expected number of events is generated on each CPU It works as expected. 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-test.c | 110 ++++++++++++++++++++++++++++++++++++++++++++++ tools/perf/util/evsel.c | 82 ++++++++++++++++++++-------------- 2 files changed, 159 insertions(+), 33 deletions(-) (limited to 'tools') diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c index e12753f976a1..ed5696198d3d 100644 --- a/tools/perf/builtin-test.c +++ b/tools/perf/builtin-test.c @@ -234,6 +234,7 @@ out: return err; } +#include "util/cpumap.h" #include "util/evsel.h" #include @@ -321,6 +322,111 @@ out_thread_map_delete: return err; } +#include + +static int test__open_syscall_event_on_all_cpus(void) +{ + int err = -1, fd, cpu; + struct thread_map *threads; + struct cpu_map *cpus; + struct perf_evsel *evsel; + struct perf_event_attr attr; + unsigned int nr_open_calls = 111, i; + cpu_set_t *cpu_set; + size_t cpu_set_size; + int id = trace_event__id("sys_enter_open"); + + if (id < 0) { + pr_debug("is debugfs mounted on /sys/kernel/debug?\n"); + return -1; + } + + threads = thread_map__new(-1, getpid()); + if (threads == NULL) { + pr_debug("thread_map__new\n"); + return -1; + } + + cpus = cpu_map__new(NULL); + if (threads == NULL) { + pr_debug("thread_map__new\n"); + return -1; + } + + cpu_set = CPU_ALLOC(cpus->nr); + + if (cpu_set == NULL) + goto out_thread_map_delete; + + cpu_set_size = CPU_ALLOC_SIZE(cpus->nr); + CPU_ZERO_S(cpu_set_size, cpu_set); + + memset(&attr, 0, sizeof(attr)); + attr.type = PERF_TYPE_TRACEPOINT; + attr.config = id; + evsel = perf_evsel__new(&attr, 0); + if (evsel == NULL) { + pr_debug("perf_evsel__new\n"); + goto out_cpu_free; + } + + if (perf_evsel__open(evsel, cpus, threads) < 0) { + pr_debug("failed to open counter: %s, " + "tweak /proc/sys/kernel/perf_event_paranoid?\n", + strerror(errno)); + goto out_evsel_delete; + } + + for (cpu = 0; cpu < cpus->nr; ++cpu) { + unsigned int ncalls = nr_open_calls + cpu; + + CPU_SET(cpu, cpu_set); + sched_setaffinity(0, cpu_set_size, cpu_set); + for (i = 0; i < ncalls; ++i) { + fd = open("/etc/passwd", O_RDONLY); + close(fd); + } + CPU_CLR(cpu, cpu_set); + } + + /* + * Here we need to explicitely preallocate the counts, as if + * we use the auto allocation it will allocate just for 1 cpu, + * as we start by cpu 0. + */ + if (perf_evsel__alloc_counts(evsel, cpus->nr) < 0) { + pr_debug("perf_evsel__alloc_counts(ncpus=%d)\n", cpus->nr); + goto out_close_fd; + } + + for (cpu = 0; cpu < cpus->nr; ++cpu) { + unsigned int expected; + + if (perf_evsel__read_on_cpu(evsel, cpu, 0) < 0) { + pr_debug("perf_evsel__open_read_on_cpu\n"); + goto out_close_fd; + } + + expected = nr_open_calls + cpu; + if (evsel->counts->cpu[cpu].val != expected) { + pr_debug("perf_evsel__read_on_cpu: expected to intercept %d calls on cpu %d, got %Ld\n", + expected, cpu, evsel->counts->cpu[cpu].val); + goto out_close_fd; + } + } + + err = 0; +out_close_fd: + perf_evsel__close_fd(evsel, 1, threads->nr); +out_evsel_delete: + perf_evsel__delete(evsel); +out_cpu_free: + CPU_FREE(cpu_set); +out_thread_map_delete: + thread_map__delete(threads); + return err; +} + static struct test { const char *desc; int (*func)(void); @@ -333,6 +439,10 @@ static struct test { .desc = "detect open syscall event", .func = test__open_syscall_event, }, + { + .desc = "detect open syscall event on all cpus", + .func = test__open_syscall_event_on_all_cpus, + }, { .func = NULL, }, diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 1a5591d7a245..f5cfed60af98 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -127,59 +127,75 @@ int __perf_evsel__read(struct perf_evsel *evsel, return 0; } -int perf_evsel__open_per_cpu(struct perf_evsel *evsel, struct cpu_map *cpus) +static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, + struct thread_map *threads) { - int cpu; + int cpu, thread; - if (evsel->fd == NULL && perf_evsel__alloc_fd(evsel, cpus->nr, 1) < 0) + if (evsel->fd == NULL && + perf_evsel__alloc_fd(evsel, cpus->nr, threads->nr) < 0) return -1; for (cpu = 0; cpu < cpus->nr; cpu++) { - FD(evsel, cpu, 0) = sys_perf_event_open(&evsel->attr, -1, - cpus->map[cpu], -1, 0); - if (FD(evsel, cpu, 0) < 0) - goto out_close; + for (thread = 0; thread < threads->nr; thread++) { + FD(evsel, cpu, thread) = sys_perf_event_open(&evsel->attr, + threads->map[thread], + cpus->map[cpu], -1, 0); + if (FD(evsel, cpu, thread) < 0) + goto out_close; + } } return 0; out_close: - while (--cpu >= 0) { - close(FD(evsel, cpu, 0)); - FD(evsel, cpu, 0) = -1; - } + do { + while (--thread >= 0) { + close(FD(evsel, cpu, thread)); + FD(evsel, cpu, thread) = -1; + } + thread = threads->nr; + } while (--cpu >= 0); return -1; } -int perf_evsel__open_per_thread(struct perf_evsel *evsel, struct thread_map *threads) +static struct { + struct cpu_map map; + int cpus[1]; +} empty_cpu_map = { + .map.nr = 1, + .cpus = { -1, }, +}; + +static struct { + struct thread_map map; + int threads[1]; +} empty_thread_map = { + .map.nr = 1, + .threads = { -1, }, +}; + +int perf_evsel__open(struct perf_evsel *evsel, + struct cpu_map *cpus, struct thread_map *threads) { - int thread; - - if (evsel->fd == NULL && perf_evsel__alloc_fd(evsel, 1, threads->nr)) - return -1; - for (thread = 0; thread < threads->nr; thread++) { - FD(evsel, 0, thread) = sys_perf_event_open(&evsel->attr, - threads->map[thread], -1, -1, 0); - if (FD(evsel, 0, thread) < 0) - goto out_close; + if (cpus == NULL) { + /* Work around old compiler warnings about strict aliasing */ + cpus = &empty_cpu_map.map; } - return 0; + if (threads == NULL) + threads = &empty_thread_map.map; -out_close: - while (--thread >= 0) { - close(FD(evsel, 0, thread)); - FD(evsel, 0, thread) = -1; - } - return -1; + return __perf_evsel__open(evsel, cpus, threads); } -int perf_evsel__open(struct perf_evsel *evsel, - struct cpu_map *cpus, struct thread_map *threads) +int perf_evsel__open_per_cpu(struct perf_evsel *evsel, struct cpu_map *cpus) { - if (threads == NULL) - return perf_evsel__open_per_cpu(evsel, cpus); + return __perf_evsel__open(evsel, cpus, &empty_thread_map.map); +} - return perf_evsel__open_per_thread(evsel, threads); +int perf_evsel__open_per_thread(struct perf_evsel *evsel, struct thread_map *threads) +{ + return __perf_evsel__open(evsel, &empty_cpu_map.map, threads); } -- cgit v1.2.3 From 3d03e2ea74103a50c23d6ab1906cf73399c0dafb Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 10 Jan 2011 21:37:57 -0200 Subject: perf session: Fix infinite loop in __perf_session__process_events In this if statement: if (head + event->header.size >= mmap_size) { if (mmaps[map_idx]) { munmap(mmaps[map_idx], mmap_size); mmaps[map_idx] = NULL; } page_offset = page_size * (head / page_size); file_offset += page_offset; head -= page_offset; goto remap; } With, for instance, these values: head=2992 event->header.size=48 mmap_size=3040 We end up endlessly looping back to remap. Off by one. Problem introduced in 55b4462. Reported-by: Linus Torvalds Reported-by: Ingo Molnar Reported-by: David Ahern Bisected-by: David Ahern Tested-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: Thomas Gleixner Cc: Tom Zanussi LKML-Reference: Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/session.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 6fb4694d05fa..313dac2d94ce 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -1007,7 +1007,7 @@ more: if (size == 0) size = 8; - if (head + event->header.size >= mmap_size) { + if (head + event->header.size > mmap_size) { if (mmaps[map_idx]) { munmap(mmaps[map_idx], mmap_size); mmaps[map_idx] = NULL; -- cgit v1.2.3