perf script: Separate events from branch types
authorLeo Yan <leo.yan@arm.com>
Tue, 4 Mar 2025 11:12:31 +0000 (11:12 +0000)
committerNamhyung Kim <namhyung@kernel.org>
Wed, 5 Mar 2025 17:13:19 +0000 (09:13 -0800)
Branch types and events are two different things.  A branch type can be
a conditional branch, an indirect branch, a procedure call, a return, or
an exception taken, etc.  The extra event information is provided for
what happens during a branch, e.g. if a branch is mispredicted or not
taken (specific to conditional branches).

To deliver information about branches, this commit separates events from
branch types.  It parses branch types first, then appends event strings
embraced by the '/' character.  If multiple events occur, the events is
separated with a comma (,).

Also add a minor improvement by adding char 'm' in char array for branch
mispredict event.

Below are extracted sample flags.

Before:
        branch:   br miss
  instructions:   br miss

After:
        branch:   jmp/miss/
  instructions:   jmp/miss/

Reviewed-by: Ian Rogers <irogers@google.com>
Reviewed-by: James Clark <james.clark@linaro.org>
Signed-off-by: Leo Yan <leo.yan@arm.com>
Link: https://lore.kernel.org/r/20250304111240.3378214-4-leo.yan@arm.com
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
tools/perf/util/event.h
tools/perf/util/trace-event-scripting.c

index cd75efc09834f66a373bc128881a59de183d0abd..962fbc1714cf4c2bad27fb1e6e3efba61d12eaed 100644 (file)
@@ -69,7 +69,7 @@ enum {
        PERF_IP_FLAG_BRANCH_MISS        = 1ULL << 15,
 };
 
-#define PERF_IP_FLAG_CHARS "bcrosyiABExghDt"
+#define PERF_IP_FLAG_CHARS "bcrosyiABExghDtm"
 
 #define PERF_ADDITIONAL_STATE_MASK     \
        (PERF_IP_FLAG_IN_TX |           \
@@ -90,6 +90,9 @@ enum {
        PERF_IP_FLAG_VMENTRY            |\
        PERF_IP_FLAG_VMEXIT)
 
+#define PERF_IP_FLAG_BRACH_EVENT_MASK  \
+       PERF_IP_FLAG_BRANCH_MISS
+
 #define PERF_MEM_DATA_SRC_NONE \
        (PERF_MEM_S(OP, NA) |\
         PERF_MEM_S(LVL, NA) |\
index 712ba3a51bbe61268f955784b3b0f1e14e5d3d63..55d7e4e612d50c7cdedd796364c52ddac7aa060b 100644 (file)
@@ -309,7 +309,14 @@ static const struct {
        {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_TRACE_END, "tr end"},
        {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | PERF_IP_FLAG_VMENTRY, "vmentry"},
        {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | PERF_IP_FLAG_VMEXIT, "vmexit"},
-       {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_BRANCH_MISS, "br miss"},
+       {0, NULL}
+};
+
+static const struct {
+       u32 flags;
+       const char *name;
+} branch_events[] = {
+       {PERF_IP_FLAG_BRANCH_MISS, "miss"},
        {0, NULL}
 };
 
@@ -317,8 +324,9 @@ static int sample_flags_to_name(u32 flags, char *str, size_t size)
 {
        int i;
        const char *prefix;
-       int pos = 0, ret;
+       int pos = 0, ret, ev_idx = 0;
        u32 xf = flags & PERF_ADDITIONAL_STATE_MASK;
+       u32 types, events;
        char xs[16] = { 0 };
 
        /* Clear additional state bits */
@@ -338,8 +346,9 @@ static int sample_flags_to_name(u32 flags, char *str, size_t size)
 
        flags &= ~(PERF_IP_FLAG_TRACE_BEGIN | PERF_IP_FLAG_TRACE_END);
 
+       types = flags & ~PERF_IP_FLAG_BRACH_EVENT_MASK;
        for (i = 0; sample_flags[i].name; i++) {
-               if (sample_flags[i].flags != flags)
+               if (sample_flags[i].flags != types)
                        continue;
 
                ret = snprintf(str + pos, size - pos, "%s", sample_flags[i].name);
@@ -349,6 +358,27 @@ static int sample_flags_to_name(u32 flags, char *str, size_t size)
                break;
        }
 
+       events = flags & PERF_IP_FLAG_BRACH_EVENT_MASK;
+       for (i = 0; branch_events[i].name; i++) {
+               if (!(branch_events[i].flags & events))
+                       continue;
+
+               ret = snprintf(str + pos, size - pos, !ev_idx ? "/%s" : ",%s",
+                              branch_events[i].name);
+               if (ret < 0)
+                       return ret;
+               pos += ret;
+               ev_idx++;
+       }
+
+       /* Add an end character '/' for events */
+       if (ev_idx) {
+               ret = snprintf(str + pos, size - pos, "/");
+               if (ret < 0)
+                       return ret;
+               pos += ret;
+       }
+
        if (!xf)
                return pos;