diff options
Diffstat (limited to 'tools/perf/util/evsel.c')
| -rw-r--r-- | tools/perf/util/evsel.c | 163 |
1 files changed, 127 insertions, 36 deletions
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index ea9fa04429f0..d4cb455f4a7d 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -16,9 +16,11 @@ #include <errno.h> #include <inttypes.h> #include <stdlib.h> +#include <string.h> #include <dirent.h> #include <linux/bitops.h> +#include <linux/bitmap.h> #include <linux/compiler.h> #include <linux/ctype.h> #include <linux/err.h> @@ -422,6 +424,11 @@ void evsel__set_sample_id(struct evsel *evsel, evsel->core.attr.read_format |= PERF_FORMAT_ID; } +bool evsel__is_non_perf_event_open_pmu(const struct evsel *evsel) +{ + return evsel->pmu && evsel->pmu->type > PERF_PMU_TYPE_PE_END; +} + /** * evsel__is_function_event - Return whether given evsel is a function * trace event @@ -440,17 +447,16 @@ bool evsel__is_function_event(struct evsel *evsel) #undef FUNCTION_EVENT } -void evsel__init(struct evsel *evsel, +static void evsel__init(struct evsel *evsel, struct perf_event_attr *attr, int idx) { perf_evsel__init(&evsel->core, attr, idx); + refcount_set(&evsel->refcnt, 1); evsel->tracking = !idx; evsel->unit = strdup(""); evsel->scale = 1.0; evsel->max_events = ULONG_MAX; evsel->evlist = NULL; - evsel->bpf_obj = NULL; - evsel->bpf_fd = -1; INIT_LIST_HEAD(&evsel->config_terms); INIT_LIST_HEAD(&evsel->bpf_counter_list); INIT_LIST_HEAD(&evsel->bpf_filters); @@ -525,7 +531,7 @@ static int evsel__copy_config_terms(struct evsel *dst, struct evsel *src) * The assumption is that @orig is not configured nor opened yet. * So we only care about the attributes that can be set while it's parsed. */ -struct evsel *evsel__clone(struct evsel *dest, struct evsel *orig) +struct evsel *evsel__clone(struct evsel *orig) { struct evsel *evsel; @@ -534,15 +540,7 @@ struct evsel *evsel__clone(struct evsel *dest, struct evsel *orig) BUG_ON(orig->priv); BUG_ON(orig->per_pkg_mask); - /* cannot handle BPF objects for now */ - if (orig->bpf_obj) - return NULL; - - if (dest) - evsel = dest; - else - evsel = evsel__new(&orig->core.attr); - + evsel = evsel__new(&orig->core.attr); if (evsel == NULL) return NULL; @@ -615,7 +613,13 @@ struct evsel *evsel__clone(struct evsel *dest, struct evsel *orig) evsel->sample_read = orig->sample_read; evsel->collect_stat = orig->collect_stat; evsel->weak_group = orig->weak_group; + evsel->bpf_counter = orig->bpf_counter; evsel->use_config_name = orig->use_config_name; + evsel->skippable = orig->skippable; + evsel->dont_regroup = orig->dont_regroup; + evsel->default_metricgroup = orig->default_metricgroup; + evsel->default_show_events = orig->default_show_events; + evsel->pmu = orig->pmu; evsel->first_wildcard_match = orig->first_wildcard_match; @@ -624,10 +628,14 @@ struct evsel *evsel__clone(struct evsel *dest, struct evsel *orig) evsel->alternate_hw_config = orig->alternate_hw_config; + evsel->retire_lat = orig->retire_lat; + if (evsel->retire_lat) + evsel->retirement_latency = orig->retirement_latency; + return evsel; out_err: - evsel__delete(evsel); + evsel__put(evsel); return NULL; } @@ -686,6 +694,12 @@ out_err: return ERR_PTR(err); } +struct evsel *evsel__get(struct evsel *evsel) +{ + refcount_inc(&evsel->refcnt); + return evsel; +} + #ifdef HAVE_LIBTRACEEVENT struct tep_event *evsel__tp_format(struct evsel *evsel) { @@ -703,7 +717,7 @@ struct tep_event *evsel__tp_format(struct evsel *evsel) tp_format = trace_event__tp_format(evsel->tp_sys, evsel->tp_name); if (IS_ERR(tp_format)) { - int err = -PTR_ERR(evsel->tp_format); + int err = -PTR_ERR(tp_format); errno = err; pr_err("Error getting tracepoint format '%s': %m\n", @@ -2024,7 +2038,7 @@ void evsel__set_priv_destructor(void (*destructor)(void *priv)) evsel__priv_destructor = destructor; } -void evsel__exit(struct evsel *evsel) +static void evsel__exit(struct evsel *evsel) { assert(list_empty(&evsel->core.node)); assert(evsel->evlist == NULL); @@ -2061,11 +2075,14 @@ void evsel__exit(struct evsel *evsel) } } -void evsel__delete(struct evsel *evsel) +void evsel__put(struct evsel *evsel) { if (!evsel) return; + if (!refcount_dec_and_test(&evsel->refcnt)) + return; + evsel__exit(evsel); free(evsel); } @@ -3058,21 +3075,6 @@ retry_open: /* Debug message used by test scripts */ pr_debug2_peo(" = %d\n", fd); - if (evsel->bpf_fd >= 0) { - int evt_fd = fd; - int bpf_fd = evsel->bpf_fd; - - err = ioctl(evt_fd, - PERF_EVENT_IOC_SET_BPF, - bpf_fd); - if (err && errno != EEXIST) { - pr_err("failed to attach bpf fd %d: %m\n", - bpf_fd); - err = -EINVAL; - goto out_close; - } - } - set_rlimit = NO_CHANGE; /* @@ -3350,7 +3352,7 @@ static inline bool evsel__has_branch_counters(const struct evsel *evsel) if (!leader || !evsel->evlist) return false; - if (evsel->evlist->nr_br_cntr < 0) + if (evlist__nr_br_cntr(evsel->evlist) < 0) evlist__update_br_cntr(evsel->evlist); if (leader->br_cntr_nr > 0) @@ -3407,7 +3409,7 @@ int __evsel__parse_sample(struct evsel *evsel, union perf_event *event, union u64_swap u; perf_sample__init(data, /*all=*/true); - data->evsel = evsel; + data->evsel = evsel__get(evsel); data->cpu = data->pid = data->tid = -1; data->stream_id = data->id = data->time = -1ULL; data->period = evsel->core.attr.sample_period; @@ -3933,6 +3935,95 @@ void *perf_sample__rawptr(struct perf_sample *sample, const char *name) return sample->raw_data + offset; } +void *format_field__get_raw_data(struct tep_format_field *field, struct + perf_sample *sample, bool needs_swap, + u16 *len_out) +{ + int offset = field->offset; + int size = field->size; + + if (field->flags & TEP_FIELD_IS_DYNAMIC) { + unsigned int dynamic_data; + + if (out_of_bounds(field, field->offset, field->size, sample->raw_size)) + return NULL; + + dynamic_data = format_field__intval(field, sample, needs_swap); + + offset = dynamic_data & 0xffff; + size = (dynamic_data >> 16) & 0xffff; + + if (tep_field_is_relative(field->flags)) + offset += field->offset + field->size; + } + + if (out_of_bounds(field, offset, size, sample->raw_size)) + return NULL; + + *len_out = size; + return sample->raw_data + offset; +} + +unsigned long *format_field__get_cpumask(struct tep_format_field *field, + struct perf_sample *sample, + bool needs_swap, u16 *len_out) +{ + u16 len; + void *ptr = format_field__get_raw_data(field, sample, needs_swap, &len); + unsigned long *mask; + struct perf_env *env; + bool target_is_64; + int target_word_size; + int nr_words; + int bit_idx; + int nbits; + + if (!ptr) + return NULL; + + nbits = len * 8; + mask = bitmap_zalloc(nbits ?: 1); + if (!mask) + return NULL; + + env = evsel__env(sample->evsel); + target_is_64 = env ? perf_env__kernel_is_64_bit(env) : (sizeof(void *) == 8); + target_word_size = target_is_64 ? 8 : 4; + nr_words = len / target_word_size; + + for (bit_idx = 0; bit_idx < nbits; bit_idx++) { + int w_idx = bit_idx / (target_word_size * 8); + int bit_in_word = bit_idx % (target_word_size * 8); + bool set = false; + + if (w_idx >= nr_words) + break; + + if (target_is_64) { + u64 word; + memcpy(&word, (unsigned char *)ptr + w_idx * 8, 8); + if (needs_swap) + word = bswap_64(word); + set = (word & (1ULL << bit_in_word)) != 0; + } else { + u32 word32; + memcpy(&word32, (unsigned char *)ptr + w_idx * 4, 4); + if (needs_swap) + word32 = bswap_32(word32); + set = (word32 & (1U << bit_in_word)) != 0; + } + + if (set) { + int host_w_idx = bit_idx / BITS_PER_LONG; + int host_bit_in_word = bit_idx % BITS_PER_LONG; + mask[host_w_idx] |= (1UL << host_bit_in_word); + } + } + + *len_out = len; + return mask; +} + u64 format_field__intval(struct tep_format_field *field, struct perf_sample *sample, bool needs_swap) { @@ -4382,7 +4473,7 @@ int evsel__open_strerror(struct evsel *evsel, struct target *target, struct perf_session *evsel__session(struct evsel *evsel) { - return evsel && evsel->evlist ? evsel->evlist->session : NULL; + return evsel && evsel->evlist ? evlist__session(evsel->evlist) : NULL; } struct perf_env *evsel__env(struct evsel *evsel) @@ -4407,7 +4498,7 @@ static int store_evsel_ids(struct evsel *evsel, struct evlist *evlist) thread++) { int fd = FD(evsel, cpu_map_idx, thread); - if (perf_evlist__id_add_fd(&evlist->core, &evsel->core, + if (perf_evlist__id_add_fd(evlist__core(evlist), &evsel->core, cpu_map_idx, thread, fd) < 0) return -1; } |
