On 28 August 2015 at 22:20, Etsuro Fujita <fujita.ets...@lab.ntt.co.jp> wrote:
> On 2015/07/22 15:25, Etsuro Fujita wrote: > >> On 2015/07/10 21:59, David Rowley wrote: > > I just glanced at this and noticed that the method for determining if >>> there's any system columns could be made a bit nicer. >>> >> > /* Now, are any system columns requested from rel? */ >>> scan_plan->fsSystemCol = false; >>> for (i = FirstLowInvalidHeapAttributeNumber + 1; i < 0; i++) >>> { >>> if (bms_is_member(i - FirstLowInvalidHeapAttributeNumber, attrs_used)) >>> { >>> scan_plan->fsSystemCol = true; >>> break; >>> } >>> } >>> >> > I think could just be written as: >>> /* Now, are any system columns requested from rel? */ >>> if (!bms_is_empty(attrs_used) && >>> bms_next_member(attrs_used, -1) < -FirstLowInvalidHeapAttributeNumber) >>> scan_plan->fsSystemCol = true; >>> else >>> scan_plan->fsSystemCol = false; >>> >> > I know you didn't change this, but just thought I'd mention it while >>> there's an opportunity to fix it. >>> >> > On second thought, I noticed that there is a case when that fix doesn't > work well; bms_next_member wouldn't be efficient when only the rear > user-columns are requested from a foreign table that has a large number of > user-columns. So, I'm inclined to leave that as-is. > > You might be right here. I'd failed to think about that. It's likely not worth changing if there's cases when it'll be slower, but curiosity got the better of me and I wondered how extreme a case it would take to actually see a slowdown, and per my benchmark results the first used column would have to be about attnum 500. I used the attached to benchmark. has_system_columns is the current method, has_system_columns2 has my changes. Lines are prefixed by the position where the first (and only) attnum appears in the bitmap set. 1 has_system_columns complete in 1.196000 1 has_system_columns2 complete in 0.170000 2 has_system_columns complete in 1.198000 2 has_system_columns2 complete in 0.167000 4 has_system_columns complete in 1.197000 4 has_system_columns2 complete in 0.170000 8 has_system_columns complete in 1.206000 8 has_system_columns2 complete in 0.203000 16 has_system_columns complete in 1.202000 16 has_system_columns2 complete in 0.237000 32 has_system_columns complete in 1.206000 32 has_system_columns2 complete in 0.232000 64 has_system_columns complete in 1.207000 64 has_system_columns2 complete in 0.268000 128 has_system_columns complete in 1.205000 128 has_system_columns2 complete in 0.368000 256 has_system_columns complete in 1.203000 256 has_system_columns2 complete in 0.780000 512 has_system_columns complete in 1.202000 512 has_system_columns2 complete in 1.302000 1024 has_system_columns complete in 1.199000 1024 has_system_columns2 complete in 3.539000 So, for what it's worth, could be 6 times faster for an "average" sized table, but hey, we're talking nanoseconds anyway... Regards David Rowley -- David Rowley http://www.2ndQuadrant.com/ <http://www.2ndquadrant.com/> PostgreSQL Development, 24x7 Support, Training & Services
#include <stdio.h> #include <time.h> #include <stdlib.h> #include <stddef.h> #define FirstLowInvalidHeapAttributeNumber (-8) #define FLEXIBLE_ARRAY_MEMBER 1 #define elog(elevel, s) \ do { \ printf("%s\n", s); \ exit(EXIT_FAILURE); \ } while(0) #define BITS_PER_BITMAPWORD 32 #define WORDNUM(x) ((x) / BITS_PER_BITMAPWORD) #define BITNUM(x) ((x) % BITS_PER_BITMAPWORD) #define BITMAPSET_SIZE(nwords) \ (offsetof(Bitmapset, words) + (nwords) * sizeof(bitmapword)) typedef unsigned int bitmapword; /* must be an unsigned type */ typedef int signedbitmapword; /* must be the matching signed type */ typedef char bool; #define true 1 #define false 0 typedef struct Bitmapset { int nwords; /* number of words in array */ bitmapword words[FLEXIBLE_ARRAY_MEMBER]; /* really [nwords] */ } Bitmapset; void * palloc0(size_t size) { void *p = malloc(size); if (!p) elog(ERROR, "out of memory"); memset(p, 0, size); return p; } /* * bms_is_member - is X a member of A? */ bool bms_is_member(int x, const Bitmapset *a) { int wordnum, bitnum; /* XXX better to just return false for x<0 ? */ if (x < 0) elog(ERROR, "negative bitmapset member not allowed"); if (a == NULL) return false; wordnum = WORDNUM(x); bitnum = BITNUM(x); if (wordnum >= a->nwords) return false; if ((a->words[wordnum] & ((bitmapword) 1 << bitnum)) != 0) return true; return false; } static const unsigned char rightmost_one_pos[256] = { 0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 }; int bms_next_member(const Bitmapset *a, int prevbit) { int nwords; int wordnum; bitmapword mask; if (a == NULL) return -2; nwords = a->nwords; prevbit++; mask = (~(bitmapword) 0) << BITNUM(prevbit); for (wordnum = WORDNUM(prevbit); wordnum < nwords; wordnum++) { bitmapword w = a->words[wordnum]; /* ignore bits before prevbit */ w &= mask; if (w != 0) { int result; result = wordnum * BITS_PER_BITMAPWORD; while ((w & 255) == 0) { w >>= 8; result += 8; } result += rightmost_one_pos[w & 255]; return result; } /* in subsequent words, consider all bits */ mask = (~(bitmapword) 0); } return -2; } Bitmapset * bms_make_singleton(int x) { Bitmapset *result; int wordnum, bitnum; if (x < 0) elog(ERROR, "negative bitmapset member not allowed"); wordnum = WORDNUM(x); bitnum = BITNUM(x); result = (Bitmapset *) palloc0(BITMAPSET_SIZE(wordnum + 1)); result->nwords = wordnum + 1; result->words[wordnum] = ((bitmapword) 1 << bitnum); return result; } int has_system_columns(Bitmapset *attrs_used) { int i; for (i = FirstLowInvalidHeapAttributeNumber + 1; i < 0; i++) { if (bms_is_member(i - FirstLowInvalidHeapAttributeNumber, attrs_used)) { return 1; } } return 0; } int has_system_columns2(Bitmapset *attrs_used) { int first = bms_next_member(attrs_used, -1); if (first >= 0 && first < -FirstLowInvalidHeapAttributeNumber) return 1; return 0; } #define LOOPS 100000000 int main(void) { clock_t start, finish; int firstcol; for (firstcol = 1; firstcol <= 1024; firstcol <<= 1) { int loop; int dummycounter; Bitmapset *attrs_used = bms_make_singleton(firstcol - FirstLowInvalidHeapAttributeNumber); start = clock(); for (loop = 0; loop <= LOOPS; loop++) dummycounter += has_system_columns(attrs_used); finish = clock(); printf("%d has_system_columns complete in %f\n", firstcol, (double) (finish - start) / CLOCKS_PER_SEC); start = clock(); for (loop = 0; loop <= LOOPS; loop++) dummycounter += has_system_columns2(attrs_used); finish = clock(); printf("%d has_system_columns2 complete in %f\n", firstcol, (double) (finish - start) / CLOCKS_PER_SEC); } }
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers