Speed up printing of integers in snprintf.c.
authorTom Lane <[email protected]>
Thu, 28 Oct 2021 17:39:57 +0000 (13:39 -0400)
committerTom Lane <[email protected]>
Thu, 28 Oct 2021 17:39:57 +0000 (13:39 -0400)
Since the only possible divisors are 8, 10, and 16, it doesn't cost
much code space to replace the division loop with three copies using
constant divisors.  On most machines, division by a constant can be
done a lot more cheaply than division by an arbitrary value.
A microbenchmark testing just snprintf("foo %d") with a 9-digit value
showed about a 2X speedup for me (tgl).  Most of Postgres isn't too
dependent on the speed of snprintf, so that the effect in real-world
cases is barely measurable.  Still, a cycle saved is a cycle earned.

Arjan van de Ven

Discussion: https://postgr.es/m/40a4b32a-b841-4667-11b2-a0baedb12714@linux.intel.com
Discussion: https://postgr.es/m/6e51c644-1b6d-956e-ac24-2d1b0541d532@linux.intel.com

src/port/snprintf.c

index 7c214293699b43396387f60bfdc9593a18061f91..1e59ca36e2c9675e645dc6abe89d7d578baac8d7 100644 (file)
@@ -1015,8 +1015,8 @@ fmtint(long long value, char type, int forcesign, int leftjust,
           int minlen, int zpad, int precision, int pointflag,
           PrintfTarget *target)
 {
-       unsigned long long base;
        unsigned long long uvalue;
+       int                     base;
        int                     dosign;
        const char *cvt = "0123456789abcdef";
        int                     signvalue = 0;
@@ -1075,12 +1075,36 @@ fmtint(long long value, char type, int forcesign, int leftjust,
                vallen = 0;
        else
        {
-               /* make integer string */
-               do
+               /*
+                * Convert integer to string.  We special-case each of the possible
+                * base values so as to avoid general-purpose divisions.  On most
+                * machines, division by a fixed constant can be done much more
+                * cheaply than a general divide.
+                */
+               if (base == 10)
+               {
+                       do
+                       {
+                               convert[sizeof(convert) - (++vallen)] = cvt[uvalue % 10];
+                               uvalue = uvalue / 10;
+                       } while (uvalue);
+               }
+               else if (base == 16)
                {
-                       convert[sizeof(convert) - (++vallen)] = cvt[uvalue % base];
-                       uvalue = uvalue / base;
-               } while (uvalue);
+                       do
+                       {
+                               convert[sizeof(convert) - (++vallen)] = cvt[uvalue % 16];
+                               uvalue = uvalue / 16;
+                       } while (uvalue);
+               }
+               else                                    /* base == 8 */
+               {
+                       do
+                       {
+                               convert[sizeof(convert) - (++vallen)] = cvt[uvalue % 8];
+                               uvalue = uvalue / 8;
+                       } while (uvalue);
+               }
        }
 
        zeropad = Max(0, precision - vallen);