>     perf: Use a union to clear branch entry bitfields
>
>     perf_clear_branch_entry_bitfields() zeroes individual bitfields of struct
>     perf_branch_entry but has repeatedly fallen out of sync when new fields
>     were added (new_type and priv were missed).
>
>     Wrap the bitfields in an anonymous struct inside a union with a u64
>     bitfields member, and clear them all with a single assignment. This
>     avoids having to update the clearing function every time a new bitfield
>     is added.
>
>     Fixes: bfe4daf850f4 ("perf/core: Add perf_clear_branch_entry_bitfields() 
> helper")
>     Signed-off-by: Puranjay Mohan <[email protected]>

The Fixes tag points to commit bfe4daf850f4 which introduced the
perf_clear_branch_entry_bitfields() helper, but that commit was correct
at the time.

The actual bug was introduced by commit b190bc4ac9e6 which added the
'new_type' field without updating the clearing function. Commit
5402d25aa571 also added the 'priv' field with the same issue.

Should the Fixes tag be:

  Fixes: b190bc4ac9e6 ("perf: Extend branch type classification")

> diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
> index 48d851fbd8ea..f7360c43f902 100644
> --- a/include/linux/perf_event.h
> +++ b/include/linux/perf_event.h
> @@ -1474,14 +1474,7 @@ static inline u32 perf_sample_data_size(struct 
> perf_sample_data *data,
>   */
>  static inline void perf_clear_branch_entry_bitfields(struct 
> perf_branch_entry *br)
>  {
> -     br->mispred     = 0;
> -     br->predicted   = 0;
> -     br->in_tx       = 0;
> -     br->abort       = 0;
> -     br->cycles      = 0;
> -     br->type        = 0;
> -     br->spec        = PERF_BR_SPEC_NA;
> -     br->reserved    = 0;
> +     br->bitfields = 0;
>  }
>
>  extern void perf_output_sample(struct perf_output_handle *handle,
> diff --git a/include/uapi/linux/perf_event.h b/include/uapi/linux/perf_event.h
> index fd10aa8d697f..c2e7b1b1c4fa 100644
> --- a/include/uapi/linux/perf_event.h
> +++ b/include/uapi/linux/perf_event.h
> @@ -1491,16 +1491,21 @@ union perf_mem_data_src {
>  struct perf_branch_entry {
>       __u64   from;
>       __u64   to;
> -     __u64   mispred   :  1, /* target mispredicted */
> -             predicted :  1, /* target predicted */
> -             in_tx     :  1, /* in transaction */
> -             abort     :  1, /* transaction abort */
> -             cycles    : 16, /* cycle count to last branch */
> -             type      :  4, /* branch type */
> -             spec      :  2, /* branch speculation info */
> -             new_type  :  4, /* additional branch type */
> -             priv      :  3, /* privilege level */
> -             reserved  : 31;
> +     union {
> +             struct {
> +                     __u64   mispred   :  1, /* target mispredicted */
> +                             predicted :  1, /* target predicted */
> +                             in_tx     :  1, /* in transaction */
> +                             abort     :  1, /* transaction abort */
> +                             cycles    : 16, /* cycle count to last branch */
> +                             type      :  4, /* branch type */
> +                             spec      :  2, /* branch speculation info */
> +                             new_type  :  4, /* additional branch type */
> +                             priv      :  3, /* privilege level */
> +                             reserved  : 31;
> +             };
> +             __u64   bitfields;
> +     };
>  };
>
>  /* Size of used info bits in struct perf_branch_entry */
> diff --git a/tools/include/uapi/linux/perf_event.h 
> b/tools/include/uapi/linux/perf_event.h
> index fd10aa8d697f..c2e7b1b1c4fa 100644
> --- a/tools/include/uapi/linux/perf_event.h
> +++ b/tools/include/uapi/linux/perf_event.h
> @@ -1491,16 +1491,21 @@ union perf_mem_data_src {
>  struct perf_branch_entry {
>       __u64   from;
>       __u64   to;
> -     __u64   mispred   :  1, /* target mispredicted */
> -             predicted :  1, /* target predicted */
> -             in_tx     :  1, /* in transaction */
> -             abort     :  1, /* transaction abort */
> -             cycles    : 16, /* cycle count to last branch */
> -             type      :  4, /* branch type */
> -             spec      :  2, /* branch speculation info */
> -             new_type  :  4, /* additional branch type */
> -             priv      :  3, /* privilege level */
> -             reserved  : 31;
> +     union {
> +             struct {
> +                     __u64   mispred   :  1, /* target mispredicted */
> +                             predicted :  1, /* target predicted */
> +                             in_tx     :  1, /* in transaction */
> +                             abort     :  1, /* transaction abort */
> +                             cycles    : 16, /* cycle count to last branch */
> +                             type      :  4, /* branch type */
> +                             spec      :  2, /* branch speculation info */
> +                             new_type  :  4, /* additional branch type */
> +                             priv      :  3, /* privilege level */
> +                             reserved  : 31;
> +             };
> +             __u64   bitfields;
> +     };
>  };
>
>  /* Size of used info bits in struct perf_branch_entry */

---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md

CI run summary: https://github.com/kernel-patches/bpf/actions/runs/26510917353

Reply via email to