> 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