diff options
Diffstat (limited to 'tools')
41 files changed, 545 insertions, 218 deletions
diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 158c30e8210..207dee5c5b1 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-annotate.c b/tools/perf/builtin-annotate.c index 695de4b5ae6..e18eb7ed30a 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -42,9 +42,9 @@ static const char *sym_hist_filter; static int perf_evlist__add_sample(struct perf_evlist *evlist, struct perf_sample *sample, + struct perf_evsel *evsel, struct addr_location *al) { - struct perf_evsel *evsel; struct hist_entry *he; int ret; @@ -59,18 +59,6 @@ static int perf_evlist__add_sample(struct perf_evlist *evlist, return 0; } - evsel = perf_evlist__id2evsel(evlist, sample->id); - if (evsel == NULL) { - /* - * FIXME: Propagate this back, but at least we're in a builtin, - * where exit() is allowed. ;-) - */ - ui__warning("Invalid %s file, contains samples with id not in " - "its header!\n", input_name); - exit_browser(0); - exit(1); - } - he = __hists__add_entry(&evsel->hists, al, NULL, 1); if (he == NULL) return -ENOMEM; @@ -92,6 +80,7 @@ static int perf_evlist__add_sample(struct perf_evlist *evlist, static int process_sample_event(union perf_event *event, struct perf_sample *sample, + struct perf_evsel *evsel, struct perf_session *session) { struct addr_location al; @@ -103,7 +92,8 @@ static int process_sample_event(union perf_event *event, return -1; } - if (!al.filtered && perf_evlist__add_sample(session->evlist, sample, &al)) { + if (!al.filtered && + perf_evlist__add_sample(session->evlist, sample, evsel, &al)) { pr_warning("problem incrementing symbol count, " "skipping event\n"); return -1; diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index 6b7d91160ec..e8219990f8b 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c @@ -32,6 +32,7 @@ static int hists__add_entry(struct hists *self, static int diff__process_sample_event(union perf_event *event, struct perf_sample *sample, + struct perf_evsel *evsel __used, struct perf_session *session) { struct addr_location al; diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c index e29f04ed339..8dfc12bb119 100644 --- a/tools/perf/builtin-inject.c +++ b/tools/perf/builtin-inject.c @@ -43,6 +43,14 @@ static int perf_event__repipe(union perf_event *event, return perf_event__repipe_synth(event, session); } +static int perf_event__repipe_sample(union perf_event *event, + struct perf_sample *sample __used, + struct perf_evsel *evsel __used, + struct perf_session *session) +{ + return perf_event__repipe_synth(event, session); +} + static int perf_event__repipe_mmap(union perf_event *event, struct perf_sample *sample, struct perf_session *session) @@ -124,6 +132,7 @@ static int dso__inject_build_id(struct dso *self, struct perf_session *session) static int perf_event__inject_buildid(union perf_event *event, struct perf_sample *sample, + struct perf_evsel *evsel __used, struct perf_session *session) { struct addr_location al; @@ -164,7 +173,7 @@ repipe: } struct perf_event_ops inject_ops = { - .sample = perf_event__repipe, + .sample = perf_event__repipe_sample, .mmap = perf_event__repipe, .comm = perf_event__repipe, .fork = perf_event__repipe, diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c index 7f618f4e7b7..225e963df10 100644 --- a/tools/perf/builtin-kmem.c +++ b/tools/perf/builtin-kmem.c @@ -305,6 +305,7 @@ static void process_raw_event(union perf_event *raw_event __used, void *data, static int process_sample_event(union perf_event *event, struct perf_sample *sample, + struct perf_evsel *evsel __used, struct perf_session *session) { struct thread *thread = perf_session__findnew(session, event->ip.pid); diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c index 7a2a79d2cf2..9ac05aafd9b 100644 --- a/tools/perf/builtin-lock.c +++ b/tools/perf/builtin-lock.c @@ -845,7 +845,9 @@ static void dump_info(void) die("Unknown type of information\n"); } -static int process_sample_event(union perf_event *event, struct perf_sample *sample, +static int process_sample_event(union perf_event *event, + struct perf_sample *sample, + struct perf_evsel *evsel __used, struct perf_session *s) { struct thread *thread = perf_session__findnew(s, sample->tid); diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 6febcc168a8..416538248a4 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; @@ -163,6 +163,7 @@ static void config_attr(struct perf_evsel *evsel, struct perf_evlist *evlist) struct perf_event_attr *attr = &evsel->attr; int track = !evsel->idx; /* only the first counter needs these */ + attr->inherit = !no_inherit; attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | PERF_FORMAT_TOTAL_TIME_RUNNING | PERF_FORMAT_ID; @@ -251,6 +252,9 @@ static void open_counters(struct perf_evlist *evlist) { struct perf_evsel *pos; + if (evlist->cpus->map[0] < 0) + no_inherit = true; + list_for_each_entry(pos, &evlist->entries, node) { struct perf_event_attr *attr = &pos->attr; /* @@ -271,15 +275,13 @@ static void open_counters(struct perf_evlist *evlist) retry_sample_id: attr->sample_id_all = sample_id_all_avail ? 1 : 0; try_again: - if (perf_evsel__open(pos, evlist->cpus, evlist->threads, group, - !no_inherit) < 0) { + if (perf_evsel__open(pos, evlist->cpus, evlist->threads, group) < 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 +304,19 @@ try_again: && 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 +516,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-report.c b/tools/perf/builtin-report.c index b1b82009ab9..498c6f70a74 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -50,12 +50,12 @@ static symbol_filter_t annotate_init; static int perf_session__add_hist_entry(struct perf_session *session, struct addr_location *al, - struct perf_sample *sample) + struct perf_sample *sample, + struct perf_evsel *evsel) { struct symbol *parent = NULL; int err = 0; struct hist_entry *he; - struct perf_evsel *evsel; if ((sort__has_parent || symbol_conf.use_callchain) && sample->callchain) { err = perf_session__resolve_callchain(session, al->thread, @@ -64,18 +64,6 @@ static int perf_session__add_hist_entry(struct perf_session *session, return err; } - evsel = perf_evlist__id2evsel(session->evlist, sample->id); - if (evsel == NULL) { - /* - * FIXME: Propagate this back, but at least we're in a builtin, - * where exit() is allowed. ;-) - */ - ui__warning("Invalid %s file, contains samples with id %" PRIu64 " not in " - "its header!\n", input_name, sample->id); - exit_browser(0); - exit(1); - } - he = __hists__add_entry(&evsel->hists, al, parent, sample->period); if (he == NULL) return -ENOMEM; @@ -113,6 +101,7 @@ out: static int process_sample_event(union perf_event *event, struct perf_sample *sample, + struct perf_evsel *evsel, struct perf_session *session) { struct addr_location al; @@ -127,7 +116,7 @@ static int process_sample_event(union perf_event *event, if (al.filtered || (hide_unresolved && al.sym == NULL)) return 0; - if (perf_session__add_hist_entry(session, &al, sample)) { + if (perf_session__add_hist_entry(session, &al, sample, evsel)) { pr_debug("problem incrementing symbol period, skipping event\n"); return -1; } diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index a32f411faea..dcfe8873c9a 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c @@ -1603,6 +1603,7 @@ static void process_raw_event(union perf_event *raw_event __used, static int process_sample_event(union perf_event *event, struct perf_sample *sample, + struct perf_evsel *evsel __used, struct perf_session *session) { struct thread *thread; diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 9f5fc549214..ac574ea2391 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -162,19 +162,11 @@ static void print_sample_start(struct perf_sample *sample, static void process_event(union perf_event *event __unused, struct perf_sample *sample, + struct perf_evsel *evsel, struct perf_session *session, struct thread *thread) { - struct perf_event_attr *attr; - struct perf_evsel *evsel; - - evsel = perf_evlist__id2evsel(session->evlist, sample->id); - if (evsel == NULL) { - pr_err("Invalid data. Contains samples with id not in " - "its header!\n"); - return; - } - attr = &evsel->attr; + struct perf_event_attr *attr = &evsel->attr; if (output_fields[attr->type] == 0) return; @@ -244,6 +236,7 @@ static char const *input_name = "perf.data"; static int process_sample_event(union perf_event *event, struct perf_sample *sample, + struct perf_evsel *evsel, struct perf_session *session) { struct thread *thread = perf_session__findnew(session, event->ip.pid); @@ -264,7 +257,7 @@ static int process_sample_event(union perf_event *event, last_timestamp = sample->time; return 0; } - scripting_ops->process_event(event, sample, session, thread); + scripting_ops->process_event(event, sample, evsel, session, thread); session->hists.stats.total_period += sample->period; return 0; diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index e2109f9b43e..03f0e45f147 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -167,16 +167,17 @@ static int create_perf_stat_counter(struct perf_evsel *evsel) attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | PERF_FORMAT_TOTAL_TIME_RUNNING; + attr->inherit = !no_inherit; + if (system_wide) - return perf_evsel__open_per_cpu(evsel, evsel_list->cpus, false, false); + return perf_evsel__open_per_cpu(evsel, evsel_list->cpus, false); - attr->inherit = !no_inherit; if (target_pid == -1 && target_tid == -1) { attr->disabled = 1; attr->enable_on_exec = 1; } - return perf_evsel__open_per_thread(evsel, evsel_list->threads, false, false); + return perf_evsel__open_per_thread(evsel, evsel_list->threads, false); } /* diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c index 1b2106c58f6..11e3c845836 100644 --- a/tools/perf/builtin-test.c +++ b/tools/perf/builtin-test.c @@ -290,7 +290,7 @@ static int test__open_syscall_event(void) goto out_thread_map_delete; } - if (perf_evsel__open_per_thread(evsel, threads, false, false) < 0) { + if (perf_evsel__open_per_thread(evsel, threads, false) < 0) { pr_debug("failed to open counter: %s, " "tweak /proc/sys/kernel/perf_event_paranoid?\n", strerror(errno)); @@ -303,7 +303,7 @@ static int test__open_syscall_event(void) } if (perf_evsel__read_on_cpu(evsel, 0, 0) < 0) { - pr_debug("perf_evsel__open_read_on_cpu\n"); + pr_debug("perf_evsel__read_on_cpu\n"); goto out_close_fd; } @@ -365,7 +365,7 @@ static int test__open_syscall_event_on_all_cpus(void) goto out_thread_map_delete; } - if (perf_evsel__open(evsel, cpus, threads, false, false) < 0) { + if (perf_evsel__open(evsel, cpus, threads, false) < 0) { pr_debug("failed to open counter: %s, " "tweak /proc/sys/kernel/perf_event_paranoid?\n", strerror(errno)); @@ -418,7 +418,7 @@ static int test__open_syscall_event_on_all_cpus(void) continue; if (perf_evsel__read_on_cpu(evsel, cpu, 0) < 0) { - pr_debug("perf_evsel__open_read_on_cpu\n"); + pr_debug("perf_evsel__read_on_cpu\n"); err = -1; break; } @@ -529,7 +529,7 @@ static int test__basic_mmap(void) perf_evlist__add(evlist, evsels[i]); - if (perf_evsel__open(evsels[i], cpus, threads, false, false) < 0) { + if (perf_evsel__open(evsels[i], cpus, threads, false) < 0) { pr_debug("failed to open counter: %s, " "tweak /proc/sys/kernel/perf_event_paranoid?\n", strerror(errno)); diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c index 67c0459dc32..aa26f4d66d1 100644 --- a/tools/perf/builtin-timechart.c +++ b/tools/perf/builtin-timechart.c @@ -488,6 +488,7 @@ static void sched_switch(int cpu, u64 timestamp, struct trace_entry *te) static int process_sample_event(union perf_event *event __used, struct perf_sample *sample, + struct perf_evsel *evsel __used, struct perf_session *session) { struct trace_entry *te; @@ -506,6 +507,16 @@ static int process_sample_event(union perf_event *event __used, struct power_entry_old *peo; peo = (void *)te; #endif + /* + * FIXME: use evsel, its already mapped from id to perf_evsel, + * remove perf_header__find_event infrastructure bits. + * Mapping all these "power:cpu_idle" strings to the tracepoint + * ID and then just comparing against evsel->attr.config. + * + * e.g.: + * + * if (evsel->attr.config == power_cpu_idle_id) + */ event_str = perf_header__find_event(te->type); if (!event_str) diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 70f1075cc5b..7e3d6e310bf 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) @@ -843,15 +845,16 @@ 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) - 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 @@ -859,25 +862,41 @@ 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); + + 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/build-id.c b/tools/perf/util/build-id.c index 31f934af986..a91cd99f26e 100644 --- a/tools/perf/util/build-id.c +++ b/tools/perf/util/build-id.c @@ -16,6 +16,7 @@ static int build_id__mark_dso_hit(union perf_event *event, struct perf_sample *sample __used, + struct perf_evsel *evsel __used, struct perf_session *session) { struct addr_location al; diff --git a/tools/perf/util/cgroup.c b/tools/perf/util/cgroup.c index 9fea7553522..96bee5c4600 100644 --- a/tools/perf/util/cgroup.c +++ b/tools/perf/util/cgroup.c @@ -13,7 +13,7 @@ cgroupfs_find_mountpoint(char *buf, size_t maxlen) { FILE *fp; char mountpoint[MAX_PATH+1], tokens[MAX_PATH+1], type[MAX_PATH+1]; - char *token, *saved_ptr; + char *token, *saved_ptr = NULL; int found = 0; fp = fopen("/proc/mounts", "r"); diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c index d4536a9e0d8..155749d7435 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 93516cf4682..fd53db47e3d 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 2b15c362ef5..1023f67633a 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -710,7 +710,7 @@ try_again: * 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/evlist.c b/tools/perf/util/evlist.c index d852cefa20d..45da8d186b4 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -12,6 +12,7 @@ #include "evlist.h" #include "evsel.h" #include "util.h" +#include "debug.h" #include <sys/mman.h> @@ -250,15 +251,19 @@ int perf_evlist__alloc_mmap(struct perf_evlist *evlist) return evlist->mmap != NULL ? 0 : -ENOMEM; } -static int __perf_evlist__mmap(struct perf_evlist *evlist, int cpu, int prot, - int mask, int fd) +static int __perf_evlist__mmap(struct perf_evlist *evlist, struct perf_evsel *evsel, + int cpu, int prot, int mask, int fd) { evlist->mmap[cpu].prev = 0; evlist->mmap[cpu].mask = mask; evlist->mmap[cpu].base = mmap(NULL, evlist->mmap_len, prot, MAP_SHARED, fd, 0); - if (evlist->mmap[cpu].base == MAP_FAILED) + if (evlist->mmap[cpu].base == MAP_FAILED) { + if (evlist->cpus->map[cpu] == -1 && evsel->attr.inherit) + ui__warning("Inherit is not allowed on per-task " + "events using mmap.\n"); return -1; + } perf_evlist__add_pollfd(evlist, fd); return 0; @@ -312,7 +317,8 @@ int perf_evlist__mmap(struct perf_evlist *evlist, int pages, bool overwrite) if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, FD(first_evsel, cpu, 0)) != 0) goto out_unmap; - } else if (__perf_evlist__mmap(evlist, cpu, prot, mask, fd) < 0) + } else if (__perf_evlist__mmap(evlist, evsel, cpu, + prot, mask, fd) < 0) goto out_unmap; if ((evsel->attr.read_format & PERF_FORMAT_ID) && diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 662596afd7f..d6fd59beb86 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -175,7 +175,7 @@ int __perf_evsel__read(struct perf_evsel *evsel, } static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, - struct thread_map *threads, bool group, bool inherit) + struct thread_map *threads, bool group) { int cpu, thread; unsigned long flags = 0; @@ -192,19 +192,6 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, for (cpu = 0; cpu < cpus->nr; cpu++) { int group_fd = -1; - /* - * Don't allow mmap() of inherited per-task counters. This - * would create a performance issue due to all children writing - * to the same buffer. - * - * FIXME: - * Proper fix is not to pass 'inherit' to perf_evsel__open*, - * but a 'flags' parameter, with 'group' folded there as well, - * then introduce a PERF_O_{MMAP,GROUP,INHERIT} enum, and if - * O_MMAP is set, emit a warning if cpu < 0 and O_INHERIT is - * set. Lets go for the minimal fix first tho. - */ - evsel->attr.inherit = (cpus->map[cpu] >= 0) && inherit; for (thread = 0; thread < threads->nr; thread++) { @@ -253,7 +240,7 @@ static struct { }; int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, - struct thread_map *threads, bool group, bool inherit) + struct thread_map *threads, bool group) { if (cpus == NULL) { /* Work around old compiler warnings about strict aliasing */ @@ -263,19 +250,19 @@ int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, if (threads == NULL) threads = &empty_thread_map.map; - return __perf_evsel__open(evsel, cpus, threads, group, inherit); + return __perf_evsel__open(evsel, cpus, threads, group); } int perf_evsel__open_per_cpu(struct perf_evsel *evsel, - struct cpu_map *cpus, bool group, bool inherit) + struct cpu_map *cpus, bool group) { - return __perf_evsel__open(evsel, cpus, &empty_thread_map.map, group, inherit); + return __perf_evsel__open(evsel, cpus, &empty_thread_map.map, group); } int perf_evsel__open_per_thread(struct perf_evsel *evsel, - struct thread_map *threads, bool group, bool inherit) + struct thread_map *threads, bool group) { - return __perf_evsel__open(evsel, &empty_cpu_map.map, threads, group, inherit); + return __perf_evsel__open(evsel, &empty_cpu_map.map, threads, group); } static int perf_event__parse_id_sample(const union perf_event *event, u64 type, diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 6710ab53834..f79bb2c09a6 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h @@ -81,11 +81,11 @@ void perf_evsel__free_id(struct perf_evsel *evsel); void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads); int perf_evsel__open_per_cpu(struct perf_evsel *evsel, - struct cpu_map *cpus, bool group, bool inherit); + struct cpu_map *cpus, bool group); int perf_evsel__open_per_thread(struct perf_evsel *evsel, - struct thread_map *threads, bool group, bool inherit); + struct thread_map *threads, bool group); int perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus, - struct thread_map *threads, bool group, bool inherit); + struct thread_map *threads, bool group); #define perf_evsel__match(evsel, t, c) \ (evsel->attr.type == PERF_TYPE_##t && \ diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index e5230c0ef95..93862a8027e 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -695,13 +695,50 @@ out: return err; } +static int perf_header__read_build_ids_abi_quirk(struct perf_header *header, + int input, u64 offset, u64 size) +{ + struct perf_session *session = container_of(header, struct perf_session, header); + struct { + struct perf_event_header header; + u8 build_id[ALIGN(BUILD_ID_SIZE, sizeof(u64))]; + char filename[0]; + } old_bev; + struct build_id_event bev; + char filename[PATH_MAX]; + u64 limit = offset + size; + + while (offset < limit) { + ssize_t len; + + if (read(input, &old_bev, sizeof(old_bev)) != sizeof(old_bev)) + return -1; + + if (header->needs_swap) + perf_event_header__bswap(&old_bev.header); + + len = old_bev.header.size - sizeof(old_bev); + if (read(input, filename, len) != len) + return -1; + + bev.header = old_bev.header; + bev.pid = 0; + memcpy(bev.build_id, old_bev.build_id, sizeof(bev.build_id)); + __event_process_build_id(&bev, filename, session); + + offset += bev.header.size; + } + + return 0; +} + static int perf_header__read_build_ids(struct perf_header *header, int input, u64 offset, u64 size) { struct perf_session *session = container_of(header, struct perf_session, header); struct build_id_event bev; char filename[PATH_MAX]; - u64 limit = offset + size; + u64 limit = offset + size, orig_offset = offset; int err = -1; while (offset < limit) { @@ -716,6 +753,24 @@ static int perf_header__read_build_ids(struct perf_header *header, len = bev.header.size - sizeof(bev); if (read(input, filename, len) != len) goto out; + /* + * The a1645ce1 changeset: + * + * "perf: 'perf kvm' tool for monitoring guest performance from host" + * + * Added a field to struct build_id_event that broke the file + * format. + * + * Since the kernel build-id is the first entry, process the + * table using the old format if the well known + * '[kernel.kallsyms]' string for the kernel build-id has the + * first 4 characters chopped off (where the pid_t sits). + */ + if (memcmp(filename, "nel.kallsyms]", 13) == 0) { + if (lseek(input, orig_offset, SEEK_SET) == (off_t)-1) + return -1; + return perf_header__read_build_ids_abi_quirk(header, input, offset, size); + } __event_process_build_id(&bev, filename, session); diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index cb6858a2f9a..3beb97c4d82 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h @@ -29,6 +29,7 @@ struct events_stats { u32 nr_events[PERF_RECORD_HEADER_MAX]; u32 nr_unknown_events; u32 nr_invalid_chains; + u32 nr_unknown_id; }; enum hist_column { diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 5ddee66020a..f0223166e76 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -234,7 +234,6 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev, /* Searching trace events corresponding to probe event */ ntevs = find_probe_trace_events(fd, pev, tevs, max_tevs); - close(fd); if (ntevs > 0) { /* Succeeded to find trace events */ pr_debug("find %d probe_trace_events.\n", ntevs); @@ -388,7 +387,6 @@ int show_line_range(struct line_range *lr, const char *module) } ret = find_line_range(fd, lr); - close(fd); if (ret == 0) { pr_warning("Specified source line is not found.\n"); return -ENOENT; @@ -512,19 +510,18 @@ int show_available_vars(struct perf_probe_event *pevs, int npevs, if (ret < 0) return ret; - fd = open_vmlinux(module); - if (fd < 0) { - pr_warning("Failed to open debug information file.\n"); - return fd; - } - setup_pager(); - for (i = 0; i < npevs && ret >= 0; i++) + for (i = 0; i < npevs && ret >= 0; i++) { + fd = open_vmlinux(module); + if (fd < 0) { + pr_warning("Failed to open debug information file.\n"); + ret = fd; + break; + } ret = show_available_vars_at(fd, &pevs[i], max_vls, _filter, externs); - - close(fd); + } return ret; } diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index 194f9e2a328..b7c85ce466a 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c @@ -273,6 +273,25 @@ static const char *cu_get_comp_dir(Dwarf_Die *cu_die) return dwarf_formstring(&attr); } +/* Get a line number and file name for given address */ +static int cu_find_lineinfo(Dwarf_Die *cudie, unsigned long addr, + const char **fname, int *lineno) +{ + Dwarf_Line *line; + Dwarf_Addr laddr; + + line = dwarf_getsrc_die(cudie, (Dwarf_Addr)addr); + if (line && dwarf_lineaddr(line, &laddr) == 0 && + addr == (unsigned long)laddr && dwarf_lineno(line, lineno) == 0) { + *fname = dwarf_linesrc(line, NULL, NULL); + if (!*fname) + /* line number is useless without filename */ + *lineno = 0; + } + + return *lineno ?: -ENOENT; +} + /* Compare diename and tname */ static bool die_compare_name(Dwarf_Die *dw_die, const char *tname) { @@ -497,7 +516,20 @@ static int __die_find_inline_cb(Dwarf_Die *die_mem, void *data) static Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr, Dwarf_Die *die_mem) { - return die_find_child(sp_die, __die_find_inline_cb, &addr, die_mem); + Dwarf_Die tmp_die; + + sp_die = die_find_child(sp_die, __die_find_inline_cb, &addr, &tmp_die); + if (!sp_die) + return NULL; + + /* Inlined function could be recursive. Trace it until fail */ + while (sp_die) { + memcpy(die_mem, sp_die, sizeof(Dwarf_Die)); + sp_die = die_find_child(sp_die, __die_find_inline_cb, &addr, + &tmp_die); + } + + return die_mem; } /* Walker on lines (Note: line number will not be sorted) */ @@ -1395,6 +1427,10 @@ static int probe_point_search_cb(Dwarf_Die *sp_die, void *data) !die_compare_name(sp_die, pp->function)) return DWARF_CB_OK; + /* Check declared file */ + if (pp->file && strtailcmp(pp->file, dwarf_decl_file(sp_die))) + return DWARF_CB_OK; + pf->fname = dwarf_decl_file(sp_die); if (pp->line) { /* Function relative line */ dwarf_decl_line(sp_die, &pf->lno); @@ -1451,6 +1487,7 @@ static int find_probes(int fd, struct probe_finder *pf) if (!dbg) { pr_warning("No debug information found in the vmlinux - " "please rebuild with CONFIG_DEBUG_INFO=y.\n"); + close(fd); /* Without dwfl_end(), fd isn't closed. */ return -EBADF; } @@ -1686,11 +1723,9 @@ int find_perf_probe_point(unsigned long addr, struct perf_probe_point *ppt) Dwarf_Die cudie, spdie, indie; Dwarf *dbg = NULL; Dwfl *dwfl = NULL; - Dwarf_Line *line; - Dwarf_Addr laddr, eaddr, bias = 0; - const char *tmp; - int lineno, ret = 0; - bool found = false; + Dwarf_Addr _addr, baseaddr, bias = 0; + const char *fname = NULL, *func = NULL, *tmp; + int baseline = 0, lineno = 0, ret = 0; /* Open the live linux kernel */ dbg = dwfl_init_live_kernel_dwarf(addr, &dwfl, &bias); @@ -1711,68 +1746,79 @@ int find_perf_probe_point(unsigned long addr, struct perf_probe_point *ppt) goto end; } - /* Find a corresponding line */ - line = dwarf_getsrc_die(&cudie, (Dwarf_Addr)addr); - if (line) { - if (dwarf_lineaddr(line, &laddr) == 0 && - (Dwarf_Addr)addr == laddr && - dwarf_lineno(line, &lineno) == 0) { - tmp = dwarf_linesrc(line, NULL, NULL); - if (tmp) { - ppt->line = lineno; - ppt->file = strdup(tmp); - if (ppt->file == NULL) { - ret = -ENOMEM; - goto end; - } - found = true; - } - } - } + /* Find a corresponding line (filename and lineno) */ + cu_find_lineinfo(&cudie, addr, &fname, &lineno); + /* Don't care whether it failed or not */ - /* Find a corresponding function */ + /* Find a corresponding function (name, baseline and baseaddr) */ if (die_find_real_subprogram(&cudie, (Dwarf_Addr)addr, &spdie)) { + /* Get function entry information */ tmp = dwarf_diename(&spdie); - if (!tmp || dwarf_entrypc(&spdie, &eaddr) != 0) - goto end; - - if (ppt->line) { - if (die_find_inlinefunc(&spdie, (Dwarf_Addr)addr, - &indie)) { - /* addr in an inline function */ + if (!tmp || + dwarf_entrypc(&spdie, &baseaddr) != 0 || + dwarf_decl_line(&spdie, &baseline) != 0) + goto post; + func = tmp; + + if (addr == (unsigned long)baseaddr) + /* Function entry - Relative line number is 0 */ + lineno = baseline; + else if (die_find_inlinefunc(&spdie, (Dwarf_Addr)addr, + &indie)) { + if (dwarf_entrypc(&indie, &_addr) == 0 && + _addr == addr) + /* + * addr is at an inline function entry. + * In this case, lineno should be the call-site + * line number. + */ + lineno = die_get_call_lineno(&indie); + else { + /* + * addr is in an inline function body. + * Since lineno points one of the lines + * of the inline function, baseline should + * be the entry line of the inline function. + */ tmp = dwarf_diename(&indie); - if (!tmp) - goto end; - ret = dwarf_decl_line(&indie, &lineno); - } else { - if (eaddr == addr) { /* Function entry */ - lineno = ppt->line; - ret = 0; - } else - ret = dwarf_decl_line(&spdie, &lineno); - } - if (ret == 0) { - /* Make a relative line number */ - ppt->line -= lineno; - goto found; + if (tmp && + dwarf_decl_line(&spdie, &baseline) == 0) + func = tmp; } } - /* We don't have a line number, let's use offset */ - ppt->offset = addr - (unsigned long)eaddr; -found: - ppt->function = strdup(tmp); + } + +post: + /* Make a relative line number or an offset */ + if (lineno) + ppt->line = lineno - baseline; + else if (func) + ppt->offset = addr - (unsigned long)baseaddr; + + /* Duplicate strings */ + if (func) { + ppt->function = strdup(func); if (ppt->function == NULL) { ret = -ENOMEM; goto end; } - found = true; } - + if (fname) { + ppt->file = strdup(fname); + if (ppt->file == NULL) { + if (ppt->function) { + free(ppt->function); + ppt->function = NULL; + } + ret = -ENOMEM; + goto end; + } + } end: if (dwfl) dwfl_end(dwfl); - if (ret >= 0) - ret = found ? 1 : 0; + if (ret == 0 && (fname || func)) + ret = 1; /* Found a point */ return ret; } @@ -1840,6 +1886,10 @@ static int line_range_search_cb(Dwarf_Die *sp_die, void *data) struct line_finder *lf = param->data; struct line_range *lr = lf->lr; + /* Check declared file */ + if (lr->file && strtailcmp(lr->file, dwarf_decl_file(sp_die))) + return DWARF_CB_OK; + if (dwarf_tag(sp_die) == DW_TAG_subprogram && die_compare_name(sp_die, lr->function)) { lf->fname = dwarf_decl_file(sp_die); @@ -1892,6 +1942,7 @@ int find_line_range(int fd, struct line_range *lr) if (!dbg) { pr_warning("No debug information found in the vmlinux - " "please rebuild with CONFIG_DEBUG_INFO=y.\n"); + close(fd); /* Without dwfl_end(), fd isn't closed. */ return -EBADF; } diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c index a9f2d7e1204..f5e38451fdc 100644 --- a/tools/perf/util/python.c +++ b/tools/perf/util/python.c @@ -498,11 +498,11 @@ static PyObject *pyrf_evsel__open(struct pyrf_evsel *pevsel, struct cpu_map *cpus = NULL; struct thread_map *threads = NULL; PyObject *pcpus = NULL, *pthreads = NULL; - int group = 0, overwrite = 0; - static char *kwlist[] = {"cpus", "threads", "group", "overwrite", NULL, NULL}; + int group = 0, inherit = 0; + static char *kwlist[] = {"cpus", "threads", "group", "inherit", NULL, NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|OOii", kwlist, - &pcpus, &pthreads, &group, &overwrite)) + &pcpus, &pthreads, &group, &inherit)) return NULL; if (pthreads != NULL) @@ -511,7 +511,8 @@ static PyObject *pyrf_evsel__open(struct pyrf_evsel *pevsel, if (pcpus != NULL) cpus = ((struct pyrf_cpu_map *)pcpus)->cpus; - if (perf_evsel__open(evsel, cpus, threads, group, overwrite) < 0) { + evsel->attr.inherit = inherit; + if (perf_evsel__open(evsel, cpus, threads, group) < 0) { PyErr_SetFromErrno(PyExc_OSError); return NULL; } diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c index 621427212e8..74350ffb57f 100644 --- a/tools/perf/util/scripting-engines/trace-event-perl.c +++ b/tools/perf/util/scripting-engines/trace-event-perl.c @@ -247,6 +247,7 @@ static inline struct event *find_cache_event(int type) static void perl_process_event(union perf_event *pevent __unused, struct perf_sample *sample, + struct perf_evsel *evsel, struct perf_session *session __unused, struct thread *thread) { diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index 1b85d605515..6ccf70e8d8f 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c @@ -206,6 +206,7 @@ static inline struct event *find_cache_event(int type) static void python_process_event(union perf_event *pevent __unused, struct perf_sample *sample, + struct perf_evsel *evsel __unused, struct perf_session *session __unused, struct thread *thread) { diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index c68cf40764f..caa224522fe 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -280,6 +280,15 @@ static int process_event_synth_stub(union perf_event *event __used, return 0; } +static int process_event_sample_stub(union perf_event *event __used, + struct perf_sample *sample __used, + struct perf_evsel *evsel __used, + struct perf_session *session __used) +{ + dump_printf(": unhandled!\n"); + return 0; +} + static int process_event_stub(union perf_event *event __used, struct perf_sample *sample __used, struct perf_session *session __used) @@ -303,7 +312,7 @@ static int process_finished_round(union perf_event *event, static void perf_event_ops__fill_defaults(struct perf_event_ops *handler) { if (handler->sample == NULL) - handler->sample = process_event_stub; + handler->sample = process_event_sample_stub; if (handler->mmap == NULL) handler->mmap = process_event_stub; if (handler->comm == NULL) @@ -698,12 +707,19 @@ static int perf_session_deliver_event(struct perf_session *session, struct perf_event_ops *ops, u64 file_offset) { + struct perf_evsel *evsel; + dump_event(session, event, file_offset, sample); switch (event->header.type) { case PERF_RECORD_SAMPLE: dump_sample(session, event, sample); - return ops->sample(event, sample, session); + evsel = perf_evlist__id2evsel(session->evlist, sample->id); + if (evsel == NULL) { + ++session->hists.stats.nr_unknown_id; + return -1; + } + return ops->sample(event, sample, evsel, session); case PERF_RECORD_MMAP: return ops->mmap(event, sample, session); case PERF_RECORD_COMM: @@ -845,6 +861,11 @@ static void perf_session__warn_about_errors(const struct perf_session *session, session->hists.stats.nr_unknown_events); } + if (session->hists.stats.nr_unknown_id != 0) { + ui__warning("%u samples with id not present in the header\n", + session->hists.stats.nr_unknown_id); + } + if (session->hists.stats.nr_invalid_chains != 0) { ui__warning("Found invalid callchains!\n\n" "%u out of %u events were discarded for this reason.\n\n" diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index 0b3c9afecaa..1ac481fc110 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h @@ -55,8 +55,11 @@ struct perf_session { char filename[0]; }; +struct perf_evsel; struct perf_event_ops; +typedef int (*event_sample)(union perf_event *event, struct perf_sample *sample, + struct perf_evsel *evsel, struct perf_session *session); typedef int (*event_op)(union perf_event *self, struct perf_sample *sample, struct perf_session *session); typedef int (*event_synth_op)(union perf_event *self, @@ -65,8 +68,8 @@ typedef int (*event_op2)(union perf_event *self, struct perf_session *session, struct perf_event_ops *ops); struct perf_event_ops { - event_op sample, - mmap, + event_sample sample; + event_op mmap, comm, fork, exit, diff --git a/tools/perf/util/setup.py b/tools/perf/util/setup.py index e24ffadb20b..bbc982f5dd8 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/string.c b/tools/perf/util/string.c index 8fc0bd3a3a4..b9a985dadd0 100644 --- a/tools/perf/util/string.c +++ b/tools/perf/util/string.c @@ -85,7 +85,7 @@ out: /* * Helper function for splitting a string into an argv-like array. - * originaly copied from lib/argv_split.c + * originally copied from lib/argv_split.c */ static const char *skip_sep(const char *cp) { diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 651dbfe7f4f..f06c10f092b 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) { @@ -1486,7 +1488,9 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) * On the first pass, only load images if they have a full symtab. * Failing that, do a second pass where we accept .dynsym also */ - for (self->symtab_type = SYMTAB__BUILD_ID_CACHE, want_symtab = 1; + want_symtab = 1; +restart: + for (self->symtab_type = SYMTAB__BUILD_ID_CACHE; self->symtab_type != SYMTAB__NOT_FOUND; self->symtab_type++) { switch (self->symtab_type) { @@ -1536,17 +1540,7 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) snprintf(name, size, "%s%s", symbol_conf.symfs, self->long_name); break; - - default: - /* - * If we wanted a full symtab but no image had one, - * relax our requirements and repeat the search. - */ - if (want_symtab) { - want_symtab = 0; - self->symtab_type = SYMTAB__BUILD_ID_CACHE; - } else - continue; + default:; } /* Name is now the name of the next image to try */ @@ -1573,6 +1567,15 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) } } + /* + * If we wanted a full symtab but no image had one, + * relax our requirements and repeat the search. + */ + if (ret <= 0 && want_symtab) { + want_symtab = 0; + goto restart; + } + free(name); if (ret < 0 && strstr(self->name, " (deleted)") != NULL) return 0; @@ -1841,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); @@ -2402,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) - diff --git a/tools/perf/util/trace-event-scripting.c b/tools/perf/util/trace-event-scripting.c index 66f4b78737a..c9dcbec7d80 100644 --- a/tools/perf/util/trace-event-scripting.c +++ b/tools/perf/util/trace-event-scripting.c @@ -38,6 +38,7 @@ static int stop_script_unsupported(void) static void process_event_unsupported(union perf_event *event __unused, struct perf_sample *sample __unused, + struct perf_evsel *evsel __unused, struct perf_session *session __unused, struct thread *thread __unused) { diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h index b04da572243..f674dda3363 100644 --- a/tools/perf/util/trace-event.h +++ b/tools/perf/util/trace-event.h @@ -280,6 +280,7 @@ struct scripting_ops { int (*stop_script) (void); void (*process_event) (union perf_event *event, struct perf_sample *sample, + struct perf_evsel *evsel, struct perf_session *session, struct thread *thread); int (*generate_script) (const char *outfile); diff --git a/tools/perf/util/ui/browsers/annotate.c b/tools/perf/util/ui/browsers/annotate.c index 8c17a8730e4..15633d60813 100644 --- a/tools/perf/util/ui/browsers/annotate.c +++ b/tools/perf/util/ui/browsers/annotate.c @@ -256,10 +256,9 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, int refresh) { struct objdump_line *pos, *n; - struct annotation *notes = symbol__annotation(sym); + struct annotation *notes; struct annotate_browser browser = { .b = { - .entries = ¬es->src->source, .refresh = ui_browser__list_head_refresh, .seek = ui_browser__list_head_seek, .write = annotate_browser__write, @@ -281,6 +280,8 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, ui_helpline__push("Press <- or ESC to exit"); + notes = symbol__annotation(sym); + list_for_each_entry(pos, ¬es->src->source, node) { struct objdump_line_rb_node *rbpos; size_t line_len = strlen(pos->line); @@ -291,6 +292,7 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, int evidx, rbpos->idx = browser.b.nr_entries++; } + browser.b.entries = ¬es->src->source, browser.b.width += 18; /* Percentage */ ret = annotate_browser__run(&browser, evidx, refresh); list_for_each_entry_safe(pos, n, ¬es->src->source, node) { diff --git a/tools/perf/util/ui/browsers/hists.c b/tools/perf/util/ui/browsers/hists.c index 798efdca3ea..5d767c622df 100644 --- a/tools/perf/util/ui/browsers/hists.c +++ b/tools/perf/util/ui/browsers/hists.c @@ -851,7 +851,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, goto out_free_stack; case 'a': if (browser->selection == NULL || - browser->selection->map == NULL || + browser->selection->sym == NULL || browser->selection->map->dso->annotate_warned) continue; goto do_annotate; diff --git a/tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.c b/tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.c index d9678a34dd7..2618ef2ba31 100644 --- a/tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.c +++ b/tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.c @@ -46,7 +46,7 @@ int cpu = -1; * * performance * Performance is paramount. - * Unwilling to sacrafice any performance + * Unwilling to sacrifice any performance * for the sake of energy saving. (hardware default) * * normal diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl index ba7c63af6f3..8ce792ea08e 100755 --- a/tools/testing/ktest/ktest.pl +++ b/tools/testing/ktest/ktest.pl @@ -37,6 +37,8 @@ $default{"POWEROFF_ON_SUCCESS"} = 0; $default{"BUILD_OPTIONS"} = ""; $default{"BISECT_SLEEP_TIME"} = 60; # sleep time between bisects $default{"CLEAR_LOG"} = 0; +$default{"BISECT_MANUAL"} = 0; +$default{"BISECT_SKIP"} = 1; $default{"SUCCESS_LINE"} = "login:"; $default{"BOOTED_TIMEOUT"} = 1; $default{"DIE_ON_FAILURE"} = 1; @@ -45,6 +47,7 @@ $default{"SCP_TO_TARGET"} = "scp \$SRC_FILE \$SSH_USER\@\$MACHINE:\$DST_FILE"; $default{"REBOOT"} = "ssh \$SSH_USER\@\$MACHINE reboot"; $default{"STOP_AFTER_SUCCESS"} = 10; $default{"STOP_AFTER_FAILURE"} = 60; +$default{"STOP_TEST_AFTER"} = 600; $default{"LOCALVERSION"} = "-test"; my $ktest_config; @@ -81,6 +84,8 @@ my $addconfig; my $in_bisect = 0; my $bisect_bad = ""; my $reverse_bisect; +my $bisect_manual; +my $bisect_skip; my $in_patchcheck = 0; my $run_test; my $redirect; @@ -98,6 +103,7 @@ my $console; my $success_line; my $stop_after_success; my $stop_after_failure; +my $stop_test_after; my $build_target; my $target_image; my $localversion; @@ -462,6 +468,10 @@ sub dodie { `$power_off`; } + if (defined($opt{"LOG_FILE"})) { + print " See $opt{LOG_FILE} for more info.\n"; + } + die @_, "\n"; } @@ -760,8 +770,10 @@ sub monitor { my $success_start; my $failure_start; + my $monitor_start = time; + my $done = 0; - for (;;) { + while (!$done) { if ($booted) { $line = wait_for_input($monitor_fp, $booted_timeout); @@ -796,7 +808,7 @@ sub monitor { } if ($full_line =~ /call trace:/i) { - if (!$skip_call_trace) { + if (!$bug && !$skip_call_trace) { $bug = 1; $failure_start = time; } @@ -816,12 +828,19 @@ sub monitor { } if ($full_line =~ /Kernel panic -/) { + $failure_start = time; $bug = 1; } if ($line =~ /\n/) { $full_line = ""; } + + if ($stop_test_after > 0 && !$booted && !$bug) { + if (time - $monitor_start > $stop_test_after) { + $done = 1; + } + } } close(DMESG); @@ -925,6 +944,18 @@ sub check_buildlog { return 1; } +sub make_oldconfig { + my ($defconfig) = @_; + + if (!run_command "$defconfig $make oldnoconfig") { + # Perhaps oldnoconfig doesn't exist in this version of the kernel + # try a yes '' | oldconfig + doprint "oldnoconfig failed, trying yes '' | make oldconfig\n"; + run_command "yes '' | $defconfig $make oldconfig" or + dodie "failed make config oldconfig"; + } +} + sub build { my ($type) = @_; my $defconfig = ""; @@ -970,8 +1001,12 @@ sub build { $defconfig = "KCONFIG_ALLCONFIG=$minconfig"; } - run_command "$defconfig $make $type" or - dodie "failed make config"; + if ($type eq "oldnoconfig") { + make_oldconfig $defconfig; + } else { + run_command "$defconfig $make $type" or + dodie "failed make config"; + } $redirect = "$buildlog"; if (!run_command "$make $build_options") { @@ -1025,6 +1060,21 @@ sub get_version { doprint "$version\n"; } +sub answer_bisect { + for (;;) { + doprint "Pass or fail? [p/f]"; + my $ans = <STDIN>; + chomp $ans; + if ($ans eq "p" || $ans eq "P") { + return 1; + } elsif ($ans eq "f" || $ans eq "F") { + return 0; + } else { + print "Please answer 'P' or 'F'\n"; + } + } +} + sub child_run_test { my $failed = 0; @@ -1070,6 +1120,7 @@ sub do_run_test { # we are not guaranteed to get a full line $full_line .= $line; + doprint $line; if ($full_line =~ /call trace:/i) { $bug = 1; @@ -1086,6 +1137,19 @@ sub do_run_test { } while (!$child_done && !$bug); if ($bug) { + my $failure_start = time; + my $now; + do { + $line = wait_for_input($monitor_fp, 1); + if (defined($line)) { + doprint $line; + } + $now = time; + if ($now - $failure_start >= $stop_after_failure) { + last; + } + } while (defined($line)); + doprint "Detected kernel crash!\n"; # kill the child with extreme prejudice kill 9, $child_pid; @@ -1131,7 +1195,15 @@ sub run_git_bisect { return 1; } -# returns 1 on success, 0 on failure +sub bisect_reboot { + doprint "Reboot and sleep $bisect_sleep_time seconds\n"; + reboot; + start_monitor; + wait_for_monitor $bisect_sleep_time; + end_monitor; +} + +# returns 1 on success, 0 on failure, -1 on skip sub run_bisect_test { my ($type, $buildtype) = @_; @@ -1145,6 +1217,10 @@ sub run_bisect_test { build $buildtype or $failed = 1; if ($type ne "build") { + if ($failed && $bisect_skip) { + $in_bisect = 0; + return -1; + } dodie "Failed on build" if $failed; # Now boot the box @@ -1156,6 +1232,12 @@ sub run_bisect_test { monitor or $failed = 1; if ($type ne "boot") { + if ($failed && $bisect_skip) { + end_monitor; + bisect_reboot; + $in_bisect = 0; + return -1; + } dodie "Failed on boot" if $failed; do_run_test or $failed = 1; @@ -1168,11 +1250,7 @@ sub run_bisect_test { # reboot the box to a good kernel if ($type ne "build") { - doprint "Reboot and sleep $bisect_sleep_time seconds\n"; - reboot; - start_monitor; - wait_for_monitor $bisect_sleep_time; - end_monitor; + bisect_reboot; } } else { $result = 1; @@ -1193,16 +1271,22 @@ sub run_bisect { my $ret = run_bisect_test $type, $buildtype; + if ($bisect_manual) { + $ret = answer_bisect; + } # Are we looking for where it worked, not failed? if ($reverse_bisect) { $ret = !$ret; } - if ($ret) { + if ($ret > 0) { return "good"; - } else { + } elsif ($ret == 0) { return "bad"; + } elsif ($bisect_skip) { + doprint "HIT A BAD COMMIT ... SKIPPING\n"; + return "skip"; } } @@ -1220,6 +1304,13 @@ sub bisect { my $type = $opt{"BISECT_TYPE[$i]"}; my $start = $opt{"BISECT_START[$i]"}; my $replay = $opt{"BISECT_REPLAY[$i]"}; + my $start_files = $opt{"BISECT_FILES[$i]"}; + + if (defined($start_files)) { + $start_files = " -- " . $start_files; + } else { + $start_files = ""; + } # convert to true sha1's $good = get_sha1($good); @@ -1273,7 +1364,7 @@ sub bisect { die "Failed to checkout $head"; } - run_command "git bisect start" or + run_command "git bisect start$start_files" or dodie "could not start bisect"; run_command "git bisect good $good" or @@ -1390,9 +1481,7 @@ sub create_config { close(OUT); # exit; - run_command "$make oldnoconfig" or - dodie "failed make config oldconfig"; - + make_oldconfig ""; } sub compare_configs { @@ -1505,7 +1594,9 @@ sub run_config_bisect { } $ret = run_config_bisect_test $type; - + if ($bisect_manual) { + $ret = answer_bisect; + } if ($ret) { process_passed %current_config; return 0; @@ -1536,7 +1627,13 @@ sub run_config_bisect { $half = int($#start_list / 2); } while ($half > 0); - # we found a single config, try it again + # we found a single config, try it again unless we are running manually + + if ($bisect_manual) { + process_failed $start_list[0]; + return 1; + } + my @tophalf = @start_list[0 .. 0]; $ret = run_config_bisect_test $type; @@ -1594,8 +1691,7 @@ sub config_bisect { close(IN); # Now run oldconfig with the minconfig (and addconfigs) - run_command "$defconfig $make oldnoconfig" or - dodie "failed make config oldconfig"; + make_oldconfig $defconfig; # check to see what we lost (or gained) open (IN, $output_config) @@ -1907,6 +2003,8 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) { $poweroff_after_halt = set_test_option("POWEROFF_AFTER_HALT", $i); $sleep_time = set_test_option("SLEEP_TIME", $i); $bisect_sleep_time = set_test_option("BISECT_SLEEP_TIME", $i); + $bisect_manual = set_test_option("BISECT_MANUAL", $i); + $bisect_skip = set_test_option("BISECT_SKIP", $i); $store_failures = set_test_option("STORE_FAILURES", $i); $timeout = set_test_option("TIMEOUT", $i); $booted_timeout = set_test_option("BOOTED_TIMEOUT", $i); @@ -1914,6 +2012,7 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) { $success_line = set_test_option("SUCCESS_LINE", $i); $stop_after_success = set_test_option("STOP_AFTER_SUCCESS", $i); $stop_after_failure = set_test_option("STOP_AFTER_FAILURE", $i); + $stop_test_after = set_test_option("STOP_TEST_AFTER", $i); $build_target = set_test_option("BUILD_TARGET", $i); $ssh_exec = set_test_option("SSH_EXEC", $i); $scp_to_target = set_test_option("SCP_TO_TARGET", $i); diff --git a/tools/testing/ktest/sample.conf b/tools/testing/ktest/sample.conf index 3408c594b2d..4c5d6bd74a0 100644 --- a/tools/testing/ktest/sample.conf +++ b/tools/testing/ktest/sample.conf @@ -306,6 +306,14 @@ # (default 60) #STOP_AFTER_FAILURE = 60 +# In case the console constantly fills the screen, having +# a specified time to stop the test if it never succeeds nor fails +# is recommended. +# Note: this is ignored if a success or failure is detected. +# (in seconds) +# (default 600, -1 is to never stop) +#STOP_TEST_AFTER = 600 + # Stop testing if a build fails. If set, the script will end if # a failure is detected, otherwise it will save off the .config, # dmesg and bootlog in a directory called @@ -519,6 +527,24 @@ # git bisect good, git bisect bad, and running the git bisect replay # if the BISECT_REPLAY is set. # +# BISECT_SKIP = 1 (optional, default 0) +# +# If BISECT_TYPE is set to test but the build fails, ktest will +# simply fail the test and end their. You could use BISECT_REPLAY +# and BISECT_START to resume after you found a new starting point, +# or you could set BISECT_SKIP to 1. If BISECT_SKIP is set to 1, +# when something other than the BISECT_TYPE fails, ktest.pl will +# run "git bisect skip" and try again. +# +# BISECT_FILES = <path> (optional, default undefined) +# +# To just run the git bisect on a specific path, set BISECT_FILES. +# For example: +# +# BISECT_FILES = arch/x86 kernel/time +# +# Will run the bisect with "git bisect start -- arch/x86 kernel/time" +# # BISECT_REVERSE = 1 (optional, default 0) # # In those strange instances where it was broken forever @@ -528,6 +554,15 @@ # With BISECT_REVERSE = 1, The test will consider failures as # good, and success as bad. # +# BISECT_MANUAL = 1 (optional, default 0) +# +# In case there's a problem with automating the bisect for +# whatever reason. (Can't reboot, want to inspect each iteration) +# Doing a BISECT_MANUAL will have the test wait for you to +# tell it if the test passed or failed after each iteration. +# This is basicall the same as running git bisect yourself +# but ktest will rebuild and install the kernel for you. +# # BISECT_CHECK = 1 (optional, default 0) # # Just to be sure the good is good and bad is bad, setting @@ -613,10 +648,17 @@ # # CONFIG_BISECT is the config that failed to boot # +# If BISECT_MANUAL is set, it will pause between iterations. +# This is useful to use just ktest.pl just for the config bisect. +# If you set it to build, it will run the bisect and you can +# control what happens in between iterations. It will ask you if +# the test succeeded or not and continue the config bisect. +# # Example: # TEST_START # TEST_TYPE = config_bisect # CONFIG_BISECT_TYPE = build # CONFIG_BISECT = /home/test/˘onfig-bad # MIN_CONFIG = /home/test/config-min +# BISECT_MANUAL = 1 # |