diff options
Diffstat (limited to 'tools/perf/util/evsel.c')
| -rw-r--r-- | tools/perf/util/evsel.c | 174 |
1 files changed, 89 insertions, 85 deletions
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 0ce9febf1ba..8606175fe1e 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -9,7 +9,7 @@ #include <byteswap.h> #include <linux/bitops.h> -#include <lk/debugfs.h> +#include <api/fs/debugfs.h> #include <traceevent/event-parse.h> #include <linux/hw_breakpoint.h> #include <linux/perf_event.h> @@ -23,6 +23,7 @@ #include "target.h" #include "perf_regs.h" #include "debug.h" +#include "trace-event.h" static struct { bool sample_id_all; @@ -162,13 +163,15 @@ void perf_evsel__init(struct perf_evsel *evsel, evsel->idx = idx; evsel->attr = *attr; evsel->leader = evsel; + evsel->unit = ""; + evsel->scale = 1.0; INIT_LIST_HEAD(&evsel->node); hists__init(&evsel->hists); evsel->sample_size = __perf_evsel__sample_size(attr->sample_type); perf_evsel__calc_id_pos(evsel); } -struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx) +struct perf_evsel *perf_evsel__new_idx(struct perf_event_attr *attr, int idx) { struct perf_evsel *evsel = zalloc(sizeof(*evsel)); @@ -178,48 +181,7 @@ struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx) return evsel; } -struct event_format *event_format__new(const char *sys, const char *name) -{ - int fd, n; - char *filename; - void *bf = NULL, *nbf; - size_t size = 0, alloc_size = 0; - struct event_format *format = NULL; - - if (asprintf(&filename, "%s/%s/%s/format", tracing_events_path, sys, name) < 0) - goto out; - - fd = open(filename, O_RDONLY); - if (fd < 0) - goto out_free_filename; - - do { - if (size == alloc_size) { - alloc_size += BUFSIZ; - nbf = realloc(bf, alloc_size); - if (nbf == NULL) - goto out_free_bf; - bf = nbf; - } - - n = read(fd, bf + size, alloc_size - size); - if (n < 0) - goto out_free_bf; - size += n; - } while (n > 0); - - pevent_parse_format(&format, bf, size, sys); - -out_free_bf: - free(bf); - close(fd); -out_free_filename: - free(filename); -out: - return format; -} - -struct perf_evsel *perf_evsel__newtp(const char *sys, const char *name, int idx) +struct perf_evsel *perf_evsel__newtp_idx(const char *sys, const char *name, int idx) { struct perf_evsel *evsel = zalloc(sizeof(*evsel)); @@ -233,7 +195,7 @@ struct perf_evsel *perf_evsel__newtp(const char *sys, const char *name, int idx) if (asprintf(&evsel->name, "%s:%s", sys, name) < 0) goto out_free; - evsel->tp_format = event_format__new(sys, name); + evsel->tp_format = trace_event__tp_format(sys, name); if (evsel->tp_format == NULL) goto out_free; @@ -246,7 +208,7 @@ struct perf_evsel *perf_evsel__newtp(const char *sys, const char *name, int idx) return evsel; out_free: - free(evsel->name); + zfree(&evsel->name); free(evsel); return NULL; } @@ -538,6 +500,34 @@ int perf_evsel__group_desc(struct perf_evsel *evsel, char *buf, size_t size) return ret; } +static void +perf_evsel__config_callgraph(struct perf_evsel *evsel, + struct record_opts *opts) +{ + bool function = perf_evsel__is_function_event(evsel); + struct perf_event_attr *attr = &evsel->attr; + + perf_evsel__set_sample_bit(evsel, CALLCHAIN); + + if (opts->call_graph == CALLCHAIN_DWARF) { + if (!function) { + perf_evsel__set_sample_bit(evsel, REGS_USER); + perf_evsel__set_sample_bit(evsel, STACK_USER); + attr->sample_regs_user = PERF_REGS_MASK; + attr->sample_stack_user = opts->stack_dump_size; + attr->exclude_callchain_user = 1; + } else { + pr_info("Cannot use DWARF unwind for function trace event," + " falling back to framepointers.\n"); + } + } + + if (function) { + pr_info("Disabling user space callchains for function trace event.\n"); + attr->exclude_callchain_user = 1; + } +} + /* * The enable_on_exec/disabled value strategy: * @@ -566,12 +556,12 @@ int perf_evsel__group_desc(struct perf_evsel *evsel, char *buf, size_t size) * enable/disable events specifically, as there's no * initial traced exec call. */ -void perf_evsel__config(struct perf_evsel *evsel, - struct perf_record_opts *opts) +void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts) { struct perf_evsel *leader = evsel->leader; struct perf_event_attr *attr = &evsel->attr; int track = !evsel->idx; /* only the first counter needs these */ + bool per_cpu = opts->target.default_per_cpu && !opts->target.per_thread; attr->sample_id_all = perf_missing_features.sample_id_all ? 0 : 1; attr->inherit = !opts->no_inherit; @@ -599,10 +589,10 @@ void perf_evsel__config(struct perf_evsel *evsel, } /* - * We default some events to a 1 default interval. But keep + * We default some events to have a default interval. But keep * it a weak assumption overridable by the user. */ - if (!attr->sample_period || (opts->user_freq != UINT_MAX && + if (!attr->sample_period || (opts->user_freq != UINT_MAX || opts->user_interval != ULLONG_MAX)) { if (opts->freq) { perf_evsel__set_sample_bit(evsel, PERIOD); @@ -633,19 +623,10 @@ void perf_evsel__config(struct perf_evsel *evsel, attr->mmap_data = track; } - if (opts->call_graph) { - perf_evsel__set_sample_bit(evsel, CALLCHAIN); + if (opts->call_graph_enabled) + perf_evsel__config_callgraph(evsel, opts); - if (opts->call_graph == CALLCHAIN_DWARF) { - perf_evsel__set_sample_bit(evsel, REGS_USER); - perf_evsel__set_sample_bit(evsel, STACK_USER); - attr->sample_regs_user = PERF_REGS_MASK; - attr->sample_stack_user = opts->stack_dump_size; - attr->exclude_callchain_user = 1; - } - } - - if (perf_target__has_cpu(&opts->target)) + if (target__has_cpu(&opts->target)) perf_evsel__set_sample_bit(evsel, CPU); if (opts->period) @@ -653,7 +634,7 @@ void perf_evsel__config(struct perf_evsel *evsel, if (!perf_missing_features.sample_id_all && (opts->sample_time || !opts->no_inherit || - perf_target__has_cpu(&opts->target))) + target__has_cpu(&opts->target) || per_cpu)) perf_evsel__set_sample_bit(evsel, TIME); if (opts->raw_samples) { @@ -663,9 +644,9 @@ void perf_evsel__config(struct perf_evsel *evsel, } if (opts->sample_address) - attr->sample_type |= PERF_SAMPLE_DATA_SRC; + perf_evsel__set_sample_bit(evsel, DATA_SRC); - if (opts->no_delay) { + if (opts->no_buffering) { attr->watermark = 0; attr->wakeup_events = 1; } @@ -675,12 +656,15 @@ void perf_evsel__config(struct perf_evsel *evsel, } if (opts->sample_weight) - attr->sample_type |= PERF_SAMPLE_WEIGHT; + perf_evsel__set_sample_bit(evsel, WEIGHT); attr->mmap = track; attr->mmap2 = track && !perf_missing_features.mmap2; attr->comm = track; + if (opts->sample_transaction) + perf_evsel__set_sample_bit(evsel, TRANSACTION); + /* * XXX see the function comment above * @@ -694,7 +678,8 @@ void perf_evsel__config(struct perf_evsel *evsel, * Setting enable_on_exec for independent events and * group leaders for traced executed by perf. */ - if (perf_target__none(&opts->target) && perf_evsel__is_group_leader(evsel)) + if (target__none(&opts->target) && perf_evsel__is_group_leader(evsel) && + !opts->initial_delay) attr->enable_on_exec = 1; } @@ -786,8 +771,7 @@ void perf_evsel__free_id(struct perf_evsel *evsel) { xyarray__delete(evsel->sample_id); evsel->sample_id = NULL; - free(evsel->id); - evsel->id = NULL; + zfree(&evsel->id); } void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads) @@ -803,7 +787,7 @@ void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads) void perf_evsel__free_counts(struct perf_evsel *evsel) { - free(evsel->counts); + zfree(&evsel->counts); } void perf_evsel__exit(struct perf_evsel *evsel) @@ -817,10 +801,10 @@ void perf_evsel__delete(struct perf_evsel *evsel) { perf_evsel__exit(evsel); close_cgroup(evsel->cgrp); - free(evsel->group_name); + zfree(&evsel->group_name); if (evsel->tp_format) pevent_free_format(evsel->tp_format); - free(evsel->name); + zfree(&evsel->name); free(evsel); } @@ -983,6 +967,7 @@ static size_t perf_event_attr__fprintf(struct perf_event_attr *attr, FILE *fp) ret += PRINT_ATTR2(exclude_host, exclude_guest); ret += PRINT_ATTR2N("excl.callchain_kern", exclude_callchain_kernel, "excl.callchain_user", exclude_callchain_user); + ret += PRINT_ATTR_U32(mmap2); ret += PRINT_ATTR_U32(wakeup_events); ret += PRINT_ATTR_U32(wakeup_watermark); @@ -1039,7 +1024,7 @@ retry_sample_id: group_fd = get_group_fd(evsel, cpu, thread); retry_open: - pr_debug2("perf_event_open: pid %d cpu %d group_fd %d flags %#lx\n", + pr_debug2("sys_perf_event_open: pid %d cpu %d group_fd %d flags %#lx\n", pid, cpus->map[cpu], group_fd, flags); FD(evsel, cpu, thread) = sys_perf_event_open(&evsel->attr, @@ -1048,6 +1033,8 @@ retry_open: group_fd, flags); if (FD(evsel, cpu, thread) < 0) { err = -errno; + pr_debug2("sys_perf_event_open failed, error %d\n", + err); goto try_fallback; } set_rlimit = NO_CHANGE; @@ -1114,7 +1101,6 @@ void perf_evsel__close(struct perf_evsel *evsel, int ncpus, int nthreads) perf_evsel__close_fd(evsel, ncpus, nthreads); perf_evsel__free_fd(evsel); - evsel->fd = NULL; } static struct { @@ -1214,6 +1200,7 @@ static int perf_evsel__parse_id_sample(const struct perf_evsel *evsel, sample->pid = u.val32[0]; sample->tid = u.val32[1]; + array--; } return 0; @@ -1253,7 +1240,7 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event, memset(data, 0, sizeof(*data)); data->cpu = data->pid = data->tid = -1; data->stream_id = data->id = data->time = -1ULL; - data->period = 1; + data->period = evsel->attr.sample_period; data->weight = 0; if (event->header.type != PERF_RECORD_SAMPLE) { @@ -1429,10 +1416,11 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event, array++; if (data->user_regs.abi) { - u64 regs_user = evsel->attr.sample_regs_user; + u64 mask = evsel->attr.sample_regs_user; - sz = hweight_long(regs_user) * sizeof(u64); + sz = hweight_long(mask) * sizeof(u64); OVERFLOW_CHECK(array, sz, max_size); + data->user_regs.mask = mask; data->user_regs.regs = (u64 *)array; array = (void *)array + sz; } @@ -1453,6 +1441,9 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event, array = (void *)array + sz; OVERFLOW_CHECK_u64(array); data->user_stack.size = *array++; + if (WARN_ONCE(data->user_stack.size > sz, + "user stack dump failure\n")) + return -EFAULT; } } @@ -1470,11 +1461,18 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event, array++; } + data->transaction = 0; + if (type & PERF_SAMPLE_TRANSACTION) { + OVERFLOW_CHECK_u64(array); + data->transaction = *array; + array++; + } + return 0; } size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type, - u64 sample_regs_user, u64 read_format) + u64 read_format) { size_t sz, result = sizeof(struct sample_event); @@ -1540,7 +1538,7 @@ size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type, if (type & PERF_SAMPLE_REGS_USER) { if (sample->user_regs.abi) { result += sizeof(u64); - sz = hweight_long(sample_regs_user) * sizeof(u64); + sz = hweight_long(sample->user_regs.mask) * sizeof(u64); result += sz; } else { result += sizeof(u64); @@ -1562,11 +1560,14 @@ size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type, if (type & PERF_SAMPLE_DATA_SRC) result += sizeof(u64); + if (type & PERF_SAMPLE_TRANSACTION) + result += sizeof(u64); + return result; } int perf_event__synthesize_sample(union perf_event *event, u64 type, - u64 sample_regs_user, u64 read_format, + u64 read_format, const struct perf_sample *sample, bool swapped) { @@ -1707,7 +1708,7 @@ int perf_event__synthesize_sample(union perf_event *event, u64 type, if (type & PERF_SAMPLE_REGS_USER) { if (sample->user_regs.abi) { *array++ = sample->user_regs.abi; - sz = hweight_long(sample_regs_user) * sizeof(u64); + sz = hweight_long(sample->user_regs.mask) * sizeof(u64); memcpy(array, sample->user_regs.regs, sz); array = (void *)array + sz; } else { @@ -1735,6 +1736,11 @@ int perf_event__synthesize_sample(union perf_event *event, u64 type, array++; } + if (type & PERF_SAMPLE_TRANSACTION) { + *array = sample->transaction; + array++; + } + return 0; } @@ -1974,16 +1980,14 @@ bool perf_evsel__fallback(struct perf_evsel *evsel, int err, evsel->attr.type = PERF_TYPE_SOFTWARE; evsel->attr.config = PERF_COUNT_SW_CPU_CLOCK; - free(evsel->name); - evsel->name = NULL; + zfree(&evsel->name); return true; } return false; } -int perf_evsel__open_strerror(struct perf_evsel *evsel, - struct perf_target *target, +int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target, int err, char *msg, size_t size) { switch (err) { |
