summaryrefslogtreecommitdiff
path: root/tools/perf/util/evlist.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util/evlist.c')
-rw-r--r--tools/perf/util/evlist.c377
1 files changed, 238 insertions, 139 deletions
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index f0dd174e2deb..ee971d15b3c6 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -13,6 +13,7 @@
#include "util/mmap.h"
#include "thread_map.h"
#include "target.h"
+#include "dwarf-regs.h"
#include "evlist.h"
#include "evsel.h"
#include "record.h"
@@ -35,6 +36,8 @@
#include "util/util.h"
#include "util/env.h"
#include "util/intel-tpebs.h"
+#include "util/metricgroup.h"
+#include "util/strbuf.h"
#include <signal.h>
#include <unistd.h>
#include <sched.h>
@@ -82,6 +85,8 @@ void evlist__init(struct evlist *evlist, struct perf_cpu_map *cpus,
evlist->ctl_fd.ack = -1;
evlist->ctl_fd.pos = -1;
evlist->nr_br_cntr = -1;
+ metricgroup__rblist_init(&evlist->metric_events);
+ INIT_LIST_HEAD(&evlist->deferred_samples);
}
struct evlist *evlist__new(void)
@@ -94,30 +99,47 @@ struct evlist *evlist__new(void)
return evlist;
}
-struct evlist *evlist__new_default(void)
+struct evlist *evlist__new_default(const struct target *target, bool sample_callchains)
{
struct evlist *evlist = evlist__new();
bool can_profile_kernel;
+ struct perf_pmu *pmu = NULL;
+ struct evsel *evsel;
+ char buf[256];
int err;
if (!evlist)
return NULL;
can_profile_kernel = perf_event_paranoid_check(1);
- err = parse_event(evlist, can_profile_kernel ? "cycles:P" : "cycles:Pu");
- if (err) {
- evlist__delete(evlist);
- return NULL;
+
+ if (EM_HOST == EM_S390 && sample_callchains) {
+ snprintf(buf, sizeof(buf), "software/%s/%s",
+ target__has_cpu(target) ? "cpu-clock" : "task-clock",
+ can_profile_kernel ? "P" : "Pu");
+ err = parse_event(evlist, buf);
+ if (err)
+ goto out_err;
+ } else {
+ while ((pmu = perf_pmus__scan_core(pmu)) != NULL) {
+ snprintf(buf, sizeof(buf), "%s/cycles/%s", pmu->name,
+ can_profile_kernel ? "P" : "Pu");
+ err = parse_event(evlist, buf);
+ if (err)
+ goto out_err;
+ }
}
+ /* If there is only 1 event a sample identifier isn't necessary. */
if (evlist->core.nr_entries > 1) {
- struct evsel *evsel;
-
evlist__for_each_entry(evlist, evsel)
evsel__set_sample_id(evsel, /*can_sample_identifier=*/false);
}
return evlist;
+out_err:
+ evlist__delete(evlist);
+ return NULL;
}
struct evlist *evlist__new_dummy(void)
@@ -172,6 +194,7 @@ static void evlist__purge(struct evlist *evlist)
void evlist__exit(struct evlist *evlist)
{
+ metricgroup__rblist_exit(&evlist->metric_events);
event_enable_timer__exit(&evlist->eet);
zfree(&evlist->mmap);
zfree(&evlist->overwrite_mmap);
@@ -183,7 +206,6 @@ void evlist__delete(struct evlist *evlist)
if (evlist == NULL)
return;
- tpebs_delete();
evlist__free_stats(evlist);
evlist__munmap(evlist);
evlist__close(evlist);
@@ -347,36 +369,107 @@ int evlist__add_newtp(struct evlist *evlist, const char *sys, const char *name,
}
#endif
-struct evlist_cpu_iterator evlist__cpu_begin(struct evlist *evlist, struct affinity *affinity)
+/*
+ * Should sched_setaffinity be used with evlist__for_each_cpu? Determine if
+ * migrating the thread will avoid possibly numerous IPIs.
+ */
+static bool evlist__use_affinity(struct evlist *evlist)
{
- struct evlist_cpu_iterator itr = {
+ struct evsel *pos;
+ struct perf_cpu_map *used_cpus = NULL;
+ bool ret = false;
+
+ if (evlist->no_affinity || !evlist->core.user_requested_cpus ||
+ cpu_map__is_dummy(evlist->core.user_requested_cpus))
+ return false;
+
+ evlist__for_each_entry(evlist, pos) {
+ struct perf_cpu_map *intersect;
+
+ if (!perf_pmu__benefits_from_affinity(pos->pmu))
+ continue;
+
+ if (evsel__is_dummy_event(pos)) {
+ /*
+ * The dummy event is opened on all CPUs so assume >1
+ * event with shared CPUs.
+ */
+ ret = true;
+ break;
+ }
+ if (evsel__is_retire_lat(pos)) {
+ /*
+ * Retirement latency events are similar to tool ones in
+ * their implementation, and so don't require affinity.
+ */
+ continue;
+ }
+ if (perf_cpu_map__is_empty(used_cpus)) {
+ /* First benefitting event, we want >1 on a common CPU. */
+ used_cpus = perf_cpu_map__get(pos->core.cpus);
+ continue;
+ }
+ if ((pos->core.attr.read_format & PERF_FORMAT_GROUP) &&
+ evsel__leader(pos) != pos) {
+ /* Skip members of the same sample group. */
+ continue;
+ }
+ intersect = perf_cpu_map__intersect(used_cpus, pos->core.cpus);
+ if (!perf_cpu_map__is_empty(intersect)) {
+ /* >1 event with shared CPUs. */
+ perf_cpu_map__put(intersect);
+ ret = true;
+ break;
+ }
+ perf_cpu_map__put(intersect);
+ perf_cpu_map__merge(&used_cpus, pos->core.cpus);
+ }
+ perf_cpu_map__put(used_cpus);
+ return ret;
+}
+
+void evlist_cpu_iterator__init(struct evlist_cpu_iterator *itr, struct evlist *evlist)
+{
+ *itr = (struct evlist_cpu_iterator){
.container = evlist,
.evsel = NULL,
.cpu_map_idx = 0,
.evlist_cpu_map_idx = 0,
.evlist_cpu_map_nr = perf_cpu_map__nr(evlist->core.all_cpus),
.cpu = (struct perf_cpu){ .cpu = -1},
- .affinity = affinity,
+ .affinity = NULL,
};
if (evlist__empty(evlist)) {
/* Ensure the empty list doesn't iterate. */
- itr.evlist_cpu_map_idx = itr.evlist_cpu_map_nr;
- } else {
- itr.evsel = evlist__first(evlist);
- if (itr.affinity) {
- itr.cpu = perf_cpu_map__cpu(evlist->core.all_cpus, 0);
- affinity__set(itr.affinity, itr.cpu.cpu);
- itr.cpu_map_idx = perf_cpu_map__idx(itr.evsel->core.cpus, itr.cpu);
- /*
- * If this CPU isn't in the evsel's cpu map then advance
- * through the list.
- */
- if (itr.cpu_map_idx == -1)
- evlist_cpu_iterator__next(&itr);
- }
+ itr->evlist_cpu_map_idx = itr->evlist_cpu_map_nr;
+ return;
+ }
+
+ if (evlist__use_affinity(evlist)) {
+ if (affinity__setup(&itr->saved_affinity) == 0)
+ itr->affinity = &itr->saved_affinity;
}
- return itr;
+ itr->evsel = evlist__first(evlist);
+ itr->cpu = perf_cpu_map__cpu(evlist->core.all_cpus, 0);
+ if (itr->affinity)
+ affinity__set(itr->affinity, itr->cpu.cpu);
+ itr->cpu_map_idx = perf_cpu_map__idx(itr->evsel->core.cpus, itr->cpu);
+ /*
+ * If this CPU isn't in the evsel's cpu map then advance
+ * through the list.
+ */
+ if (itr->cpu_map_idx == -1)
+ evlist_cpu_iterator__next(itr);
+}
+
+void evlist_cpu_iterator__exit(struct evlist_cpu_iterator *itr)
+{
+ if (!itr->affinity)
+ return;
+
+ affinity__cleanup(itr->affinity);
+ itr->affinity = NULL;
}
void evlist_cpu_iterator__next(struct evlist_cpu_iterator *evlist_cpu_itr)
@@ -406,14 +499,11 @@ void evlist_cpu_iterator__next(struct evlist_cpu_iterator *evlist_cpu_itr)
*/
if (evlist_cpu_itr->cpu_map_idx == -1)
evlist_cpu_iterator__next(evlist_cpu_itr);
+ } else {
+ evlist_cpu_iterator__exit(evlist_cpu_itr);
}
}
-bool evlist_cpu_iterator__end(const struct evlist_cpu_iterator *evlist_cpu_itr)
-{
- return evlist_cpu_itr->evlist_cpu_map_idx >= evlist_cpu_itr->evlist_cpu_map_nr;
-}
-
static int evsel__strcmp(struct evsel *pos, char *evsel_name)
{
if (!evsel_name)
@@ -441,19 +531,11 @@ static void __evlist__disable(struct evlist *evlist, char *evsel_name, bool excl
{
struct evsel *pos;
struct evlist_cpu_iterator evlist_cpu_itr;
- struct affinity saved_affinity, *affinity = NULL;
bool has_imm = false;
- // See explanation in evlist__close()
- if (!cpu_map__is_dummy(evlist->core.user_requested_cpus)) {
- if (affinity__setup(&saved_affinity) < 0)
- return;
- affinity = &saved_affinity;
- }
-
/* Disable 'immediate' events last */
for (int imm = 0; imm <= 1; imm++) {
- evlist__for_each_cpu(evlist_cpu_itr, evlist, affinity) {
+ evlist__for_each_cpu(evlist_cpu_itr, evlist) {
pos = evlist_cpu_itr.evsel;
if (evsel__strcmp(pos, evsel_name))
continue;
@@ -471,7 +553,6 @@ static void __evlist__disable(struct evlist *evlist, char *evsel_name, bool excl
break;
}
- affinity__cleanup(affinity);
evlist__for_each_entry(evlist, pos) {
if (evsel__strcmp(pos, evsel_name))
continue;
@@ -511,16 +592,8 @@ static void __evlist__enable(struct evlist *evlist, char *evsel_name, bool excl_
{
struct evsel *pos;
struct evlist_cpu_iterator evlist_cpu_itr;
- struct affinity saved_affinity, *affinity = NULL;
-
- // See explanation in evlist__close()
- if (!cpu_map__is_dummy(evlist->core.user_requested_cpus)) {
- if (affinity__setup(&saved_affinity) < 0)
- return;
- affinity = &saved_affinity;
- }
- evlist__for_each_cpu(evlist_cpu_itr, evlist, affinity) {
+ evlist__for_each_cpu(evlist_cpu_itr, evlist) {
pos = evlist_cpu_itr.evsel;
if (evsel__strcmp(pos, evsel_name))
continue;
@@ -530,7 +603,6 @@ static void __evlist__enable(struct evlist *evlist, char *evsel_name, bool excl_
continue;
evsel__enable_cpu(pos, evlist_cpu_itr.cpu_map_idx);
}
- affinity__cleanup(affinity);
evlist__for_each_entry(evlist, pos) {
if (evsel__strcmp(pos, evsel_name))
continue;
@@ -753,9 +825,8 @@ static struct mmap *evlist__alloc_mmap(struct evlist *evlist,
bool overwrite)
{
int i;
- struct mmap *map;
+ struct mmap *map = calloc(evlist->core.nr_mmaps, sizeof(struct mmap));
- map = zalloc(evlist->core.nr_mmaps * sizeof(struct mmap));
if (!map)
return NULL;
@@ -1006,8 +1077,7 @@ int evlist__create_maps(struct evlist *evlist, struct target *target)
* per-thread data. thread_map__new_str will call
* thread_map__new_all_cpus to enumerate all threads.
*/
- threads = thread_map__new_str(target->pid, target->tid, target->uid,
- all_threads);
+ threads = thread_map__new_str(target->pid, target->tid, all_threads);
if (!threads)
return -1;
@@ -1328,28 +1398,14 @@ void evlist__close(struct evlist *evlist)
{
struct evsel *evsel;
struct evlist_cpu_iterator evlist_cpu_itr;
- struct affinity affinity;
- /*
- * With perf record core.user_requested_cpus is usually NULL.
- * Use the old method to handle this for now.
- */
- if (!evlist->core.user_requested_cpus ||
- cpu_map__is_dummy(evlist->core.user_requested_cpus)) {
- evlist__for_each_entry_reverse(evlist, evsel)
- evsel__close(evsel);
- return;
- }
-
- if (affinity__setup(&affinity) < 0)
- return;
-
- evlist__for_each_cpu(evlist_cpu_itr, evlist, &affinity) {
+ evlist__for_each_cpu(evlist_cpu_itr, evlist) {
+ if (evlist_cpu_itr.cpu_map_idx == 0 && evsel__is_retire_lat(evlist_cpu_itr.evsel))
+ evsel__tpebs_close(evlist_cpu_itr.evsel);
perf_evsel__close_cpu(&evlist_cpu_itr.evsel->core,
evlist_cpu_itr.cpu_map_idx);
}
- affinity__cleanup(&affinity);
evlist__for_each_entry_reverse(evlist, evsel) {
perf_evsel__free_fd(&evsel->core);
perf_evsel__free_id(&evsel->core);
@@ -1373,19 +1429,18 @@ static int evlist__create_syswide_maps(struct evlist *evlist)
*/
cpus = perf_cpu_map__new_online_cpus();
if (!cpus)
- goto out;
+ return -ENOMEM;
threads = perf_thread_map__new_dummy();
- if (!threads)
- goto out_put;
+ if (!threads) {
+ perf_cpu_map__put(cpus);
+ return -ENOMEM;
+ }
perf_evlist__set_maps(&evlist->core, cpus, threads);
-
perf_thread_map__put(threads);
-out_put:
perf_cpu_map__put(cpus);
-out:
- return -ENOMEM;
+ return 0;
}
int evlist__open(struct evlist *evlist)
@@ -1576,8 +1631,11 @@ int evlist__parse_sample(struct evlist *evlist, union perf_event *event, struct
struct evsel *evsel = evlist__event2evsel(evlist, event);
int ret;
- if (!evsel)
+ if (!evsel) {
+ /* Ensure the sample is okay for perf_sample__exit. */
+ perf_sample__init(sample, /*all=*/false);
return -EFAULT;
+ }
ret = evsel__parse_sample(evsel, event, sample);
if (ret)
return ret;
@@ -1604,14 +1662,14 @@ int evlist__parse_sample_timestamp(struct evlist *evlist, union perf_event *even
int evlist__strerror_open(struct evlist *evlist, int err, char *buf, size_t size)
{
int printed, value;
- char sbuf[STRERR_BUFSIZE], *emsg = str_error_r(err, sbuf, sizeof(sbuf));
switch (err) {
case EACCES:
case EPERM:
+ errno = err;
printed = scnprintf(buf, size,
- "Error:\t%s.\n"
- "Hint:\tCheck /proc/sys/kernel/perf_event_paranoid setting.", emsg);
+ "Error:\t%m.\n"
+ "Hint:\tCheck /proc/sys/kernel/perf_event_paranoid setting.");
value = perf_event_paranoid();
@@ -1638,16 +1696,18 @@ int evlist__strerror_open(struct evlist *evlist, int err, char *buf, size_t size
if (first->core.attr.sample_freq < (u64)max_freq)
goto out_default;
+ errno = err;
printed = scnprintf(buf, size,
- "Error:\t%s.\n"
+ "Error:\t%m.\n"
"Hint:\tCheck /proc/sys/kernel/perf_event_max_sample_rate.\n"
"Hint:\tThe current value is %d and %" PRIu64 " is being requested.",
- emsg, max_freq, first->core.attr.sample_freq);
+ max_freq, first->core.attr.sample_freq);
break;
}
default:
out_default:
- scnprintf(buf, size, "%s", emsg);
+ errno = err;
+ scnprintf(buf, size, "%m");
break;
}
@@ -1656,17 +1716,17 @@ out_default:
int evlist__strerror_mmap(struct evlist *evlist, int err, char *buf, size_t size)
{
- char sbuf[STRERR_BUFSIZE], *emsg = str_error_r(err, sbuf, sizeof(sbuf));
int pages_attempted = evlist->core.mmap_len / 1024, pages_max_per_user, printed = 0;
switch (err) {
case EPERM:
sysctl__read_int("kernel/perf_event_mlock_kb", &pages_max_per_user);
+ errno = err;
printed += scnprintf(buf + printed, size - printed,
- "Error:\t%s.\n"
+ "Error:\t%m.\n"
"Hint:\tCheck /proc/sys/kernel/perf_event_mlock_kb (%d kB) setting.\n"
"Hint:\tTried using %zd kB.\n",
- emsg, pages_max_per_user, pages_attempted);
+ pages_max_per_user, pages_attempted);
if (pages_attempted >= pages_max_per_user) {
printed += scnprintf(buf + printed, size - printed,
@@ -1678,7 +1738,8 @@ int evlist__strerror_mmap(struct evlist *evlist, int err, char *buf, size_t size
"Hint:\tTry using a smaller -m/--mmap-pages value.");
break;
default:
- scnprintf(buf, size, "%s", emsg);
+ errno = err;
+ scnprintf(buf, size, "%m");
break;
}
@@ -1910,8 +1971,8 @@ static int evlist__parse_control_fifo(const char *str, int *ctl_fd, int *ctl_fd_
*/
fd = open(s, O_RDWR | O_NONBLOCK | O_CLOEXEC);
if (fd < 0) {
- pr_err("Failed to open '%s'\n", s);
ret = -errno;
+ pr_err("Failed to open '%s': %m\n", s);
goto out_free;
}
*ctl_fd = fd;
@@ -1921,7 +1982,7 @@ static int evlist__parse_control_fifo(const char *str, int *ctl_fd, int *ctl_fd_
/* O_RDWR | O_NONBLOCK means the other end need not be open */
fd = open(p, O_RDWR | O_NONBLOCK | O_CLOEXEC);
if (fd < 0) {
- pr_err("Failed to open '%s'\n", p);
+ pr_err("Failed to open '%s': %m\n", p);
ret = -errno;
goto out_free;
}
@@ -1935,7 +1996,8 @@ out_free:
int evlist__parse_control(const char *str, int *ctl_fd, int *ctl_fd_ack, bool *ctl_fd_close)
{
- char *comma = NULL, *endptr = NULL;
+ const char *comma = NULL;
+ char *endptr = NULL;
*ctl_fd_close = false;
@@ -2353,7 +2415,7 @@ int evlist__parse_event_enable_time(struct evlist *evlist, struct record_opts *o
eet->timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC);
if (eet->timerfd == -1) {
err = -errno;
- pr_err("timerfd_create failed: %s\n", strerror(errno));
+ pr_err("timerfd_create failed: %m\n");
goto free_eet_times;
}
@@ -2388,7 +2450,7 @@ static int event_enable_timer__set_timer(struct event_enable_timer *eet, int ms)
if (timerfd_settime(eet->timerfd, 0, &its, NULL) < 0) {
err = -errno;
- pr_err("timerfd_settime failed: %s\n", strerror(errno));
+ pr_err("timerfd_settime failed: %m\n");
}
return err;
}
@@ -2469,23 +2531,36 @@ struct evsel *evlist__find_evsel(struct evlist *evlist, int idx)
return NULL;
}
-int evlist__scnprintf_evsels(struct evlist *evlist, size_t size, char *bf)
+void evlist__format_evsels(struct evlist *evlist, struct strbuf *sb, size_t max_length)
{
- struct evsel *evsel;
- int printed = 0;
+ struct evsel *evsel, *leader = NULL;
+ bool first = true;
evlist__for_each_entry(evlist, evsel) {
+ struct evsel *new_leader = evsel__leader(evsel);
+
if (evsel__is_dummy_event(evsel))
continue;
- if (size > (strlen(evsel__name(evsel)) + (printed ? 2 : 1))) {
- printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "," : "", evsel__name(evsel));
- } else {
- printed += scnprintf(bf + printed, size - printed, "%s...", printed ? "," : "");
- break;
+
+ if (leader != new_leader && leader && leader->core.nr_members > 1)
+ strbuf_addch(sb, '}');
+
+ if (!first)
+ strbuf_addch(sb, ',');
+
+ if (sb->len > max_length) {
+ strbuf_addstr(sb, "...");
+ return;
}
- }
+ if (leader != new_leader && new_leader->core.nr_members > 1)
+ strbuf_addch(sb, '{');
- return printed;
+ strbuf_addstr(sb, evsel__name(evsel));
+ first = false;
+ leader = new_leader;
+ }
+ if (leader && leader->core.nr_members > 1)
+ strbuf_addch(sb, '}');
}
void evlist__check_mem_load_aux(struct evlist *evlist)
@@ -2535,51 +2610,61 @@ void evlist__warn_user_requested_cpus(struct evlist *evlist, const char *cpu_lis
return;
evlist__for_each_entry(evlist, pos) {
- struct perf_cpu_map *intersect, *to_test;
- const struct perf_pmu *pmu = evsel__find_pmu(pos);
+ evsel__warn_user_requested_cpus(pos, user_requested_cpus);
+ }
+ perf_cpu_map__put(user_requested_cpus);
+}
- to_test = pmu && pmu->is_core ? pmu->cpus : cpu_map__online();
- intersect = perf_cpu_map__intersect(to_test, user_requested_cpus);
- if (!perf_cpu_map__equal(intersect, user_requested_cpus)) {
- char buf[128];
+/* Should uniquify be disabled for the evlist? */
+static bool evlist__disable_uniquify(const struct evlist *evlist)
+{
+ struct evsel *counter;
+ struct perf_pmu *last_pmu = NULL;
+ bool first = true;
- cpu_map__snprint(to_test, buf, sizeof(buf));
- pr_warning("WARNING: A requested CPU in '%s' is not supported by PMU '%s' (CPUs %s) for event '%s'\n",
- cpu_list, pmu ? pmu->name : "cpu", buf, evsel__name(pos));
+ evlist__for_each_entry(evlist, counter) {
+ /* If PMUs vary then uniquify can be useful. */
+ if (!first && counter->pmu != last_pmu)
+ return false;
+ first = false;
+ if (counter->pmu) {
+ /* Allow uniquify for uncore PMUs. */
+ if (!counter->pmu->is_core)
+ return false;
+ /* Keep hybrid event names uniquified for clarity. */
+ if (perf_pmus__num_core_pmus() > 1)
+ return false;
}
- perf_cpu_map__put(intersect);
+ last_pmu = counter->pmu;
}
- perf_cpu_map__put(user_requested_cpus);
+ return true;
}
-void evlist__uniquify_name(struct evlist *evlist)
+static bool evlist__set_needs_uniquify(struct evlist *evlist, const struct perf_stat_config *config)
{
- char *new_name, empty_attributes[2] = ":", *attributes;
- struct evsel *pos;
-
- if (perf_pmus__num_core_pmus() == 1)
- return;
+ struct evsel *counter;
+ bool needs_uniquify = false;
- evlist__for_each_entry(evlist, pos) {
- if (!evsel__is_hybrid(pos))
- continue;
+ if (evlist__disable_uniquify(evlist)) {
+ evlist__for_each_entry(evlist, counter)
+ counter->uniquified_name = true;
+ return false;
+ }
- if (strchr(pos->name, '/'))
- continue;
+ evlist__for_each_entry(evlist, counter) {
+ if (evsel__set_needs_uniquify(counter, config))
+ needs_uniquify = true;
+ }
+ return needs_uniquify;
+}
- attributes = strchr(pos->name, ':');
- if (attributes)
- *attributes = '\0';
- else
- attributes = empty_attributes;
+void evlist__uniquify_evsel_names(struct evlist *evlist, const struct perf_stat_config *config)
+{
+ if (evlist__set_needs_uniquify(evlist, config)) {
+ struct evsel *pos;
- if (asprintf(&new_name, "%s/%s/%s", pos->pmu ? pos->pmu->name : "",
- pos->name, attributes + 1)) {
- free(pos->name);
- pos->name = new_name;
- } else {
- *attributes = ':';
- }
+ evlist__for_each_entry(evlist, pos)
+ evsel__uniquify_counter(pos);
}
}
@@ -2594,3 +2679,17 @@ bool evlist__has_bpf_output(struct evlist *evlist)
return false;
}
+
+bool evlist__needs_bpf_sb_event(struct evlist *evlist)
+{
+ struct evsel *evsel;
+
+ evlist__for_each_entry(evlist, evsel) {
+ if (evsel__is_dummy_event(evsel))
+ continue;
+ if (!evsel->core.attr.exclude_kernel)
+ return true;
+ }
+
+ return false;
+}