diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c index 8dace181c88e51a19a8b3fb767d9d28f46b0a2f5..cf9750004a08fe673eb312414090c7b0c7759b09 100644 --- a/arch/x86/oprofile/nmi_int.c +++ b/arch/x86/oprofile/nmi_int.c @@ -49,6 +49,10 @@ u64 op_x86_get_ctrl(struct op_x86_model_spec const *model, val |= counter_config->user ? ARCH_PERFMON_EVENTSEL_USR : 0; val |= counter_config->kernel ? ARCH_PERFMON_EVENTSEL_OS : 0; val |= (counter_config->unit_mask & 0xFF) << 8; + counter_config->extra &= (ARCH_PERFMON_EVENTSEL_INV | + ARCH_PERFMON_EVENTSEL_EDGE | + ARCH_PERFMON_EVENTSEL_CMASK); + val |= counter_config->extra; event &= model->event_mask ? model->event_mask : 0xFF; val |= event & 0xFF; val |= (event & 0x0F00) << 24; @@ -440,6 +444,7 @@ static int nmi_create_files(struct super_block *sb, struct dentry *root) oprofilefs_create_ulong(sb, dir, "unit_mask", &counter_config[i].unit_mask); oprofilefs_create_ulong(sb, dir, "kernel", &counter_config[i].kernel); oprofilefs_create_ulong(sb, dir, "user", &counter_config[i].user); + oprofilefs_create_ulong(sb, dir, "extra", &counter_config[i].extra); } return 0; diff --git a/arch/x86/oprofile/op_counter.h b/arch/x86/oprofile/op_counter.h index e28398df0df2959bc391a1aa028487264e746d85..0b7b7b179cbeeff36b559ab0b0f139d616998bc1 100644 --- a/arch/x86/oprofile/op_counter.h +++ b/arch/x86/oprofile/op_counter.h @@ -22,6 +22,7 @@ struct op_counter_config { unsigned long kernel; unsigned long user; unsigned long unit_mask; + unsigned long extra; }; extern struct op_counter_config counter_config[]; diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index 311b4dc785a19b5188cdd32260b50041d3403cc6..04d75a8a20ee2b67d6c0d51cd203f36cc53adfd3 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -1086,7 +1086,7 @@ void perf_event_task_sched_out(struct task_struct *task, struct task_struct *nex { perf_sw_event(PERF_COUNT_SW_CONTEXT_SWITCHES, 1, 1, NULL, 0); - COND_STMT(&perf_sched_events, __perf_event_task_sched_out(task, next)); + __perf_event_task_sched_out(task, next); } extern void perf_event_mmap(struct vm_area_struct *vma); diff --git a/kernel/perf_event.c b/kernel/perf_event.c index c75925c4d1e29a3296bed32a6f0eeb7e6c189c29..27960f114efd73f9fb6ebec3d90952a643cd4284 100644 --- a/kernel/perf_event.c +++ b/kernel/perf_event.c @@ -145,8 +145,8 @@ static struct srcu_struct pmus_srcu; */ int sysctl_perf_event_paranoid __read_mostly = 1; -/* Minimum for 128 pages + 1 for the user control page */ -int sysctl_perf_event_mlock __read_mostly = 516; /* 'free' kb per user */ +/* Minimum for 512 kiB + 1 user control page */ +int sysctl_perf_event_mlock __read_mostly = 512 + (PAGE_SIZE / 1024); /* 'free' kiB per user */ /* * max perf event sample rate @@ -6531,6 +6531,11 @@ SYSCALL_DEFINE5(perf_event_open, goto err_alloc; } + if (task) { + put_task_struct(task); + task = NULL; + } + /* * Look up the group leader (we will attach this event to it): */ diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 158c30e8210c64f7bde2915a7fee4700ee6a4cdd..207dee5c5b163fd51ceafbb6b171df9c0708893f 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile @@ -165,8 +165,12 @@ grep-libs = $(filter -l%,$(1)) strip-libs = $(filter-out -l%,$(1)) $(OUTPUT)python/perf.so: $(PYRF_OBJS) - $(QUIET_GEN)python util/setup.py --quiet build_ext --build-lib='$(OUTPUT)python' \ - --build-temp='$(OUTPUT)python/temp' + $(QUIET_GEN)( \ + export CFLAGS="$(BASIC_CFLAGS)"; \ + python util/setup.py --quiet build_ext --build-lib='$(OUTPUT)python' \ + --build-temp='$(OUTPUT)python/temp' \ + ) + # # No Perl scripts right now: # diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 6febcc168a8cc261e2dc10314ef082d40c717ec8..17d1dcb3c66771cb1d7603cff6a5ed981d44ca69 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -41,7 +41,7 @@ static u64 user_interval = ULLONG_MAX; static u64 default_interval = 0; static unsigned int page_size; -static unsigned int mmap_pages = 128; +static unsigned int mmap_pages = UINT_MAX; static unsigned int user_freq = UINT_MAX; static int freq = 1000; static int output; @@ -275,11 +275,10 @@ static void open_counters(struct perf_evlist *evlist) !no_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"); - else if (err == ENODEV && cpu_list) { + if (err == EPERM || err == EACCES) { + ui__warning_paranoid(); + exit(EXIT_FAILURE); + } else if (err == ENODEV && cpu_list) { die("No such device - did you specify" " an out-of-range profile CPU?\n"); } else if (err == EINVAL && sample_id_all_avail) { @@ -302,11 +301,19 @@ static void open_counters(struct perf_evlist *evlist) && attr->config == PERF_COUNT_HW_CPU_CYCLES) { if (verbose) - warning(" ... trying to fall back to cpu-clock-ticks\n"); + ui__warning("The cycles event is not supported, " + "trying to fall back to cpu-clock-ticks\n"); attr->type = PERF_TYPE_SOFTWARE; attr->config = PERF_COUNT_SW_CPU_CLOCK; goto try_again; } + + if (err == ENOENT) { + ui__warning("The %s event is not supported.\n", + event_name(pos)); + exit(EXIT_FAILURE); + } + printf("\n"); error("sys_perf_event_open() syscall returned with %d (%s). /bin/dmesg may provide additional information.\n", err, strerror(err)); @@ -506,6 +513,10 @@ static int __cmd_record(int argc, const char **argv) if (have_tracepoints(&evsel_list->entries)) perf_header__set_feat(&session->header, HEADER_TRACE_INFO); + /* 512 kiB: default amount of unprivileged mlocked memory */ + if (mmap_pages == UINT_MAX) + mmap_pages = (512 * 1024) / page_size; + if (forks) { child_pid = fork(); if (child_pid < 0) { diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 676b4fb0070f09be3d09fcb253f776754f7f711c..fc1273e976c58f4c25d6321abf578392ba1126ad 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -850,10 +850,10 @@ static void start_counters(struct perf_evlist *evlist) 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,41 @@ static void start_counters(struct perf_evlist *evlist) */ 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); + + 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" + "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) diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c index d4536a9e0d8cc35a4d1cf49f677cf97932f99482..155749d74350a670c166ed14d7f8f4629e4bea23 100644 --- a/tools/perf/util/debug.c +++ b/tools/perf/util/debug.c @@ -57,6 +57,16 @@ void ui__warning(const char *format, ...) } #endif +void ui__warning_paranoid(void) +{ + ui__warning("Permission error - are you root?\n" + "Consider tweaking /proc/sys/kernel/perf_event_paranoid:\n" + " -1 - Not paranoid at all\n" + " 0 - Disallow raw tracepoint access for unpriv\n" + " 1 - Disallow cpu events for unpriv\n" + " 2 - Disallow kernel profiling for unpriv\n"); +} + void trace_event(union perf_event *event) { unsigned char *raw_event = (void *)event; diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h index 93516cf4682ca3127ca36e26049bdfb92681f59f..fd53db47e3de1200ce0229629410b5d8006d1652 100644 --- a/tools/perf/util/debug.h +++ b/tools/perf/util/debug.h @@ -36,5 +36,6 @@ int ui_helpline__show_help(const char *format, va_list ap); #endif void ui__warning(const char *format, ...) __attribute__((format(printf, 1, 2))); +void ui__warning_paranoid(void); #endif /* __PERF_DEBUG_H */ diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 2b15c362ef568e2ac8b11a581f36ee52f789c2d5..1023f67633a4c16ada61dc8f69796016283dabd4 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -710,7 +710,7 @@ void thread__find_addr_map(struct thread *self, * in the whole kernel symbol list. */ if ((long long)al->addr < 0 && - cpumode == PERF_RECORD_MISC_KERNEL && + cpumode == PERF_RECORD_MISC_USER && machine && mg != &machine->kmaps) { mg = &machine->kmaps; goto try_again; diff --git a/tools/perf/util/setup.py b/tools/perf/util/setup.py index e24ffadb20b29f91cd835914512c7fc9a3f08215..bbc982f5dd8b9ced999577ced4822a21c9a28779 100644 --- a/tools/perf/util/setup.py +++ b/tools/perf/util/setup.py @@ -1,13 +1,18 @@ #!/usr/bin/python2 from distutils.core import setup, Extension +from os import getenv + +cflags = ['-fno-strict-aliasing', '-Wno-write-strings'] +cflags += getenv('CFLAGS', '').split() perf = Extension('perf', sources = ['util/python.c', 'util/ctype.c', 'util/evlist.c', 'util/evsel.c', 'util/cpumap.c', 'util/thread_map.c', 'util/util.c', 'util/xyarray.c', 'util/cgroup.c'], include_dirs = ['util/include'], - extra_compile_args = ['-fno-strict-aliasing', '-Wno-write-strings']) + extra_compile_args = cflags, + ) setup(name='perf', version='0.1', diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 17df793c89243a44324c5c0deafa45807d0b7f6b..f06c10f092ba53036a379a3c05983e3e928808aa 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -1196,6 +1196,8 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name, if (curr_dso == NULL) goto out_elf_end; curr_dso->kernel = self->kernel; + curr_dso->long_name = self->long_name; + curr_dso->long_name_len = self->long_name_len; curr_map = map__new2(start, curr_dso, map->type); if (curr_map == NULL) { @@ -1842,6 +1844,7 @@ int dso__load_vmlinux(struct dso *self, struct map *map, if (fd < 0) return -1; + dso__set_long_name(self, (char *)vmlinux); dso__set_loaded(self, map->type); err = dso__load_sym(self, map, symfs_vmlinux, fd, filter, 0, 0); close(fd); @@ -2403,6 +2406,8 @@ int symbol__init(void) if (symbol_conf.initialized) return 0; + symbol_conf.priv_size = ALIGN(symbol_conf.priv_size, sizeof(u64)); + elf_version(EV_CURRENT); if (symbol_conf.sort_by_name) symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) -