From 4d5981889745b8f4d2012ec71f04bca68b863764 Mon Sep 17 00:00:00 2001 From: Leo Yan Date: Tue, 4 Mar 2025 11:12:30 +0000 Subject: perf script: Refactor sample_flags_to_name() function When generating a string for sample flags, the sample_flags_to_name() function lacks the ability to parse the trace start bit or trace end bit. Therefore, the function is invoked multiple times after clearing its unsupported bits. This commit improves the sample_flags_to_name() function to parse sample flags in one go for three kinds of information: - The prefix info for trace start, trace end, etc. - Branch types. - Extra info for transaction and interrupt related info. As a result, the code is simplified to call the sample_flags_to_name() only once. No expectation for any changes in the perf script output. Reviewed-by: Ian Rogers Reviewed-by: James Clark Signed-off-by: Leo Yan Link: https://lore.kernel.org/r/20250304111240.3378214-3-leo.yan@arm.com Signed-off-by: Namhyung Kim --- tools/perf/util/trace-event-scripting.c | 85 +++++++++++++++++++++------------ 1 file changed, 54 insertions(+), 31 deletions(-) (limited to 'tools/perf/util/trace-event-scripting.c') diff --git a/tools/perf/util/trace-event-scripting.c b/tools/perf/util/trace-event-scripting.c index 4e81e02a4f18..712ba3a51bbe 100644 --- a/tools/perf/util/trace-event-scripting.c +++ b/tools/perf/util/trace-event-scripting.c @@ -313,49 +313,72 @@ static const struct { {0, NULL} }; -static const char *sample_flags_to_name(u32 flags) +static int sample_flags_to_name(u32 flags, char *str, size_t size) { int i; - - for (i = 0; sample_flags[i].name ; i++) { - if (sample_flags[i].flags == flags) - return sample_flags[i].name; + const char *prefix; + int pos = 0, ret; + u32 xf = flags & PERF_ADDITIONAL_STATE_MASK; + char xs[16] = { 0 }; + + /* Clear additional state bits */ + flags &= ~PERF_ADDITIONAL_STATE_MASK; + + if (flags & PERF_IP_FLAG_TRACE_BEGIN) + prefix = "tr strt "; + else if (flags & PERF_IP_FLAG_TRACE_END) + prefix = "tr end "; + else + prefix = ""; + + ret = snprintf(str + pos, size - pos, "%s", prefix); + if (ret < 0) + return ret; + pos += ret; + + flags &= ~(PERF_IP_FLAG_TRACE_BEGIN | PERF_IP_FLAG_TRACE_END); + + for (i = 0; sample_flags[i].name; i++) { + if (sample_flags[i].flags != flags) + continue; + + ret = snprintf(str + pos, size - pos, "%s", sample_flags[i].name); + if (ret < 0) + return ret; + pos += ret; + break; } - return NULL; + if (!xf) + return pos; + + snprintf(xs, sizeof(xs), "(%s%s%s)", + flags & PERF_IP_FLAG_IN_TX ? "x" : "", + flags & PERF_IP_FLAG_INTR_DISABLE ? "D" : "", + flags & PERF_IP_FLAG_INTR_TOGGLE ? "t" : ""); + + /* Right align the string if its length is less than the limit */ + if ((pos + strlen(xs)) < SAMPLE_FLAGS_STR_ALIGNED_SIZE) + ret = snprintf(str + pos, size - pos, "%*s", + (int)(SAMPLE_FLAGS_STR_ALIGNED_SIZE - ret), xs); + else + ret = snprintf(str + pos, size - pos, " %s", xs); + if (ret < 0) + return ret; + + return pos + ret; } int perf_sample__sprintf_flags(u32 flags, char *str, size_t sz) { - u32 xf = PERF_IP_FLAG_IN_TX | PERF_IP_FLAG_INTR_DISABLE | - PERF_IP_FLAG_INTR_TOGGLE; const char *chars = PERF_IP_FLAG_CHARS; const size_t n = strlen(PERF_IP_FLAG_CHARS); - const char *name = NULL; size_t i, pos = 0; - char xs[16] = {0}; - - if (flags & xf) - snprintf(xs, sizeof(xs), "(%s%s%s)", - flags & PERF_IP_FLAG_IN_TX ? "x" : "", - flags & PERF_IP_FLAG_INTR_DISABLE ? "D" : "", - flags & PERF_IP_FLAG_INTR_TOGGLE ? "t" : ""); - - name = sample_flags_to_name(flags & ~xf); - if (name) - return snprintf(str, sz, "%-15s%6s", name, xs); - - if (flags & PERF_IP_FLAG_TRACE_BEGIN) { - name = sample_flags_to_name(flags & ~(xf | PERF_IP_FLAG_TRACE_BEGIN)); - if (name) - return snprintf(str, sz, "tr strt %-7s%6s", name, xs); - } + int ret; - if (flags & PERF_IP_FLAG_TRACE_END) { - name = sample_flags_to_name(flags & ~(xf | PERF_IP_FLAG_TRACE_END)); - if (name) - return snprintf(str, sz, "tr end %-7s%6s", name, xs); - } + ret = sample_flags_to_name(flags, str, sz); + if (ret > 0) + return ret; for (i = 0; i < n; i++, flags >>= 1) { if ((flags & 1) && pos < sz) -- cgit From 88b1473135e4c6667bac12aff25be11399cf8819 Mon Sep 17 00:00:00 2001 From: Leo Yan Date: Tue, 4 Mar 2025 11:12:31 +0000 Subject: perf script: Separate events from branch types 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 Reviewed-by: James Clark Signed-off-by: Leo Yan Link: https://lore.kernel.org/r/20250304111240.3378214-4-leo.yan@arm.com Signed-off-by: Namhyung Kim --- tools/perf/util/trace-event-scripting.c | 36 ++++++++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-) (limited to 'tools/perf/util/trace-event-scripting.c') diff --git a/tools/perf/util/trace-event-scripting.c b/tools/perf/util/trace-event-scripting.c index 712ba3a51bbe..55d7e4e612d5 100644 --- a/tools/perf/util/trace-event-scripting.c +++ b/tools/perf/util/trace-event-scripting.c @@ -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; -- cgit From 4caa971050875ef17491ccf7c8d6defd4d99763f Mon Sep 17 00:00:00 2001 From: Leo Yan Date: Tue, 4 Mar 2025 11:12:32 +0000 Subject: perf script: Add not taken event for branches Some hardware (e.g., Arm SPE) can trace the not taken event for branches. Add a flag for this event and support printing it. Reviewed-by: Ian Rogers Reviewed-by: James Clark Signed-off-by: Leo Yan Link: https://lore.kernel.org/r/20250304111240.3378214-5-leo.yan@arm.com Signed-off-by: Namhyung Kim --- tools/perf/util/trace-event-scripting.c | 1 + 1 file changed, 1 insertion(+) (limited to 'tools/perf/util/trace-event-scripting.c') diff --git a/tools/perf/util/trace-event-scripting.c b/tools/perf/util/trace-event-scripting.c index 55d7e4e612d5..29cc467be14a 100644 --- a/tools/perf/util/trace-event-scripting.c +++ b/tools/perf/util/trace-event-scripting.c @@ -317,6 +317,7 @@ static const struct { const char *name; } branch_events[] = { {PERF_IP_FLAG_BRANCH_MISS, "miss"}, + {PERF_IP_FLAG_NOT_TAKEN, "not_taken"}, {0, NULL} }; -- cgit From 2f39edece13da7b4fa2a783e05bc5a9bb00b20ca Mon Sep 17 00:00:00 2001 From: Yujie Liu Date: Wed, 12 Mar 2025 15:56:36 +0800 Subject: perf script: Fix typo in branch event mask BRACH -> BRANCH Fixes: 88b1473135e4 ("perf script: Separate events from branch types") Signed-off-by: Yujie Liu Reviewed-by: Leo Yan Reviewed-by: James Clark Link: https://lore.kernel.org/r/20250312075636.429127-1-yujie.liu@intel.com Signed-off-by: Namhyung Kim --- tools/perf/util/trace-event-scripting.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'tools/perf/util/trace-event-scripting.c') diff --git a/tools/perf/util/trace-event-scripting.c b/tools/perf/util/trace-event-scripting.c index 29cc467be14a..72abb28b7b5a 100644 --- a/tools/perf/util/trace-event-scripting.c +++ b/tools/perf/util/trace-event-scripting.c @@ -347,7 +347,7 @@ 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; + types = flags & ~PERF_IP_FLAG_BRANCH_EVENT_MASK; for (i = 0; sample_flags[i].name; i++) { if (sample_flags[i].flags != types) continue; @@ -359,7 +359,7 @@ static int sample_flags_to_name(u32 flags, char *str, size_t size) break; } - events = flags & PERF_IP_FLAG_BRACH_EVENT_MASK; + events = flags & PERF_IP_FLAG_BRANCH_EVENT_MASK; for (i = 0; branch_events[i].name; i++) { if (!(branch_events[i].flags & events)) continue; -- cgit