perf trace -p <PID> work on a syscall that is unaugmented, but doesn't
work on a syscall that's augmented (when it calls perf_event_output() in
BPF).
Let's take open() as an example. open() is augmented in perf trace.
Before:
```
perf $ perf trace -e open -p 3792392
? ( ): ... [continued]: open()) = -1 ENOENT (No such file or directory)
? ( ): ... [continued]: open()) = -1 ENOENT (No such file or directory)
```
We can see there's no output.
After:
```
perf $ perf trace -e open -p 3792392
0.000 ( 0.123 ms): a.out/3792392 open(filename: "DINGZHEN", flags: WRONLY) = -1 ENOENT (No such file or directory)
1000.398 ( 0.116 ms): a.out/3792392 open(filename: "DINGZHEN", flags: WRONLY) = -1 ENOENT (No such file or directory)
```
Reason:
bpf_perf_event_output() will fail when you specify a pid in perf trace (EOPNOTSUPP).
When using perf trace -p 114, before perf_event_open(), we'll have PID
= 114, and CPU = -1.
This is bad for bpf-output event, because the ring buffer won't accept
output from BPF's perf_event_output(), making it fail. I'm still trying
to find out why.
If we open bpf-output for every cpu, instead of setting it to -1, like
this:
PID = <PID>, CPU = 0
PID = <PID>, CPU = 1
PID = <PID>, CPU = 2
PID = <PID>, CPU = 3
...
Everything works.
You can test it with this script:
```
#include <unistd.h>
#include <sys/syscall.h>
int main()
{
int i1 = 1, i2 = 2, i3 = 3, i4 = 4;
char s1[] = "DINGZHEN", s2[] = "XUEBAO";
while (1) {
syscall(SYS_open, s1, i1, i2);
sleep(1);
}
return 0;
}
```
save, compile
```
gcc open.c
```
perf trace
```
perf trace -e open <path-to-the-executable>
```
Signed-off-by: Howard Chu <howardchu95@gmail.com>
---
tools/perf/util/evlist.c | 14 +++++++++++++-
tools/perf/util/evlist.h | 1 +
2 files changed, 14 insertions(+), 1 deletion(-)
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index c0379fa1ccfe..f14b7e6ff1dc 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -1067,7 +1067,7 @@ int evlist__create_maps(struct evlist *evlist, struct target *target)
if (!threads)
return -1;
- if (target__uses_dummy_map(target))
+ if (target__uses_dummy_map(target) && !evlist__has_bpf_output(evlist))
cpus = perf_cpu_map__new_any_cpu();
else
cpus = perf_cpu_map__new(target->cpu_list);
@@ -2627,3 +2627,15 @@ void evlist__uniquify_name(struct evlist *evlist)
}
}
}
+
+bool evlist__has_bpf_output(struct evlist *evlist)
+{
+ struct evsel *evsel;
+
+ evlist__for_each_entry(evlist, evsel) {
+ if (evsel__is_bpf_output(evsel))
+ return true;
+ }
+
+ return false;
+}
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index b46f1a320783..bcc1c6984bb5 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -447,5 +447,6 @@ int evlist__scnprintf_evsels(struct evlist *evlist, size_t size, char *bf);
void evlist__check_mem_load_aux(struct evlist *evlist);
void evlist__warn_user_requested_cpus(struct evlist *evlist, const char *cpu_list);
void evlist__uniquify_name(struct evlist *evlist);
+bool evlist__has_bpf_output(struct evlist *evlist);
#endif /* __PERF_EVLIST_H */
--
2.45.2
On Wed, Aug 14, 2024 at 6:36 PM Howard Chu <howardchu95@gmail.com> wrote:
>
> perf trace -p <PID> work on a syscall that is unaugmented, but doesn't
> work on a syscall that's augmented (when it calls perf_event_output() in
> BPF).
>
> Let's take open() as an example. open() is augmented in perf trace.
>
> Before:
> ```
> perf $ perf trace -e open -p 3792392
> ? ( ): ... [continued]: open()) = -1 ENOENT (No such file or directory)
> ? ( ): ... [continued]: open()) = -1 ENOENT (No such file or directory)
> ```
>
> We can see there's no output.
>
> After:
> ```
> perf $ perf trace -e open -p 3792392
> 0.000 ( 0.123 ms): a.out/3792392 open(filename: "DINGZHEN", flags: WRONLY) = -1 ENOENT (No such file or directory)
> 1000.398 ( 0.116 ms): a.out/3792392 open(filename: "DINGZHEN", flags: WRONLY) = -1 ENOENT (No such file or directory)
> ```
>
> Reason:
>
> bpf_perf_event_output() will fail when you specify a pid in perf trace (EOPNOTSUPP).
>
> When using perf trace -p 114, before perf_event_open(), we'll have PID
> = 114, and CPU = -1.
>
> This is bad for bpf-output event, because the ring buffer won't accept
> output from BPF's perf_event_output(), making it fail. I'm still trying
> to find out why.
>
> If we open bpf-output for every cpu, instead of setting it to -1, like
> this:
> PID = <PID>, CPU = 0
> PID = <PID>, CPU = 1
> PID = <PID>, CPU = 2
> PID = <PID>, CPU = 3
> ...
>
> Everything works.
>
> You can test it with this script:
> ```
> #include <unistd.h>
> #include <sys/syscall.h>
>
> int main()
> {
> int i1 = 1, i2 = 2, i3 = 3, i4 = 4;
> char s1[] = "DINGZHEN", s2[] = "XUEBAO";
>
> while (1) {
> syscall(SYS_open, s1, i1, i2);
> sleep(1);
> }
>
> return 0;
> }
> ```
>
> save, compile
> ```
> gcc open.c
> ```
>
> perf trace
> ```
> perf trace -e open <path-to-the-executable>
> ```
>
> Signed-off-by: Howard Chu <howardchu95@gmail.com>
> ---
> tools/perf/util/evlist.c | 14 +++++++++++++-
> tools/perf/util/evlist.h | 1 +
> 2 files changed, 14 insertions(+), 1 deletion(-)
>
> diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
> index c0379fa1ccfe..f14b7e6ff1dc 100644
> --- a/tools/perf/util/evlist.c
> +++ b/tools/perf/util/evlist.c
> @@ -1067,7 +1067,7 @@ int evlist__create_maps(struct evlist *evlist, struct target *target)
> if (!threads)
> return -1;
>
> - if (target__uses_dummy_map(target))
> + if (target__uses_dummy_map(target) && !evlist__has_bpf_output(evlist))
I'm wondering if there should be a comment above this, something like:
Do we need the "any"/-1 CPU value or do we need to open an event on
all target CPUs (the default NULL implies all online CPUs). The dummy
map indicates that we need sideband perf record events in order to
symbolize samples. The mmap-ed ring buffers need CPUs. Similarly BPF
output events need ring buffers.
I'm not 100% on the ring buffer perf_event_open restrictions, and the
man page doesn't cover it, my knowledge is implied from failures and
seeing what the tool does.
Thanks,
Ian
> cpus = perf_cpu_map__new_any_cpu();
> else
> cpus = perf_cpu_map__new(target->cpu_list);
> @@ -2627,3 +2627,15 @@ void evlist__uniquify_name(struct evlist *evlist)
> }
> }
> }
> +
> +bool evlist__has_bpf_output(struct evlist *evlist)
> +{
> + struct evsel *evsel;
> +
> + evlist__for_each_entry(evlist, evsel) {
> + if (evsel__is_bpf_output(evsel))
> + return true;
> + }
> +
> + return false;
> +}
> diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
> index b46f1a320783..bcc1c6984bb5 100644
> --- a/tools/perf/util/evlist.h
> +++ b/tools/perf/util/evlist.h
> @@ -447,5 +447,6 @@ int evlist__scnprintf_evsels(struct evlist *evlist, size_t size, char *bf);
> void evlist__check_mem_load_aux(struct evlist *evlist);
> void evlist__warn_user_requested_cpus(struct evlist *evlist, const char *cpu_list);
> void evlist__uniquify_name(struct evlist *evlist);
> +bool evlist__has_bpf_output(struct evlist *evlist);
>
> #endif /* __PERF_EVLIST_H */
> --
> 2.45.2
>
On Thu, Aug 15, 2024 at 11:28:17AM -0700, Ian Rogers wrote:
> On Wed, Aug 14, 2024 at 6:36 PM Howard Chu <howardchu95@gmail.com> wrote:
> >
> > perf trace -p <PID> work on a syscall that is unaugmented, but doesn't
> > work on a syscall that's augmented (when it calls perf_event_output() in
> > BPF).
> >
> > Let's take open() as an example. open() is augmented in perf trace.
> >
> > Before:
> > ```
> > perf $ perf trace -e open -p 3792392
> > ? ( ): ... [continued]: open()) = -1 ENOENT (No such file or directory)
> > ? ( ): ... [continued]: open()) = -1 ENOENT (No such file or directory)
> > ```
> >
> > We can see there's no output.
> >
> > After:
> > ```
> > perf $ perf trace -e open -p 3792392
> > 0.000 ( 0.123 ms): a.out/3792392 open(filename: "DINGZHEN", flags: WRONLY) = -1 ENOENT (No such file or directory)
> > 1000.398 ( 0.116 ms): a.out/3792392 open(filename: "DINGZHEN", flags: WRONLY) = -1 ENOENT (No such file or directory)
> > ```
> >
> > Reason:
> >
> > bpf_perf_event_output() will fail when you specify a pid in perf trace (EOPNOTSUPP).
Trying to figure out why it returns EOPNOTSUPP:
static __always_inline u64
__bpf_perf_event_output(struct pt_regs *regs, struct bpf_map *map,
u64 flags, struct perf_sample_data *sd)
{
struct bpf_array *array = container_of(map, struct bpf_array, map);
unsigned int cpu = smp_processor_id();
u64 index = flags & BPF_F_INDEX_MASK;
struct bpf_event_entry *ee;
struct perf_event *event;
if (index == BPF_F_CURRENT_CPU)
index = cpu;
if (unlikely(index >= array->map.max_entries))
return -E2BIG;
ee = READ_ONCE(array->ptrs[index]);
<SNIP>
if (unlikely(event->oncpu != cpu))
return -EOPNOTSUPP;
return perf_event_output(event, sd, regs);
}
⬢[acme@toolbox perf-tools-next]$ git grep -- '->oncpu'
arch/x86/kvm/vmx/pmu_intel.c: * cpu pinned event reclaims LBR, the event->oncpu will be set to -1;
kernel/events/core.c: event->oncpu = -1;
kernel/events/core.c: WRITE_ONCE(event->oncpu, smp_processor_id());
kernel/events/core.c: * ->oncpu if it sees ACTIVE.
kernel/events/core.c: event->oncpu = -1;
kernel/events/core.c: if (READ_ONCE(event->oncpu) != smp_processor_id())
kernel/events/core.c: * inactive here (event->oncpu==-1), there's nothing more to do;
kernel/events/core.c: ret = cpu_function_call(READ_ONCE(event->oncpu),
kernel/events/core.c: event_oncpu = __perf_event_read_cpu(event, event->oncpu);
kernel/events/core.c: * Orders the ->state and ->oncpu loads such that if we see
kernel/events/core.c: * ACTIVE we must also see the right ->oncpu.
kernel/events/core.c: event_cpu = READ_ONCE(event->oncpu);
kernel/events/core.c: int cpu = READ_ONCE(event->oncpu);
kernel/events/core.c: if (WARN_ON_ONCE(READ_ONCE(sampler->oncpu) != smp_processor_id()))
kernel/events/core.c: cpu = READ_ONCE(iter->oncpu);
kernel/events/core.c: event->oncpu = -1;
kernel/trace/bpf_trace.c: if (unlikely(event->oncpu != cpu))
⬢[acme@toolbox perf-tools-next]$
This looks like a bug, no? It seems what this patch is doing is papering
onver that bug :-\
Alexei, Peter?
That part in the cset introducing bpf_perf_output_event() says:
"User space needs to perf_event_open() it (either for one or all cpus)"
-1 should mean all cpus, right, or is bpf_perf_event_output() only
supported if we do as Howard did in this patch?
---
commit a43eec304259a6c637f4014a6d4767159b6a3aa3
Author: Alexei Starovoitov <ast@kernel.org>
Date: Tue Oct 20 20:02:34 2015 -0700
bpf: introduce bpf_perf_event_output() helper
This helper is used to send raw data from eBPF program into
special PERF_TYPE_SOFTWARE/PERF_COUNT_SW_BPF_OUTPUT perf_event.
User space needs to perf_event_open() it (either for one or all cpus) and
store FD into perf_event_array (similar to bpf_perf_event_read() helper)
before eBPF program can send data into it.
---
We're missing something, can you help?
- Arnaldo
> > When using perf trace -p 114, before perf_event_open(), we'll have PID
> > = 114, and CPU = -1.
> >
> > This is bad for bpf-output event, because the ring buffer won't accept
> > output from BPF's perf_event_output(), making it fail. I'm still trying
> > to find out why.
> >
> > If we open bpf-output for every cpu, instead of setting it to -1, like
> > this:
> > PID = <PID>, CPU = 0
> > PID = <PID>, CPU = 1
> > PID = <PID>, CPU = 2
> > PID = <PID>, CPU = 3
> > ...
> >
> > Everything works.
> >
> > You can test it with this script:
> > ```
> > #include <unistd.h>
> > #include <sys/syscall.h>
> >
> > int main()
> > {
> > int i1 = 1, i2 = 2, i3 = 3, i4 = 4;
> > char s1[] = "DINGZHEN", s2[] = "XUEBAO";
> >
> > while (1) {
> > syscall(SYS_open, s1, i1, i2);
> > sleep(1);
> > }
> >
> > return 0;
> > }
> > ```
> >
> > save, compile
> > ```
> > gcc open.c
> > ```
> >
> > perf trace
> > ```
> > perf trace -e open <path-to-the-executable>
> > ```
> >
> > Signed-off-by: Howard Chu <howardchu95@gmail.com>
> > ---
> > tools/perf/util/evlist.c | 14 +++++++++++++-
> > tools/perf/util/evlist.h | 1 +
> > 2 files changed, 14 insertions(+), 1 deletion(-)
> >
> > diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
> > index c0379fa1ccfe..f14b7e6ff1dc 100644
> > --- a/tools/perf/util/evlist.c
> > +++ b/tools/perf/util/evlist.c
> > @@ -1067,7 +1067,7 @@ int evlist__create_maps(struct evlist *evlist, struct target *target)
> > if (!threads)
> > return -1;
> >
> > - if (target__uses_dummy_map(target))
> > + if (target__uses_dummy_map(target) && !evlist__has_bpf_output(evlist))
>
> I'm wondering if there should be a comment above this, something like:
>
> Do we need the "any"/-1 CPU value or do we need to open an event on
> all target CPUs (the default NULL implies all online CPUs). The dummy
> map indicates that we need sideband perf record events in order to
> symbolize samples. The mmap-ed ring buffers need CPUs. Similarly BPF
> output events need ring buffers.
>
> I'm not 100% on the ring buffer perf_event_open restrictions, and the
> man page doesn't cover it, my knowledge is implied from failures and
> seeing what the tool does.
>
> Thanks,
> Ian
>
>
> > cpus = perf_cpu_map__new_any_cpu();
> > else
> > cpus = perf_cpu_map__new(target->cpu_list);
> > @@ -2627,3 +2627,15 @@ void evlist__uniquify_name(struct evlist *evlist)
> > }
> > }
> > }
> > +
> > +bool evlist__has_bpf_output(struct evlist *evlist)
> > +{
> > + struct evsel *evsel;
> > +
> > + evlist__for_each_entry(evlist, evsel) {
> > + if (evsel__is_bpf_output(evsel))
> > + return true;
> > + }
> > +
> > + return false;
> > +}
> > diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
> > index b46f1a320783..bcc1c6984bb5 100644
> > --- a/tools/perf/util/evlist.h
> > +++ b/tools/perf/util/evlist.h
> > @@ -447,5 +447,6 @@ int evlist__scnprintf_evsels(struct evlist *evlist, size_t size, char *bf);
> > void evlist__check_mem_load_aux(struct evlist *evlist);
> > void evlist__warn_user_requested_cpus(struct evlist *evlist, const char *cpu_list);
> > void evlist__uniquify_name(struct evlist *evlist);
> > +bool evlist__has_bpf_output(struct evlist *evlist);
> >
> > #endif /* __PERF_EVLIST_H */
> > --
> > 2.45.2
> >
Hello,
Thanks to Namhyung Kim <namhyung@kernel.org>, this bug is fixed. There
is no problem in BPF, sorry for causing the trouble.
Thanks,
Howard
On Fri, Aug 16, 2024 at 10:52 PM Arnaldo Carvalho de Melo
<acme@kernel.org> wrote:
>
> On Thu, Aug 15, 2024 at 11:28:17AM -0700, Ian Rogers wrote:
> > On Wed, Aug 14, 2024 at 6:36 PM Howard Chu <howardchu95@gmail.com> wrote:
> > >
> > > perf trace -p <PID> work on a syscall that is unaugmented, but doesn't
> > > work on a syscall that's augmented (when it calls perf_event_output() in
> > > BPF).
> > >
> > > Let's take open() as an example. open() is augmented in perf trace.
> > >
> > > Before:
> > > ```
> > > perf $ perf trace -e open -p 3792392
> > > ? ( ): ... [continued]: open()) = -1 ENOENT (No such file or directory)
> > > ? ( ): ... [continued]: open()) = -1 ENOENT (No such file or directory)
> > > ```
> > >
> > > We can see there's no output.
> > >
> > > After:
> > > ```
> > > perf $ perf trace -e open -p 3792392
> > > 0.000 ( 0.123 ms): a.out/3792392 open(filename: "DINGZHEN", flags: WRONLY) = -1 ENOENT (No such file or directory)
> > > 1000.398 ( 0.116 ms): a.out/3792392 open(filename: "DINGZHEN", flags: WRONLY) = -1 ENOENT (No such file or directory)
> > > ```
> > >
> > > Reason:
> > >
> > > bpf_perf_event_output() will fail when you specify a pid in perf trace (EOPNOTSUPP).
>
> Trying to figure out why it returns EOPNOTSUPP:
>
> static __always_inline u64
> __bpf_perf_event_output(struct pt_regs *regs, struct bpf_map *map,
> u64 flags, struct perf_sample_data *sd)
> {
> struct bpf_array *array = container_of(map, struct bpf_array, map);
> unsigned int cpu = smp_processor_id();
> u64 index = flags & BPF_F_INDEX_MASK;
> struct bpf_event_entry *ee;
> struct perf_event *event;
>
> if (index == BPF_F_CURRENT_CPU)
> index = cpu;
> if (unlikely(index >= array->map.max_entries))
> return -E2BIG;
>
> ee = READ_ONCE(array->ptrs[index]);
> <SNIP>
> if (unlikely(event->oncpu != cpu))
> return -EOPNOTSUPP;
>
> return perf_event_output(event, sd, regs);
> }
>
> ⬢[acme@toolbox perf-tools-next]$ git grep -- '->oncpu'
> arch/x86/kvm/vmx/pmu_intel.c: * cpu pinned event reclaims LBR, the event->oncpu will be set to -1;
> kernel/events/core.c: event->oncpu = -1;
> kernel/events/core.c: WRITE_ONCE(event->oncpu, smp_processor_id());
> kernel/events/core.c: * ->oncpu if it sees ACTIVE.
> kernel/events/core.c: event->oncpu = -1;
> kernel/events/core.c: if (READ_ONCE(event->oncpu) != smp_processor_id())
> kernel/events/core.c: * inactive here (event->oncpu==-1), there's nothing more to do;
> kernel/events/core.c: ret = cpu_function_call(READ_ONCE(event->oncpu),
> kernel/events/core.c: event_oncpu = __perf_event_read_cpu(event, event->oncpu);
> kernel/events/core.c: * Orders the ->state and ->oncpu loads such that if we see
> kernel/events/core.c: * ACTIVE we must also see the right ->oncpu.
> kernel/events/core.c: event_cpu = READ_ONCE(event->oncpu);
> kernel/events/core.c: int cpu = READ_ONCE(event->oncpu);
> kernel/events/core.c: if (WARN_ON_ONCE(READ_ONCE(sampler->oncpu) != smp_processor_id()))
> kernel/events/core.c: cpu = READ_ONCE(iter->oncpu);
> kernel/events/core.c: event->oncpu = -1;
> kernel/trace/bpf_trace.c: if (unlikely(event->oncpu != cpu))
> ⬢[acme@toolbox perf-tools-next]$
>
> This looks like a bug, no? It seems what this patch is doing is papering
> onver that bug :-\
>
> Alexei, Peter?
>
> That part in the cset introducing bpf_perf_output_event() says:
>
> "User space needs to perf_event_open() it (either for one or all cpus)"
>
> -1 should mean all cpus, right, or is bpf_perf_event_output() only
> supported if we do as Howard did in this patch?
>
> ---
> commit a43eec304259a6c637f4014a6d4767159b6a3aa3
> Author: Alexei Starovoitov <ast@kernel.org>
> Date: Tue Oct 20 20:02:34 2015 -0700
>
> bpf: introduce bpf_perf_event_output() helper
>
> This helper is used to send raw data from eBPF program into
> special PERF_TYPE_SOFTWARE/PERF_COUNT_SW_BPF_OUTPUT perf_event.
> User space needs to perf_event_open() it (either for one or all cpus) and
> store FD into perf_event_array (similar to bpf_perf_event_read() helper)
> before eBPF program can send data into it.
> ---
>
> We're missing something, can you help?
>
> - Arnaldo
>
> > > When using perf trace -p 114, before perf_event_open(), we'll have PID
> > > = 114, and CPU = -1.
> > >
> > > This is bad for bpf-output event, because the ring buffer won't accept
> > > output from BPF's perf_event_output(), making it fail. I'm still trying
> > > to find out why.
> > >
> > > If we open bpf-output for every cpu, instead of setting it to -1, like
> > > this:
> > > PID = <PID>, CPU = 0
> > > PID = <PID>, CPU = 1
> > > PID = <PID>, CPU = 2
> > > PID = <PID>, CPU = 3
> > > ...
> > >
> > > Everything works.
> > >
> > > You can test it with this script:
> > > ```
> > > #include <unistd.h>
> > > #include <sys/syscall.h>
> > >
> > > int main()
> > > {
> > > int i1 = 1, i2 = 2, i3 = 3, i4 = 4;
> > > char s1[] = "DINGZHEN", s2[] = "XUEBAO";
> > >
> > > while (1) {
> > > syscall(SYS_open, s1, i1, i2);
> > > sleep(1);
> > > }
> > >
> > > return 0;
> > > }
> > > ```
> > >
> > > save, compile
> > > ```
> > > gcc open.c
> > > ```
> > >
> > > perf trace
> > > ```
> > > perf trace -e open <path-to-the-executable>
> > > ```
> > >
> > > Signed-off-by: Howard Chu <howardchu95@gmail.com>
> > > ---
> > > tools/perf/util/evlist.c | 14 +++++++++++++-
> > > tools/perf/util/evlist.h | 1 +
> > > 2 files changed, 14 insertions(+), 1 deletion(-)
> > >
> > > diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
> > > index c0379fa1ccfe..f14b7e6ff1dc 100644
> > > --- a/tools/perf/util/evlist.c
> > > +++ b/tools/perf/util/evlist.c
> > > @@ -1067,7 +1067,7 @@ int evlist__create_maps(struct evlist *evlist, struct target *target)
> > > if (!threads)
> > > return -1;
> > >
> > > - if (target__uses_dummy_map(target))
> > > + if (target__uses_dummy_map(target) && !evlist__has_bpf_output(evlist))
> >
> > I'm wondering if there should be a comment above this, something like:
> >
> > Do we need the "any"/-1 CPU value or do we need to open an event on
> > all target CPUs (the default NULL implies all online CPUs). The dummy
> > map indicates that we need sideband perf record events in order to
> > symbolize samples. The mmap-ed ring buffers need CPUs. Similarly BPF
> > output events need ring buffers.
> >
> > I'm not 100% on the ring buffer perf_event_open restrictions, and the
> > man page doesn't cover it, my knowledge is implied from failures and
> > seeing what the tool does.
> >
> > Thanks,
> > Ian
> >
> >
> > > cpus = perf_cpu_map__new_any_cpu();
> > > else
> > > cpus = perf_cpu_map__new(target->cpu_list);
> > > @@ -2627,3 +2627,15 @@ void evlist__uniquify_name(struct evlist *evlist)
> > > }
> > > }
> > > }
> > > +
> > > +bool evlist__has_bpf_output(struct evlist *evlist)
> > > +{
> > > + struct evsel *evsel;
> > > +
> > > + evlist__for_each_entry(evlist, evsel) {
> > > + if (evsel__is_bpf_output(evsel))
> > > + return true;
> > > + }
> > > +
> > > + return false;
> > > +}
> > > diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
> > > index b46f1a320783..bcc1c6984bb5 100644
> > > --- a/tools/perf/util/evlist.h
> > > +++ b/tools/perf/util/evlist.h
> > > @@ -447,5 +447,6 @@ int evlist__scnprintf_evsels(struct evlist *evlist, size_t size, char *bf);
> > > void evlist__check_mem_load_aux(struct evlist *evlist);
> > > void evlist__warn_user_requested_cpus(struct evlist *evlist, const char *cpu_list);
> > > void evlist__uniquify_name(struct evlist *evlist);
> > > +bool evlist__has_bpf_output(struct evlist *evlist);
> > >
> > > #endif /* __PERF_EVLIST_H */
> > > --
> > > 2.45.2
> > >
© 2016 - 2026 Red Hat, Inc.