Re: [PATCH v5 bpf-next 2/3] bpf: introduce helper bpf_get_branch_snapshot

From: Andrii Nakryiko
Date: Fri Sep 03 2021 - 13:10:31 EST


On Fri, Sep 3, 2021 at 1:49 AM Peter Zijlstra <peterz@xxxxxxxxxxxxx> wrote:
>
> On Thu, Sep 02, 2021 at 09:57:05AM -0700, Song Liu wrote:
> > +BPF_CALL_3(bpf_get_branch_snapshot, void *, buf, u32, size, u64, flags)
> > +{
> > + static const u32 br_entry_size = sizeof(struct perf_branch_entry);
> > + u32 entry_cnt = size / br_entry_size;
> > +
> > + if (unlikely(flags))
> > + return -EINVAL;
> > +
> > + if (!buf || (size % br_entry_size != 0))

I think buf can't be NULL, this should be enforced already by verifier
due to ARG_PTR_TO_UNINIT_MEM, so we can drop that.

> > + return -EINVAL;
> > +
> > + entry_cnt = static_call(perf_snapshot_branch_stack)(buf, entry_cnt);
>
> That's at least 2, possibly 3 branches just from the sanity checks, plus
> at least one from starting the BPF prog and one from calling this
> function, gets you at ~5 branch entries gone before you even do the
> snapshot thing.
>
> Less if you're in branch-stack mode.
>
> Can't the validator help with getting rid of the some of that?
>

Good points. I think we can drop !buf check completely. The flags and
size checks can be moved after perf_snapshot_branch_stack call. In
common cases those checks should always pass, but even if they don't
we'll just capture the LBR anyways, but will return an error later,
which seems totally acceptable.

As Alexei mentioned, there is a whole non-inlined migrate_disable()
call before this, which we should inline as well. It's good for
performance, not just LBR.

> I suppose you have to have this helper function because the JIT cannot
> emit static_call()... although in this case one could cheat and simply
> emit a call to static_call_query() and not bother with dynamic updates
> (because there aren't any).

If that's safe, let's do it.