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 <[email protected]>
---
  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 */


Reply via email to