[PATCH v4 3/3] perf test: Avoid stack trace noise in verbose=1 failure snippets

From: Ian Rogers

Date: Mon Oct 12 2026 - 19:53:02 EST


When a test fails with a signal or times out, child_test_sig_handler()
appends '---- unexpected signal (<sig>) ----' followed by a multi-line
stack trace (' #0 ...' through '_start').

In verbose=1 mode, print_test_failure_snippet() selects up to
failure_snippet_lines (10) lines:
- Pass 1 selects lines matching failure keywords plus their immediate
next line (' #0 ... in child_test_sig_handler').
- Pass 2 fills the remaining quota by scanning backwards from the end
of the output buffer, which consumes the remaining lines on outermost
stack frames ('handle_internal_command', 'run_argv', 'main',
'__libc_start_main', '_start') and hides the trailing test output
showing where the test had run to.

Improve print_test_failure_snippet() by:
- Skipping blank lines and stack trace lines (' #<digit>...') when
selecting context in Pass 1 and when scanning backwards from the end
in Pass 2, with a Pass 3 fallback from the top of the buffer if quota
still remains.
- Prioritizing the non-blank line immediately preceding
'---- unexpected signal' so there is no '...' gap before the signal
message.
- Only printing '...' between selected lines when at least one non-blank
line was omitted between them.

Assisted-by: Antigravity:gemini-3.1-pro
Signed-off-by: Ian Rogers <irogers@xxxxxxxxxx>
---
tools/perf/tests/builtin-test.c | 101 +++++++++++++++++++++++++-------
1 file changed, 81 insertions(+), 20 deletions(-)

diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c
index d0c2783cb312..b95e9704b79f 100644
--- a/tools/perf/tests/builtin-test.c
+++ b/tools/perf/tests/builtin-test.c
@@ -774,6 +774,47 @@ static void print_line_highlighted(FILE *fp, const char *line, size_t len)
}


+static bool is_blank_line(const char *line, size_t len)
+{
+ for (size_t i = 0; i < len; i++) {
+ if (!isspace((unsigned char)line[i]))
+ return false;
+ }
+ return true;
+}
+
+static bool is_stack_line(const char *line, size_t len)
+{
+ size_t i = 0;
+
+ while (i < len && isspace((unsigned char)line[i]))
+ i++;
+ return i + 1 < len && line[i] == '#' && isdigit((unsigned char)line[i + 1]);
+}
+
+static bool is_ignorable_snippet_line(const char *line, size_t len)
+{
+ return is_blank_line(line, len) || is_stack_line(line, len);
+}
+
+static bool has_non_blank_between(const char **lines, const size_t *line_lens,
+ size_t start, size_t end)
+{
+ for (size_t j = start + 1; j < end; j++) {
+ if (!is_blank_line(lines[j], line_lens[j]))
+ return true;
+ }
+ return false;
+}
+
+static void pick_snippet_line(bool *pick, size_t idx, unsigned int *picked_count)
+{
+ if (!pick[idx] && *picked_count < failure_snippet_lines) {
+ pick[idx] = true;
+ (*picked_count)++;
+ }
+}
+
static void print_test_failure_snippet(FILE *fp, const char *buf)
{
size_t num_lines = 0;
@@ -844,43 +885,63 @@ static void print_test_failure_snippet(FILE *fp, const char *buf)
}

/* Pass 0: Always pick the very first line */
- if (num_lines > 0 && picked_count < failure_snippet_lines) {
- pick[0] = true;
- picked_count++;
- }
+ if (num_lines > 0)
+ pick_snippet_line(pick, 0, &picked_count);

/* Pass 1: Pick lines with failure keywords from start (Highest Priority) */
for (i = 0; i < num_lines && picked_count < failure_snippet_lines; i++) {
size_t dummy;

- if (find_next_keyword(lines[i], line_lens[i], &dummy)) {
- if (!pick[i]) {
- pick[i] = true;
- picked_count++;
- }
- /* Prioritize getting the immediate next line for context */
- if (i + 1 < num_lines && !pick[i + 1] &&
- picked_count < failure_snippet_lines) {
- pick[i + 1] = true;
- picked_count++;
+ if (is_ignorable_snippet_line(lines[i], line_lens[i]))
+ continue;
+ if (!find_next_keyword(lines[i], line_lens[i], &dummy))
+ continue;
+
+ pick_snippet_line(pick, i, &picked_count);
+ /*
+ * For unexpected signals, prioritize the preceding non-blank
+ * line showing where the test had run to before the signal.
+ */
+ if (!strncmp(lines[i], "---- unexpected signal", 22)) {
+ size_t j = i;
+
+ while (j > 0) {
+ j--;
+ if (!is_ignorable_snippet_line(lines[j], line_lens[j])) {
+ pick_snippet_line(pick, j, &picked_count);
+ break;
+ }
}
}
+ /* Prioritize getting the immediate next line for context */
+ if (i + 1 < num_lines &&
+ !is_ignorable_snippet_line(lines[i + 1], line_lens[i + 1]))
+ pick_snippet_line(pick, i + 1, &picked_count);
}

- /* Pass 2: Fill remaining quota from the end backwards */
+ /*
+ * Pass 2: Fill remaining quota from the end backwards, skipping blank
+ * and stack trace lines so trailing test progress is shown instead of
+ * outermost stack frames like main/_start.
+ */
i = num_lines;
while (i > 0 && picked_count < failure_snippet_lines) {
i--;
- if (!pick[i]) {
- pick[i] = true;
- picked_count++;
- }
+ if (!is_ignorable_snippet_line(lines[i], line_lens[i]))
+ pick_snippet_line(pick, i, &picked_count);
+ }
+
+ /* Pass 3: Fallback to top stack frames if quota remains */
+ for (i = 0; i < num_lines && picked_count < failure_snippet_lines; i++) {
+ if (!is_blank_line(lines[i], line_lens[i]))
+ pick_snippet_line(pick, i, &picked_count);
}

for (i = 0; i < num_lines; i++) {
if (!pick[i])
continue;
- if (last_printed != -1 && (int)i > last_printed + 1) {
+ if (last_printed != -1 &&
+ has_non_blank_between(lines, line_lens, last_printed, i)) {
if (perf_use_color_default)
fprintf(fp, "%s...%s\n", PERF_COLOR_BLUE, PERF_COLOR_RESET);
else
--
2.56.0.385.gd3acb90ef8-goog