diff options
Diffstat (limited to 'tools/perf/util/evlist.c')
| -rw-r--r-- | tools/perf/util/evlist.c | 189 |
1 files changed, 116 insertions, 73 deletions
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index b939221efd8..59ef2802fcf 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -7,7 +7,7 @@ * Released under the GPL v2. (and only v2, not any later version) */ #include "util.h" -#include <lk/debugfs.h> +#include <api/fs/debugfs.h> #include <poll.h> #include "cpumap.h" #include "thread_map.h" @@ -81,7 +81,7 @@ static void perf_evlist__update_id_pos(struct perf_evlist *evlist) { struct perf_evsel *evsel; - list_for_each_entry(evsel, &evlist->entries, node) + evlist__for_each(evlist, evsel) perf_evsel__calc_id_pos(evsel); perf_evlist__set_id_pos(evlist); @@ -91,7 +91,7 @@ static void perf_evlist__purge(struct perf_evlist *evlist) { struct perf_evsel *pos, *n; - list_for_each_entry_safe(pos, n, &evlist->entries, node) { + evlist__for_each_safe(evlist, n, pos) { list_del_init(&pos->node); perf_evsel__delete(pos); } @@ -101,14 +101,18 @@ static void perf_evlist__purge(struct perf_evlist *evlist) void perf_evlist__exit(struct perf_evlist *evlist) { - free(evlist->mmap); - free(evlist->pollfd); - evlist->mmap = NULL; - evlist->pollfd = NULL; + zfree(&evlist->mmap); + zfree(&evlist->pollfd); } void perf_evlist__delete(struct perf_evlist *evlist) { + perf_evlist__munmap(evlist); + perf_evlist__close(evlist); + cpu_map__delete(evlist->cpus); + thread_map__delete(evlist->threads); + evlist->cpus = NULL; + evlist->threads = NULL; perf_evlist__purge(evlist); perf_evlist__exit(evlist); free(evlist); @@ -117,6 +121,8 @@ void perf_evlist__delete(struct perf_evlist *evlist) void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry) { list_add_tail(&entry->node, &evlist->entries); + entry->idx = evlist->nr_entries; + if (!evlist->nr_entries++) perf_evlist__set_id_pos(evlist); } @@ -142,7 +148,7 @@ void __perf_evlist__set_leader(struct list_head *list) leader->nr_members = evsel->idx - leader->idx + 1; - list_for_each_entry(evsel, list, node) { + __evlist__for_each(list, evsel) { evsel->leader = leader; } } @@ -165,7 +171,7 @@ int perf_evlist__add_default(struct perf_evlist *evlist) event_attr_init(&attr); - evsel = perf_evsel__new(&attr, 0); + evsel = perf_evsel__new(&attr); if (evsel == NULL) goto error; @@ -190,7 +196,7 @@ static int perf_evlist__add_attrs(struct perf_evlist *evlist, size_t i; for (i = 0; i < nr_attrs; i++) { - evsel = perf_evsel__new(attrs + i, evlist->nr_entries + i); + evsel = perf_evsel__new_idx(attrs + i, evlist->nr_entries + i); if (evsel == NULL) goto out_delete_partial_list; list_add_tail(&evsel->node, &head); @@ -201,7 +207,7 @@ static int perf_evlist__add_attrs(struct perf_evlist *evlist, return 0; out_delete_partial_list: - list_for_each_entry_safe(evsel, n, &head, node) + __evlist__for_each_safe(&head, n, evsel) perf_evsel__delete(evsel); return -1; } @@ -222,7 +228,7 @@ perf_evlist__find_tracepoint_by_id(struct perf_evlist *evlist, int id) { struct perf_evsel *evsel; - list_for_each_entry(evsel, &evlist->entries, node) { + evlist__for_each(evlist, evsel) { if (evsel->attr.type == PERF_TYPE_TRACEPOINT && (int)evsel->attr.config == id) return evsel; @@ -237,7 +243,7 @@ perf_evlist__find_tracepoint_by_name(struct perf_evlist *evlist, { struct perf_evsel *evsel; - list_for_each_entry(evsel, &evlist->entries, node) { + evlist__for_each(evlist, evsel) { if ((evsel->attr.type == PERF_TYPE_TRACEPOINT) && (strcmp(evsel->name, name) == 0)) return evsel; @@ -249,9 +255,8 @@ perf_evlist__find_tracepoint_by_name(struct perf_evlist *evlist, int perf_evlist__add_newtp(struct perf_evlist *evlist, const char *sys, const char *name, void *handler) { - struct perf_evsel *evsel; + struct perf_evsel *evsel = perf_evsel__newtp(sys, name); - evsel = perf_evsel__newtp(sys, name, evlist->nr_entries); if (evsel == NULL) return -1; @@ -268,7 +273,7 @@ void perf_evlist__disable(struct perf_evlist *evlist) int nr_threads = thread_map__nr(evlist->threads); for (cpu = 0; cpu < nr_cpus; cpu++) { - list_for_each_entry(pos, &evlist->entries, node) { + evlist__for_each(evlist, pos) { if (!perf_evsel__is_group_leader(pos) || !pos->fd) continue; for (thread = 0; thread < nr_threads; thread++) @@ -286,7 +291,7 @@ void perf_evlist__enable(struct perf_evlist *evlist) int nr_threads = thread_map__nr(evlist->threads); for (cpu = 0; cpu < nr_cpus; cpu++) { - list_for_each_entry(pos, &evlist->entries, node) { + evlist__for_each(evlist, pos) { if (!perf_evsel__is_group_leader(pos) || !pos->fd) continue; for (thread = 0; thread < nr_threads; thread++) @@ -583,11 +588,13 @@ void perf_evlist__munmap(struct perf_evlist *evlist) { int i; + if (evlist->mmap == NULL) + return; + for (i = 0; i < evlist->nr_mmaps; i++) __perf_evlist__munmap(evlist, i); - free(evlist->mmap); - evlist->mmap = NULL; + zfree(&evlist->mmap); } static int perf_evlist__alloc_mmap(struct perf_evlist *evlist) @@ -623,7 +630,7 @@ static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx, { struct perf_evsel *evsel; - list_for_each_entry(evsel, &evlist->entries, node) { + evlist__for_each(evlist, evsel) { int fd = FD(evsel, cpu, thread); if (*output == -1) { @@ -704,12 +711,10 @@ static size_t perf_evlist__mmap_size(unsigned long pages) return (pages + 1) * page_size; } -int perf_evlist__parse_mmap_pages(const struct option *opt, const char *str, - int unset __maybe_unused) +static long parse_pages_arg(const char *str, unsigned long min, + unsigned long max) { - unsigned int *mmap_pages = opt->value; unsigned long pages, val; - size_t size; static struct parse_tag tags[] = { { .tag = 'B', .mult = 1 }, { .tag = 'K', .mult = 1 << 10 }, @@ -718,33 +723,51 @@ int perf_evlist__parse_mmap_pages(const struct option *opt, const char *str, { .tag = 0 }, }; + if (str == NULL) + return -EINVAL; + val = parse_tag_value(str, tags); if (val != (unsigned long) -1) { /* we got file size value */ pages = PERF_ALIGN(val, page_size) / page_size; - if (pages < (1UL << 31) && !is_power_of_2(pages)) { - pages = next_pow2(pages); - pr_info("rounding mmap pages size to %lu (%lu pages)\n", - pages * page_size, pages); - } } else { /* we got pages count value */ char *eptr; pages = strtoul(str, &eptr, 10); - if (*eptr != '\0') { - pr_err("failed to parse --mmap_pages/-m value\n"); - return -1; - } + if (*eptr != '\0') + return -EINVAL; } - if (pages > UINT_MAX || pages > SIZE_MAX / page_size) { - pr_err("--mmap_pages/-m value too big\n"); - return -1; + if (pages == 0 && min == 0) { + /* leave number of pages at 0 */ + } else if (!is_power_of_2(pages)) { + /* round pages up to next power of 2 */ + pages = next_pow2_l(pages); + if (!pages) + return -EINVAL; + pr_info("rounding mmap pages size to %lu bytes (%lu pages)\n", + pages * page_size, pages); } - size = perf_evlist__mmap_size(pages); - if (!size) { - pr_err("--mmap_pages/-m value must be a power of two."); + if (pages > max) + return -EINVAL; + + return pages; +} + +int perf_evlist__parse_mmap_pages(const struct option *opt, const char *str, + int unset __maybe_unused) +{ + unsigned int *mmap_pages = opt->value; + unsigned long max = UINT_MAX; + long pages; + + if (max > SIZE_MAX / page_size) + max = SIZE_MAX / page_size; + + pages = parse_pages_arg(str, 1, max); + if (pages < 0) { + pr_err("Invalid argument for --mmap_pages/-m\n"); return -1; } @@ -783,7 +806,7 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages, pr_debug("mmap size %zuB\n", evlist->mmap_len); mask = evlist->mmap_len - page_size - 1; - list_for_each_entry(evsel, &evlist->entries, node) { + evlist__for_each(evlist, evsel) { if ((evsel->attr.read_format & PERF_FORMAT_ID) && evsel->sample_id == NULL && perf_evsel__alloc_id(evsel, cpu_map__nr(cpus), threads->nr) < 0) @@ -796,8 +819,7 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages, return perf_evlist__mmap_per_cpu(evlist, prot, mask); } -int perf_evlist__create_maps(struct perf_evlist *evlist, - struct perf_target *target) +int perf_evlist__create_maps(struct perf_evlist *evlist, struct target *target) { evlist->threads = thread_map__new_str(target->pid, target->tid, target->uid); @@ -805,9 +827,7 @@ int perf_evlist__create_maps(struct perf_evlist *evlist, if (evlist->threads == NULL) return -1; - if (perf_target__has_task(target)) - evlist->cpus = cpu_map__dummy_new(); - else if (!perf_target__has_cpu(target) && !target->uses_mmap) + if (target__uses_dummy_map(target)) evlist->cpus = cpu_map__dummy_new(); else evlist->cpus = cpu_map__new(target->cpu_list); @@ -822,14 +842,6 @@ out_delete_threads: return -1; } -void perf_evlist__delete_maps(struct perf_evlist *evlist) -{ - cpu_map__delete(evlist->cpus); - thread_map__delete(evlist->threads); - evlist->cpus = NULL; - evlist->threads = NULL; -} - int perf_evlist__apply_filters(struct perf_evlist *evlist) { struct perf_evsel *evsel; @@ -837,7 +849,7 @@ int perf_evlist__apply_filters(struct perf_evlist *evlist) const int ncpus = cpu_map__nr(evlist->cpus), nthreads = thread_map__nr(evlist->threads); - list_for_each_entry(evsel, &evlist->entries, node) { + evlist__for_each(evlist, evsel) { if (evsel->filter == NULL) continue; @@ -856,7 +868,7 @@ int perf_evlist__set_filter(struct perf_evlist *evlist, const char *filter) const int ncpus = cpu_map__nr(evlist->cpus), nthreads = thread_map__nr(evlist->threads); - list_for_each_entry(evsel, &evlist->entries, node) { + evlist__for_each(evlist, evsel) { err = perf_evsel__set_filter(evsel, ncpus, nthreads, filter); if (err) break; @@ -875,7 +887,7 @@ bool perf_evlist__valid_sample_type(struct perf_evlist *evlist) if (evlist->id_pos < 0 || evlist->is_pos < 0) return false; - list_for_each_entry(pos, &evlist->entries, node) { + evlist__for_each(evlist, pos) { if (pos->id_pos != evlist->id_pos || pos->is_pos != evlist->is_pos) return false; @@ -891,7 +903,7 @@ u64 __perf_evlist__combined_sample_type(struct perf_evlist *evlist) if (evlist->combined_sample_type) return evlist->combined_sample_type; - list_for_each_entry(evsel, &evlist->entries, node) + evlist__for_each(evlist, evsel) evlist->combined_sample_type |= evsel->attr.sample_type; return evlist->combined_sample_type; @@ -909,7 +921,7 @@ bool perf_evlist__valid_read_format(struct perf_evlist *evlist) u64 read_format = first->attr.read_format; u64 sample_type = first->attr.sample_type; - list_for_each_entry_continue(pos, &evlist->entries, node) { + evlist__for_each(evlist, pos) { if (read_format != pos->attr.read_format) return false; } @@ -966,7 +978,7 @@ bool perf_evlist__valid_sample_id_all(struct perf_evlist *evlist) { struct perf_evsel *first = perf_evlist__first(evlist), *pos = first; - list_for_each_entry_continue(pos, &evlist->entries, node) { + evlist__for_each_continue(evlist, pos) { if (first->attr.sample_id_all != pos->attr.sample_id_all) return false; } @@ -991,9 +1003,12 @@ void perf_evlist__close(struct perf_evlist *evlist) struct perf_evsel *evsel; int ncpus = cpu_map__nr(evlist->cpus); int nthreads = thread_map__nr(evlist->threads); + int n; - list_for_each_entry_reverse(evsel, &evlist->entries, node) - perf_evsel__close(evsel, ncpus, nthreads); + evlist__for_each_reverse(evlist, evsel) { + n = evsel->cpus ? evsel->cpus->nr : ncpus; + perf_evsel__close(evsel, n, nthreads); + } } int perf_evlist__open(struct perf_evlist *evlist) @@ -1003,7 +1018,7 @@ int perf_evlist__open(struct perf_evlist *evlist) perf_evlist__update_id_pos(evlist); - list_for_each_entry(evsel, &evlist->entries, node) { + evlist__for_each(evlist, evsel) { err = perf_evsel__open(evsel, evlist->cpus, evlist->threads); if (err < 0) goto out_err; @@ -1016,10 +1031,9 @@ out_err: return err; } -int perf_evlist__prepare_workload(struct perf_evlist *evlist, - struct perf_target *target, +int perf_evlist__prepare_workload(struct perf_evlist *evlist, struct target *target, const char *argv[], bool pipe_output, - bool want_signal) + void (*exec_error)(int signo, siginfo_t *info, void *ucontext)) { int child_ready_pipe[2], go_pipe[2]; char bf; @@ -1063,13 +1077,26 @@ int perf_evlist__prepare_workload(struct perf_evlist *evlist, execvp(argv[0], (char **)argv); - perror(argv[0]); - if (want_signal) - kill(getppid(), SIGUSR1); + if (exec_error) { + union sigval val; + + val.sival_int = errno; + if (sigqueue(getppid(), SIGUSR1, val)) + perror(argv[0]); + } else + perror(argv[0]); exit(-1); } - if (perf_target__none(target)) + if (exec_error) { + struct sigaction act = { + .sa_flags = SA_SIGINFO, + .sa_sigaction = exec_error, + }; + sigaction(SIGUSR1, &act, NULL); + } + + if (target__none(target)) evlist->threads->map[0] = evlist->workload.pid; close(child_ready_pipe[1]); @@ -1130,12 +1157,12 @@ size_t perf_evlist__fprintf(struct perf_evlist *evlist, FILE *fp) struct perf_evsel *evsel; size_t printed = 0; - list_for_each_entry(evsel, &evlist->entries, node) { + evlist__for_each(evlist, evsel) { printed += fprintf(fp, "%s%s", evsel->idx ? ", " : "", perf_evsel__name(evsel)); } - return printed + fprintf(fp, "\n");; + return printed + fprintf(fp, "\n"); } int perf_evlist__strerror_tp(struct perf_evlist *evlist __maybe_unused, @@ -1178,8 +1205,7 @@ int perf_evlist__strerror_open(struct perf_evlist *evlist __maybe_unused, "Error:\t%s.\n" "Hint:\tCheck /proc/sys/kernel/perf_event_paranoid setting.", emsg); - if (filename__read_int("/proc/sys/kernel/perf_event_paranoid", &value)) - break; + value = perf_event_paranoid(); printed += scnprintf(buf + printed, size - printed, "\nHint:\t"); @@ -1200,3 +1226,20 @@ int perf_evlist__strerror_open(struct perf_evlist *evlist __maybe_unused, return 0; } + +void perf_evlist__to_front(struct perf_evlist *evlist, + struct perf_evsel *move_evsel) +{ + struct perf_evsel *evsel, *n; + LIST_HEAD(move); + + if (move_evsel == perf_evlist__first(evlist)) + return; + + evlist__for_each_safe(evlist, n, evsel) { + if (evsel->leader == move_evsel->leader) + list_move_tail(&evsel->node, &move); + } + + list_splice(&move, &evlist->entries); +} |
