Re: [PATCH 2/7] stdio-common: Iterate over the huge width for one printf function only
Adhemerval Zanella Netto <[email protected]>
| Newsgroups | gmane.comp.lib.glibc.alpha |
|---|---|
| Organization | Linaro |
| Message-ID | <[email protected]> |
On 24/08/26 19:16, Matt Turner wrote: > HUGE_WIDTH is chosen so that none of the strings produced are truncated, > which for the floating-point types means every record it takes part in > carries hundreds or thousands of digits. Those records dominate the > cost of this whole family of tests: for the long double conversions they > are 99% of the bytes produced, and the long double targets alone account > for 92% of the time the tests take. > > The digits being checked are produced by the same conversion code > whichever of the printf family of functions is used; what differs > between the twelve of them is the sink the result is written to, which > the smaller widths cover already. > > Iterate over HUGE_WIDTH for a single function then, chosen as printf, > and let the remaining eleven stop at MID_WIDTH. This applies to the > double and long double conversions only; for the other types > full-precision output is short and costs nothing, so they keep iterating > over it as before. > > Together with the switch to verifying in Python this takes the tests > from 935s to 375s of processor time on x86_64-linux-gnu, with all 576 > results continuing to pass. What remains is mostly intrinsic: the f and > F conversions print the whole integer part regardless of the precision > requested, so LDBL_MAX runs to some 4932 digits even at MID_WIDTH. Since 2.37 all twelve functions are thin wrappers that call the same __vfprintf_internal core, so it should be ok to use the output of one function as a proxy for the others. However, there some internal differences on each implementation that makes the sink behavior not width-independent: * asprintf reallocs past 200 bytes (PRINTF_BUFFER_SIZE_ASPRINTF), * dprintf writes out its 2048-byte buffer (PRINTF_BUFFER_SIZE_DPRINTF), * snprintf switches to a 128-byte discard buffer, * fprintf flushes through stdio. But I think theses tests does not aim to tests the overflow patch support (which is not stressed in all cases anyway, for instance dprintf one). So I think it should be ok to only tests one function. LGTM, thanks. I think it can also be applied independently. Reviewed-by: Adhemerval Zanella <[email protected]> > --- > stdio-common/tst-printf-format-p.h | 4 ++++ > .../tst-printf-format-skeleton-double.c | 2 ++ > .../tst-printf-format-skeleton-ldouble.c | 2 ++ > stdio-common/tst-printf-format-skeleton.c | 19 ++++++++++++++++++- > 4 files changed, 26 insertions(+), 1 deletion(-) > > diff --git ./stdio-common/tst-printf-format-p.h ./stdio-common/tst-printf-format-p.h > index 48dcc3b48c..c35ca2c44d 100644 > --- ./stdio-common/tst-printf-format-p.h > +++ ./stdio-common/tst-printf-format-p.h > @@ -18,6 +18,10 @@ > > #include <stdio.h> > > +/* Conversions are verified at the full width and precision through this > + function; see the comment on WPHUGE in tst-printf-format-skeleton.c. */ > +#define TST_PRINTF_HUGE 1 > + > #define printf_under_test(...) \ > ({ \ > int result; \ > diff --git ./stdio-common/tst-printf-format-skeleton-double.c ./stdio-common/tst-printf-format-skeleton-double.c > index e740c193b5..4dbf3fc1ed 100644 > --- ./stdio-common/tst-printf-format-skeleton-double.c > +++ ./stdio-common/tst-printf-format-skeleton-double.c > @@ -21,6 +21,8 @@ > > #define MID_WIDTH 20 > #define HUGE_WIDTH 320 > +/* Full-precision output runs to hundreds of digits here. */ > +#define TST_PRINTF_WIDE_TYPE 1 > #define REF_FMT ".35e" > #define REF_VAL(v) (v) > #define PREC DBL_MANT_DIG > diff --git ./stdio-common/tst-printf-format-skeleton-ldouble.c ./stdio-common/tst-printf-format-skeleton-ldouble.c > index 29bc8b7d36..d959f9dc2d 100644 > --- ./stdio-common/tst-printf-format-skeleton-ldouble.c > +++ ./stdio-common/tst-printf-format-skeleton-ldouble.c > @@ -22,6 +22,8 @@ > > #define MID_WIDTH 20 > #define HUGE_WIDTH 4950 > +/* Full-precision output runs to thousands of digits here. */ > +#define TST_PRINTF_WIDE_TYPE 1 > #define REF_FMT ".35Le" > #define REF_VAL(v) (v) > #define PREC LDBL_MANT_DIG > diff --git ./stdio-common/tst-printf-format-skeleton.c ./stdio-common/tst-printf-format-skeleton.c > index 000d8fa50d..3594124513 100644 > --- ./stdio-common/tst-printf-format-skeleton.c > +++ ./stdio-common/tst-printf-format-skeleton.c > @@ -102,6 +102,23 @@ static struct > #define STR(v) #v > #define WPINIT(v) {0, STR (v)}, {v, NULL}, {-v, NULL} > > +/* HUGE_WIDTH is chosen so that nothing is truncated, which for the wider > + floating-point types means thousands of digits in every record it takes > + part in. Those records dominate the run time of this whole family of > + tests. The digits they check are produced by the same conversion code > + regardless of which of the printf family of functions is used; only the > + sink the result is written to differs, and that is covered at the > + smaller widths already. So iterate over HUGE_WIDTH for one function > + only, chosen as 'printf' by having tst-printf-format-p.h define > + TST_PRINTF_HUGE, and let the remaining functions stop at MID_WIDTH. > + Types whose full-precision output is short keep it unconditionally, as > + it costs nothing there. */ > +#if defined TST_PRINTF_WIDE_TYPE && !defined TST_PRINTF_HUGE > +# define WPHUGE > +#else > +# define WPHUGE , WPINIT (HUGE_WIDTH) > +#endif > + > /* Width and precision settings to iterate over; zero is initialized > directly as it has no corresponding negated value and other values > use the helper above. */ > @@ -113,7 +130,7 @@ static struct wp > const char *s; > } const wp[] = > { {0, "0"}, {0, NULL}, WPINIT (1), WPINIT (2), > - WPINIT (MID_WIDTH), WPINIT (HUGE_WIDTH) }; > + WPINIT (MID_WIDTH) WPHUGE }; > > /* Produce a record according to '%' and zero or more output format flags > already provided in FMT at indices 0..IDX-1, width W if non-NULL, '.'