diff options
Diffstat (limited to 'tools/perf/util')
32 files changed, 460 insertions, 624 deletions
diff --git a/tools/perf/util/Build b/tools/perf/util/Build index 8dcfca1a882f..39814b1806a6 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build @@ -95,6 +95,7 @@ perf-y += cloexec.o perf-y += call-path.o perf-y += rwsem.o perf-y += thread-stack.o +perf-y += spark.o perf-$(CONFIG_AUXTRACE) += auxtrace.o perf-$(CONFIG_AUXTRACE) += intel-pt-decoder/ perf-$(CONFIG_AUXTRACE) += intel-pt.o diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index e42bf572358c..ef1866a902c4 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -43,6 +43,7 @@ #include <linux/string.h> #include <bpf/libbpf.h> #include <subcmd/parse-options.h> +#include <subcmd/run-command.h> /* FIXME: For the HE_COLORSET */ #include "ui/browser.h" @@ -853,6 +854,10 @@ static int __symbol__account_cycles(struct cyc_hist *ch, ch[offset].start < start) return 0; } + + if (ch[offset].num < NUM_SPARKS) + ch[offset].cycles_spark[ch[offset].num] = cycles; + ch[offset].have_start = have_start; ch[offset].start = start; ch[offset].cycles += cycles; @@ -1485,44 +1490,26 @@ annotation_line__print(struct annotation_line *al, struct symbol *sym, u64 start * means that it's not a disassembly line so should be treated differently. * The ops.raw part will be parsed further according to type of the instruction. */ -static int symbol__parse_objdump_line(struct symbol *sym, FILE *file, +static int symbol__parse_objdump_line(struct symbol *sym, struct annotate_args *args, - int *line_nr) + char *parsed_line, int *line_nr) { struct map *map = args->ms.map; struct annotation *notes = symbol__annotation(sym); struct disasm_line *dl; - char *line = NULL, *parsed_line, *tmp, *tmp2; - size_t line_len; + char *tmp; s64 line_ip, offset = -1; regmatch_t match[2]; - if (getline(&line, &line_len, file) < 0) - return -1; - - if (!line) - return -1; - - line_ip = -1; - parsed_line = strim(line); - /* /filename:linenr ? Save line number and ignore. */ if (regexec(&file_lineno, parsed_line, 2, match, 0) == 0) { *line_nr = atoi(parsed_line + match[1].rm_so); return 0; } - tmp = skip_spaces(parsed_line); - if (*tmp) { - /* - * Parse hexa addresses followed by ':' - */ - line_ip = strtoull(tmp, &tmp2, 16); - if (*tmp2 != ':' || tmp == tmp2 || tmp2[1] == '\0') - line_ip = -1; - } - - if (line_ip != -1) { + /* Process hex address followed by ':'. */ + line_ip = strtoull(parsed_line, &tmp, 16); + if (parsed_line != tmp && tmp[0] == ':' && tmp[1] != '\0') { u64 start = map__rip_2objdump(map, sym->start), end = map__rip_2objdump(map, sym->end); @@ -1530,7 +1517,7 @@ static int symbol__parse_objdump_line(struct symbol *sym, FILE *file, if ((u64)line_ip < start || (u64)line_ip >= end) offset = -1; else - parsed_line = tmp2 + 1; + parsed_line = tmp + 1; } args->offset = offset; @@ -1539,7 +1526,6 @@ static int symbol__parse_objdump_line(struct symbol *sym, FILE *file, args->ms.sym = sym; dl = disasm_line__new(args); - free(line); (*line_nr)++; if (dl == NULL) @@ -1857,6 +1843,67 @@ static int symbol__disassemble_bpf(struct symbol *sym __maybe_unused, } #endif // defined(HAVE_LIBBFD_SUPPORT) && defined(HAVE_LIBBPF_SUPPORT) +/* + * Possibly create a new version of line with tabs expanded. Returns the + * existing or new line, storage is updated if a new line is allocated. If + * allocation fails then NULL is returned. + */ +static char *expand_tabs(char *line, char **storage, size_t *storage_len) +{ + size_t i, src, dst, len, new_storage_len, num_tabs; + char *new_line; + size_t line_len = strlen(line); + + for (num_tabs = 0, i = 0; i < line_len; i++) + if (line[i] == '\t') + num_tabs++; + + if (num_tabs == 0) + return line; + + /* + * Space for the line and '\0', less the leading and trailing + * spaces. Each tab may introduce 7 additional spaces. + */ + new_storage_len = line_len + 1 + (num_tabs * 7); + + new_line = malloc(new_storage_len); + if (new_line == NULL) { + pr_err("Failure allocating memory for tab expansion\n"); + return NULL; + } + + /* + * Copy regions starting at src and expand tabs. If there are two + * adjacent tabs then 'src == i', the memcpy is of size 0 and the spaces + * are inserted. + */ + for (i = 0, src = 0, dst = 0; i < line_len && num_tabs; i++) { + if (line[i] == '\t') { + len = i - src; + memcpy(&new_line[dst], &line[src], len); + dst += len; + new_line[dst++] = ' '; + while (dst % 8 != 0) + new_line[dst++] = ' '; + src = i + 1; + num_tabs--; + } + } + + /* Expand the last region. */ + len = line_len + 1 - src; + memcpy(&new_line[dst], &line[src], len); + dst += len; + new_line[dst] = '\0'; + + free(*storage); + *storage = new_line; + *storage_len = new_storage_len; + return new_line; + +} + static int symbol__disassemble(struct symbol *sym, struct annotate_args *args) { struct annotation_options *opts = args->options; @@ -1868,10 +1915,19 @@ static int symbol__disassemble(struct symbol *sym, struct annotate_args *args) struct kcore_extract kce; bool delete_extract = false; bool decomp = false; - int stdout_fd[2]; int lineno = 0; int nline; - pid_t pid; + char *line; + size_t line_len; + const char *objdump_argv[] = { + "/bin/sh", + "-c", + NULL, /* Will be the objdump command to run. */ + "--", + NULL, /* Will be the symfs path. */ + NULL, + }; + struct child_process objdump_process; int err = dso__disassemble_filename(dso, symfs_filename, sizeof(symfs_filename)); if (err) @@ -1901,7 +1957,7 @@ static int symbol__disassemble(struct symbol *sym, struct annotate_args *args) if (dso__decompress_kmodule_path(dso, symfs_filename, tmp, sizeof(tmp)) < 0) - goto out; + return -1; decomp = true; strcpy(symfs_filename, tmp); @@ -1910,13 +1966,13 @@ static int symbol__disassemble(struct symbol *sym, struct annotate_args *args) err = asprintf(&command, "%s %s%s --start-address=0x%016" PRIx64 " --stop-address=0x%016" PRIx64 - " -l -d %s %s -C \"$1\" 2>/dev/null|grep -v \"$1:\"|expand", + " -l -d %s %s -C \"$1\"", opts->objdump_path ?: "objdump", opts->disassembler_style ? "-M " : "", opts->disassembler_style ?: "", map__rip_2objdump(map, sym->start), map__rip_2objdump(map, sym->end), - opts->show_asm_raw ? "" : "--no-show-raw", + opts->show_asm_raw ? "" : "--no-show-raw-insn", opts->annotate_src ? "-S" : ""); if (err < 0) { @@ -1926,55 +1982,73 @@ static int symbol__disassemble(struct symbol *sym, struct annotate_args *args) pr_debug("Executing: %s\n", command); - err = -1; - if (pipe(stdout_fd) < 0) { - pr_err("Failure creating the pipe to run %s\n", command); - goto out_free_command; - } + objdump_argv[2] = command; + objdump_argv[4] = symfs_filename; - pid = fork(); - if (pid < 0) { - pr_err("Failure forking to run %s\n", command); - goto out_close_stdout; - } - - if (pid == 0) { - close(stdout_fd[0]); - dup2(stdout_fd[1], 1); - close(stdout_fd[1]); - execl("/bin/sh", "sh", "-c", command, "--", symfs_filename, - NULL); - perror(command); - exit(-1); + /* Create a pipe to read from for stdout */ + memset(&objdump_process, 0, sizeof(objdump_process)); + objdump_process.argv = objdump_argv; + objdump_process.out = -1; + if (start_command(&objdump_process)) { + pr_err("Failure starting to run %s\n", command); + err = -1; + goto out_free_command; } - close(stdout_fd[1]); - - file = fdopen(stdout_fd[0], "r"); + file = fdopen(objdump_process.out, "r"); if (!file) { pr_err("Failure creating FILE stream for %s\n", command); /* * If we were using debug info should retry with * original binary. */ - goto out_free_command; + err = -1; + goto out_close_stdout; } + /* Storage for getline. */ + line = NULL; + line_len = 0; + nline = 0; while (!feof(file)) { + const char *match; + char *expanded_line; + + if (getline(&line, &line_len, file) < 0 || !line) + break; + + /* Skip lines containing "filename:" */ + match = strstr(line, symfs_filename); + if (match && match[strlen(symfs_filename)] == ':') + continue; + + expanded_line = strim(line); + expanded_line = expand_tabs(expanded_line, &line, &line_len); + if (!expanded_line) + break; + /* * The source code line number (lineno) needs to be kept in * across calls to symbol__parse_objdump_line(), so that it * can associate it with the instructions till the next one. * See disasm_line__new() and struct disasm_line::line_nr. */ - if (symbol__parse_objdump_line(sym, file, args, &lineno) < 0) + if (symbol__parse_objdump_line(sym, args, expanded_line, + &lineno) < 0) break; nline++; } + free(line); - if (nline == 0) + err = finish_command(&objdump_process); + if (err) + pr_err("Error running %s\n", command); + + if (nline == 0) { + err = -1; pr_err("No output from %s\n", command); + } /* * kallsyms does not have symbol sizes so there may a nop at the end. @@ -1984,23 +2058,21 @@ static int symbol__disassemble(struct symbol *sym, struct annotate_args *args) delete_last_nop(sym); fclose(file); - err = 0; + +out_close_stdout: + close(objdump_process.out); + out_free_command: free(command); -out_remove_tmp: - close(stdout_fd[0]); +out_remove_tmp: if (decomp) unlink(symfs_filename); if (delete_extract) kcore_extract__delete(&kce); -out: - return err; -out_close_stdout: - close(stdout_fd[1]); - goto out_free_command; + return err; } static void calc_percent(struct sym_hist *sym_hist, diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index d76fd0e81f46..3528bd4f8f21 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -11,6 +11,7 @@ #include <pthread.h> #include <asm/bug.h> #include "symbol_conf.h" +#include "spark.h" struct hist_browser_timer; struct hist_entry; @@ -235,6 +236,7 @@ struct cyc_hist { u64 cycles_aggr; u64 cycles_max; u64 cycles_min; + s64 cycles_spark[NUM_SPARKS]; u32 num; u32 num_aggr; u8 have_start; diff --git a/tools/perf/util/env.c b/tools/perf/util/env.c index 3baca06786fb..2a91a10ccfcc 100644 --- a/tools/perf/util/env.c +++ b/tools/perf/util/env.c @@ -2,6 +2,7 @@ #include "cpumap.h" #include "debug.h" #include "env.h" +#include "util/header.h" #include <linux/ctype.h> #include <linux/zalloc.h> #include "bpf-event.h" @@ -256,6 +257,21 @@ int perf_env__read_cpu_topology_map(struct perf_env *env) return 0; } +int perf_env__read_cpuid(struct perf_env *env) +{ + char cpuid[128]; + int err = get_cpuid(cpuid, sizeof(cpuid)); + + if (err) + return err; + + free(env->cpuid); + env->cpuid = strdup(cpuid); + if (env->cpuid == NULL) + return ENOMEM; + return 0; +} + static int perf_env__read_arch(struct perf_env *env) { struct utsname uts; diff --git a/tools/perf/util/env.h b/tools/perf/util/env.h index db40906e2937..a3059dc1abe5 100644 --- a/tools/perf/util/env.h +++ b/tools/perf/util/env.h @@ -104,6 +104,7 @@ void perf_env__exit(struct perf_env *env); int perf_env__set_cmdline(struct perf_env *env, int argc, const char *argv[]); +int perf_env__read_cpuid(struct perf_env *env); int perf_env__read_cpu_topology_map(struct perf_env *env); void cpu_cache_level__free(struct cpu_cache_level *cache); diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index de79c735e441..fdce590d2278 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -21,6 +21,7 @@ #include "../perf.h" #include "asm/bug.h" #include "bpf-event.h" +#include "util/string2.h" #include <signal.h> #include <unistd.h> #include <sched.h> @@ -42,6 +43,7 @@ #include <perf/evlist.h> #include <perf/evsel.h> #include <perf/cpumap.h> +#include <perf/mmap.h> #include <internal/xyarray.h> @@ -57,7 +59,6 @@ void evlist__init(struct evlist *evlist, struct perf_cpu_map *cpus, { perf_evlist__init(&evlist->core); perf_evlist__set_maps(&evlist->core, cpus, threads); - fdarray__init(&evlist->core.pollfd, 64); evlist->workload.pid = -1; evlist->bkw_mmap_state = BKW_MMAP_NOTREADY; } @@ -138,7 +139,7 @@ void evlist__exit(struct evlist *evlist) { zfree(&evlist->mmap); zfree(&evlist->overwrite_mmap); - fdarray__exit(&evlist->core.pollfd); + perf_evlist__exit(&evlist->core); } void evlist__delete(struct evlist *evlist) @@ -148,10 +149,6 @@ void evlist__delete(struct evlist *evlist) evlist__munmap(evlist); evlist__close(evlist); - perf_cpu_map__put(evlist->core.cpus); - perf_thread_map__put(evlist->core.threads); - evlist->core.cpus = NULL; - evlist->core.threads = NULL; evlist__purge(evlist); evlist__exit(evlist); free(evlist); @@ -186,6 +183,30 @@ void perf_evlist__splice_list_tail(struct evlist *evlist, } } +int __evlist__set_tracepoints_handlers(struct evlist *evlist, + const struct evsel_str_handler *assocs, size_t nr_assocs) +{ + struct evsel *evsel; + size_t i; + int err; + + for (i = 0; i < nr_assocs; i++) { + // Adding a handler for an event not in this evlist, just ignore it. + evsel = perf_evlist__find_tracepoint_by_name(evlist, assocs[i].name); + if (evsel == NULL) + continue; + + err = -EEXIST; + if (evsel->handler != NULL) + goto out; + evsel->handler = assocs[i].handler; + } + + err = 0; +out: + return err; +} + void __perf_evlist__set_leader(struct list_head *list) { struct evsel *evsel, *leader; @@ -403,19 +424,9 @@ int evlist__add_pollfd(struct evlist *evlist, int fd) return perf_evlist__add_pollfd(&evlist->core, fd, NULL, POLLIN); } -static void perf_evlist__munmap_filtered(struct fdarray *fda, int fd, - void *arg __maybe_unused) -{ - struct mmap *map = fda->priv[fd].ptr; - - if (map) - perf_mmap__put(map); -} - int evlist__filter_pollfd(struct evlist *evlist, short revents_and_mask) { - return fdarray__filter(&evlist->core.pollfd, revents_and_mask, - perf_evlist__munmap_filtered, NULL); + return perf_evlist__filter_pollfd(&evlist->core, revents_and_mask); } int evlist__poll(struct evlist *evlist, int timeout) @@ -423,22 +434,6 @@ int evlist__poll(struct evlist *evlist, int timeout) return perf_evlist__poll(&evlist->core, timeout); } -static void perf_evlist__set_sid_idx(struct evlist *evlist, - struct evsel *evsel, int idx, int cpu, - int thread) -{ - struct perf_sample_id *sid = SID(evsel, cpu, thread); - sid->idx = idx; - if (evlist->core.cpus && cpu >= 0) - sid->cpu = evlist->core.cpus->map[cpu]; - else - sid->cpu = -1; - if (!evsel->core.system_wide && evlist->core.threads && thread >= 0) - sid->tid = perf_thread_map__pid(evlist->core.threads, thread); - else - sid->tid = -1; -} - struct perf_sample_id *perf_evlist__id2sid(struct evlist *evlist, u64 id) { struct hlist_head *head; @@ -577,11 +572,11 @@ static void evlist__munmap_nofree(struct evlist *evlist) if (evlist->mmap) for (i = 0; i < evlist->core.nr_mmaps; i++) - perf_mmap__munmap(&evlist->mmap[i]); + perf_mmap__munmap(&evlist->mmap[i].core); if (evlist->overwrite_mmap) for (i = 0; i < evlist->core.nr_mmaps; i++) - perf_mmap__munmap(&evlist->overwrite_mmap[i]); + perf_mmap__munmap(&evlist->overwrite_mmap[i].core); } void evlist__munmap(struct evlist *evlist) @@ -591,22 +586,26 @@ void evlist__munmap(struct evlist *evlist) zfree(&evlist->overwrite_mmap); } +static void perf_mmap__unmap_cb(struct perf_mmap *map) +{ + struct mmap *m = container_of(map, struct mmap, core); + + mmap__munmap(m); +} + static struct mmap *evlist__alloc_mmap(struct evlist *evlist, bool overwrite) { int i; struct mmap *map; - evlist->core.nr_mmaps = perf_cpu_map__nr(evlist->core.cpus); - if (perf_cpu_map__empty(evlist->core.cpus)) - evlist->core.nr_mmaps = perf_thread_map__nr(evlist->core.threads); map = zalloc(evlist->core.nr_mmaps * sizeof(struct mmap)); if (!map) return NULL; for (i = 0; i < evlist->core.nr_mmaps; i++) { - map[i].core.fd = -1; - map[i].core.overwrite = overwrite; + struct perf_mmap *prev = i ? &map[i - 1].core : NULL; + /* * When the perf_mmap() call is made we grab one refcount, plus * one extra to let perf_mmap__consume() get the last @@ -616,151 +615,56 @@ static struct mmap *evlist__alloc_mmap(struct evlist *evlist, * Each PERF_EVENT_IOC_SET_OUTPUT points to this mmap and * thus does perf_mmap__get() on it. */ - refcount_set(&map[i].core.refcnt, 0); + perf_mmap__init(&map[i].core, prev, overwrite, perf_mmap__unmap_cb); } + return map; } -static bool -perf_evlist__should_poll(struct evlist *evlist __maybe_unused, - struct evsel *evsel) +static void +perf_evlist__mmap_cb_idx(struct perf_evlist *_evlist, + struct perf_mmap_param *_mp, + int idx, bool per_cpu) { - if (evsel->core.attr.write_backward) - return false; - return true; + struct evlist *evlist = container_of(_evlist, struct evlist, core); + struct mmap_params *mp = container_of(_mp, struct mmap_params, core); + + auxtrace_mmap_params__set_idx(&mp->auxtrace_mp, evlist, idx, per_cpu); } -static int evlist__mmap_per_evsel(struct evlist *evlist, int idx, - struct mmap_params *mp, int cpu_idx, - int thread, int *_output, int *_output_overwrite) +static struct perf_mmap* +perf_evlist__mmap_cb_get(struct perf_evlist *_evlist, bool overwrite, int idx) { - struct evsel *evsel; - int revent; - int evlist_cpu = cpu_map__cpu(evlist->core.cpus, cpu_idx); - - evlist__for_each_entry(evlist, evsel) { - struct mmap *maps = evlist->mmap; - int *output = _output; - int fd; - int cpu; - - mp->prot = PROT_READ | PROT_WRITE; - if (evsel->core.attr.write_backward) { - output = _output_overwrite; - maps = evlist->overwrite_mmap; - - if (!maps) { - maps = evlist__alloc_mmap(evlist, true); - if (!maps) - return -1; - evlist->overwrite_mmap = maps; - if (evlist->bkw_mmap_state == BKW_MMAP_NOTREADY) - perf_evlist__toggle_bkw_mmap(evlist, BKW_MMAP_RUNNING); - } - mp->prot &= ~PROT_WRITE; - } - - if (evsel->core.system_wide && thread) - continue; + struct evlist *evlist = container_of(_evlist, struct evlist, core); + struct mmap *maps; - cpu = perf_cpu_map__idx(evsel->core.cpus, evlist_cpu); - if (cpu == -1) - continue; - - fd = FD(evsel, cpu, thread); + maps = overwrite ? evlist->overwrite_mmap : evlist->mmap; - if (*output == -1) { - *output = fd; + if (!maps) { + maps = evlist__alloc_mmap(evlist, overwrite); + if (!maps) + return NULL; - if (perf_mmap__mmap(&maps[idx], mp, *output, evlist_cpu) < 0) - return -1; + if (overwrite) { + evlist->overwrite_mmap = maps; + if (evlist->bkw_mmap_state == BKW_MMAP_NOTREADY) + perf_evlist__toggle_bkw_mmap(evlist, BKW_MMAP_RUNNING); } else { - if (ioctl(fd, PERF_EVENT_IOC_SET_OUTPUT, *output) != 0) - return -1; - - perf_mmap__get(&maps[idx]); - } - - revent = perf_evlist__should_poll(evlist, evsel) ? POLLIN : 0; - - /* - * The system_wide flag causes a selected event to be opened - * always without a pid. Consequently it will never get a - * POLLHUP, but it is used for tracking in combination with - * other events, so it should not need to be polled anyway. - * Therefore don't add it for polling. - */ - if (!evsel->core.system_wide && - perf_evlist__add_pollfd(&evlist->core, fd, &maps[idx], revent) < 0) { - perf_mmap__put(&maps[idx]); - return -1; - } - - if (evsel->core.attr.read_format & PERF_FORMAT_ID) { - if (perf_evlist__id_add_fd(&evlist->core, &evsel->core, cpu, thread, - fd) < 0) - return -1; - perf_evlist__set_sid_idx(evlist, evsel, idx, cpu, - thread); + evlist->mmap = maps; } } - return 0; + return &maps[idx].core; } -static int evlist__mmap_per_cpu(struct evlist *evlist, - struct mmap_params *mp) +static int +perf_evlist__mmap_cb_mmap(struct perf_mmap *_map, struct perf_mmap_param *_mp, + int output, int cpu) { - int cpu, thread; - int nr_cpus = perf_cpu_map__nr(evlist->core.cpus); - int nr_threads = perf_thread_map__nr(evlist->core.threads); - - pr_debug2("perf event ring buffer mmapped per cpu\n"); - for (cpu = 0; cpu < nr_cpus; cpu++) { - int output = -1; - int output_overwrite = -1; - - auxtrace_mmap_params__set_idx(&mp->auxtrace_mp, evlist, cpu, - true); + struct mmap *map = container_of(_map, struct mmap, core); + struct mmap_params *mp = container_of(_mp, struct mmap_params, core); - for (thread = 0; thread < nr_threads; thread++) { - if (evlist__mmap_per_evsel(evlist, cpu, mp, cpu, - thread, &output, &output_overwrite)) - goto out_unmap; - } - } - - return 0; - -out_unmap: - evlist__munmap_nofree(evlist); - return -1; -} - -static int evlist__mmap_per_thread(struct evlist *evlist, - struct mmap_params *mp) -{ - int thread; - int nr_threads = perf_thread_map__nr(evlist->core.threads); - - pr_debug2("perf event ring buffer mmapped per thread\n"); - for (thread = 0; thread < nr_threads; thread++) { - int output = -1; - int output_overwrite = -1; - - auxtrace_mmap_params__set_idx(&mp->auxtrace_mp, evlist, thread, - false); - - if (evlist__mmap_per_evsel(evlist, thread, mp, 0, thread, - &output, &output_overwrite)) - goto out_unmap; - } - - return 0; - -out_unmap: - evlist__munmap_nofree(evlist); - return -1; + return mmap__mmap(map, mp, output, cpu); } unsigned long perf_event_mlock_kb_in_pages(void) @@ -890,43 +794,30 @@ int evlist__mmap_ex(struct evlist *evlist, unsigned int pages, bool auxtrace_overwrite, int nr_cblocks, int affinity, int flush, int comp_level) { - struct evsel *evsel; - const struct perf_cpu_map *cpus = evlist->core.cpus; - const struct perf_thread_map *threads = evlist->core.threads; /* * Delay setting mp.prot: set it before calling perf_mmap__mmap. * Its value is decided by evsel's write_backward. * So &mp should not be passed through const pointer. */ - struct mmap_params mp = { .nr_cblocks = nr_cblocks, .affinity = affinity, .flush = flush, - .comp_level = comp_level }; - - if (!evlist->mmap) - evlist->mmap = evlist__alloc_mmap(evlist, false); - if (!evlist->mmap) - return -ENOMEM; - - if (evlist->core.pollfd.entries == NULL && perf_evlist__alloc_pollfd(&evlist->core) < 0) - return -ENOMEM; + struct mmap_params mp = { + .nr_cblocks = nr_cblocks, + .affinity = affinity, + .flush = flush, + .comp_level = comp_level + }; + struct perf_evlist_mmap_ops ops = { + .idx = perf_evlist__mmap_cb_idx, + .get = perf_evlist__mmap_cb_get, + .mmap = perf_evlist__mmap_cb_mmap, + }; evlist->core.mmap_len = evlist__mmap_size(pages); pr_debug("mmap size %zuB\n", evlist->core.mmap_len); - mp.mask = evlist->core.mmap_len - page_size - 1; auxtrace_mmap_params__init(&mp.auxtrace_mp, evlist->core.mmap_len, auxtrace_pages, auxtrace_overwrite); - evlist__for_each_entry(evlist, evsel) { - if ((evsel->core.attr.read_format & PERF_FORMAT_ID) && - evsel->core.sample_id == NULL && - perf_evsel__alloc_id(&evsel->core, perf_cpu_map__nr(cpus), threads->nr) < 0) - return -ENOMEM; - } - - if (perf_cpu_map__empty(cpus)) - return evlist__mmap_per_thread(evlist, &mp); - - return evlist__mmap_per_cpu(evlist, &mp); + return perf_evlist__mmap_ops(&evlist->core, &ops, &mp.core); } int evlist__mmap(struct evlist *evlist, unsigned int pages) @@ -1029,6 +920,9 @@ int perf_evlist__set_tp_filter(struct evlist *evlist, const char *filter) struct evsel *evsel; int err = 0; + if (filter == NULL) + return -1; + evlist__for_each_entry(evlist, evsel) { if (evsel->core.attr.type != PERF_TYPE_TRACEPOINT) continue; @@ -1041,16 +935,35 @@ int perf_evlist__set_tp_filter(struct evlist *evlist, const char *filter) return err; } -int perf_evlist__set_tp_filter_pids(struct evlist *evlist, size_t npids, pid_t *pids) +int perf_evlist__append_tp_filter(struct evlist *evlist, const char *filter) +{ + struct evsel *evsel; + int err = 0; + + if (filter == NULL) + return -1; + + evlist__for_each_entry(evlist, evsel) { + if (evsel->core.attr.type != PERF_TYPE_TRACEPOINT) + continue; + + err = perf_evsel__append_tp_filter(evsel, filter); + if (err) + break; + } + + return err; +} + +char *asprintf__tp_filter_pids(size_t npids, pid_t *pids) { char *filter; - int ret = -1; size_t i; for (i = 0; i < npids; ++i) { if (i == 0) { if (asprintf(&filter, "common_pid != %d", pids[i]) < 0) - return -1; + return NULL; } else { char *tmp; @@ -1062,9 +975,18 @@ int perf_evlist__set_tp_filter_pids(struct evlist *evlist, size_t npids, pid_t * } } - ret = perf_evlist__set_tp_filter(evlist, filter); + return filter; out_free: free(filter); + return NULL; +} + +int perf_evlist__set_tp_filter_pids(struct evlist *evlist, size_t npids, pid_t *pids) +{ + char *filter = asprintf__tp_filter_pids(npids, pids); + int ret = perf_evlist__set_tp_filter(evlist, filter); + + free(filter); return ret; } @@ -1073,6 +995,20 @@ int perf_evlist__set_tp_filter_pid(struct evlist *evlist, pid_t pid) return perf_evlist__set_tp_filter_pids(evlist, 1, &pid); } +int perf_evlist__append_tp_filter_pids(struct evlist *evlist, size_t npids, pid_t *pids) +{ + char *filter = asprintf__tp_filter_pids(npids, pids); + int ret = perf_evlist__append_tp_filter(evlist, filter); + + free(filter); + return ret; +} + +int perf_evlist__append_tp_filter_pid(struct evlist *evlist, pid_t pid) +{ + return perf_evlist__append_tp_filter_pids(evlist, 1, &pid); +} + bool perf_evlist__valid_sample_type(struct evlist *evlist) { struct evsel *pos; @@ -1729,9 +1665,9 @@ static void *perf_evlist__poll_thread(void *arg) struct mmap *map = &evlist->mmap[i]; union perf_event *event; - if (perf_mmap__read_init(map)) + if (perf_mmap__read_init(&map->core)) continue; - while ((event = perf_mmap__read_event(map)) != NULL) { + while ((event = perf_mmap__read_event(&map->core)) != NULL) { struct evsel *evsel = perf_evlist__event2evsel(evlist, event); if (evsel && evsel->side_band.cb) @@ -1739,10 +1675,10 @@ static void *perf_evlist__poll_thread(void *arg) else pr_warning("cannot locate proper evsel for the side band event\n"); - perf_mmap__consume(map); + perf_mmap__consume(&map->core); got_data = true; } - perf_mmap__read_done(map); + perf_mmap__read_done(&map->core); } if (draining && !got_data) diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index 7cfe75522ba5..13051409fd22 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h @@ -118,6 +118,13 @@ void perf_evlist__stop_sb_thread(struct evlist *evlist); int perf_evlist__add_newtp(struct evlist *evlist, const char *sys, const char *name, void *handler); +int __evlist__set_tracepoints_handlers(struct evlist *evlist, + const struct evsel_str_handler *assocs, + size_t nr_assocs); + +#define evlist__set_tracepoints_handlers(evlist, array) \ + __evlist__set_tracepoints_handlers(evlist, array, ARRAY_SIZE(array)) + void __perf_evlist__set_sample_bit(struct evlist *evlist, enum perf_event_sample_format bit); void __perf_evlist__reset_sample_bit(struct evlist *evlist, @@ -133,6 +140,11 @@ int perf_evlist__set_tp_filter(struct evlist *evlist, const char *filter); int perf_evlist__set_tp_filter_pid(struct evlist *evlist, pid_t pid); int perf_evlist__set_tp_filter_pids(struct evlist *evlist, size_t npids, pid_t *pids); +int perf_evlist__append_tp_filter(struct evlist *evlist, const char *filter); + +int perf_evlist__append_tp_filter_pid(struct evlist *evlist, pid_t pid); +int perf_evlist__append_tp_filter_pids(struct evlist *evlist, size_t npids, pid_t *pids); + struct evsel * perf_evlist__find_tracepoint_by_id(struct evlist *evlist, int id); diff --git a/tools/perf/util/mmap.c b/tools/perf/util/mmap.c index a35dc57d5995..063d1b93c53d 100644 --- a/tools/perf/util/mmap.c +++ b/tools/perf/util/mmap.c @@ -13,6 +13,7 @@ #include <stdlib.h> #include <string.h> #include <unistd.h> // sysconf() +#include <perf/mmap.h> #ifdef HAVE_LIBNUMA_SUPPORT #include <numaif.h> #endif @@ -23,116 +24,9 @@ #include "../perf.h" #include <internal/lib.h> /* page_size */ -size_t perf_mmap__mmap_len(struct mmap *map) +size_t mmap__mmap_len(struct mmap *map) { - return map->core.mask + 1 + page_size; -} - -/* When check_messup is true, 'end' must points to a good entry */ -static union perf_event *perf_mmap__read(struct mmap *map, - u64 *startp, u64 end) -{ - unsigned char *data = map->core.base + page_size; - union perf_event *event = NULL; - int diff = end - *startp; - - if (diff >= (int)sizeof(event->header)) { - size_t size; - - event = (union perf_event *)&data[*startp & map->core.mask]; - size = event->header.size; - - if (size < sizeof(event->header) || diff < (int)size) - return NULL; - - /* - * Event straddles the mmap boundary -- header should always - * be inside due to u64 alignment of output. - */ - if ((*startp & map->core.mask) + size != ((*startp + size) & map->core.mask)) { - unsigned int offset = *startp; - unsigned int len = min(sizeof(*event), size), cpy; - void *dst = map->core.event_copy; - - do { - cpy = min(map->core.mask + 1 - (offset & map->core.mask), len); - memcpy(dst, &data[offset & map->core.mask], cpy); - offset += cpy; - dst += cpy; - len -= cpy; - } while (len); - - event = (union perf_event *)map->core.event_copy; - } - - *startp += size; - } - - return event; -} - -/* - * Read event from ring buffer one by one. - * Return one event for each call. - * - * Usage: - * perf_mmap__read_init() - * while(event = perf_mmap__read_event()) { - * //process the event - * perf_mmap__consume() - * } - * perf_mmap__read_done() - */ -union perf_event *perf_mmap__read_event(struct mmap *map) -{ - union perf_event *event; - - /* - * Check if event was unmapped due to a POLLHUP/POLLERR. - */ - if (!refcount_read(&map->core.refcnt)) - return NULL; - - /* non-overwirte doesn't pause the ringbuffer */ - if (!map->core.overwrite) - map->core.end = perf_mmap__read_head(map); - - event = perf_mmap__read(map, &map->core.start, map->core.end); - - if (!map->core.overwrite) - map->core.prev = map->core.start; - - return event; -} - -static bool perf_mmap__empty(struct mmap *map) -{ - return perf_mmap__read_head(map) == map->core.prev && !map->auxtrace_mmap.base; -} - -void perf_mmap__get(struct mmap *map) -{ - refcount_inc(&map->core.refcnt); -} - -void perf_mmap__put(struct mmap *map) -{ - BUG_ON(map->core.base && refcount_read(&map->core.refcnt) == 0); - - if (refcount_dec_and_test(&map->core.refcnt)) - perf_mmap__munmap(map); -} - -void perf_mmap__consume(struct mmap *map) -{ - if (!map->core.overwrite) { - u64 old = map->core.prev; - - perf_mmap__write_tail(map, old); - } - - if (refcount_read(&map->core.refcnt) == 1 && perf_mmap__empty(map)) - perf_mmap__put(map); + return perf_mmap__mmap_len(&map->core); } int __weak auxtrace_mmap__mmap(struct auxtrace_mmap *mm __maybe_unused, @@ -170,7 +64,7 @@ static int perf_mmap__aio_enabled(struct mmap *map) #ifdef HAVE_LIBNUMA_SUPPORT static int perf_mmap__aio_alloc(struct mmap *map, int idx) { - map->aio.data[idx] = mmap(NULL, perf_mmap__mmap_len(map), PROT_READ|PROT_WRITE, + map->aio.data[idx] = mmap(NULL, mmap__mmap_len(map), PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0); if (map->aio.data[idx] == MAP_FAILED) { map->aio.data[idx] = NULL; @@ -183,7 +77,7 @@ static int perf_mmap__aio_alloc(struct mmap *map, int idx) static void perf_mmap__aio_free(struct mmap *map, int idx) { if (map->aio.data[idx]) { - munmap(map->aio.data[idx], perf_mmap__mmap_len(map)); + munmap(map->aio.data[idx], mmap__mmap_len(map)); map->aio.data[idx] = NULL; } } @@ -196,7 +90,7 @@ static int perf_mmap__aio_bind(struct mmap *map, int idx, int cpu, int affinity) if (affinity != PERF_AFFINITY_SYS && cpu__max_node() > 1) { data = map->aio.data[idx]; - mmap_len = perf_mmap__mmap_len(map); + mmap_len = mmap__mmap_len(map); node_mask = 1UL << cpu__get_node(cpu); if (mbind(data, mmap_len, MPOL_BIND, &node_mask, 1, 0)) { pr_err("Failed to bind [%p-%p] AIO buffer to node %d: error %m\n", @@ -210,7 +104,7 @@ static int perf_mmap__aio_bind(struct mmap *map, int idx, int cpu, int affinity) #else /* !HAVE_LIBNUMA_SUPPORT */ static int perf_mmap__aio_alloc(struct mmap *map, int idx) { - map->aio.data[idx] = malloc(perf_mmap__mmap_len(map)); + map->aio.data[idx] = malloc(mmap__mmap_len(map)); if (map->aio.data[idx] == NULL) return -1; @@ -311,19 +205,13 @@ static void perf_mmap__aio_munmap(struct mmap *map __maybe_unused) } #endif -void perf_mmap__munmap(struct mmap *map) +void mmap__munmap(struct mmap *map) { perf_mmap__aio_munmap(map); if (map->data != NULL) { - munmap(map->data, perf_mmap__mmap_len(map)); + munmap(map->data, mmap__mmap_len(map)); map->data = NULL; } - if (map->core.base != NULL) { - munmap(map->core.base, perf_mmap__mmap_len(map)); - map->core.base = NULL; - map->core.fd = -1; - refcount_set(&map->core.refcnt, 0); - } auxtrace_mmap__munmap(&map->auxtrace_mmap); } @@ -353,34 +241,13 @@ static void perf_mmap__setup_affinity_mask(struct mmap *map, struct mmap_params CPU_SET(map->core.cpu, &map->affinity_mask); } -int perf_mmap__mmap(struct mmap *map, struct mmap_params *mp, int fd, int cpu) +int mmap__mmap(struct mmap *map, struct mmap_params *mp, int fd, int cpu) { - /* - * The last one will be done at perf_mmap__consume(), so that we - * make sure we don't prevent tools from consuming every last event in - * the ring buffer. - * - * I.e. we can get the POLLHUP meaning that the fd doesn't exist - * anymore, but the last events for it are still in the ring buffer, - * waiting to be consumed. - * - * Tools can chose to ignore this at their own discretion, but the - * evlist layer can't just drop it when filtering events in - * perf_evlist__filter_pollfd(). - */ - refcount_set(&map->core.refcnt, 2); - map->core.prev = 0; - map->core.mask = mp->mask; - map->core.base = mmap(NULL, perf_mmap__mmap_len(map), mp->prot, - MAP_SHARED, fd, 0); - if (map->core.base == MAP_FAILED) { + if (perf_mmap__mmap(&map->core, &mp->core, fd, cpu)) { pr_debug2("failed to mmap perf event ring buffer, error %d\n", errno); - map->core.base = NULL; return -1; } - map->core.fd = fd; - map->core.cpu = cpu; perf_mmap__setup_affinity_mask(map, mp); @@ -389,7 +256,7 @@ int perf_mmap__mmap(struct mmap *map, struct mmap_params *mp, int fd, int cpu) map->comp_level = mp->comp_level; if (map->comp_level && !perf_mmap__aio_enabled(map)) { - map->data = mmap(NULL, perf_mmap__mmap_len(map), PROT_READ|PROT_WRITE, + map->data = mmap(NULL, mmap__mmap_len(map), PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0); if (map->data == MAP_FAILED) { pr_debug2("failed to mmap data buffer, error %d\n", @@ -406,96 +273,16 @@ int perf_mmap__mmap(struct mmap *map, struct mmap_params *mp, int fd, int cpu) return perf_mmap__aio_mmap(map, mp); } -static int overwrite_rb_find_range(void *buf, int mask, u64 *start, u64 *end) -{ - struct perf_event_header *pheader; - u64 evt_head = *start; - int size = mask + 1; - - pr_debug2("%s: buf=%p, start=%"PRIx64"\n", __func__, buf, *start); - pheader = (struct perf_event_header *)(buf + (*start & mask)); - while (true) { - if (evt_head - *start >= (unsigned int)size) { - pr_debug("Finished reading overwrite ring buffer: rewind\n"); - if (evt_head - *start > (unsigned int)size) - evt_head -= pheader->size; - *end = evt_head; - return 0; - } - - pheader = (struct perf_event_header *)(buf + (evt_head & mask)); - - if (pheader->size == 0) { - pr_debug("Finished reading overwrite ring buffer: get start\n"); - *end = evt_head; - return 0; - } - - evt_head += pheader->size; - pr_debug3("move evt_head: %"PRIx64"\n", evt_head); - } - WARN_ONCE(1, "Shouldn't get here\n"); - return -1; -} - -/* - * Report the start and end of the available data in ringbuffer - */ -static int __perf_mmap__read_init(struct mmap *md) -{ - u64 head = perf_mmap__read_head(md); - u64 old = md->core.prev; - unsigned char *data = md->core.base + page_size; - unsigned long size; - - md->core.start = md->core.overwrite ? head : old; - md->core.end = md->core.overwrite ? old : head; - - if ((md->core.end - md->core.start) < md->core.flush) - return -EAGAIN; - - size = md->core.end - md->core.start; - if (size > (unsigned long)(md->core.mask) + 1) { - if (!md->core.overwrite) { - WARN_ONCE(1, "failed to keep up with mmap data. (warn only once)\n"); - - md->core.prev = head; - perf_mmap__consume(md); - return -EAGAIN; - } - - /* - * Backward ring buffer is full. We still have a chance to read - * most of data from it. - */ - if (overwrite_rb_find_range(data, md->core.mask, &md->core.start, &md->core.end)) - return -EINVAL; - } - - return 0; -} - -int perf_mmap__read_init(struct mmap *map) -{ - /* - * Check if event was unmapped due to a POLLHUP/POLLERR. - */ - if (!refcount_read(&map->core.refcnt)) - return -ENOENT; - - return __perf_mmap__read_init(map); -} - int perf_mmap__push(struct mmap *md, void *to, int push(struct mmap *map, void *to, void *buf, size_t size)) { - u64 head = perf_mmap__read_head(md); + u64 head = perf_mmap__read_head(&md->core); unsigned char *data = md->core.base + page_size; unsigned long size; void *buf; int rc = 0; - rc = perf_mmap__read_init(md); + rc = perf_mmap__read_init(&md->core); if (rc < 0) return (rc == -EAGAIN) ? 1 : -1; @@ -522,24 +309,7 @@ int perf_mmap__push(struct mmap *md, void *to, } md->core.prev = head; - perf_mmap__consume(md); + perf_mmap__consume(&md->core); out: return rc; } - -/* - * Mandatory for overwrite mode - * The direction of overwrite mode is backward. - * The last perf_mmap__read() will set tail to map->core.prev. - * Need to correct the map->core.prev to head which is the end of next read. - */ -void perf_mmap__read_done(struct mmap *map) -{ - /* - * Check if event was unmapped due to a POLLHUP/POLLERR. - */ - if (!refcount_read(&map->core.refcnt)) - return; - - map->core.prev = perf_mmap__read_head(map); -} diff --git a/tools/perf/util/mmap.h b/tools/perf/util/mmap.h index e567c1c875bd..bee4e83f7109 100644 --- a/tools/perf/util/mmap.h +++ b/tools/perf/util/mmap.h @@ -37,37 +37,19 @@ struct mmap { }; struct mmap_params { - int prot, mask, nr_cblocks, affinity, flush, comp_level; + struct perf_mmap_param core; + int nr_cblocks, affinity, flush, comp_level; struct auxtrace_mmap_params auxtrace_mp; }; -int perf_mmap__mmap(struct mmap *map, struct mmap_params *mp, int fd, int cpu); -void perf_mmap__munmap(struct mmap *map); - -void perf_mmap__get(struct mmap *map); -void perf_mmap__put(struct mmap *map); - -void perf_mmap__consume(struct mmap *map); - -static inline u64 perf_mmap__read_head(struct mmap *mm) -{ - return ring_buffer_read_head(mm->core.base); -} - -static inline void perf_mmap__write_tail(struct mmap *md, u64 tail) -{ - ring_buffer_write_tail(md->core.base, tail); -} +int mmap__mmap(struct mmap *map, struct mmap_params *mp, int fd, int cpu); +void mmap__munmap(struct mmap *map); union perf_event *perf_mmap__read_forward(struct mmap *map); -union perf_event *perf_mmap__read_event(struct mmap *map); - int perf_mmap__push(struct mmap *md, void *to, int push(struct mmap *map, void *to, void *buf, size_t size)); -size_t perf_mmap__mmap_len(struct mmap *map); +size_t mmap__mmap_len(struct mmap *map); -int perf_mmap__read_init(struct mmap *md); -void perf_mmap__read_done(struct mmap *map); #endif /*__PERF_MMAP_H */ diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index b5e2adef49de..db882f630f7e 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -2600,7 +2600,7 @@ out_enomem: * Print the help text for the event symbols: */ void print_events(const char *event_glob, bool name_only, bool quiet_flag, - bool long_desc, bool details_flag) + bool long_desc, bool details_flag, bool deprecated) { print_symbol_events(event_glob, PERF_TYPE_HARDWARE, event_symbols_hw, PERF_COUNT_HW_MAX, name_only); @@ -2612,7 +2612,7 @@ void print_events(const char *event_glob, bool name_only, bool quiet_flag, print_hwcache_events(event_glob, name_only); print_pmu_events(event_glob, name_only, quiet_flag, long_desc, - details_flag); + details_flag, deprecated); if (event_glob != NULL) return; diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index 616ca1eda0eb..769e07cddaa2 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h @@ -195,7 +195,7 @@ void parse_events_evlist_error(struct parse_events_state *parse_state, int idx, const char *str); void print_events(const char *event_glob, bool name_only, bool quiet, - bool long_desc, bool details_flag); + bool long_desc, bool details_flag, bool deprecated); struct event_symbol { const char *symbol; diff --git a/tools/perf/util/parse-regs-options.c b/tools/perf/util/parse-regs-options.c index ef46c2848808..e687497b3aac 100644 --- a/tools/perf/util/parse-regs-options.c +++ b/tools/perf/util/parse-regs-options.c @@ -13,7 +13,7 @@ static int __parse_regs(const struct option *opt, const char *str, int unset, bool intr) { uint64_t *mode = (uint64_t *)opt->value; - const struct sample_reg *r; + const struct sample_reg *r = NULL; char *s, *os = NULL, *p; int ret = -1; uint64_t mask; @@ -46,19 +46,23 @@ __parse_regs(const struct option *opt, const char *str, int unset, bool intr) if (!strcmp(s, "?")) { fprintf(stderr, "available registers: "); +#ifdef HAVE_PERF_REGS_SUPPORT for (r = sample_reg_masks; r->name; r++) { if (r->mask & mask) fprintf(stderr, "%s ", r->name); } +#endif fputc('\n', stderr); /* just printing available regs */ return -1; } +#ifdef HAVE_PERF_REGS_SUPPORT for (r = sample_reg_masks; r->name; r++) { if ((r->mask & mask) && !strcasecmp(s, r->name)) break; } - if (!r->name) { +#endif + if (!r || !r->name) { ui__warning("Unknown register \"%s\", check man page or run \"perf record %s?\"\n", s, intr ? "-I" : "--user-regs="); goto error; diff --git a/tools/perf/util/perf_regs.c b/tools/perf/util/perf_regs.c index 2774cec1f15f..5ee47ae1509c 100644 --- a/tools/perf/util/perf_regs.c +++ b/tools/perf/util/perf_regs.c @@ -3,10 +3,6 @@ #include "perf_regs.h" #include "event.h" -const struct sample_reg __weak sample_reg_masks[] = { - SMPL_REG_END -}; - int __weak arch_sdt_arg_parse_op(char *old_op __maybe_unused, char **new_op __maybe_unused) { diff --git a/tools/perf/util/perf_regs.h b/tools/perf/util/perf_regs.h index 47fe34e5f7d5..e014c2c038f4 100644 --- a/tools/perf/util/perf_regs.h +++ b/tools/perf/util/perf_regs.h @@ -15,8 +15,6 @@ struct sample_reg { #define SMPL_REG2(n, b) { .name = #n, .mask = 3ULL << (b) } #define SMPL_REG_END { .name = NULL } -extern const struct sample_reg sample_reg_masks[]; - enum { SDT_ARG_VALID = 0, SDT_ARG_SKIP, @@ -27,6 +25,8 @@ uint64_t arch__intr_reg_mask(void); uint64_t arch__user_reg_mask(void); #ifdef HAVE_PERF_REGS_SUPPORT +extern const struct sample_reg sample_reg_masks[]; + #include <perf_regs.h> #define DWARF_MINIMAL_REGS ((1ULL << PERF_REG_IP) | (1ULL << PERF_REG_SP)) diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index 5608da82ad23..adbe97e941dd 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c @@ -308,7 +308,8 @@ static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name, char *long_desc, char *topic, char *unit, char *perpkg, char *metric_expr, - char *metric_name) + char *metric_name, + char *deprecated) { struct parse_events_term *term; struct perf_pmu_alias *alias; @@ -325,6 +326,7 @@ static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name, alias->unit[0] = '\0'; alias->per_pkg = false; alias->snapshot = false; + alias->deprecated = false; ret = parse_events_terms(&alias->terms, val); if (ret) { @@ -379,6 +381,9 @@ static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name, alias->per_pkg = perpkg && sscanf(perpkg, "%d", &num) == 1 && num == 1; alias->str = strdup(newval); + if (deprecated) + alias->deprecated = true; + if (!perf_pmu_merge_alias(alias, list)) list_add_tail(&alias->list, list); @@ -400,7 +405,7 @@ static int perf_pmu__new_alias(struct list_head *list, char *dir, char *name, FI strim(buf); return __perf_pmu__new_alias(list, dir, name, NULL, buf, NULL, NULL, NULL, - NULL, NULL, NULL); + NULL, NULL, NULL, NULL); } static inline bool pmu_alias_info_file(char *name) @@ -787,7 +792,8 @@ new_alias: (char *)pe->long_desc, (char *)pe->topic, (char *)pe->unit, (char *)pe->perpkg, (char *)pe->metric_expr, - (char *)pe->metric_name); + (char *)pe->metric_name, + (char *)pe->deprecated); } } @@ -1383,7 +1389,7 @@ static void wordwrap(char *s, int start, int max, int corr) } void print_pmu_events(const char *event_glob, bool name_only, bool quiet_flag, - bool long_desc, bool details_flag) + bool long_desc, bool details_flag, bool deprecated) { struct perf_pmu *pmu; struct perf_pmu_alias *alias; @@ -1414,6 +1420,9 @@ void print_pmu_events(const char *event_glob, bool name_only, bool quiet_flag, format_alias(buf, sizeof(buf), pmu, alias); bool is_cpu = !strcmp(pmu->name, "cpu"); + if (alias->deprecated && !deprecated) + continue; + if (event_glob != NULL && !(strglobmatch_nocase(name, event_glob) || (!is_cpu && strglobmatch_nocase(alias->name, diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h index f36ade6df76d..3e8cd31a89cc 100644 --- a/tools/perf/util/pmu.h +++ b/tools/perf/util/pmu.h @@ -57,6 +57,7 @@ struct perf_pmu_alias { double scale; bool per_pkg; bool snapshot; + bool deprecated; char *metric_expr; char *metric_name; }; @@ -85,7 +86,8 @@ int perf_pmu__format_parse(char *dir, struct list_head *head); struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu); void print_pmu_events(const char *event_glob, bool name_only, bool quiet, - bool long_desc, bool details_flag); + bool long_desc, bool details_flag, + bool deprecated); bool pmu_have_event(const char *pname, const char *name); int perf_pmu__scan_file(struct perf_pmu *pmu, const char *name, const char *fmt, ...) __scanf(3, 4); diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c index 02460362256d..25118605f3f8 100644 --- a/tools/perf/util/python.c +++ b/tools/perf/util/python.c @@ -6,6 +6,7 @@ #include <linux/err.h> #include <perf/cpumap.h> #include <traceevent/event-parse.h> +#include <perf/mmap.h> #include "evlist.h" #include "callchain.h" #include "evsel.h" @@ -1022,10 +1023,10 @@ static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist, if (!md) return NULL; - if (perf_mmap__read_init(md) < 0) + if (perf_mmap__read_init(&md->core) < 0) goto end; - event = perf_mmap__read_event(md); + event = perf_mmap__read_event(&md->core); if (event != NULL) { PyObject *pyevent = pyrf_event__new(event); struct pyrf_event *pevent = (struct pyrf_event *)pyevent; @@ -1045,7 +1046,7 @@ static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist, err = perf_evsel__parse_sample(evsel, event, &pevent->sample); /* Consume the even only after we parsed it out. */ - perf_mmap__consume(md); + perf_mmap__consume(&md->core); if (err) return PyErr_Format(PyExc_OSError, diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c index 15961854ba67..741f040648b5 100644 --- a/tools/perf/util/scripting-engines/trace-event-perl.c +++ b/tools/perf/util/scripting-engines/trace-event-perl.c @@ -539,10 +539,11 @@ static int perl_stop_script(void) static int perl_generate_script(struct tep_handle *pevent, const char *outfile) { + int i, not_first, count, nr_events; + struct tep_event **all_events; struct tep_event *event = NULL; struct tep_format_field *f; char fname[PATH_MAX]; - int not_first, count; FILE *ofp; sprintf(fname, "%s.pl", outfile); @@ -603,8 +604,11 @@ sub print_backtrace\n\ }\n\n\ "); + nr_events = tep_get_events_count(pevent); + all_events = tep_list_events(pevent, TEP_EVENT_SORT_ID); - while ((event = trace_find_next_event(pevent, event))) { + for (i = 0; all_events && i < nr_events; i++) { + event = all_events[i]; fprintf(ofp, "sub %s::%s\n{\n", event->system, event->name); fprintf(ofp, "\tmy ("); diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index 5d341efc3237..93c03b39cd9c 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c @@ -1687,10 +1687,11 @@ static int python_stop_script(void) static int python_generate_script(struct tep_handle *pevent, const char *outfile) { + int i, not_first, count, nr_events; + struct tep_event **all_events; struct tep_event *event = NULL; struct tep_format_field *f; char fname[PATH_MAX]; - int not_first, count; FILE *ofp; sprintf(fname, "%s.py", outfile); @@ -1735,7 +1736,11 @@ static int python_generate_script(struct tep_handle *pevent, const char *outfile fprintf(ofp, "def trace_end():\n"); fprintf(ofp, "\tprint(\"in trace_end\")\n\n"); - while ((event = trace_find_next_event(pevent, event))) { + nr_events = tep_get_events_count(pevent); + all_events = tep_list_events(pevent, TEP_EVENT_SORT_ID); + + for (i = 0; all_events && i < nr_events; i++) { + event = all_events[i]; fprintf(ofp, "def %s__%s(", event->system, event->name); fprintf(ofp, "event_name, "); fprintf(ofp, "context, "); diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 061bb4d6a3f5..6cc32f5ec043 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -2355,35 +2355,6 @@ void perf_session__fprintf_info(struct perf_session *session, FILE *fp, fprintf(fp, "# ========\n#\n"); } - -int __perf_session__set_tracepoints_handlers(struct perf_session *session, - const struct evsel_str_handler *assocs, - size_t nr_assocs) -{ - struct evsel *evsel; - size_t i; - int err; - - for (i = 0; i < nr_assocs; i++) { - /* - * Adding a handler for an event not in the session, - * just ignore it. - */ - evsel = perf_evlist__find_tracepoint_by_name(session->evlist, assocs[i].name); - if (evsel == NULL) - continue; - - err = -EEXIST; - if (evsel->handler != NULL) - goto out; - evsel->handler = assocs[i].handler; - } - - err = 0; -out: - return err; -} - int perf_event__process_id_index(struct perf_session *session, union perf_event *event) { diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index b4c9428c18f0..8456e1d868fd 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h @@ -120,12 +120,8 @@ void perf_session__fprintf_info(struct perf_session *s, FILE *fp, bool full); struct evsel_str_handler; -int __perf_session__set_tracepoints_handlers(struct perf_session *session, - const struct evsel_str_handler *assocs, - size_t nr_assocs); - #define perf_session__set_tracepoints_handlers(session, array) \ - __perf_session__set_tracepoints_handlers(session, array, ARRAY_SIZE(array)) + __evlist__set_tracepoints_handlers(session->evlist, array, ARRAY_SIZE(array)) extern volatile int session_done; diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h index 7b93f34ac1f4..5aff9542d9b7 100644 --- a/tools/perf/util/sort.h +++ b/tools/perf/util/sort.h @@ -10,6 +10,8 @@ #include "callchain.h" #include "values.h" #include "hist.h" +#include "stat.h" +#include "spark.h" struct option; struct thread; @@ -71,6 +73,8 @@ struct hist_entry_diff { /* PERF_HPP_DIFF__CYCLES */ s64 cycles; }; + struct stats stats; + unsigned long svals[NUM_SPARKS]; }; struct hist_entry_ops { diff --git a/tools/perf/util/spark.c b/tools/perf/util/spark.c new file mode 100644 index 000000000000..70272a8b81a6 --- /dev/null +++ b/tools/perf/util/spark.c @@ -0,0 +1,34 @@ +#include <stdio.h> +#include <limits.h> +#include <string.h> +#include <stdlib.h> +#include "spark.h" +#include "stat.h" + +#define SPARK_SHIFT 8 + +/* Print spark lines on outf for numval values in val. */ +int print_spark(char *bf, int size, unsigned long *val, int numval) +{ + static const char *ticks[NUM_SPARKS] = { + "▁", "▂", "▃", "▄", "▅", "▆", "▇", "█" + }; + int i, printed = 0; + unsigned long min = ULONG_MAX, max = 0, f; + + for (i = 0; i < numval; i++) { + if (val[i] < min) + min = val[i]; + if (val[i] > max) + max = val[i]; + } + f = ((max - min) << SPARK_SHIFT) / (NUM_SPARKS - 1); + if (f < 1) + f = 1; + for (i = 0; i < numval; i++) { + printed += scnprintf(bf + printed, size - printed, "%s", + ticks[((val[i] - min) << SPARK_SHIFT) / f]); + } + + return printed; +} diff --git a/tools/perf/util/spark.h b/tools/perf/util/spark.h new file mode 100644 index 000000000000..25402d7d7a64 --- /dev/null +++ b/tools/perf/util/spark.h @@ -0,0 +1,8 @@ +#ifndef SPARK_H +#define SPARK_H 1 + +#define NUM_SPARKS 8 + +int print_spark(char *bf, int size, unsigned long *val, int numval); + +#endif diff --git a/tools/perf/util/stat.c b/tools/perf/util/stat.c index ebdd130557fb..6822e4ffe224 100644 --- a/tools/perf/util/stat.c +++ b/tools/perf/util/stat.c @@ -490,6 +490,16 @@ int create_perf_stat_counter(struct evsel *evsel, if (config->identifier) attr->sample_type = PERF_SAMPLE_IDENTIFIER; + if (config->all_user) { + attr->exclude_kernel = 1; + attr->exclude_user = 0; + } + + if (config->all_kernel) { + attr->exclude_kernel = 0; + attr->exclude_user = 1; + } + /* * Disabling all counters initially, they will be enabled * either manually by us or by kernel via enable_on_exec diff --git a/tools/perf/util/stat.h b/tools/perf/util/stat.h index edbeb2f63e8d..081c4a5113c6 100644 --- a/tools/perf/util/stat.h +++ b/tools/perf/util/stat.h @@ -106,6 +106,8 @@ struct perf_stat_config { bool big_num; bool no_merge; bool walltime_run_table; + bool all_kernel; + bool all_user; FILE *output; unsigned int interval; unsigned int timeout; diff --git a/tools/perf/util/string2.h b/tools/perf/util/string2.h index 708805f5573e..73df616ced43 100644 --- a/tools/perf/util/string2.h +++ b/tools/perf/util/string2.h @@ -4,6 +4,7 @@ #include <linux/string.h> #include <linux/types.h> +#include <sys/types.h> // pid_t #include <stddef.h> #include <string.h> @@ -32,6 +33,8 @@ static inline char *asprintf_expr_not_in_ints(const char *var, size_t nints, int return asprintf_expr_inout_ints(var, false, nints, ints); } +char *asprintf__tp_filter_pids(size_t npids, pid_t *pids); + char *strpbrk_esc(char *str, const char *stopset); char *strdup_esc(const char *str); diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 0b0c6b5b1899..cc2a89b99d3d 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -11,6 +11,7 @@ #include <stdio.h> #include "path.h" #include "symbol_conf.h" +#include "spark.h" #ifdef HAVE_LIBELF_SUPPORT #include <libelf.h> @@ -111,6 +112,7 @@ struct block_info { u64 end; u64 cycles; u64 cycles_aggr; + s64 cycles_spark[NUM_SPARKS]; int num; int num_aggr; refcount_t refcnt; diff --git a/tools/perf/util/time-utils.c b/tools/perf/util/time-utils.c index 9796a2e43f67..302443921681 100644 --- a/tools/perf/util/time-utils.c +++ b/tools/perf/util/time-utils.c @@ -458,10 +458,11 @@ bool perf_time__ranges_skip_sample(struct perf_time_interval *ptime_buf, return true; } -int perf_time__parse_for_ranges(const char *time_str, +int perf_time__parse_for_ranges_reltime(const char *time_str, struct perf_session *session, struct perf_time_interval **ranges, - int *range_size, int *range_num) + int *range_size, int *range_num, + bool reltime) { bool has_percent = strchr(time_str, '%'); struct perf_time_interval *ptime_range; @@ -471,7 +472,7 @@ int perf_time__parse_for_ranges(const char *time_str, if (!ptime_range) return -ENOMEM; - if (has_percent) { + if (has_percent || reltime) { if (session->evlist->first_sample_time == 0 && session->evlist->last_sample_time == 0) { pr_err("HINT: no first/last sample time found in perf data.\n" @@ -479,7 +480,9 @@ int perf_time__parse_for_ranges(const char *time_str, "(if '--buildid-all' is enabled, please set '--timestamp-boundary').\n"); goto error; } + } + if (has_percent) { num = perf_time__percent_parse_str( ptime_range, size, time_str, @@ -492,6 +495,15 @@ int perf_time__parse_for_ranges(const char *time_str, if (num < 0) goto error_invalid; + if (reltime) { + int i; + + for (i = 0; i < num; i++) { + ptime_range[i].start += session->evlist->first_sample_time; + ptime_range[i].end += session->evlist->first_sample_time; + } + } + *range_size = size; *range_num = num; *ranges = ptime_range; @@ -504,6 +516,15 @@ error: return ret; } +int perf_time__parse_for_ranges(const char *time_str, + struct perf_session *session, + struct perf_time_interval **ranges, + int *range_size, int *range_num) +{ + return perf_time__parse_for_ranges_reltime(time_str, session, ranges, + range_size, range_num, false); +} + int timestamp__scnprintf_usec(u64 timestamp, char *buf, size_t sz) { u64 sec = timestamp / NSEC_PER_SEC; diff --git a/tools/perf/util/time-utils.h b/tools/perf/util/time-utils.h index 4f42988eb2f7..1142b0bddd5e 100644 --- a/tools/perf/util/time-utils.h +++ b/tools/perf/util/time-utils.h @@ -26,6 +26,11 @@ bool perf_time__ranges_skip_sample(struct perf_time_interval *ptime_buf, struct perf_session; +int perf_time__parse_for_ranges_reltime(const char *str, struct perf_session *session, + struct perf_time_interval **ranges, + int *range_size, int *range_num, + bool reltime); + int perf_time__parse_for_ranges(const char *str, struct perf_session *session, struct perf_time_interval **ranges, int *range_size, int *range_num); diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c index 5d6bfc70b210..9634f0ae57be 100644 --- a/tools/perf/util/trace-event-parse.c +++ b/tools/perf/util/trace-event-parse.c @@ -173,37 +173,6 @@ int parse_event_file(struct tep_handle *pevent, return tep_parse_event(pevent, buf, size, sys); } -struct tep_event *trace_find_next_event(struct tep_handle *pevent, - struct tep_event *event) -{ - static int idx; - int events_count; - struct tep_event *all_events; - - all_events = tep_get_first_event(pevent); - events_count = tep_get_events_count(pevent); - if (!pevent || !all_events || events_count < 1) - return NULL; - - if (!event) { - idx = 0; - return all_events; - } - - if (idx < events_count && event == (all_events + idx)) { - idx++; - if (idx == events_count) - return NULL; - return (all_events + idx); - } - - for (idx = 1; idx < events_count; idx++) { - if (event == (all_events + (idx - 1))) - return (all_events + idx); - } - return NULL; -} - struct flag { const char *name; unsigned long long value; diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h index 2e158387b3d7..72fdf2a3577c 100644 --- a/tools/perf/util/trace-event.h +++ b/tools/perf/util/trace-event.h @@ -47,8 +47,6 @@ void parse_saved_cmdline(struct tep_handle *pevent, char *file, unsigned int siz ssize_t trace_report(int fd, struct trace_event *tevent, bool repipe); -struct tep_event *trace_find_next_event(struct tep_handle *pevent, - struct tep_event *event); unsigned long long read_size(struct tep_event *event, void *ptr, int size); unsigned long long eval_flag(const char *flag); |