]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
perf test: Add summary reporting
authorIan Rogers <irogers@google.com>
Tue, 2 Jun 2026 17:41:21 +0000 (10:41 -0700)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Thu, 4 Jun 2026 14:37:57 +0000 (11:37 -0300)
Currently, when running test suites (perf test), users must scroll
through hundreds of lines of console output to manually tally the number
of passed, skipped, or failed test cases.

Introduce an automated, global execution summary printed at the absolute
tail of the test run:

1. Track counts mid-flight inside the print_test_result() accumulator,
   clearly separating pass counts into standalone main tests vs.
   individual subtests (where num_test_cases > 1).

2. Accumulate the precise descriptions of all failed test cases
   directly into a global string buffer, formatted with their suite
   indices (e.g., 3.1: Parse event definition strings) for effortless
   cross-referencing.

3. Define a summary printer function print_tests_summary() that
   emits a colored outline of the final pass, skip, and fail totals,
   followed by the explicit list of failed tests.

4. Invoke the summary printer right before freeing the test array at
   the absolute tail of __cmd_test(), guaranteeing that the summary is
   successfully printed even if an internal emergency signal cleanup
   occurs or if the user interrupts the run early.

Example output:
```
$ sudo perf test -v
  1: vmlinux symtab matches kallsyms                                 : Skip
  2: Detect openat syscall event                                     : Ok
  3: Detect openat syscall event on all cpus                         : Ok
...
163: perf trace summary                                              : Ok

=== Test Summary ===
Passed main tests : 123
Passed subtests   : 145
Skipped tests     : 22
Failed tests      : 6
List of failed tests:
   92: perf kvm tests
   95: kernel lock contention analysis test
  120: perf metrics value validation
  124: Check branch stack sampling
  143: perftool-testsuite_probe
  158: test Intel TPEBS counting mode
```

Assisted-by: Gemini-CLI:Google Gemini 3
Signed-off-by: Ian Rogers <irogers@google.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: James Clark <james.clark@linaro.org>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
tools/perf/tests/builtin-test.c

index 3401d79a1d24a659aee03feed8a5985a4bf72831..8883d4744057fd6f7b69b866dea8b15c3dcb8b9c 100644 (file)
@@ -363,8 +363,14 @@ err_out:
 
 static struct pollfd *global_pfds;
 static size_t *global_pfd_indices;
+static unsigned int summary_tests_passed;
+static unsigned int summary_subtests_passed;
+static unsigned int summary_tests_skipped;
+static unsigned int summary_tests_failed;
+static struct strbuf summary_failed_tests_buf = STRBUF_INIT;
 
 static int strbuf_addstr_safe(struct strbuf *sb, const char *s);
+static int __printf(2, 3) strbuf_addf_safe(struct strbuf *sb, const char *fmt, ...);
 
 static int print_test_result(struct test_suite *t, int curr_suite, int curr_test_case,
                             int result, int width, int running)
@@ -382,11 +388,16 @@ static int print_test_result(struct test_suite *t, int curr_suite, int curr_test
                color_fprintf(stderr, PERF_COLOR_YELLOW, " Running (%d active)\n", running);
                break;
        case TEST_OK:
+               if (test_suite__num_test_cases(t) > 1)
+                       summary_subtests_passed++;
+               else
+                       summary_tests_passed++;
                pr_info(" Ok\n");
                break;
        case TEST_SKIP: {
                const char *reason = skip_reason(t, curr_test_case);
 
+               summary_tests_skipped++;
                if (reason)
                        color_fprintf(stderr, PERF_COLOR_YELLOW, " Skip (%s)\n", reason);
                else
@@ -395,6 +406,15 @@ static int print_test_result(struct test_suite *t, int curr_suite, int curr_test
                break;
        case TEST_FAIL:
        default:
+               summary_tests_failed++;
+               if (test_suite__num_test_cases(t) > 1)
+                       strbuf_addf_safe(&summary_failed_tests_buf, "  %3d.%1d: %s\n",
+                                   curr_suite + 1, curr_test_case + 1,
+                                   test_description(t, curr_test_case));
+               else
+                       strbuf_addf_safe(&summary_failed_tests_buf, "  %3d: %s\n",
+                                   curr_suite + 1,
+                                   test_description(t, curr_test_case));
                color_fprintf(stderr, PERF_COLOR_RED, " FAILED!\n");
                break;
        }
@@ -736,6 +756,47 @@ static int strbuf_addstr_safe(struct strbuf *sb, const char *s)
        return ret;
 }
 
+static int __printf(2, 3) strbuf_addf_safe(struct strbuf *sb, const char *fmt, ...)
+{
+       char buf[1024];
+       va_list ap;
+       int len;
+       sigset_t set, oldset;
+       int ret;
+
+       sigemptyset(&set);
+       sigaddset(&set, SIGINT);
+       sigaddset(&set, SIGTERM);
+       sigprocmask(SIG_BLOCK, &set, &oldset);
+
+       va_start(ap, fmt);
+       len = vsnprintf(buf, sizeof(buf), fmt, ap);
+       va_end(ap);
+
+       if (len < 0) {
+               sigprocmask(SIG_SETMASK, &oldset, NULL);
+               return len;
+       }
+       if ((size_t)len >= sizeof(buf)) {
+               char *dynamic_buf = malloc(len + 1);
+
+               if (!dynamic_buf) {
+                       sigprocmask(SIG_SETMASK, &oldset, NULL);
+                       return -ENOMEM;
+               }
+               va_start(ap, fmt);
+               vsnprintf(dynamic_buf, len + 1, fmt, ap);
+               va_end(ap);
+               ret = strbuf_addstr(sb, dynamic_buf);
+               free(dynamic_buf);
+       } else {
+               ret = strbuf_addstr(sb, buf);
+       }
+
+       sigprocmask(SIG_SETMASK, &oldset, NULL);
+       return ret;
+}
+
 static void drain_child_process_err(struct child_test *child)
 {
        char buf[512];
@@ -1013,6 +1074,23 @@ static void cmd_test_sig_handler(int sig)
        siglongjmp(cmd_test_jmp_buf, sig);
 }
 
+static void print_tests_summary(void)
+{
+       pr_info("\n=== Test Summary ===\n");
+       pr_info("Passed main tests : %u\n", summary_tests_passed);
+       pr_info("Passed subtests   : %u\n", summary_subtests_passed);
+       pr_info("Skipped tests     : %u\n", summary_tests_skipped);
+       if (summary_tests_failed > 0) {
+               color_fprintf(stderr, PERF_COLOR_RED, "Failed tests      : %u\n",
+                             summary_tests_failed);
+               pr_info("List of failed tests:\n");
+               pr_info("%s", summary_failed_tests_buf.buf);
+       } else {
+               color_fprintf(stderr, PERF_COLOR_GREEN, "Failed tests      : 0\n");
+       }
+       strbuf_release(&summary_failed_tests_buf);
+}
+
 static int __cmd_test(struct test_suite **suites, int argc, const char *argv[],
                      struct intlist *skiplist)
 {
@@ -1090,9 +1168,13 @@ static int __cmd_test(struct test_suite **suites, int argc, const char *argv[],
                        }
 
                        if (intlist__find(skiplist, curr_suite + 1)) {
-                               pr_info("%3d: %-*s:", curr_suite + 1, width,
-                                       test_description(*t, -1));
-                               color_fprintf(stderr, PERF_COLOR_YELLOW, " Skip (user override)\n");
+                               if (pass == 1) {
+                                       pr_info("%3d: %-*s:", curr_suite + 1, width,
+                                               test_description(*t, -1));
+                                       color_fprintf(stderr, PERF_COLOR_YELLOW,
+                                                     " Skip (user override)\n");
+                                       summary_tests_skipped++;
+                               }
                                continue;
                        }
 
@@ -1125,6 +1207,7 @@ err_out:
                for (size_t x = 0; x < num_tests; x++)
                        finish_test(child_tests, x, num_tests, width);
        }
+       print_tests_summary();
        free(global_pfds);
        free(global_pfd_indices);
        global_pfds = NULL;