I wrote: > ... So we would be taking a hit on most platforms, but I've not really > seen sprintf as a major component of very many profiles. Moreover, > at least for the elog/ereport use-case, we'd be buying back some > nontrivial part of that hit by getting rid of expand_fmt_string(). > Also worth noting is that we've never made any effort at all to > micro-optimize snprintf.c, so maybe there's some gold to be mined > there to reduce the penalty.
Oh, the plot thickens: apparently, a very large chunk of the time in that test scenario went into the %g format item, which I think we can all agree isn't performance-critical for Postgres. Changing the test case to test %lld in place of %g, I get (on the same five platforms as before) RHEL6: snprintf time = 357.634 ms total, 0.000357634 ms per iteration pg_snprintf time = 281.708 ms total, 0.000281708 ms per iteration ratio = 0.788 macOS: snprintf time = 155.86 ms total, 0.00015586 ms per iteration pg_snprintf time = 104.074 ms total, 0.000104074 ms per iteration ratio = 0.668 FreeBSD: snprintf time = 268.883 ms total, 0.000268883 ms per iteration pg_snprintf time = 185.294 ms total, 0.000185294 ms per iteration ratio = 0.689 OpenBSD: snprintf time = 276.418 ms total, 0.000276418 ms per iteration pg_snprintf time = 153.334 ms total, 0.000153334 ms per iteration ratio = 0.555 NetBSD: snprintf time = 1174.13 ms total, 0.00117413 ms per iteration pg_snprintf time = 1508.82 ms total, 0.00150882 ms per iteration ratio = 1.285 So there's actually a plausible argument to be made that we'd get a net speed win on most platforms and test cases. regards, tom lane
#include "postgres_fe.h" #include "portability/instr_time.h" #include "snprintf.c" int main(int argc, char **argv) { int count = 0; char buffer[1000]; instr_time start; instr_time stop; double elapsed; double elapsed2; int i; if (argc > 1) count = atoi(argv[1]); if (count <= 0) count = 1000000; INSTR_TIME_SET_CURRENT(start); for (i = 0; i < count; i++) { snprintf(buffer, sizeof(buffer), "%d %lld %s", 42, (long long) 42, "01234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890"); } INSTR_TIME_SET_CURRENT(stop); INSTR_TIME_SUBTRACT(stop, start); elapsed = INSTR_TIME_GET_MILLISEC(stop); printf("snprintf time = %g ms total, %g ms per iteration\n", elapsed, elapsed / count); INSTR_TIME_SET_CURRENT(start); for (i = 0; i < count; i++) { pg_snprintf(buffer, sizeof(buffer), "%d %lld %s", 42, (long long) 42, "01234567890012345678900123456789001234567890012345678900123456789001234567890012345678900123456789001234567890"); } INSTR_TIME_SET_CURRENT(stop); INSTR_TIME_SUBTRACT(stop, start); elapsed2 = INSTR_TIME_GET_MILLISEC(stop); printf("pg_snprintf time = %g ms total, %g ms per iteration\n", elapsed2, elapsed2 / count); printf("ratio = %.3f\n", elapsed2 / elapsed); return 0; }