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, '.'
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.