This is the mail archive of the mailing list for the GCC project.

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Preparsing sprintf format strings

Denys Vlasenko wrote:
> On Tuesday 09 October 2007 20:48, Heikki Linnakangas wrote:
>> but it does beat glibc (5.20s) by a wide margin. 
>> However, preparsing the format string in gcc still beats the linux
>> version hands down (0.82s).
> You preparse "%d-%d-%d"? Into what?


sprintf(dest, "%d-%d-%d", a, b, c);

is transformed into:

dest += sprintf_prim_d(dest, a);
*(dest++) = '-';
dest += sprintf_prim_d(dest, b);
*(dest++) = '-';
dest += sprintf_prim_d(dest, c);

Where sprintf_prim_d is a new library function that converts an integer
to a string, like sprintf(dest, "%d", integer).

Not sure if "preparsing" was the right term here...

> I am from "small is beautiful" camp. I don't like "code growth
> for everyone for the benefit of 5% of code which really needs
> that last bit of speed" policy.
> I hate 80MB+ Oracle executables with passion.

Sure. I'm not sure what optimization level this would be enabled in. In
some cases the transformation might even result in smaller code, usually
slightly larger, sometimes much larger. Unless we figure out a way to
estimate when it leads to larger code size and when it doesn't, we'd
want to always disable it with -Os.

> What problems do you see with this:
> sprintf(char *dst, const char *fmt, ...)
> {
>   char *d;
>   char *p = strchr(fmt, '%');
>   /* Literal string? */
>   if (!p) {
>     d = stpcpy(dst, fmt);
>     return d - dst;
>   }
>   va_start(ap, fmt);
>   /* Copy leading literal prefix */
>   d = mempcpy(dst, fmt, p - fmt);
>   fmt = p;
>   /* Fast path for "...%s...%s...%s..." */
>   while (p[1] == 's') {
>     char *q = va_arg(ap, char*);
>     d = stpcpy(d, q);
>     fmt += 2; /* skip %s */
>     p = strchr(fmt, '%');
>     if (!p) {
>       d = stpcpy(d, fmt);
>       return d - dst; 
>     }
>     d = mempcpy(d, fmt, p - fmt);
>     fmt = p;
>   }
>   ...continue with original sprintf code...
> }
> It's small code increase, only in ONE place,
> catches even cases where format is not constant.

I tried that, after modifying it so that it handles %d instead of %s,
and ran the "%d-%d-%d" test program I've been using. It took 2.16s.
However, I'm afraid that won't scale. As you add new special cases for
different format strings, it starts to look more and more like the glibc
or linux sprintf, and you lose the gain performance. The nice thing in
doing it at compile time is that you can add any number of specialized
handlers for different format strings, and it won't slow you down at

  Heikki Linnakangas

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]