Hi,

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.

The format string is almost always a string literal, so instead of
parsing it at runtime in glibc sprintf, we can preparse it in gcc. We
already rewrite two simple cases:

sprintf(dest, "constant") -> strcpy(dest, "constant")
sprintf(dest, "%s", ptr) -> strcpy(dest, ptr)

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...);

sprintf(dest, "%dconstant%...", args1, args...) -> sprintf(dest, "%d",
args1); memcpy(dest+X, "constant", 8); sprintf(dest+XX, "%...", args...);

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
overhead.

I don't have much experience with GCC hacking, but I did put together a
prototype to do some of the above, and it does look like you can get
very significant speedups. Before I continue with that, has something
like this been proposed before? I couldn't find anything relevant in the
archives.

One small problem I see is that if you replace one of the output
handlers for something like %s with register_printf_function, the
simplified code won't honor that replacement. Actually, we have that
problem with the simplifications we already do, and replacing %s would
be a pretty dumb thing to do anyway, so I don't think that's a show stopper.

Thoughts?

-- 
  Heikki Linnakangas
  EnterpriseDB   http://www.enterprisedb.com

Reply via email to