On 2012-12-20 16:04:49 +0100, Andres Freund wrote: > On 2012-12-20 15:51:37 +0100, Andres Freund wrote: > When doing a source/assembly annotation in SearchCatCache about half of > the misses are attributed to the memcpy() directly at the beginning.
Using a separate array for storing the arguments instead of copying & modifying cache->cc_skey yields a 2% speedup in pgbench -S for me... The attached patch is clearly not ready and I don't really have time & energy to pursue it right now, but it seems interesting enough to post. The approach seems solid and sensible although the implementation is not (too much c&p, no comments). Greetings, Andres Freund -- Andres Freund http://www.2ndQuadrant.com/ PostgreSQL Development, 24x7 Support, Training & Services
diff --git a/src/backend/utils/cache/catcache.c b/src/backend/utils/cache/catcache.c index 9ae1432..bee6f3d 100644 --- a/src/backend/utils/cache/catcache.c +++ b/src/backend/utils/cache/catcache.c @@ -73,7 +73,7 @@ static CatCacheHeader *CacheHdr = NULL; static uint32 CatalogCacheComputeHashValue(CatCache *cache, int nkeys, - ScanKey cur_skey); + ScanKey cur_skey, Datum *argument); static uint32 CatalogCacheComputeTupleHashValue(CatCache *cache, HeapTuple tuple); @@ -173,7 +173,7 @@ GetCCHashEqFuncs(Oid keytype, PGFunction *hashfunc, RegProcedure *eqfunc) * Compute the hash value associated with a given set of lookup keys */ static uint32 -CatalogCacheComputeHashValue(CatCache *cache, int nkeys, ScanKey cur_skey) +CatalogCacheComputeHashValue(CatCache *cache, int nkeys, ScanKey cur_skey, Datum *argument) { uint32 hashValue = 0; uint32 oneHash; @@ -188,28 +188,28 @@ CatalogCacheComputeHashValue(CatCache *cache, int nkeys, ScanKey cur_skey) case 4: oneHash = DatumGetUInt32(DirectFunctionCall1(cache->cc_hashfunc[3], - cur_skey[3].sk_argument)); + argument[3])); hashValue ^= oneHash << 24; hashValue ^= oneHash >> 8; /* FALLTHROUGH */ case 3: oneHash = DatumGetUInt32(DirectFunctionCall1(cache->cc_hashfunc[2], - cur_skey[2].sk_argument)); + argument[2])); hashValue ^= oneHash << 16; hashValue ^= oneHash >> 16; /* FALLTHROUGH */ case 2: oneHash = DatumGetUInt32(DirectFunctionCall1(cache->cc_hashfunc[1], - cur_skey[1].sk_argument)); + argument[1])); hashValue ^= oneHash << 8; hashValue ^= oneHash >> 24; /* FALLTHROUGH */ case 1: oneHash = DatumGetUInt32(DirectFunctionCall1(cache->cc_hashfunc[0], - cur_skey[0].sk_argument)); + argument[0])); hashValue ^= oneHash; break; default: @@ -228,17 +228,14 @@ CatalogCacheComputeHashValue(CatCache *cache, int nkeys, ScanKey cur_skey) static uint32 CatalogCacheComputeTupleHashValue(CatCache *cache, HeapTuple tuple) { - ScanKeyData cur_skey[CATCACHE_MAXKEYS]; + Datum arguments[CATCACHE_MAXKEYS]; bool isNull = false; - /* Copy pre-initialized overhead data for scankey */ - memcpy(cur_skey, cache->cc_skey, sizeof(cur_skey)); - /* Now extract key fields from tuple, insert into scankey */ switch (cache->cc_nkeys) { case 4: - cur_skey[3].sk_argument = + arguments[3] = (cache->cc_key[3] == ObjectIdAttributeNumber) ? ObjectIdGetDatum(HeapTupleGetOid(tuple)) : fastgetattr(tuple, @@ -248,7 +245,7 @@ CatalogCacheComputeTupleHashValue(CatCache *cache, HeapTuple tuple) Assert(!isNull); /* FALLTHROUGH */ case 3: - cur_skey[2].sk_argument = + arguments[2] = (cache->cc_key[2] == ObjectIdAttributeNumber) ? ObjectIdGetDatum(HeapTupleGetOid(tuple)) : fastgetattr(tuple, @@ -258,7 +255,7 @@ CatalogCacheComputeTupleHashValue(CatCache *cache, HeapTuple tuple) Assert(!isNull); /* FALLTHROUGH */ case 2: - cur_skey[1].sk_argument = + arguments[1] = (cache->cc_key[1] == ObjectIdAttributeNumber) ? ObjectIdGetDatum(HeapTupleGetOid(tuple)) : fastgetattr(tuple, @@ -268,7 +265,7 @@ CatalogCacheComputeTupleHashValue(CatCache *cache, HeapTuple tuple) Assert(!isNull); /* FALLTHROUGH */ case 1: - cur_skey[0].sk_argument = + arguments[0] = (cache->cc_key[0] == ObjectIdAttributeNumber) ? ObjectIdGetDatum(HeapTupleGetOid(tuple)) : fastgetattr(tuple, @@ -282,7 +279,7 @@ CatalogCacheComputeTupleHashValue(CatCache *cache, HeapTuple tuple) break; } - return CatalogCacheComputeHashValue(cache, cache->cc_nkeys, cur_skey); + return CatalogCacheComputeHashValue(cache, cache->cc_nkeys, cache->cc_skey, arguments); } @@ -1058,6 +1055,7 @@ SearchCatCache(CatCache *cache, Datum v4) { ScanKeyData cur_skey[CATCACHE_MAXKEYS]; + Datum arguments[CATCACHE_MAXKEYS]; uint32 hashValue; Index hashIndex; dlist_iter iter; @@ -1080,16 +1078,15 @@ SearchCatCache(CatCache *cache, /* * initialize the search key information */ - memcpy(cur_skey, cache->cc_skey, sizeof(cur_skey)); - cur_skey[0].sk_argument = v1; - cur_skey[1].sk_argument = v2; - cur_skey[2].sk_argument = v3; - cur_skey[3].sk_argument = v4; + arguments[0] = v1; + arguments[1] = v2; + arguments[2] = v3; + arguments[3] = v4; /* * find the hash bucket in which to look for the tuple */ - hashValue = CatalogCacheComputeHashValue(cache, cache->cc_nkeys, cur_skey); + hashValue = CatalogCacheComputeHashValue(cache, cache->cc_nkeys, cache->cc_skey, arguments); hashIndex = HASH_INDEX(hashValue, cache->cc_nbuckets); /* @@ -1114,10 +1111,11 @@ SearchCatCache(CatCache *cache, /* * see if the cached tuple matches our key. */ - HeapKeyTest(&ct->tuple, + HeapKeyTestArg(&ct->tuple, cache->cc_tupdesc, cache->cc_nkeys, - cur_skey, + cache->cc_skey, + arguments, res); if (!res) continue; @@ -1162,6 +1160,12 @@ SearchCatCache(CatCache *cache, } } + memcpy(cur_skey, cache->cc_skey, sizeof(cur_skey)); + cur_skey[0].sk_argument = v1; + cur_skey[1].sk_argument = v2; + cur_skey[2].sk_argument = v3; + cur_skey[3].sk_argument = v4; + /* * Tuple was not found in cache, so we have to try to retrieve it directly * from the relation. If found, we will add it to the cache; if not @@ -1300,7 +1304,7 @@ GetCatCacheHashValue(CatCache *cache, Datum v3, Datum v4) { - ScanKeyData cur_skey[CATCACHE_MAXKEYS]; + Datum arguments[CATCACHE_MAXKEYS]; /* * one-time startup overhead for each cache @@ -1311,16 +1315,15 @@ GetCatCacheHashValue(CatCache *cache, /* * initialize the search key information */ - memcpy(cur_skey, cache->cc_skey, sizeof(cur_skey)); - cur_skey[0].sk_argument = v1; - cur_skey[1].sk_argument = v2; - cur_skey[2].sk_argument = v3; - cur_skey[3].sk_argument = v4; + arguments[0] = v1; + arguments[1] = v2; + arguments[2] = v3; + arguments[3] = v4; /* * calculate the hash value */ - return CatalogCacheComputeHashValue(cache, cache->cc_nkeys, cur_skey); + return CatalogCacheComputeHashValue(cache, cache->cc_nkeys, cache->cc_skey, arguments); } @@ -1342,6 +1345,7 @@ SearchCatCacheList(CatCache *cache, Datum v4) { ScanKeyData cur_skey[CATCACHE_MAXKEYS]; + Datum arguments[CATCACHE_MAXKEYS]; uint32 lHashValue; dlist_iter iter; CatCList *cl; @@ -1369,18 +1373,18 @@ SearchCatCacheList(CatCache *cache, /* * initialize the search key information */ - memcpy(cur_skey, cache->cc_skey, sizeof(cur_skey)); - cur_skey[0].sk_argument = v1; - cur_skey[1].sk_argument = v2; - cur_skey[2].sk_argument = v3; - cur_skey[3].sk_argument = v4; + + arguments[0] = v1; + arguments[1] = v2; + arguments[2] = v3; + arguments[3] = v4; /* * compute a hash value of the given keys for faster search. We don't * presently divide the CatCList items into buckets, but this still lets * us skip non-matching items quickly most of the time. */ - lHashValue = CatalogCacheComputeHashValue(cache, nkeys, cur_skey); + lHashValue = CatalogCacheComputeHashValue(cache, nkeys, cache->cc_skey, arguments); /* * scan the items until we find a match or exhaust our list @@ -1405,10 +1409,11 @@ SearchCatCacheList(CatCache *cache, */ if (cl->nkeys != nkeys) continue; - HeapKeyTest(&cl->tuple, + HeapKeyTestArg(&cl->tuple, cache->cc_tupdesc, nkeys, - cur_skey, + cache->cc_skey, + arguments, res); if (!res) continue; @@ -1451,6 +1456,12 @@ SearchCatCacheList(CatCache *cache, ctlist = NIL; + memcpy(cur_skey, cache->cc_skey, sizeof(cur_skey)); + cur_skey[0].sk_argument = v1; + cur_skey[1].sk_argument = v2; + cur_skey[2].sk_argument = v3; + cur_skey[3].sk_argument = v4; + PG_TRY(); { Relation relation; diff --git a/src/include/access/valid.h b/src/include/access/valid.h index ce970e4..283623d 100644 --- a/src/include/access/valid.h +++ b/src/include/access/valid.h @@ -66,4 +66,58 @@ do \ } \ } while (0) +/* + * HeapKeyTest + * + * Test a heap tuple to see if it satisfies a scan key. + */ +#define HeapKeyTestArg(tuple, \ + tupdesc, \ + nkeys, \ + keys, \ + arguments, \ + result) \ +do \ +{ \ + /* Use underscores to protect the variables passed in as parameters */ \ + int __cur_nkeys = (nkeys); \ + ScanKey __cur_keys = (keys); \ + Datum *__cur_args = (arguments); \ + \ + (result) = true; /* may change */ \ + for (; __cur_nkeys--; __cur_keys++, __cur_args++) \ + { \ + Datum __atp; \ + bool __isnull; \ + Datum __test; \ + \ + if (__cur_keys->sk_flags & SK_ISNULL) \ + { \ + (result) = false; \ + break; \ + } \ + \ + __atp = heap_getattr((tuple), \ + __cur_keys->sk_attno, \ + (tupdesc), \ + &__isnull); \ + \ + if (__isnull) \ + { \ + (result) = false; \ + break; \ + } \ + \ + __test = FunctionCall2Coll(&__cur_keys->sk_func, \ + __cur_keys->sk_collation, \ + __atp, *__cur_args); \ + \ + if (!DatumGetBool(__test)) \ + { \ + (result) = false; \ + break; \ + } \ + } \ +} while (0) + #endif /* VALID_H */ * Unmerged path src/include/commands/explain.h
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers