Preparsing sprintf format strings
Denys Vlasenko
vda.linux@googlemail.com
Mon Oct 8 17:34:00 GMT 2007
On Monday 08 October 2007 16:08, Heikki Linnakangas wrote:
> Denys Vlasenko wrote:
> > On Monday 08 October 2007 13:50, Heikki Linnakangas wrote:
> >> While profiling a test case of exporting data from PostgreSQL, I noticed
> >> that a lot of CPU time was spent in sprintf, formatting timestamps like
> >> "2007-10-01 12:34". I could speed that up by an order of magnitude by
> >> replacing the sprintf call with tailored code, but it occurred to me
> >> that we could do the same in a more generic way in GCC.
> >
> > It is already done in gcc to some extent: for example, it
> > replaces printf("message\n") with puts("Message").
> >
> > It's too far-fetched for my tastes. I think gcc should not do it.
> > How gcc can know what printf() and puts() mean in *my* libc?
>
> Well, that's what -fno-builtin is for.
>
> > I think such optimizations should be done in glibc.
>
> The point is that you can't. GCC knows if an argument is a string
> literal at compile time, but the library function would have to check
> that at run-time. At that point, it's too late to turn a sprintf(dst,
> "foo") function call into a single word-length mov instruction.
I don't think so. strchr(str, '%') is fast, or at least much faster than
the rest if printf code. I see that you already looked into
printf internals. Scary, eh? ;)
> >> sprintf(dest, "constant%...", args...) -> memcpy(dest, "constant", 8);
> >> sprintf(dest+8, "%...", args...);
> >
> > Just make printf faster instead by implementing it there.
>
> Any suggestions on how to do that?
Pseudo-C with fast path for literal format strings (no '%' at all)
and fast copying of leading literal part:
sprintf(char *dst, const char *fmt, ...)
{
char *p = strchr(fmt, '%');
if (!p) {
p = stpcpy(dst, fmt);
return p - dst;
}
dst = mempcpy(dst, fmt, p - fmt);
fmt = p;
...continue with original sprintf code...
}
(p-functions return pointer past last copied byte).
> The glibc implementation looks pretty
> well optimized already. Or it's an incomprehensible piece of code full
> of gotos for some other reason ;-).
It *tries* to be fast and also handle all weird cases.
I suspect that even printf("%s", str) still spends a lot of time
traversing thru the maze...
> > In linux kernel, decimal conversion in vsprintf() is optimized
> > with custom conversion code. x3 faster, and no, it's not written in assembly.
>
> Interesting. I copy-pasted the code from 2.6.20.4 source tree into a
> test program, but it looks like there's no measurable difference in
> performance of sprintf(dst, "%d-%d-%d",a,b,c) between glibc and linux
> sprintf. Where did that 3x faster come from?
It's not in 2.6.20, not even 2.6.22.
You need some of the recent -rc. linux-2.6.23-rc9 definitely has it.
See attached.
--
vda
-------------- next part --------------
A non-text attachment was scrubbed...
Name: vsprintf.c
Type: text/x-csrc
Size: 22479 bytes
Desc: not available
URL: <https://gcc.gnu.org/pipermail/gcc/attachments/20071008/df39c584/attachment.bin>
More information about the Gcc
mailing list