On Sat, 18 Jun 2022 at 08:06, Andres Freund <and...@anarazel.de> wrote: > I also attached my heavily-WIP patches for the ExprEvalStep issues, I > accidentally had only included a small part of the contents of the json fix.
I've now looked at the 0003 patch. I like the idea you have about moving some of the additional fields into ScalarArrayOpExprHashTable. I think the patch can even go a little further and move the hash_finfo into there too. This means we don't need to dereference the "op" in saop_element_hash(). To make this work, I did need to tag the ScalarArrayOpExpr into the ExprEvalStep. That's required now since some of the initialization of the hash function fields is delayed until ExecEvalHashedScalarArrayOp(). We need to know the ScalarArrayOpExpr's hashfuncid and inputcollid. Your v2 patch did shift off some of this initialization work to ExecEvalHashedScalarArrayOp(). The attached v3 takes that a bit further. This saves a bit more work for ScalarArrayOpExprs that are evaluated 0 times. Another small thing which I considered doing was to put the hash_fcinfo_data field as the final field in ScalarArrayOpExprHashTable so that we could allocate the memory for the hash_fcinfo_data in the same allocation as the ScalarArrayOpExprHashTable. This would reduce the pointer dereferencing done in saop_element_hash() a bit further. I just didn't notice anywhere else where we do that for FunctionCallInfo, so I resisted doing this. (There was also a small bug in your patch where you mistakenly cast to an OpExpr instead of ScalarArrayOpExpr when you were fetching the inputcollid) David
From 7a1e71a6b622eff72537ae86187b312d01a5e11d Mon Sep 17 00:00:00 2001 From: David Rowley <drow...@postgresql.org> Date: Wed, 29 Jun 2022 10:43:41 +1200 Subject: [PATCH v3] Remove size increase in ExprEvalStep caused by hashed saops 50e17ad28 increased the size of ExprEvalStep from 64 bytes up to 88 bytes. Lots of effort was spent during the development of the current expression evaluation code to make an instance of this struct fit on a single cache line. Here we remove the fn_addr field. The values from this field can be obtained via fcinfo, just with some extra pointer dereferencing. The extra indirection does not seem to cause any noticeable slowdowns. Various other fields have been been moved into the ScalarArrayOpExprHashTable struct. These fields are only used when the ScalarArrayOpExprHashTable pointer has already been dereferenced, so no additional pointer dereferences occur for these. Author: Andres Freund Discussion: https://postgr.es/m/20220616233130.rparivafipt6d...@alap3.anarazel.de --- src/backend/executor/execExpr.c | 19 +------------------ src/backend/executor/execExprInterp.c | 25 +++++++++++++++++++++---- src/include/executor/execExpr.h | 7 +------ 3 files changed, 23 insertions(+), 28 deletions(-) diff --git a/src/backend/executor/execExpr.c b/src/backend/executor/execExpr.c index 2831e7978b..2e75f3204d 100644 --- a/src/backend/executor/execExpr.c +++ b/src/backend/executor/execExpr.c @@ -1203,8 +1203,6 @@ ExecInitExprRec(Expr *node, ExprState *state, FmgrInfo *finfo; FunctionCallInfo fcinfo; AclResult aclresult; - FmgrInfo *hash_finfo; - FunctionCallInfo hash_fcinfo; Oid cmpfuncid; /* @@ -1262,18 +1260,6 @@ ExecInitExprRec(Expr *node, ExprState *state, */ if (OidIsValid(opexpr->hashfuncid)) { - hash_finfo = palloc0(sizeof(FmgrInfo)); - hash_fcinfo = palloc0(SizeForFunctionCallInfo(1)); - fmgr_info(opexpr->hashfuncid, hash_finfo); - fmgr_info_set_expr((Node *) node, hash_finfo); - InitFunctionCallInfoData(*hash_fcinfo, hash_finfo, - 1, opexpr->inputcollid, NULL, - NULL); - - scratch.d.hashedscalararrayop.hash_finfo = hash_finfo; - scratch.d.hashedscalararrayop.hash_fcinfo_data = hash_fcinfo; - scratch.d.hashedscalararrayop.hash_fn_addr = hash_finfo->fn_addr; - /* Evaluate scalar directly into left function argument */ ExecInitExprRec(scalararg, state, &fcinfo->args[0].value, &fcinfo->args[0].isnull); @@ -1292,11 +1278,8 @@ ExecInitExprRec(Expr *node, ExprState *state, scratch.d.hashedscalararrayop.inclause = opexpr->useOr; scratch.d.hashedscalararrayop.finfo = finfo; scratch.d.hashedscalararrayop.fcinfo_data = fcinfo; - scratch.d.hashedscalararrayop.fn_addr = finfo->fn_addr; + scratch.d.hashedscalararrayop.saop = opexpr; - scratch.d.hashedscalararrayop.hash_finfo = hash_finfo; - scratch.d.hashedscalararrayop.hash_fcinfo_data = hash_fcinfo; - scratch.d.hashedscalararrayop.hash_fn_addr = hash_finfo->fn_addr; ExprEvalPushStep(state, &scratch); } diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c index eaec697bb3..399bdfd861 100644 --- a/src/backend/executor/execExprInterp.c +++ b/src/backend/executor/execExprInterp.c @@ -217,6 +217,8 @@ typedef struct ScalarArrayOpExprHashTable { saophash_hash *hashtab; /* underlying hash table */ struct ExprEvalStep *op; + FunctionCallInfo hash_fcinfo_data; /* arguments etc */ + FmgrInfo *hash_finfo; /* function's lookup data */ } ScalarArrayOpExprHashTable; /* Define parameters for ScalarArrayOpExpr hash table code generation. */ @@ -3474,13 +3476,13 @@ static uint32 saop_element_hash(struct saophash_hash *tb, Datum key) { ScalarArrayOpExprHashTable *elements_tab = (ScalarArrayOpExprHashTable *) tb->private_data; - FunctionCallInfo fcinfo = elements_tab->op->d.hashedscalararrayop.hash_fcinfo_data; + FunctionCallInfo fcinfo = elements_tab->hash_fcinfo_data; Datum hash; fcinfo->args[0].value = key; fcinfo->args[0].isnull = false; - hash = elements_tab->op->d.hashedscalararrayop.hash_fn_addr(fcinfo); + hash = elements_tab->hash_finfo->fn_addr(fcinfo); return DatumGetUInt32(hash); } @@ -3502,7 +3504,7 @@ saop_hash_element_match(struct saophash_hash *tb, Datum key1, Datum key2) fcinfo->args[1].value = key2; fcinfo->args[1].isnull = false; - result = elements_tab->op->d.hashedscalararrayop.fn_addr(fcinfo); + result = elements_tab->op->d.hashedscalararrayop.finfo->fn_addr(fcinfo); return DatumGetBool(result); } @@ -3549,6 +3551,7 @@ ExecEvalHashedScalarArrayOp(ExprState *state, ExprEvalStep *op, ExprContext *eco /* Build the hash table on first evaluation */ if (elements_tab == NULL) { + ScalarArrayOpExpr *saop; int16 typlen; bool typbyval; char typalign; @@ -3560,6 +3563,8 @@ ExecEvalHashedScalarArrayOp(ExprState *state, ExprEvalStep *op, ExprContext *eco MemoryContext oldcontext; ArrayType *arr; + saop = op->d.hashedscalararrayop.saop; + arr = DatumGetArrayTypeP(*op->resvalue); nitems = ArrayGetNItems(ARR_NDIM(arr), ARR_DIMS(arr)); @@ -3575,6 +3580,18 @@ ExecEvalHashedScalarArrayOp(ExprState *state, ExprEvalStep *op, ExprContext *eco op->d.hashedscalararrayop.elements_tab = elements_tab; elements_tab->op = op; + elements_tab->hash_finfo = palloc0(sizeof(FmgrInfo)); + fmgr_info(saop->hashfuncid, elements_tab->hash_finfo); + fmgr_info_set_expr((Node *) saop, elements_tab->hash_finfo); + + elements_tab->hash_fcinfo_data = palloc0(SizeForFunctionCallInfo(1)); + InitFunctionCallInfoData(*elements_tab->hash_fcinfo_data, + elements_tab->hash_finfo, + 1, + saop->inputcollid, + NULL, + NULL); + /* * Create the hash table sizing it according to the number of elements * in the array. This does assume that the array has no duplicates. @@ -3669,7 +3686,7 @@ ExecEvalHashedScalarArrayOp(ExprState *state, ExprEvalStep *op, ExprContext *eco fcinfo->args[1].value = (Datum) 0; fcinfo->args[1].isnull = true; - result = op->d.hashedscalararrayop.fn_addr(fcinfo); + result = op->d.hashedscalararrayop.finfo->fn_addr(fcinfo); resultnull = fcinfo->isnull; /* diff --git a/src/include/executor/execExpr.h b/src/include/executor/execExpr.h index e34db8c93c..e5e4d7fc1f 100644 --- a/src/include/executor/execExpr.h +++ b/src/include/executor/execExpr.h @@ -582,12 +582,7 @@ typedef struct ExprEvalStep struct ScalarArrayOpExprHashTable *elements_tab; FmgrInfo *finfo; /* function's lookup data */ FunctionCallInfo fcinfo_data; /* arguments etc */ - /* faster to access without additional indirection: */ - PGFunction fn_addr; /* actual call address */ - FmgrInfo *hash_finfo; /* function's lookup data */ - FunctionCallInfo hash_fcinfo_data; /* arguments etc */ - /* faster to access without additional indirection: */ - PGFunction hash_fn_addr; /* actual call address */ + ScalarArrayOpExpr *saop; } hashedscalararrayop; /* for EEOP_XMLEXPR */ -- 2.34.1