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.c158
1 files changed, 143 insertions, 15 deletions
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 9cd706f62793..f59228c1a39e 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -34,6 +34,7 @@
#include "callchain.h"
#include "cgroup.h"
#include "counts.h"
+#include "dwarf-regs.h"
#include "event.h"
#include "evsel.h"
#include "time-utils.h"
@@ -648,8 +649,9 @@ struct tep_event *evsel__tp_format(struct evsel *evsel)
if (IS_ERR(tp_format)) {
int err = -PTR_ERR(evsel->tp_format);
- pr_err("Error getting tracepoint format '%s' '%s'(%d)\n",
- evsel__name(evsel), strerror(err), err);
+ errno = err;
+ pr_err("Error getting tracepoint format '%s': %m\n",
+ evsel__name(evsel));
return NULL;
}
evsel->tp_format = tp_format;
@@ -1006,6 +1008,13 @@ int evsel__group_desc(struct evsel *evsel, char *buf, size_t size)
return ret;
}
+uint16_t evsel__e_machine(struct evsel *evsel, uint32_t *e_flags)
+{
+ struct perf_session *session = evsel__session(evsel);
+
+ return perf_session__e_machine(session, e_flags);
+}
+
static void __evsel__config_callchain(struct evsel *evsel, struct record_opts *opts,
struct callchain_param *param)
{
@@ -1041,18 +1050,18 @@ static void __evsel__config_callchain(struct evsel *evsel, struct record_opts *o
if (param->record_mode == CALLCHAIN_DWARF) {
if (!function) {
- const char *arch = perf_env__arch(evsel__env(evsel));
+ uint16_t e_machine = evsel__e_machine(evsel, /*e_flags=*/NULL);
evsel__set_sample_bit(evsel, REGS_USER);
evsel__set_sample_bit(evsel, STACK_USER);
if (opts->sample_user_regs &&
- DWARF_MINIMAL_REGS(arch) != arch__user_reg_mask()) {
- attr->sample_regs_user |= DWARF_MINIMAL_REGS(arch);
+ DWARF_MINIMAL_REGS(e_machine) != perf_user_reg_mask(EM_HOST)) {
+ attr->sample_regs_user |= DWARF_MINIMAL_REGS(e_machine);
pr_warning("WARNING: The use of --call-graph=dwarf may require all the user registers, "
"specifying a subset with --user-regs may render DWARF unwinding unreliable, "
"so the minimal registers set (IP, SP) is explicitly forced.\n");
} else {
- attr->sample_regs_user |= arch__user_reg_mask();
+ attr->sample_regs_user |= perf_user_reg_mask(EM_HOST);
}
attr->sample_stack_user = param->dump_size;
attr->exclude_callchain_user = 1;
@@ -1242,7 +1251,11 @@ static void evsel__apply_config_terms(struct evsel *evsel,
case EVSEL__CONFIG_TERM_AUX_SAMPLE_SIZE:
/* Already applied by auxtrace */
break;
- case EVSEL__CONFIG_TERM_CFG_CHG:
+ case EVSEL__CONFIG_TERM_USR_CHG_CONFIG:
+ case EVSEL__CONFIG_TERM_USR_CHG_CONFIG1:
+ case EVSEL__CONFIG_TERM_USR_CHG_CONFIG2:
+ case EVSEL__CONFIG_TERM_USR_CHG_CONFIG3:
+ case EVSEL__CONFIG_TERM_USR_CHG_CONFIG4:
break;
case EVSEL__CONFIG_TERM_RATIO_TO_PREV:
rtp_buf = term->val.str;
@@ -1314,6 +1327,109 @@ struct evsel_config_term *__evsel__get_config_term(struct evsel *evsel, enum evs
return found_term;
}
+/*
+ * Set @config_name to @val as long as the user hasn't already set or cleared it
+ * by passing a config term on the command line.
+ *
+ * @val is the value to put into the bits specified by @config_name rather than
+ * the bit pattern. It is shifted into position by this function, so to set
+ * something to true, pass 1 for val rather than a pre shifted value.
+ */
+void evsel__set_config_if_unset(struct evsel *evsel, const char *config_name,
+ u64 val)
+{
+ u64 user_bits = 0;
+ struct evsel_config_term *term = evsel__get_config_term(evsel,
+ USR_CHG_CONFIG);
+ struct perf_pmu_format *format = pmu_find_format(&evsel->pmu->format,
+ config_name);
+ int fbit;
+ __u64 *vp;
+
+ if (!format)
+ return;
+
+ switch (format->value) {
+ case PERF_PMU_FORMAT_VALUE_CONFIG:
+ term = evsel__get_config_term(evsel, USR_CHG_CONFIG);
+ vp = &evsel->core.attr.config;
+ break;
+ case PERF_PMU_FORMAT_VALUE_CONFIG1:
+ term = evsel__get_config_term(evsel, USR_CHG_CONFIG1);
+ vp = &evsel->core.attr.config1;
+ break;
+ case PERF_PMU_FORMAT_VALUE_CONFIG2:
+ term = evsel__get_config_term(evsel, USR_CHG_CONFIG2);
+ vp = &evsel->core.attr.config2;
+ break;
+ case PERF_PMU_FORMAT_VALUE_CONFIG3:
+ term = evsel__get_config_term(evsel, USR_CHG_CONFIG3);
+ vp = &evsel->core.attr.config3;
+ break;
+ case PERF_PMU_FORMAT_VALUE_CONFIG4:
+ term = evsel__get_config_term(evsel, USR_CHG_CONFIG4);
+ vp = &evsel->core.attr.config4;
+ break;
+ default:
+ pr_err("Unknown format value: %d\n", format->value);
+ return;
+ }
+
+ if (!format)
+ return;
+
+ if (term)
+ user_bits = term->val.cfg_chg;
+
+ /* Do nothing if the user changed the value */
+ for_each_set_bit(fbit, format->bits, PERF_PMU_FORMAT_BITS)
+ if ((1ULL << fbit) & user_bits)
+ return;
+
+ /* Otherwise replace it */
+ perf_pmu__format_pack(format->bits, val, vp, /*zero=*/true);
+}
+
+
+int evsel__get_config_val(const struct evsel *evsel, const char *config_name,
+ u64 *val)
+{
+ struct perf_pmu_format *format = pmu_find_format(&evsel->pmu->format, config_name);
+
+ if (!format || bitmap_empty(format->bits, PERF_PMU_FORMAT_BITS)) {
+ pr_err("Unknown/empty format name: %s\n", config_name);
+ *val = 0;
+ return -EINVAL;
+ }
+
+ switch (format->value) {
+ case PERF_PMU_FORMAT_VALUE_CONFIG:
+ *val = perf_pmu__format_unpack(format->bits,
+ evsel->core.attr.config);
+ return 0;
+ case PERF_PMU_FORMAT_VALUE_CONFIG1:
+ *val = perf_pmu__format_unpack(format->bits,
+ evsel->core.attr.config1);
+ return 0;
+ case PERF_PMU_FORMAT_VALUE_CONFIG2:
+ *val = perf_pmu__format_unpack(format->bits,
+ evsel->core.attr.config2);
+ return 0;
+ case PERF_PMU_FORMAT_VALUE_CONFIG3:
+ *val = perf_pmu__format_unpack(format->bits,
+ evsel->core.attr.config3);
+ return 0;
+ case PERF_PMU_FORMAT_VALUE_CONFIG4:
+ *val = perf_pmu__format_unpack(format->bits,
+ evsel->core.attr.config4);
+ return 0;
+ default:
+ pr_err("Unknown format value: %d\n", format->value);
+ *val = 0;
+ return -EINVAL;
+ }
+}
+
void __weak arch_evsel__set_sample_weight(struct evsel *evsel)
{
evsel__set_sample_bit(evsel, WEIGHT);
@@ -1445,10 +1561,11 @@ void evsel__config(struct evsel *evsel, struct record_opts *opts,
attr->inherit_stat = 1;
}
- if (opts->sample_address) {
+ if (opts->sample_address)
evsel__set_sample_bit(evsel, ADDR);
+
+ if (opts->record_data_mmap)
attr->mmap_data = track;
- }
/*
* We don't allow user space callchains for function trace
@@ -2771,8 +2888,8 @@ retry_open:
PERF_EVENT_IOC_SET_BPF,
bpf_fd);
if (err && errno != EEXIST) {
- pr_err("failed to attach bpf fd %d: %s\n",
- bpf_fd, strerror(errno));
+ pr_err("failed to attach bpf fd %d: %m\n",
+ bpf_fd);
err = -EINVAL;
goto out_close;
}
@@ -3863,7 +3980,6 @@ int evsel__open_strerror(struct evsel *evsel, struct target *target,
int err, char *msg, size_t size)
{
struct perf_pmu *pmu;
- char sbuf[STRERR_BUFSIZE];
int printed = 0, enforced = 0;
int ret;
@@ -3996,10 +4112,11 @@ int evsel__open_strerror(struct evsel *evsel, struct target *target,
if (ret)
return ret;
+ errno = err;
return scnprintf(msg, size,
- "The sys_perf_event_open() syscall returned with %d (%s) for event (%s).\n"
- "\"dmesg | grep -i perf\" may provide additional information.\n",
- err, str_error_r(err, sbuf, sizeof(sbuf)), evsel__name(evsel));
+ "The sys_perf_event_open() syscall failed for event (%s): %m\n"
+ "\"dmesg | grep -i perf\" may provide additional information.\n",
+ evsel__name(evsel));
}
struct perf_session *evsel__session(struct evsel *evsel)
@@ -4097,6 +4214,17 @@ void evsel__set_leader(struct evsel *evsel, struct evsel *leader)
evsel->core.leader = &leader->core;
}
+bool evsel__is_aux_event(const struct evsel *evsel)
+{
+ struct perf_pmu *pmu;
+
+ if (evsel->needs_auxtrace_mmap)
+ return true;
+
+ pmu = evsel__find_pmu(evsel);
+ return pmu && pmu->auxtrace;
+}
+
int evsel__source_count(const struct evsel *evsel)
{
struct evsel *pos;