perf evsel: Add lazy-initialized probe type detection helpers

Several places in perf need to check whether an evsel is a kprobe or
uprobe, which requires looking up the PMU by name via evsel__find_pmu().
This lookup walks the PMU list each time, which is wasteful when the
same evsel is checked repeatedly.

Add evsel__is_kprobe(), evsel__is_uprobe(), and evsel__is_probe() that
resolve the probe type on first call via evsel__pmu_name() and cache
the result in a 3-bit field (probe_type) in struct evsel.  The field
fits in existing padding after the bool fields, so struct size does not
grow.

The enum uses PROBE__UNKNOWN (0) as the uninitialized sentinel —
explicitly set in evsel__init() — so the lookup happens on first use.
PROBE__NOPE (1) caches "not a probe" to avoid repeated negative lookups.

PMU-based probes (kprobe/uprobe PMU) are detected by PMU name.
Ftrace-based dynamic probes (created via tracefs, reported as PMU
"tracepoint") are detected by the __probe_ip field that the kernel
adds to all dynamic probe formats.  This covers kprobes, uprobes, and
fprobes regardless of their group/system name.

Cc: Aaron Tomlin <atomlin@atomlin.com>
Assisted-by: Claude:claude-opus-4.6
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
Arnaldo Carvalho de Melo
2026-06-16 16:35:43 -03:00
parent e22a422854
commit 9212e395c6
2 changed files with 58 additions and 0 deletions

View File

@@ -254,6 +254,58 @@ const char *evsel__pmu_name(const struct evsel *evsel)
return event_type(evsel->core.attr.type);
}
enum evsel_probe_type {
PROBE__UNKNOWN = 0,
PROBE__NOPE = 1,
PROBE__KPROBE = 2,
PROBE__UPROBE = 3,
/*
* Ftrace-based dynamic probes (kprobes/uprobes/fprobes created via
* tracefs) report PMU "tracepoint", not "kprobe"/"uprobe". Detect
* them by the __probe_ip field that the kernel adds to all dynamic
* probe formats.
*/
PROBE__FTRACE = 4,
};
static void evsel__resolve_probe_type(struct evsel *evsel)
{
const char *name = evsel__pmu_name(evsel);
if (!strcmp(name, "kprobe"))
evsel->probe_type = PROBE__KPROBE;
else if (!strcmp(name, "uprobe"))
evsel->probe_type = PROBE__UPROBE;
else if (!strcmp(name, "tracepoint") && evsel__field(evsel, "__probe_ip"))
evsel->probe_type = PROBE__FTRACE;
else
evsel->probe_type = PROBE__NOPE;
}
bool evsel__is_probe(struct evsel *evsel)
{
if (evsel->probe_type == PROBE__UNKNOWN)
evsel__resolve_probe_type(evsel);
return evsel->probe_type > PROBE__NOPE;
}
bool evsel__is_kprobe(struct evsel *evsel)
{
if (evsel->probe_type == PROBE__UNKNOWN)
evsel__resolve_probe_type(evsel);
return evsel->probe_type == PROBE__KPROBE;
}
bool evsel__is_uprobe(struct evsel *evsel)
{
if (evsel->probe_type == PROBE__UNKNOWN)
evsel__resolve_probe_type(evsel);
return evsel->probe_type == PROBE__UPROBE;
}
#define FD(e, x, y) (*(int *)xyarray__entry(e->core.fd, x, y))
int __evsel__sample_size(u64 sample_type)
@@ -413,6 +465,7 @@ void evsel__init(struct evsel *evsel,
evsel->supported = true;
evsel->alternate_hw_config = PERF_COUNT_HW_MAX;
evsel->script_output_type = -1; // FIXME: OUTPUT_TYPE_UNSET, see builtin-script.c
evsel->probe_type = PROBE__UNKNOWN;
}
struct evsel *evsel__new_idx(struct perf_event_attr *attr, int idx)

View File

@@ -126,6 +126,7 @@ struct evsel {
bool needs_uniquify;
bool fallenback_eacces;
bool fallenback_eopnotsupp;
u8 probe_type:3;
struct hashmap *per_pkg_mask;
int err;
int script_output_type;
@@ -259,6 +260,10 @@ struct perf_pmu *evsel__find_pmu(const struct evsel *evsel);
const char *evsel__pmu_name(const struct evsel *evsel);
bool evsel__is_aux_event(const struct evsel *evsel);
bool evsel__is_probe(struct evsel *evsel);
bool evsel__is_kprobe(struct evsel *evsel);
bool evsel__is_uprobe(struct evsel *evsel);
struct evsel *evsel__new_idx(struct perf_event_attr *attr, int idx);
static inline struct evsel *evsel__new(struct perf_event_attr *attr)