[PATCH v4 2/4] perf: Use a union to clear branch entry bitfields
James Clark
james.clark at linaro.org
Mon Jun 8 11:06:35 PDT 2026
On 27/05/2026 1:11 pm, Puranjay Mohan wrote:
> 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 <puranjay at kernel.org>
> ---
> include/linux/perf_event.h | 9 +--------
> include/uapi/linux/perf_event.h | 25 +++++++++++++++----------
> tools/include/uapi/linux/perf_event.h | 25 +++++++++++++++----------
> 3 files changed, 31 insertions(+), 28 deletions(-)
>
> 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;
The comment above here says:
* The to and from fields are not cleared because they are
* systematically modified by caller.
But this is an inline function and the to/from fields are always
assigned right after calling it. Surely the compiler can work that out
and this was a premature optimization.
If we rename it to perf_clear_branch_entry() and do:
*br = (struct perf_branch_entry) {0};
Then we can delete a big comment, remove a potential source of bugs if
even more members are added, not have to update the uapi headers and
simplify it instead of working around the original issue.
> }
>
> 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 */
More information about the linux-arm-kernel
mailing list