diff options
| author | Ian Rogers <irogers@google.com> | 2026-10-12 16:47:24 -0700 |
|---|---|---|
| committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2026-10-19 09:25:42 -0300 |
| commit | aa68bfb7b04dbeee303e8105094baed5e75a7255 (patch) | |
| tree | b25404c18b3c48378f505284eb470589e9ab9d77 | |
| parent | dd1c6ac2f70f6a5b2d57bec2584de7bc7c144508 (diff) | |
| download | linux-next-aa68bfb7b04dbeee303e8105094baed5e75a7255.tar.gz linux-next-aa68bfb7b04dbeee303e8105094baed5e75a7255.zip | |
perf test: Avoid stack trace noise in verbose=1 failure snippets
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@google.com>
Acked-by: Namhyung Kim <namhyung@kernel.org>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
| -rw-r--r-- | tools/perf/tests/builtin-test.c | 101 |
1 files changed, 81 insertions, 20 deletions
diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c index 880eece0bc12..0751d974a39a 100644 --- a/tools/perf/tests/builtin-test.c +++ b/tools/perf/tests/builtin-test.c @@ -694,6 +694,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; @@ -764,43 +805,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 |
