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 <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-3-leo.yan@arm.com
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
This commit is contained in:
Leo Yan
2025-03-04 11:12:30 +00:00
committed by Namhyung Kim
parent 2b747a86d8
commit 4d59818897
2 changed files with 58 additions and 30 deletions

View File

@@ -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;
const char *prefix;
int pos = 0, ret;
u32 xf = flags & PERF_ADDITIONAL_STATE_MASK;
char xs[16] = { 0 };
for (i = 0; sample_flags[i].name ; i++) {
if (sample_flags[i].flags == flags)
return sample_flags[i].name;
/* 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};
int ret;
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);
}
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)