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 ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers