[2/2] stdio-common: avoid repeated regexp matches in tst-printf-format.awk

Message ID 20260804015944.3816768-2-mattst88@gmail.com (mailing list archive)
State Committed
Commit 0cc3f9b3f3f2950844bd41cc8923215cd5d97269
Headers
Series [1/2] stdio-common: run AWK in the C locale in the printf format tests |

Checks

Context Check Description
redhat-pt-bot/TryBot-apply_patch success Patch applied to master at the time it was sent
linaro-tcwg-bot/tcwg_glibc_build--master-arm success Build passed
linaro-tcwg-bot/tcwg_glibc_build--master-aarch64 success Build passed
linaro-tcwg-bot/tcwg_glibc_check--master-arm fail Test failed
linaro-tcwg-bot/tcwg_glibc_check--master-aarch64 fail Test failed

Commit Message

Matt Turner Aug. 4, 2026, 1:59 a.m. UTC
  Whether the value is an infinity, a NaN or zero does not change between
the conversions applied to it, but was determined again for each one.
Determine it where the value is read.

Also look for the '#' flag with index() before matching the expressions
that need it, and test the value first where both have to hold.

For the %f conversion for double, in the C locale, as the median of five
runs:

  x86_64, gawk 5.4.1    1.248s -> 1.184s
  x86_64, gawk 5.3.2    0.703s -> 0.708s
  alpha,  gawk 5.4.60    26.6s ->  25.8s

So this only helps with the regular expression engine that gawk 5.4
brought in; under 5.3.2 it is lost in the noise.  Output and exit status
are unchanged for the e, f and g conversions for double under both
gawk versions and both locales.
---
 stdio-common/tst-printf-format.awk | 13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)
  

Comments

Adhemerval Zanella Netto Aug. 4, 2026, 1:39 p.m. UTC | #1
On 03/08/26 22:59, Matt Turner wrote:
> Whether the value is an infinity, a NaN or zero does not change between
> the conversions applied to it, but was determined again for each one.
> Determine it where the value is read.
> 
> Also look for the '#' flag with index() before matching the expressions
> that need it, and test the value first where both have to hold.
> 
> For the %f conversion for double, in the C locale, as the median of five
> runs:
> 
>   x86_64, gawk 5.4.1    1.248s -> 1.184s
>   x86_64, gawk 5.3.2    0.703s -> 0.708s
>   alpha,  gawk 5.4.60    26.6s ->  25.8s
> 
> So this only helps with the regular expression engine that gawk 5.4
> brought in; under 5.3.2 it is lost in the noise.  Output and exit status
> are unchanged for the e, f and g conversions for double under both
> gawk versions and both locales.

LGTM, thanks.

Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>

> ---
>  stdio-common/tst-printf-format.awk | 13 ++++++++-----
>  1 file changed, 8 insertions(+), 5 deletions(-)
> 
> diff --git ./stdio-common/tst-printf-format.awk ./stdio-common/tst-printf-format.awk
> index 5d0324c551..57bea12621 100644
> --- ./stdio-common/tst-printf-format.awk
> +++ ./stdio-common/tst-printf-format.awk
> @@ -32,6 +32,9 @@ BEGIN {
>    # non-bignum mode unless a sign has been explicitly given.  Keep
>    # original 'val' for reporting.
>    value = gensub(/^(INF|NAN|inf|nan)/, "+\\1", 1, val)
> +  # Neither changes between the conversions applied to this value.
> +  value_infnan = value ~ /(INF|NAN|inf|nan)/
> +  value_zero = value == 0
>    next
>  }
>  
> @@ -52,7 +55,7 @@ BEGIN {
>    # Discard the '#' flag with the octal conversion if output starts with
>    # 0 in the absence of this flag.  In that case no extra 0 is supposed
>    # to be produced, but gawk prepends it anyway.
> -  if (format ~ /#.*o/)
> +  if (index(format, "#") && format ~ /#.*o/)
>      {
>        tmpfmt = gensub(/#/, "", "g", format)
>        tmpout = sprintf(tmpfmt, value)
> @@ -62,7 +65,7 @@ BEGIN {
>    # Likewise with the hexadecimal conversion where zero value with the
>    # precision of zero is supposed to produce no characters, but gawk
>    # outputs 0 instead.
> -  else if (format ~ /#.*[Xx]/)
> +  else if (index(format, "#") && format ~ /#.*[Xx]/)
>      {
>        tmpfmt = gensub(/#/, "", "g", format)
>        tmpout = sprintf(tmpfmt, value)
> @@ -78,7 +81,7 @@ BEGIN {
>    # values and reprint the output produced using the string conversion,
>    # with the field width carried over and the relevant flags handled by
>    # hand.
> -  if (format ~ /[EFGefg]/ && value ~ /(INF|NAN|inf|nan)/)
> +  if (value_infnan && format ~ /[EFGefg]/)
>      {
>        minus = format ~ /-/ ? "-" : ""
>        sign = value ~ /-/ ? "-" : format ~ /\+/ ? "+" : format ~ / / ? " " : ""
> @@ -94,7 +97,7 @@ BEGIN {
>    # In that case "+" is always supposed to be produced, but with the
>    # precision of zero gawk in the non-bignum mode produces any padding
>    # requested only.
> -  else if (format ~ /\+.*[di]/ && value == 0)
> +  else if (value_zero && format ~ /\+.*[di]/)
>      {
>        output = gensub(/^( *) $/, format ~ /-/ ? "+\\1" : "\\1+", 1, output)
>        output = gensub(/^$/, "+", 1, output)
> @@ -103,7 +106,7 @@ BEGIN {
>    # conversion for zero value.  In that case at least one " " is
>    # supposed to be produced, but with the precision of zero gawk in the
>    # non-bignum mode produces nothing.
> -  else if (format ~ / .*[di]/ && value == 0)
> +  else if (value_zero && format ~ / .*[di]/)
>      {
>        output = gensub(/^$/, " ", 1, output)
>      }
  

Patch

diff --git ./stdio-common/tst-printf-format.awk ./stdio-common/tst-printf-format.awk
index 5d0324c551..57bea12621 100644
--- ./stdio-common/tst-printf-format.awk
+++ ./stdio-common/tst-printf-format.awk
@@ -32,6 +32,9 @@  BEGIN {
   # non-bignum mode unless a sign has been explicitly given.  Keep
   # original 'val' for reporting.
   value = gensub(/^(INF|NAN|inf|nan)/, "+\\1", 1, val)
+  # Neither changes between the conversions applied to this value.
+  value_infnan = value ~ /(INF|NAN|inf|nan)/
+  value_zero = value == 0
   next
 }
 
@@ -52,7 +55,7 @@  BEGIN {
   # Discard the '#' flag with the octal conversion if output starts with
   # 0 in the absence of this flag.  In that case no extra 0 is supposed
   # to be produced, but gawk prepends it anyway.
-  if (format ~ /#.*o/)
+  if (index(format, "#") && format ~ /#.*o/)
     {
       tmpfmt = gensub(/#/, "", "g", format)
       tmpout = sprintf(tmpfmt, value)
@@ -62,7 +65,7 @@  BEGIN {
   # Likewise with the hexadecimal conversion where zero value with the
   # precision of zero is supposed to produce no characters, but gawk
   # outputs 0 instead.
-  else if (format ~ /#.*[Xx]/)
+  else if (index(format, "#") && format ~ /#.*[Xx]/)
     {
       tmpfmt = gensub(/#/, "", "g", format)
       tmpout = sprintf(tmpfmt, value)
@@ -78,7 +81,7 @@  BEGIN {
   # values and reprint the output produced using the string conversion,
   # with the field width carried over and the relevant flags handled by
   # hand.
-  if (format ~ /[EFGefg]/ && value ~ /(INF|NAN|inf|nan)/)
+  if (value_infnan && format ~ /[EFGefg]/)
     {
       minus = format ~ /-/ ? "-" : ""
       sign = value ~ /-/ ? "-" : format ~ /\+/ ? "+" : format ~ / / ? " " : ""
@@ -94,7 +97,7 @@  BEGIN {
   # In that case "+" is always supposed to be produced, but with the
   # precision of zero gawk in the non-bignum mode produces any padding
   # requested only.
-  else if (format ~ /\+.*[di]/ && value == 0)
+  else if (value_zero && format ~ /\+.*[di]/)
     {
       output = gensub(/^( *) $/, format ~ /-/ ? "+\\1" : "\\1+", 1, output)
       output = gensub(/^$/, "+", 1, output)
@@ -103,7 +106,7 @@  BEGIN {
   # conversion for zero value.  In that case at least one " " is
   # supposed to be produced, but with the precision of zero gawk in the
   # non-bignum mode produces nothing.
-  else if (format ~ / .*[di]/ && value == 0)
+  else if (value_zero && format ~ / .*[di]/)
     {
       output = gensub(/^$/, " ", 1, output)
     }