Loading tools/perf/Documentation/perf-probe.txt +4 −0 Original line number Diff line number Diff line Loading @@ -73,6 +73,10 @@ OPTIONS (Only for --vars) Show external defined variables in addition to local variables. -F:: --funcs:: Show available functions in given module or kernel. -f:: --force:: Forcibly add events with existing name. Loading tools/perf/Makefile +4 −0 Original line number Diff line number Diff line Loading @@ -402,6 +402,7 @@ LIB_H += util/debug.h LIB_H += util/debugfs.h LIB_H += util/event.h LIB_H += util/evsel.h LIB_H += util/evlist.h LIB_H += util/exec_cmd.h LIB_H += util/types.h LIB_H += util/levenshtein.h Loading @@ -425,6 +426,7 @@ LIB_H += util/values.h LIB_H += util/sort.h LIB_H += util/hist.h LIB_H += util/thread.h LIB_H += util/thread_map.h LIB_H += util/trace-event.h LIB_H += util/probe-finder.h LIB_H += util/probe-event.h Loading @@ -440,6 +442,7 @@ LIB_OBJS += $(OUTPUT)util/ctype.o LIB_OBJS += $(OUTPUT)util/debugfs.o LIB_OBJS += $(OUTPUT)util/environment.o LIB_OBJS += $(OUTPUT)util/event.o LIB_OBJS += $(OUTPUT)util/evlist.o LIB_OBJS += $(OUTPUT)util/evsel.o LIB_OBJS += $(OUTPUT)util/exec_cmd.o LIB_OBJS += $(OUTPUT)util/help.o Loading Loading @@ -469,6 +472,7 @@ LIB_OBJS += $(OUTPUT)util/map.o LIB_OBJS += $(OUTPUT)util/pstack.o LIB_OBJS += $(OUTPUT)util/session.o LIB_OBJS += $(OUTPUT)util/thread.o LIB_OBJS += $(OUTPUT)util/thread_map.o LIB_OBJS += $(OUTPUT)util/trace-event-parse.o LIB_OBJS += $(OUTPUT)util/trace-event-read.o LIB_OBJS += $(OUTPUT)util/trace-event-info.o Loading tools/perf/builtin-probe.c +28 −1 Original line number Diff line number Diff line Loading @@ -52,6 +52,7 @@ static struct { bool show_lines; bool show_vars; bool show_ext_vars; bool show_funcs; bool mod_events; int nevents; struct perf_probe_event events[MAX_PROBES]; Loading Loading @@ -221,6 +222,8 @@ static const struct option options[] = { OPT__DRY_RUN(&probe_event_dry_run), OPT_INTEGER('\0', "max-probes", ¶ms.max_probe_points, "Set how many probe points can be found for a probe."), OPT_BOOLEAN('F', "funcs", ¶ms.show_funcs, "Show potential probe-able functions."), OPT_END() }; Loading @@ -246,7 +249,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used) params.max_probe_points = MAX_PROBES; if ((!params.nevents && !params.dellist && !params.list_events && !params.show_lines)) !params.show_lines && !params.show_funcs)) usage_with_options(probe_usage, options); /* Loading @@ -267,12 +270,36 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used) pr_err(" Error: Don't use --list with --vars.\n"); usage_with_options(probe_usage, options); } if (params.show_funcs) { pr_err(" Error: Don't use --list with --funcs.\n"); usage_with_options(probe_usage, options); } ret = show_perf_probe_events(); if (ret < 0) pr_err(" Error: Failed to show event list. (%d)\n", ret); return ret; } if (params.show_funcs) { if (params.nevents != 0 || params.dellist) { pr_err(" Error: Don't use --funcs with" " --add/--del.\n"); usage_with_options(probe_usage, options); } if (params.show_lines) { pr_err(" Error: Don't use --funcs with --line.\n"); usage_with_options(probe_usage, options); } if (params.show_vars) { pr_err(" Error: Don't use --funcs with --vars.\n"); usage_with_options(probe_usage, options); } ret = show_available_funcs(params.target_module); if (ret < 0) pr_err(" Error: Failed to show functions." " (%d)\n", ret); return ret; } #ifdef DWARF_SUPPORT if (params.show_lines) { Loading tools/perf/builtin-record.c +134 −194 Original line number Diff line number Diff line Loading @@ -18,17 +18,20 @@ #include "util/header.h" #include "util/event.h" #include "util/evlist.h" #include "util/evsel.h" #include "util/debug.h" #include "util/session.h" #include "util/symbol.h" #include "util/cpumap.h" #include "util/thread_map.h" #include <unistd.h> #include <sched.h> #include <sys/mman.h> #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) #define SID(e, x, y) xyarray__entry(e->id, x, y) enum write_mode_t { WRITE_FORCE, Loading @@ -46,7 +49,7 @@ static unsigned int user_freq = UINT_MAX; static int freq = 1000; static int output; static int pipe_output = 0; static const char *output_name = "perf.data"; static const char *output_name = NULL; static int group = 0; static int realtime_prio = 0; static bool nodelay = false; Loading @@ -66,51 +69,17 @@ static bool sample_address = false; static bool sample_time = false; static bool no_buildid = false; static bool no_buildid_cache = false; static struct perf_evlist *evsel_list; static long samples = 0; static u64 bytes_written = 0; static struct pollfd *event_array; static int nr_poll = 0; static int nr_cpu = 0; static int file_new = 1; static off_t post_processing_offset; static struct perf_session *session; static const char *cpu_list; struct mmap_data { void *base; unsigned int mask; unsigned int prev; }; static struct mmap_data mmap_array[MAX_NR_CPUS]; static unsigned long mmap_read_head(struct mmap_data *md) { struct perf_event_mmap_page *pc = md->base; long head; head = pc->data_head; rmb(); return head; } static void mmap_write_tail(struct mmap_data *md, unsigned long tail) { struct perf_event_mmap_page *pc = md->base; /* * ensure all reads are done before we write the tail out. */ /* mb(); */ pc->data_tail = tail; } static void advance_output(size_t size) { bytes_written += size; Loading Loading @@ -139,9 +108,9 @@ static int process_synthesized_event(event_t *event, return 0; } static void mmap_read(struct mmap_data *md) static void mmap_read(struct perf_mmap *md) { unsigned int head = mmap_read_head(md); unsigned int head = perf_mmap__read_head(md); unsigned int old = md->prev; unsigned char *data = md->base + page_size; unsigned long size; Loading Loading @@ -185,7 +154,7 @@ static void mmap_read(struct mmap_data *md) write_output(buf, size); md->prev = old; mmap_write_tail(md, old); perf_mmap__write_tail(md, old); } static volatile int done = 0; Loading @@ -209,8 +178,6 @@ static void sig_atexit(void) kill(getpid(), signr); } static int group_fd; static struct perf_header_attr *get_header_attr(struct perf_event_attr *a, int nr) { struct perf_header_attr *h_attr; Loading @@ -234,28 +201,47 @@ static void create_counter(struct perf_evsel *evsel, int cpu) char *filter = evsel->filter; struct perf_event_attr *attr = &evsel->attr; struct perf_header_attr *h_attr; int track = !evsel->idx; /* only the first counter needs these */ struct perf_sample_id *sid; int thread_index; int ret; struct { u64 count; u64 time_enabled; u64 time_running; u64 id; } read_data; /* * Check if parse_single_tracepoint_event has already asked for * PERF_SAMPLE_TIME. * * XXX this is kludgy but short term fix for problems introduced by * eac23d1c that broke 'perf script' by having different sample_types * when using multiple tracepoint events when we use a perf binary * that tries to use sample_id_all on an older kernel. * * We need to move counter creation to perf_session, support * different sample_types, etc. */ bool time_needed = attr->sample_type & PERF_SAMPLE_TIME; for (thread_index = 0; thread_index < threads->nr; thread_index++) { h_attr = get_header_attr(attr, evsel->idx); if (h_attr == NULL) die("nomem\n"); if (!file_new) { if (memcmp(&h_attr->attr, attr, sizeof(*attr))) { fprintf(stderr, "incompatible append\n"); exit(-1); } } sid = SID(evsel, cpu, thread_index); if (perf_header_attr__add_id(h_attr, sid->id) < 0) { pr_warning("Not enough memory to add id\n"); exit(-1); } if (filter != NULL) { ret = ioctl(FD(evsel, cpu, thread_index), PERF_EVENT_IOC_SET_FILTER, filter); if (ret) { error("failed to set filter with %d (%s)\n", errno, strerror(errno)); exit(-1); } } } if (!sample_type) sample_type = attr->sample_type; } 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->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | PERF_FORMAT_TOTAL_TIME_RUNNING | Loading @@ -263,7 +249,7 @@ static void create_counter(struct perf_evsel *evsel, int cpu) attr->sample_type |= PERF_SAMPLE_IP | PERF_SAMPLE_TID; if (nr_counters > 1) if (evlist->nr_entries > 1) attr->sample_type |= PERF_SAMPLE_ID; /* Loading Loading @@ -315,19 +301,39 @@ static void create_counter(struct perf_evsel *evsel, int cpu) attr->mmap = track; attr->comm = track; attr->inherit = !no_inherit; if (target_pid == -1 && target_tid == -1 && !system_wide) { attr->disabled = 1; attr->enable_on_exec = 1; } } static void open_counters(struct perf_evlist *evlist) { struct perf_evsel *pos; int cpu; list_for_each_entry(pos, &evlist->entries, node) { struct perf_event_attr *attr = &pos->attr; /* * Check if parse_single_tracepoint_event has already asked for * PERF_SAMPLE_TIME. * * XXX this is kludgy but short term fix for problems introduced by * eac23d1c that broke 'perf script' by having different sample_types * when using multiple tracepoint events when we use a perf binary * that tries to use sample_id_all on an older kernel. * * We need to move counter creation to perf_session, support * different sample_types, etc. */ bool time_needed = attr->sample_type & PERF_SAMPLE_TIME; config_attr(pos, evlist); retry_sample_id: attr->sample_id_all = sample_id_all_avail ? 1 : 0; for (thread_index = 0; thread_index < threads->nr; thread_index++) { try_again: FD(evsel, nr_cpu, thread_index) = sys_perf_event_open(attr, threads->map[thread_index], cpu, group_fd, 0); if (FD(evsel, nr_cpu, thread_index) < 0) { if (perf_evsel__open(pos, cpus, threads, group, !no_inherit) < 0) { int err = errno; if (err == EPERM || err == EACCES) Loading Loading @@ -364,7 +370,7 @@ static void create_counter(struct perf_evsel *evsel, int cpu) } printf("\n"); error("sys_perf_event_open() syscall returned with %d (%s). /bin/dmesg may provide additional information.\n", FD(evsel, nr_cpu, thread_index), strerror(err)); err, strerror(err)); #if defined(__i386__) || defined(__x86_64__) if (attr->type == PERF_TYPE_HARDWARE && err == EOPNOTSUPP) Loading @@ -375,90 +381,16 @@ static void create_counter(struct perf_evsel *evsel, int cpu) #endif die("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); exit(-1); } h_attr = get_header_attr(attr, evsel->idx); if (h_attr == NULL) die("nomem\n"); if (!file_new) { if (memcmp(&h_attr->attr, attr, sizeof(*attr))) { fprintf(stderr, "incompatible append\n"); exit(-1); } } if (read(FD(evsel, nr_cpu, thread_index), &read_data, sizeof(read_data)) == -1) { perror("Unable to read perf file descriptor"); exit(-1); } if (perf_header_attr__add_id(h_attr, read_data.id) < 0) { pr_warning("Not enough memory to add id\n"); exit(-1); } assert(FD(evsel, nr_cpu, thread_index) >= 0); fcntl(FD(evsel, nr_cpu, thread_index), F_SETFL, O_NONBLOCK); /* * First counter acts as the group leader: */ if (group && group_fd == -1) group_fd = FD(evsel, nr_cpu, thread_index); if (evsel->idx || thread_index) { struct perf_evsel *first; first = list_entry(evsel_list.next, struct perf_evsel, node); ret = ioctl(FD(evsel, nr_cpu, thread_index), PERF_EVENT_IOC_SET_OUTPUT, FD(first, nr_cpu, 0)); if (ret) { error("failed to set output: %d (%s)\n", errno, strerror(errno)); exit(-1); } } else { mmap_array[nr_cpu].prev = 0; mmap_array[nr_cpu].mask = mmap_pages*page_size - 1; mmap_array[nr_cpu].base = mmap(NULL, (mmap_pages+1)*page_size, PROT_READ | PROT_WRITE, MAP_SHARED, FD(evsel, nr_cpu, thread_index), 0); if (mmap_array[nr_cpu].base == MAP_FAILED) { error("failed to mmap with %d (%s)\n", errno, strerror(errno)); exit(-1); } event_array[nr_poll].fd = FD(evsel, nr_cpu, thread_index); event_array[nr_poll].events = POLLIN; nr_poll++; } if (filter != NULL) { ret = ioctl(FD(evsel, nr_cpu, thread_index), PERF_EVENT_IOC_SET_FILTER, filter); if (ret) { error("failed to set filter with %d (%s)\n", errno, strerror(errno)); exit(-1); } } } if (!sample_type) sample_type = attr->sample_type; } static void open_counters(int cpu) { struct perf_evsel *pos; group_fd = -1; if (perf_evlist__mmap(evlist, cpus, threads, mmap_pages, false) < 0) die("failed to mmap with %d (%s)\n", errno, strerror(errno)); list_for_each_entry(pos, &evsel_list, node) for (cpu = 0; cpu < cpus->nr; ++cpu) { list_for_each_entry(pos, &evlist->entries, node) create_counter(pos, cpu); nr_cpu++; } } static int process_buildids(void) Loading @@ -481,9 +413,9 @@ static void atexit_header(void) if (!no_buildid) process_buildids(); perf_header__write(&session->header, output, true); perf_header__write(&session->header, evsel_list, output, true); perf_session__delete(session); perf_evsel_list__delete(); perf_evlist__delete(evsel_list); symbol__exit(); } } Loading Loading @@ -533,9 +465,9 @@ static void mmap_read_all(void) { int i; for (i = 0; i < nr_cpu; i++) { if (mmap_array[i].base) mmap_read(&mmap_array[i]); for (i = 0; i < cpus->nr; i++) { if (evsel_list->mmap[i].base) mmap_read(&evsel_list->mmap[i]); } if (perf_header__has_feat(&session->header, HEADER_TRACE_INFO)) Loading Loading @@ -566,6 +498,13 @@ static int __cmd_record(int argc, const char **argv) exit(-1); } if (!output_name) { if (!fstat(STDOUT_FILENO, &st) && S_ISFIFO(st.st_mode)) pipe_output = 1; else output_name = "perf.data"; } if (output_name) { if (!strcmp(output_name, "-")) pipe_output = 1; else if (!stat(output_name, &st) && st.st_size) { Loading @@ -579,6 +518,7 @@ static int __cmd_record(int argc, const char **argv) } else if (write_mode == WRITE_APPEND) { write_mode = WRITE_FORCE; } } flags = O_CREAT|O_RDWR; if (write_mode == WRITE_APPEND) Loading Loading @@ -611,7 +551,7 @@ static int __cmd_record(int argc, const char **argv) goto out_delete_session; } if (have_tracepoints(&evsel_list)) if (have_tracepoints(&evsel_list->entries)) perf_header__set_feat(&session->header, HEADER_TRACE_INFO); /* Loading Loading @@ -673,12 +613,7 @@ static int __cmd_record(int argc, const char **argv) close(child_ready_pipe[0]); } if (!system_wide && no_inherit && !cpu_list) { open_counters(-1); } else { for (i = 0; i < cpus->nr; i++) open_counters(cpus->map[i]); } open_counters(evsel_list); perf_session__set_sample_type(session, sample_type); Loading @@ -687,7 +622,8 @@ static int __cmd_record(int argc, const char **argv) if (err < 0) return err; } else if (file_new) { err = perf_header__write(&session->header, output, false); err = perf_header__write(&session->header, evsel_list, output, false); if (err < 0) return err; } Loading @@ -712,7 +648,7 @@ static int __cmd_record(int argc, const char **argv) return err; } if (have_tracepoints(&evsel_list)) { if (have_tracepoints(&evsel_list->entries)) { /* * FIXME err <= 0 here actually means that * there were no tracepoints so its not really Loading @@ -721,7 +657,7 @@ static int __cmd_record(int argc, const char **argv) * return this more properly and also * propagate errors that now are calling die() */ err = event__synthesize_tracing_data(output, &evsel_list, err = event__synthesize_tracing_data(output, evsel_list, process_synthesized_event, session); if (err <= 0) { Loading Loading @@ -789,15 +725,15 @@ static int __cmd_record(int argc, const char **argv) if (hits == samples) { if (done) break; err = poll(event_array, nr_poll, -1); err = poll(evsel_list->pollfd, evsel_list->nr_fds, -1); waking++; } if (done) { for (i = 0; i < nr_cpu; i++) { for (i = 0; i < cpus->nr; i++) { struct perf_evsel *pos; list_for_each_entry(pos, &evsel_list, node) { list_for_each_entry(pos, &evsel_list->entries, node) { for (thread = 0; thread < threads->nr; thread++) Loading Loading @@ -838,10 +774,10 @@ static const char * const record_usage[] = { static bool force, append_file; const struct option record_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_CALLBACK(0, "filter", NULL, "filter", OPT_CALLBACK(0, "filter", &evsel_list, "filter", "event filter", parse_filter), OPT_INTEGER('p', "pid", &target_pid, "record events on existing process id"), Loading Loading @@ -892,6 +828,10 @@ int cmd_record(int argc, const char **argv, const char *prefix __used) int err = -ENOMEM; struct perf_evsel *pos; evsel_list = perf_evlist__new(); if (evsel_list == NULL) return -ENOMEM; argc = parse_options(argc, argv, record_options, record_usage, PARSE_OPT_STOP_AT_NON_OPTION); if (!argc && target_pid == -1 && target_tid == -1 && Loading @@ -913,7 +853,8 @@ int cmd_record(int argc, const char **argv, const char *prefix __used) if (no_buildid_cache || no_buildid) disable_buildid_cache(); if (list_empty(&evsel_list) && perf_evsel_list__create_default() < 0) { if (evsel_list->nr_entries == 0 && perf_evlist__add_default(evsel_list) < 0) { pr_err("Not enough memory for event selector list\n"); goto out_symbol_exit; } Loading @@ -927,21 +868,22 @@ int cmd_record(int argc, const char **argv, const char *prefix __used) usage_with_options(record_usage, record_options); } if (target_tid != -1) cpus = cpu_map__dummy_new(); else cpus = cpu_map__new(cpu_list); if (cpus == NULL) { perror("failed to parse CPUs map"); return -1; } list_for_each_entry(pos, &evsel_list, node) { if (cpus == NULL) usage_with_options(record_usage, record_options); list_for_each_entry(pos, &evsel_list->entries, node) { if (perf_evsel__alloc_fd(pos, cpus->nr, threads->nr) < 0) goto out_free_fd; if (perf_header__push_event(pos->attr.config, event_name(pos))) goto out_free_fd; } event_array = malloc((sizeof(struct pollfd) * MAX_NR_CPUS * MAX_COUNTERS * threads->nr)); if (!event_array) if (perf_evlist__alloc_pollfd(evsel_list, cpus->nr, threads->nr) < 0) goto out_free_fd; if (user_interval != ULLONG_MAX) Loading @@ -959,13 +901,11 @@ int cmd_record(int argc, const char **argv, const char *prefix __used) } else { fprintf(stderr, "frequency and count are zero, aborting\n"); err = -EINVAL; goto out_free_event_array; goto out_free_fd; } err = __cmd_record(argc, argv); out_free_event_array: free(event_array); out_free_fd: thread_map__delete(threads); threads = NULL; Loading tools/perf/builtin-report.c +14 −15 Original line number Diff line number Diff line Loading @@ -81,18 +81,17 @@ static int perf_session__add_hist_entry(struct perf_session *self, struct addr_location *al, struct sample_data *data) { struct map_symbol *syms = NULL; struct symbol *parent = NULL; int err = -ENOMEM; int err = 0; struct hist_entry *he; struct hists *hists; struct perf_event_attr *attr; if ((sort__has_parent || symbol_conf.use_callchain) && data->callchain) { syms = perf_session__resolve_callchain(self, al->thread, err = perf_session__resolve_callchain(self, al->thread, data->callchain, &parent); if (syms == NULL) return -ENOMEM; if (err) return err; } attr = perf_header__find_attr(data->id, &self->header); Loading @@ -101,16 +100,17 @@ static int perf_session__add_hist_entry(struct perf_session *self, else hists = perf_session__hists_findnew(self, data->id, 0, 0); if (hists == NULL) goto out_free_syms; return -ENOMEM; he = __hists__add_entry(hists, al, parent, data->period); if (he == NULL) goto out_free_syms; err = 0; return -ENOMEM; if (symbol_conf.use_callchain) { err = callchain_append(he->callchain, data->callchain, syms, err = callchain_append(he->callchain, &self->callchain_cursor, data->period); if (err) goto out_free_syms; return err; } /* * Only in the newt browser we are doing integrated annotation, Loading @@ -119,8 +119,7 @@ static int perf_session__add_hist_entry(struct perf_session *self, */ if (use_browser > 0) err = hist_entry__inc_addr_samples(he, al->addr); out_free_syms: free(syms); return err; } Loading Loading @@ -222,7 +221,7 @@ static int perf_session__setup_sample_type(struct perf_session *self) } else if (!dont_use_callchains && callchain_param.mode != CHAIN_NONE && !symbol_conf.use_callchain) { symbol_conf.use_callchain = true; if (register_callchain_param(&callchain_param) < 0) { if (callchain_register_param(&callchain_param) < 0) { fprintf(stderr, "Can't register callchain" " params\n"); return -EINVAL; Loading Loading @@ -424,7 +423,7 @@ parse_callchain_opt(const struct option *opt __used, const char *arg, if (tok2) callchain_param.print_limit = strtod(tok2, &endptr); setup: if (register_callchain_param(&callchain_param) < 0) { if (callchain_register_param(&callchain_param) < 0) { fprintf(stderr, "Can't register callchain params\n"); return -1; } Loading Loading
tools/perf/Documentation/perf-probe.txt +4 −0 Original line number Diff line number Diff line Loading @@ -73,6 +73,10 @@ OPTIONS (Only for --vars) Show external defined variables in addition to local variables. -F:: --funcs:: Show available functions in given module or kernel. -f:: --force:: Forcibly add events with existing name. Loading
tools/perf/Makefile +4 −0 Original line number Diff line number Diff line Loading @@ -402,6 +402,7 @@ LIB_H += util/debug.h LIB_H += util/debugfs.h LIB_H += util/event.h LIB_H += util/evsel.h LIB_H += util/evlist.h LIB_H += util/exec_cmd.h LIB_H += util/types.h LIB_H += util/levenshtein.h Loading @@ -425,6 +426,7 @@ LIB_H += util/values.h LIB_H += util/sort.h LIB_H += util/hist.h LIB_H += util/thread.h LIB_H += util/thread_map.h LIB_H += util/trace-event.h LIB_H += util/probe-finder.h LIB_H += util/probe-event.h Loading @@ -440,6 +442,7 @@ LIB_OBJS += $(OUTPUT)util/ctype.o LIB_OBJS += $(OUTPUT)util/debugfs.o LIB_OBJS += $(OUTPUT)util/environment.o LIB_OBJS += $(OUTPUT)util/event.o LIB_OBJS += $(OUTPUT)util/evlist.o LIB_OBJS += $(OUTPUT)util/evsel.o LIB_OBJS += $(OUTPUT)util/exec_cmd.o LIB_OBJS += $(OUTPUT)util/help.o Loading Loading @@ -469,6 +472,7 @@ LIB_OBJS += $(OUTPUT)util/map.o LIB_OBJS += $(OUTPUT)util/pstack.o LIB_OBJS += $(OUTPUT)util/session.o LIB_OBJS += $(OUTPUT)util/thread.o LIB_OBJS += $(OUTPUT)util/thread_map.o LIB_OBJS += $(OUTPUT)util/trace-event-parse.o LIB_OBJS += $(OUTPUT)util/trace-event-read.o LIB_OBJS += $(OUTPUT)util/trace-event-info.o Loading
tools/perf/builtin-probe.c +28 −1 Original line number Diff line number Diff line Loading @@ -52,6 +52,7 @@ static struct { bool show_lines; bool show_vars; bool show_ext_vars; bool show_funcs; bool mod_events; int nevents; struct perf_probe_event events[MAX_PROBES]; Loading Loading @@ -221,6 +222,8 @@ static const struct option options[] = { OPT__DRY_RUN(&probe_event_dry_run), OPT_INTEGER('\0', "max-probes", ¶ms.max_probe_points, "Set how many probe points can be found for a probe."), OPT_BOOLEAN('F', "funcs", ¶ms.show_funcs, "Show potential probe-able functions."), OPT_END() }; Loading @@ -246,7 +249,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used) params.max_probe_points = MAX_PROBES; if ((!params.nevents && !params.dellist && !params.list_events && !params.show_lines)) !params.show_lines && !params.show_funcs)) usage_with_options(probe_usage, options); /* Loading @@ -267,12 +270,36 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used) pr_err(" Error: Don't use --list with --vars.\n"); usage_with_options(probe_usage, options); } if (params.show_funcs) { pr_err(" Error: Don't use --list with --funcs.\n"); usage_with_options(probe_usage, options); } ret = show_perf_probe_events(); if (ret < 0) pr_err(" Error: Failed to show event list. (%d)\n", ret); return ret; } if (params.show_funcs) { if (params.nevents != 0 || params.dellist) { pr_err(" Error: Don't use --funcs with" " --add/--del.\n"); usage_with_options(probe_usage, options); } if (params.show_lines) { pr_err(" Error: Don't use --funcs with --line.\n"); usage_with_options(probe_usage, options); } if (params.show_vars) { pr_err(" Error: Don't use --funcs with --vars.\n"); usage_with_options(probe_usage, options); } ret = show_available_funcs(params.target_module); if (ret < 0) pr_err(" Error: Failed to show functions." " (%d)\n", ret); return ret; } #ifdef DWARF_SUPPORT if (params.show_lines) { Loading
tools/perf/builtin-record.c +134 −194 Original line number Diff line number Diff line Loading @@ -18,17 +18,20 @@ #include "util/header.h" #include "util/event.h" #include "util/evlist.h" #include "util/evsel.h" #include "util/debug.h" #include "util/session.h" #include "util/symbol.h" #include "util/cpumap.h" #include "util/thread_map.h" #include <unistd.h> #include <sched.h> #include <sys/mman.h> #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) #define SID(e, x, y) xyarray__entry(e->id, x, y) enum write_mode_t { WRITE_FORCE, Loading @@ -46,7 +49,7 @@ static unsigned int user_freq = UINT_MAX; static int freq = 1000; static int output; static int pipe_output = 0; static const char *output_name = "perf.data"; static const char *output_name = NULL; static int group = 0; static int realtime_prio = 0; static bool nodelay = false; Loading @@ -66,51 +69,17 @@ static bool sample_address = false; static bool sample_time = false; static bool no_buildid = false; static bool no_buildid_cache = false; static struct perf_evlist *evsel_list; static long samples = 0; static u64 bytes_written = 0; static struct pollfd *event_array; static int nr_poll = 0; static int nr_cpu = 0; static int file_new = 1; static off_t post_processing_offset; static struct perf_session *session; static const char *cpu_list; struct mmap_data { void *base; unsigned int mask; unsigned int prev; }; static struct mmap_data mmap_array[MAX_NR_CPUS]; static unsigned long mmap_read_head(struct mmap_data *md) { struct perf_event_mmap_page *pc = md->base; long head; head = pc->data_head; rmb(); return head; } static void mmap_write_tail(struct mmap_data *md, unsigned long tail) { struct perf_event_mmap_page *pc = md->base; /* * ensure all reads are done before we write the tail out. */ /* mb(); */ pc->data_tail = tail; } static void advance_output(size_t size) { bytes_written += size; Loading Loading @@ -139,9 +108,9 @@ static int process_synthesized_event(event_t *event, return 0; } static void mmap_read(struct mmap_data *md) static void mmap_read(struct perf_mmap *md) { unsigned int head = mmap_read_head(md); unsigned int head = perf_mmap__read_head(md); unsigned int old = md->prev; unsigned char *data = md->base + page_size; unsigned long size; Loading Loading @@ -185,7 +154,7 @@ static void mmap_read(struct mmap_data *md) write_output(buf, size); md->prev = old; mmap_write_tail(md, old); perf_mmap__write_tail(md, old); } static volatile int done = 0; Loading @@ -209,8 +178,6 @@ static void sig_atexit(void) kill(getpid(), signr); } static int group_fd; static struct perf_header_attr *get_header_attr(struct perf_event_attr *a, int nr) { struct perf_header_attr *h_attr; Loading @@ -234,28 +201,47 @@ static void create_counter(struct perf_evsel *evsel, int cpu) char *filter = evsel->filter; struct perf_event_attr *attr = &evsel->attr; struct perf_header_attr *h_attr; int track = !evsel->idx; /* only the first counter needs these */ struct perf_sample_id *sid; int thread_index; int ret; struct { u64 count; u64 time_enabled; u64 time_running; u64 id; } read_data; /* * Check if parse_single_tracepoint_event has already asked for * PERF_SAMPLE_TIME. * * XXX this is kludgy but short term fix for problems introduced by * eac23d1c that broke 'perf script' by having different sample_types * when using multiple tracepoint events when we use a perf binary * that tries to use sample_id_all on an older kernel. * * We need to move counter creation to perf_session, support * different sample_types, etc. */ bool time_needed = attr->sample_type & PERF_SAMPLE_TIME; for (thread_index = 0; thread_index < threads->nr; thread_index++) { h_attr = get_header_attr(attr, evsel->idx); if (h_attr == NULL) die("nomem\n"); if (!file_new) { if (memcmp(&h_attr->attr, attr, sizeof(*attr))) { fprintf(stderr, "incompatible append\n"); exit(-1); } } sid = SID(evsel, cpu, thread_index); if (perf_header_attr__add_id(h_attr, sid->id) < 0) { pr_warning("Not enough memory to add id\n"); exit(-1); } if (filter != NULL) { ret = ioctl(FD(evsel, cpu, thread_index), PERF_EVENT_IOC_SET_FILTER, filter); if (ret) { error("failed to set filter with %d (%s)\n", errno, strerror(errno)); exit(-1); } } } if (!sample_type) sample_type = attr->sample_type; } 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->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | PERF_FORMAT_TOTAL_TIME_RUNNING | Loading @@ -263,7 +249,7 @@ static void create_counter(struct perf_evsel *evsel, int cpu) attr->sample_type |= PERF_SAMPLE_IP | PERF_SAMPLE_TID; if (nr_counters > 1) if (evlist->nr_entries > 1) attr->sample_type |= PERF_SAMPLE_ID; /* Loading Loading @@ -315,19 +301,39 @@ static void create_counter(struct perf_evsel *evsel, int cpu) attr->mmap = track; attr->comm = track; attr->inherit = !no_inherit; if (target_pid == -1 && target_tid == -1 && !system_wide) { attr->disabled = 1; attr->enable_on_exec = 1; } } static void open_counters(struct perf_evlist *evlist) { struct perf_evsel *pos; int cpu; list_for_each_entry(pos, &evlist->entries, node) { struct perf_event_attr *attr = &pos->attr; /* * Check if parse_single_tracepoint_event has already asked for * PERF_SAMPLE_TIME. * * XXX this is kludgy but short term fix for problems introduced by * eac23d1c that broke 'perf script' by having different sample_types * when using multiple tracepoint events when we use a perf binary * that tries to use sample_id_all on an older kernel. * * We need to move counter creation to perf_session, support * different sample_types, etc. */ bool time_needed = attr->sample_type & PERF_SAMPLE_TIME; config_attr(pos, evlist); retry_sample_id: attr->sample_id_all = sample_id_all_avail ? 1 : 0; for (thread_index = 0; thread_index < threads->nr; thread_index++) { try_again: FD(evsel, nr_cpu, thread_index) = sys_perf_event_open(attr, threads->map[thread_index], cpu, group_fd, 0); if (FD(evsel, nr_cpu, thread_index) < 0) { if (perf_evsel__open(pos, cpus, threads, group, !no_inherit) < 0) { int err = errno; if (err == EPERM || err == EACCES) Loading Loading @@ -364,7 +370,7 @@ static void create_counter(struct perf_evsel *evsel, int cpu) } printf("\n"); error("sys_perf_event_open() syscall returned with %d (%s). /bin/dmesg may provide additional information.\n", FD(evsel, nr_cpu, thread_index), strerror(err)); err, strerror(err)); #if defined(__i386__) || defined(__x86_64__) if (attr->type == PERF_TYPE_HARDWARE && err == EOPNOTSUPP) Loading @@ -375,90 +381,16 @@ static void create_counter(struct perf_evsel *evsel, int cpu) #endif die("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); exit(-1); } h_attr = get_header_attr(attr, evsel->idx); if (h_attr == NULL) die("nomem\n"); if (!file_new) { if (memcmp(&h_attr->attr, attr, sizeof(*attr))) { fprintf(stderr, "incompatible append\n"); exit(-1); } } if (read(FD(evsel, nr_cpu, thread_index), &read_data, sizeof(read_data)) == -1) { perror("Unable to read perf file descriptor"); exit(-1); } if (perf_header_attr__add_id(h_attr, read_data.id) < 0) { pr_warning("Not enough memory to add id\n"); exit(-1); } assert(FD(evsel, nr_cpu, thread_index) >= 0); fcntl(FD(evsel, nr_cpu, thread_index), F_SETFL, O_NONBLOCK); /* * First counter acts as the group leader: */ if (group && group_fd == -1) group_fd = FD(evsel, nr_cpu, thread_index); if (evsel->idx || thread_index) { struct perf_evsel *first; first = list_entry(evsel_list.next, struct perf_evsel, node); ret = ioctl(FD(evsel, nr_cpu, thread_index), PERF_EVENT_IOC_SET_OUTPUT, FD(first, nr_cpu, 0)); if (ret) { error("failed to set output: %d (%s)\n", errno, strerror(errno)); exit(-1); } } else { mmap_array[nr_cpu].prev = 0; mmap_array[nr_cpu].mask = mmap_pages*page_size - 1; mmap_array[nr_cpu].base = mmap(NULL, (mmap_pages+1)*page_size, PROT_READ | PROT_WRITE, MAP_SHARED, FD(evsel, nr_cpu, thread_index), 0); if (mmap_array[nr_cpu].base == MAP_FAILED) { error("failed to mmap with %d (%s)\n", errno, strerror(errno)); exit(-1); } event_array[nr_poll].fd = FD(evsel, nr_cpu, thread_index); event_array[nr_poll].events = POLLIN; nr_poll++; } if (filter != NULL) { ret = ioctl(FD(evsel, nr_cpu, thread_index), PERF_EVENT_IOC_SET_FILTER, filter); if (ret) { error("failed to set filter with %d (%s)\n", errno, strerror(errno)); exit(-1); } } } if (!sample_type) sample_type = attr->sample_type; } static void open_counters(int cpu) { struct perf_evsel *pos; group_fd = -1; if (perf_evlist__mmap(evlist, cpus, threads, mmap_pages, false) < 0) die("failed to mmap with %d (%s)\n", errno, strerror(errno)); list_for_each_entry(pos, &evsel_list, node) for (cpu = 0; cpu < cpus->nr; ++cpu) { list_for_each_entry(pos, &evlist->entries, node) create_counter(pos, cpu); nr_cpu++; } } static int process_buildids(void) Loading @@ -481,9 +413,9 @@ static void atexit_header(void) if (!no_buildid) process_buildids(); perf_header__write(&session->header, output, true); perf_header__write(&session->header, evsel_list, output, true); perf_session__delete(session); perf_evsel_list__delete(); perf_evlist__delete(evsel_list); symbol__exit(); } } Loading Loading @@ -533,9 +465,9 @@ static void mmap_read_all(void) { int i; for (i = 0; i < nr_cpu; i++) { if (mmap_array[i].base) mmap_read(&mmap_array[i]); for (i = 0; i < cpus->nr; i++) { if (evsel_list->mmap[i].base) mmap_read(&evsel_list->mmap[i]); } if (perf_header__has_feat(&session->header, HEADER_TRACE_INFO)) Loading Loading @@ -566,6 +498,13 @@ static int __cmd_record(int argc, const char **argv) exit(-1); } if (!output_name) { if (!fstat(STDOUT_FILENO, &st) && S_ISFIFO(st.st_mode)) pipe_output = 1; else output_name = "perf.data"; } if (output_name) { if (!strcmp(output_name, "-")) pipe_output = 1; else if (!stat(output_name, &st) && st.st_size) { Loading @@ -579,6 +518,7 @@ static int __cmd_record(int argc, const char **argv) } else if (write_mode == WRITE_APPEND) { write_mode = WRITE_FORCE; } } flags = O_CREAT|O_RDWR; if (write_mode == WRITE_APPEND) Loading Loading @@ -611,7 +551,7 @@ static int __cmd_record(int argc, const char **argv) goto out_delete_session; } if (have_tracepoints(&evsel_list)) if (have_tracepoints(&evsel_list->entries)) perf_header__set_feat(&session->header, HEADER_TRACE_INFO); /* Loading Loading @@ -673,12 +613,7 @@ static int __cmd_record(int argc, const char **argv) close(child_ready_pipe[0]); } if (!system_wide && no_inherit && !cpu_list) { open_counters(-1); } else { for (i = 0; i < cpus->nr; i++) open_counters(cpus->map[i]); } open_counters(evsel_list); perf_session__set_sample_type(session, sample_type); Loading @@ -687,7 +622,8 @@ static int __cmd_record(int argc, const char **argv) if (err < 0) return err; } else if (file_new) { err = perf_header__write(&session->header, output, false); err = perf_header__write(&session->header, evsel_list, output, false); if (err < 0) return err; } Loading @@ -712,7 +648,7 @@ static int __cmd_record(int argc, const char **argv) return err; } if (have_tracepoints(&evsel_list)) { if (have_tracepoints(&evsel_list->entries)) { /* * FIXME err <= 0 here actually means that * there were no tracepoints so its not really Loading @@ -721,7 +657,7 @@ static int __cmd_record(int argc, const char **argv) * return this more properly and also * propagate errors that now are calling die() */ err = event__synthesize_tracing_data(output, &evsel_list, err = event__synthesize_tracing_data(output, evsel_list, process_synthesized_event, session); if (err <= 0) { Loading Loading @@ -789,15 +725,15 @@ static int __cmd_record(int argc, const char **argv) if (hits == samples) { if (done) break; err = poll(event_array, nr_poll, -1); err = poll(evsel_list->pollfd, evsel_list->nr_fds, -1); waking++; } if (done) { for (i = 0; i < nr_cpu; i++) { for (i = 0; i < cpus->nr; i++) { struct perf_evsel *pos; list_for_each_entry(pos, &evsel_list, node) { list_for_each_entry(pos, &evsel_list->entries, node) { for (thread = 0; thread < threads->nr; thread++) Loading Loading @@ -838,10 +774,10 @@ static const char * const record_usage[] = { static bool force, append_file; const struct option record_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_CALLBACK(0, "filter", NULL, "filter", OPT_CALLBACK(0, "filter", &evsel_list, "filter", "event filter", parse_filter), OPT_INTEGER('p', "pid", &target_pid, "record events on existing process id"), Loading Loading @@ -892,6 +828,10 @@ int cmd_record(int argc, const char **argv, const char *prefix __used) int err = -ENOMEM; struct perf_evsel *pos; evsel_list = perf_evlist__new(); if (evsel_list == NULL) return -ENOMEM; argc = parse_options(argc, argv, record_options, record_usage, PARSE_OPT_STOP_AT_NON_OPTION); if (!argc && target_pid == -1 && target_tid == -1 && Loading @@ -913,7 +853,8 @@ int cmd_record(int argc, const char **argv, const char *prefix __used) if (no_buildid_cache || no_buildid) disable_buildid_cache(); if (list_empty(&evsel_list) && perf_evsel_list__create_default() < 0) { if (evsel_list->nr_entries == 0 && perf_evlist__add_default(evsel_list) < 0) { pr_err("Not enough memory for event selector list\n"); goto out_symbol_exit; } Loading @@ -927,21 +868,22 @@ int cmd_record(int argc, const char **argv, const char *prefix __used) usage_with_options(record_usage, record_options); } if (target_tid != -1) cpus = cpu_map__dummy_new(); else cpus = cpu_map__new(cpu_list); if (cpus == NULL) { perror("failed to parse CPUs map"); return -1; } list_for_each_entry(pos, &evsel_list, node) { if (cpus == NULL) usage_with_options(record_usage, record_options); list_for_each_entry(pos, &evsel_list->entries, node) { if (perf_evsel__alloc_fd(pos, cpus->nr, threads->nr) < 0) goto out_free_fd; if (perf_header__push_event(pos->attr.config, event_name(pos))) goto out_free_fd; } event_array = malloc((sizeof(struct pollfd) * MAX_NR_CPUS * MAX_COUNTERS * threads->nr)); if (!event_array) if (perf_evlist__alloc_pollfd(evsel_list, cpus->nr, threads->nr) < 0) goto out_free_fd; if (user_interval != ULLONG_MAX) Loading @@ -959,13 +901,11 @@ int cmd_record(int argc, const char **argv, const char *prefix __used) } else { fprintf(stderr, "frequency and count are zero, aborting\n"); err = -EINVAL; goto out_free_event_array; goto out_free_fd; } err = __cmd_record(argc, argv); out_free_event_array: free(event_array); out_free_fd: thread_map__delete(threads); threads = NULL; Loading
tools/perf/builtin-report.c +14 −15 Original line number Diff line number Diff line Loading @@ -81,18 +81,17 @@ static int perf_session__add_hist_entry(struct perf_session *self, struct addr_location *al, struct sample_data *data) { struct map_symbol *syms = NULL; struct symbol *parent = NULL; int err = -ENOMEM; int err = 0; struct hist_entry *he; struct hists *hists; struct perf_event_attr *attr; if ((sort__has_parent || symbol_conf.use_callchain) && data->callchain) { syms = perf_session__resolve_callchain(self, al->thread, err = perf_session__resolve_callchain(self, al->thread, data->callchain, &parent); if (syms == NULL) return -ENOMEM; if (err) return err; } attr = perf_header__find_attr(data->id, &self->header); Loading @@ -101,16 +100,17 @@ static int perf_session__add_hist_entry(struct perf_session *self, else hists = perf_session__hists_findnew(self, data->id, 0, 0); if (hists == NULL) goto out_free_syms; return -ENOMEM; he = __hists__add_entry(hists, al, parent, data->period); if (he == NULL) goto out_free_syms; err = 0; return -ENOMEM; if (symbol_conf.use_callchain) { err = callchain_append(he->callchain, data->callchain, syms, err = callchain_append(he->callchain, &self->callchain_cursor, data->period); if (err) goto out_free_syms; return err; } /* * Only in the newt browser we are doing integrated annotation, Loading @@ -119,8 +119,7 @@ static int perf_session__add_hist_entry(struct perf_session *self, */ if (use_browser > 0) err = hist_entry__inc_addr_samples(he, al->addr); out_free_syms: free(syms); return err; } Loading Loading @@ -222,7 +221,7 @@ static int perf_session__setup_sample_type(struct perf_session *self) } else if (!dont_use_callchains && callchain_param.mode != CHAIN_NONE && !symbol_conf.use_callchain) { symbol_conf.use_callchain = true; if (register_callchain_param(&callchain_param) < 0) { if (callchain_register_param(&callchain_param) < 0) { fprintf(stderr, "Can't register callchain" " params\n"); return -EINVAL; Loading Loading @@ -424,7 +423,7 @@ parse_callchain_opt(const struct option *opt __used, const char *arg, if (tok2) callchain_param.print_limit = strtod(tok2, &endptr); setup: if (register_callchain_param(&callchain_param) < 0) { if (callchain_register_param(&callchain_param) < 0) { fprintf(stderr, "Can't register callchain params\n"); return -1; } Loading