Re: [PATCH v3 02/13] perf test: Truncate test description to fit terminal width

From: Ian Rogers

Date: Mon Jun 22 2026 - 20:52:08 EST


On Wed, Jun 17, 2026 at 3:33 PM Namhyung Kim <namhyung@xxxxxxxxxx> wrote:
>
> On Tue, Jun 16, 2026 at 09:48:07AM -0700, Ian Rogers wrote:
> > The parallel test harness uses the carriage return delete escape sequence
> > `PERF_COLOR_DELETE_LINE` ("\033[A\33[2K\r") to erase and update the
> > "Running (X active)" progress lines.
> >
> > However, if a test description is longer than the terminal width, the line
> > wraps around. When this happens, the cursor up escape sequence `\033[A`
> > only moves the cursor to the last wrapped row, leaving the top half of the
> > description printed on the previous line. This leads to name duplication
> > and output corruption spilling over multiple rows on consoles narrower
> > than the maximum description length (e.g., 101 columns wide).
> >
> > Fix this by dynamically querying the terminal width using
> > `get_term_dimensions` and truncating the printed test descriptions using
> > the `%-*.*s` printf format. We reserve 35 characters for prefix, status,
> > and spacing metrics to guarantee the progress line never wraps.
> >
> > Fixes: 0e036dcad4e6 ("perf test: Display number of active running tests")
> > Assisted-by: Antigravity:gemini-3.1-pro
> > Signed-off-by: Ian Rogers <irogers@xxxxxxxxxx>
> > ---
> > tools/perf/tests/builtin-test.c | 130 ++++++++++++++++++++++++--------
> > 1 file changed, 98 insertions(+), 32 deletions(-)
> >
> > diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c
> > index afc06cec4954..1dcaeb8505b7 100644
> > --- a/tools/perf/tests/builtin-test.c
> > +++ b/tools/perf/tests/builtin-test.c
> > @@ -10,35 +10,39 @@
> > #ifdef HAVE_BACKTRACE_SUPPORT
> > #include <execinfo.h>
> > #endif
> > -#include <poll.h>
> > -#include <unistd.h>
> > #include <setjmp.h>
> > -#include <string.h>
> > #include <stdlib.h>
> > -#include <sys/types.h>
> > +#include <string.h>
> > +
> > #include <dirent.h>
> > -#include <sys/wait.h>
> > +#include <linux/kernel.h>
> > +#include <linux/string.h>
> > +#include <linux/zalloc.h>
> > +#include <poll.h>
> > +#include <sys/ioctl.h>
> > #include <sys/stat.h>
> > #include <sys/time.h>
> > +#include <sys/types.h>
> > +#include <sys/wait.h>
> > +#include <unistd.h>
> > +
> > +#include <subcmd/exec-cmd.h>
> > +#include <subcmd/parse-options.h>
> > +#include <subcmd/run-command.h>
> > +
> > #include "builtin.h"
> > +#include "color.h"
> > #include "config.h"
> > +#include "debug.h"
> > #include "hist.h"
> > #include "intlist.h"
> > -#include "tests.h"
> > -#include "debug.h"
> > -#include "color.h"
> > -#include <subcmd/parse-options.h>
> > -#include <subcmd/run-command.h>
> > #include "string2.h"
> > #include "symbol.h"
> > +#include "tests-scripts.h"
> > +#include "tests.h"
> > #include "util/rlimit.h"
> > #include "util/strbuf.h"
> > -#include <linux/kernel.h>
> > -#include <linux/string.h>
> > -#include <subcmd/exec-cmd.h>
> > -#include <linux/zalloc.h>
> > -
> > -#include "tests-scripts.h"
> > +#include "util/term.h"
> >
> > static const char *junit_filename;
> > static struct strbuf junit_xml_buf = STRBUF_INIT;
> > @@ -413,23 +417,73 @@ static char *xml_escape(const char *str)
> > return res ? res : strdup("");
> > }
> >
> > +static int get_term_width(void)
> > +{
> > + struct winsize ws;
> > + int cols = 80;
> > + int term_width;
> > +
> > + /*
> > + * If output is redirected to a file or piped, we don't need to wrap
> > + * or truncate at all. Use a massive virtually infinite terminal width
> > + * so descriptions are printed in full.
> > + */
> > + if (!isatty(fileno(debug_file())))
> > + return 10000;
> > +
> > + get_term_dimensions(&ws);
> > + if (ws.ws_col > 0)
> > + cols = ws.ws_col;
> > +
> > + /*
> > + * Limit description width to fit on a single line. We subtract 35
> > + * columns of headroom to allocate space for:
> > + * - The suite index prefix: e.g. " 10.100:" (9 characters).
> > + * - The colon separator and spaces: " : " (3 characters).
> > + * - The longest status results: e.g. "Skip (some metrics failed)" (26 characters)
> > + * or "Running (XX active)" (20 characters).
>
> I don't understand how it can be 35. The suite index prefix pattern
> looks like "%3d.%1d:" which is 6. Also it seems we don't have a space
> before the colon (for the test result).

There are 2 colons, one after the test.subtest and one before the
result. I'll tweakt the comments.

>
> > + *
> > + * A minimum description width of 10 is enforced to ensure names are
> > + * legible even on very narrow consoles.
> > + */
> > + term_width = cols - 35;
> > + if (term_width < 10)
> > + term_width = 10;
> > +
> > + return term_width;
> > +}
> > +
> > +static int get_max_desc_width(int width)
> > +{
> > + int term_width = get_term_width();
> > +
> > + return width > term_width ? term_width : width;
> > +}
> > +
> > static int print_test_result(struct test_suite *t, int curr_suite, int curr_test_case,
> > int result, int width, int running,
> > const char *err_output, double elapsed)
> > {
> > + int pad_width = get_max_desc_width(width);
> > + int term_width = get_term_width();
> > +
> > if (test_suite__num_test_cases(t) > 1) {
> > char prefix[32];
> > int len = snprintf(prefix, sizeof(prefix), "%3d.%1d:",
> > curr_suite + 1, curr_test_case + 1);
> > - int subw = len >= 4 ? width + 4 - len : width;
> > + int pad = len >= 4 ? pad_width + 4 - len : pad_width;
> > + int trunc = len >= 4 ? term_width + 4 - len : term_width;
>
> Can 'len' be less than 4? I don't think so..
>
> Anyway, do you know why do we care?

It was a safety measure carried forward, maybe due to Sashiko originally.

Thanks,
Ian

> thanks,
> Namhyung
>
> >
> > - pr_info("%s %-*s:", prefix, subw, test_description(t, curr_test_case));
> > - } else
> > - pr_info("%3d: %-*s:", curr_suite + 1, width, test_description(t, curr_test_case));
> > + pr_info("%s %-*.*s:", prefix, pad, trunc,
> > + test_description(t, curr_test_case));
> > + } else {
> > + pr_info("%3d: %-*.*s:", curr_suite + 1, pad_width, term_width,
> > + test_description(t, curr_test_case));
> > + }
> >
> > switch (result) {
> > case TEST_RUNNING:
> > - color_fprintf(stderr, PERF_COLOR_YELLOW, " Running (%d active)\n", running);
> > + color_fprintf(debug_file(), PERF_COLOR_YELLOW, " Running (%d active)\n", running);
> > break;
> > case TEST_OK:
> > if (test_suite__num_test_cases(t) > 1)