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;
}

Reply via email to