summaryrefslogtreecommitdiff
path: root/tools/perf/util/evsel.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util/evsel.c')
-rw-r--r--tools/perf/util/evsel.c163
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;
}