This is the mail archive of the
mailing list for the GCC project.
Re: Preparsing sprintf format strings
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.
>> To effectively preparse any common format string, I'm proposing that we
>> add more rules to rewrite this kind of format strings as well:
>> sprintf(dest, "%d", arg1); -> a new function that does the same thing,
>> but without the overhead of parsing the format string. Like itoa on some
>> platforms. We could inline it as well. That would allow further
>> optimizations, if for example the compiler knows that arg1 is within a
>> certain range (do we do that kind of optimizations?)
>> 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? The glibc implementation looks pretty
well optimized already. Or it's an incomprehensible piece of code full
of gotos for some other reason ;-).
>> sprintf(dest, "%dconstant%...", args1, args...) -> sprintf(dest, "%d",
>> args1); memcpy(dest+X, "constant", 8); sprintf(dest+XX, "%...", args...);
> How do you know that in this place user wants faster, not smaller code?
I suppose we would only do the transformations that have a speed-space
tradeoff with -O3, and not with -Os.
>> If the sprintf and memcpy calls generated in the last two rewrites are
>> further simplified, format strings like "%d-%d-%d" wouldn't need to call
>> the glibc sprintf at all. The last form of rewrite wouldn't likely be a
>> win unless the resulting sprintf-calls can be converted into something
>> cheaper, because otherwise we're just introducing more library call
> Yes, printing dates and whatnot is very binary->decimal intensive.
> 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 188.8.131.52 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?