faster version of AllocSetFreeIndex for x86 architecture

http://archives.postgresql.org/pgsql-hackers/2009-06/msg00159.php

Postgresqlのmemory managerで、空きブロックリストのインデックスを計算する処理を高速化するパッチ。

現在のコードは、以下のようにループして計算しているが

static inline int
AllocSetFreeIndex(Size size)
{
	int         idx = 0;

	if (size > 0)
	{
		size = (size - 1) >> ALLOC_MINBITS;
		while (size != 0)
		{
			idx++;
			size >>= 1;
		}
		Assert(idx < ALLOCSET_NUM_FREELISTS);
	}

	return idx;
}

これを、x86 CPUのbsrで計算するようにした

static inline int
AllocSetFreeIndex(Size size)
{
    int idx;

    if (__builtin_expect(size < (1 << ALLOC_MINBITS), 0))
		size = (1 << ALLOC_MINBITS);

    /* bsr(Bit Scan Reverse): Search the most significant set bit */
    __asm__ ("bsr %1, %0" :"=r"(idx) :"g"(size - 1));

    return idx - (ALLOC_MINBITS - 1);
}


パッチの効果 (pgbench -c 1 -t 50000を実行し、oprofileで計測)

パッチ適用前

CPU: P4 / Xeon with 2 hyper-threads, speed 2793.55 MHz (estimated)
Counted GLOBAL_POWER_EVENTS events
samples  %        symbol name
66854     6.6725  AllocSetAlloc
11817     1.1794  AllocSetFree

パッチ適用後

CPU: P4 / Xeon with 2 hyper-threads, speed 2793.55 MHz (estimated)
Counted GLOBAL_POWER_EVENTS events
with a unit mask of 0x01 (mandatory) count 100000
samples  %        symbol name
47610     4.9333  AllocSetAlloc
6248      0.6474  AllocSetFree