diff options
author | Andres Freund | 2018-01-29 08:51:11 +0000 |
---|---|---|
committer | Andres Freund | 2018-01-29 09:44:57 +0000 |
commit | fdc6c7a6dddbd6df63717f2375637660bcd00fc6 (patch) | |
tree | e34a636274325a796015cc123202bde1ae2a68e2 | |
parent | fff9076c8ec5fd870e6ed338e7b7e91b71b4396c (diff) |
Heavily-WIP: JIT hashing.jit-before-rebase-2018-02-01
Author:
Reviewed-By:
Discussion: https://postgr.es/m/
Backpatch:
-rw-r--r-- | src/backend/executor/execExpr.c | 75 | ||||
-rw-r--r-- | src/backend/executor/execExprCompile.c | 62 | ||||
-rw-r--r-- | src/backend/executor/execExprInterp.c | 22 | ||||
-rw-r--r-- | src/backend/executor/execGrouping.c | 51 | ||||
-rw-r--r-- | src/include/executor/execExpr.h | 4 | ||||
-rw-r--r-- | src/include/executor/executor.h | 5 | ||||
-rw-r--r-- | src/include/nodes/execnodes.h | 11 |
7 files changed, 228 insertions, 2 deletions
diff --git a/src/backend/executor/execExpr.c b/src/backend/executor/execExpr.c index 6bb2bc3d40..6f101ab654 100644 --- a/src/backend/executor/execExpr.c +++ b/src/backend/executor/execExpr.c @@ -3321,3 +3321,78 @@ ExecBuildGroupingEqual(TupleDesc desc, return state; } + + +ExprState * +ExecBuildGroupingHash(TupleDesc desc, + int numCols, + AttrNumber *keyColIdx, + Oid *hashfunctions, + PlanState *parent) +{ + ExprState *state = makeNode(ExprState); + ExprEvalStep scratch = {0}; + int natt; + int maxatt = -1; + + state->expr = NULL; + state->parent = parent; + + scratch.resvalue = &state->resvalue; + scratch.resnull = &state->resnull; + + if (numCols == 0) + { + /* probably just assign a static result? */ + elog(ERROR, "hm"); + scratch.resvalue = 0; + return NULL; + } + + /* compute max needed attribute */ + for (natt = 0; natt < numCols; natt++) + { + int attno = keyColIdx[natt]; + + if (attno > maxatt) + maxatt = attno; + } + Assert(maxatt >= 0); + + /* push deform steps */ + scratch.opcode = EEOP_INNER_FETCHSOME; + scratch.d.fetch.last_var = maxatt; + scratch.d.fetch.known_desc = desc; + ExprEvalPushStep(state, &scratch); + + for (natt = 0; natt < numCols; natt++) + { + int attno = keyColIdx[natt]; + Form_pg_attribute att = TupleDescAttr(desc, attno - 1); + Var *arg; + /* + * Reusing ExecInitFunc() requires creating Vars, but still seems + * worth it from a code reuse perspective. + */ + + /* arg */ + arg = makeVar(INNER_VAR, attno, att->atttypid, + att->atttypmod, InvalidOid, 0); + + /* evaluate hash function */ + ExecInitFunc(&scratch, NULL, + list_make1(arg), hashfunctions[natt], InvalidOid, + state); + scratch.opcode = EEOP_HASH; + ExprEvalPushStep(state, &scratch); + } + + scratch.resvalue = NULL; + scratch.resnull = NULL; + scratch.opcode = EEOP_DONE; + ExprEvalPushStep(state, &scratch); + + ExecReadyExpr(state); + + return state; +} diff --git a/src/backend/executor/execExprCompile.c b/src/backend/executor/execExprCompile.c index 4d6304f748..6e8a550ba0 100644 --- a/src/backend/executor/execExprCompile.c +++ b/src/backend/executor/execExprCompile.c @@ -3009,6 +3009,68 @@ ExecReadyCompiledExpr(ExprState *state) elog(ERROR, "unimplemented in jit: %zu", op->opcode); + case EEOP_HASH: + { + FunctionCallInfo fcinfo = op->d.func.fcinfo_data; + LLVMValueRef v_fcinfo; + LLVMValueRef v_fcinfo_isnull; + + LLVMValueRef v_argnullp; + LLVMValueRef v_argnull0; + + LLVMValueRef v_tmpvalue; + LLVMValueRef v_hashvalue; + + LLVMBasicBlockRef b_null = LLVMInsertBasicBlock(opblocks[i + 1], "hash.null"); + LLVMBasicBlockRef b_nonnull = LLVMInsertBasicBlock(opblocks[i + 1], "hash.nonnull"); + //LLVMBasicBlockRef b_combine = LLVMInsertBasicBlock(opblocks[i + 1], "combine"); + + + v_fcinfo = LLVMBuildIntToPtr( + builder, + LLVMConstInt(TypeSizeT, (uintptr_t) fcinfo, false), + LLVMPointerType(StructFunctionCallInfoData, 0), + "v_fcinfo"); + + v_argnullp = + LLVMBuildStructGEP(builder, + v_fcinfo, + FIELDNO_FUNCTIONCALLINFODATA_ARGNULL, + "v_argnullp"); + + v_argnull0 = LLVMBuildLoad( + builder, + LLVMBuildStructGEP(builder, v_argnullp, 0, ""), + ""); + + v_tmpvalue = LLVMBuildLoad(builder, v_tmpvaluep, ""); + + LLVMBuildCondBr( + builder, + LLVMBuildICmp( + builder, LLVMIntEQ, v_argnull0, + LLVMConstInt(LLVMInt8Type(), 1, false), ""), + b_null, + b_nonnull); + + LLVMPositionBuilderAtEnd(builder, b_null); + v_hashvalue = LLVMConstInt(LLVMInt64Type(), 0, false); + /* FIXME combine */ + v_hashvalue = LLVMBuildXor(builder, v_hashvalue, v_tmpvalue, ""); + LLVMBuildStore(builder, v_hashvalue, v_resvaluep); + LLVMBuildBr(builder, opblocks[i + 1]); + + LLVMPositionBuilderAtEnd(builder, b_nonnull); + v_hashvalue = BuildFunctionCall(context, builder, mod, fcinfo, &v_fcinfo_isnull); + /* FIXME combine */ + v_hashvalue = LLVMBuildXor(builder, v_hashvalue, v_tmpvalue, ""); + LLVMBuildStore(builder, v_hashvalue, v_tmpvaluep); + + LLVMBuildBr(builder, opblocks[i + 1]); + + } + break; + case EEOP_LAST: Assert(false); break; diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c index 71bce37ca3..55fd0f7cf0 100644 --- a/src/backend/executor/execExprInterp.c +++ b/src/backend/executor/execExprInterp.c @@ -70,6 +70,7 @@ #include "utils/builtins.h" #include "utils/date.h" #include "utils/datum.h" +#include "utils/hashutils.h" #include "utils/lsyscache.h" #include "utils/timestamp.h" #include "utils/typcache.h" @@ -392,6 +393,7 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull) &&CASE_EEOP_AGG_PLAIN_TRANS, &&CASE_EEOP_AGG_ORDERED_TRANS_DATUM, &&CASE_EEOP_AGG_ORDERED_TRANS_TUPLE, + &&CASE_EEOP_HASH, &&CASE_EEOP_LAST }; @@ -1784,6 +1786,26 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull) EEO_NEXT(); } + EEO_CASE(EEOP_HASH) + { + FunctionCallInfo fcinfo = op->d.func.fcinfo_data; + Datum d; + + if (fcinfo->argnull[0]) + { + d = 0; + } + else + { + fcinfo->isnull = false; /* optimize away? */ + d = op->d.func.fn_addr(fcinfo); + Assert(!fcinfo->isnull); + } + state->resvalue = hash_combine((uint32) state->resvalue, (uint32) d); + + EEO_NEXT(); + } + EEO_CASE(EEOP_LAST) { /* unreachable */ diff --git a/src/backend/executor/execGrouping.c b/src/backend/executor/execGrouping.c index 2a750b3a14..1d917ed3ed 100644 --- a/src/backend/executor/execGrouping.c +++ b/src/backend/executor/execGrouping.c @@ -161,6 +161,7 @@ BuildTupleHashTable(PlanState *parent, Size entrysize = sizeof(TupleHashEntryData) + additionalsize; MemoryContext oldcontext; Oid *eqoids = (Oid *) palloc(numCols * sizeof(Oid)); + Oid *hashoids = (Oid *) palloc(numCols * sizeof(Oid)); int i; Assert(nbuckets > 0); @@ -208,12 +209,20 @@ BuildTupleHashTable(PlanState *parent, /* build comparator for all columns */ for (i = 0; i < numCols; i++) + { eqoids[i] = eqfunctions[i].fn_oid; + hashoids[i] = hashfunctions[i].fn_oid; + } hashtable->eq_func = ExecBuildGroupingEqual(inputDesc, numCols, keyColIdx, eqoids, parent); + hashtable->hash_func = ExecBuildGroupingHash(inputDesc, + numCols, + keyColIdx, hashoids, + parent); + MemoryContextSwitchTo(oldcontext); hashtable->exprcontext = CreateExprContext(parent->state); @@ -329,6 +338,7 @@ FindTupleHashEntry(TupleHashTable hashtable, TupleTableSlot *slot, * Also, the caller must select an appropriate memory context for running * the hash functions. (dynahash.c doesn't change CurrentMemoryContext.) */ +#if 0 static uint32 TupleHashTableHash(struct tuplehash_hash *tb, const MinimalTuple tuple) { @@ -383,6 +393,47 @@ TupleHashTableHash(struct tuplehash_hash *tb, const MinimalTuple tuple) return hashkey; } +#else +static uint32 +TupleHashTableHash(struct tuplehash_hash *tb, const MinimalTuple tuple) +{ + TupleHashTable hashtable = (TupleHashTable) tb->private_data; + uint32 hashkey = hashtable->hash_iv; + TupleTableSlot *slot; + ExprContext *econtext = hashtable->exprcontext; + bool isNull; + + if (tuple == NULL) + { + /* Process the current input tuple for the table */ + slot = hashtable->inputslot; + //hashfunctions = hashtable->in_hash_funcs; + } + Assert(tuple == 0); +#if 0 + else + { + /* + * Process a tuple already stored in the table. + * + * (this case never actually occurs due to the way simplehash.h is + * used, as the hash-value is stored in the entries) + */ + slot = hashtable->tableslot; + ExecStoreMinimalTuple(tuple, slot, false); + //hashfunctions = hashtable->tab_hash_funcs; + } +#endif + + econtext->ecxt_innertuple = slot; + hashtable->hash_func->resnull = false; + hashtable->hash_func->resvalue = hashtable->hash_iv; + hashkey = ExecEvalExpr(hashtable->hash_func, econtext, &isNull); + Assert(!isNull); + return hashkey; +} +#endif + /* * See whether two tuples (presumably of the same hash value) match * diff --git a/src/include/executor/execExpr.h b/src/include/executor/execExpr.h index 2eae8f38c7..399c789c64 100644 --- a/src/include/executor/execExpr.h +++ b/src/include/executor/execExpr.h @@ -231,6 +231,8 @@ typedef enum ExprEvalOp EEOP_AGG_ORDERED_TRANS_DATUM, EEOP_AGG_ORDERED_TRANS_TUPLE, + EEOP_HASH, + /* non-existent operation, used e.g. to check array lengths */ EEOP_LAST } ExprEvalOp; @@ -743,4 +745,6 @@ extern void ExecEvalAggOrderedTransDatum(ExprState *state, ExprEvalStep *op, extern void ExecEvalAggOrderedTransTuple(ExprState *state, ExprEvalStep *op, ExprContext *econtext); +extern void ExecEvalHash(ExprState *state, ExprEvalStep *op, ExprContext *econtext); + #endif /* EXEC_EXPR_H */ diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h index d6c30e6f80..8ecd4d37d5 100644 --- a/src/include/executor/executor.h +++ b/src/include/executor/executor.h @@ -260,6 +260,11 @@ extern ExprState *ExecBuildGroupingEqual(TupleDesc desc, AttrNumber *keyColIdx, Oid *eqfunctions, PlanState *parent); +extern ExprState *ExecBuildGroupingHash(TupleDesc desc, + int numCols, + AttrNumber *keyColIdx, + Oid *hashfunctions, + PlanState *parent); extern ProjectionInfo *ExecBuildProjectionInfo(List *targetList, ExprContext *econtext, TupleTableSlot *slot, diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h index d5815f047a..9493841223 100644 --- a/src/include/nodes/execnodes.h +++ b/src/include/nodes/execnodes.h @@ -613,12 +613,18 @@ typedef struct ExecAuxRowMark typedef struct TupleHashEntryData *TupleHashEntry; typedef struct TupleHashTableData *TupleHashTable; +typedef struct TupleHashKey +{ + MinimalTuple firstTuple; /* copy of first tuple in this group */ + uint32 hash; /* hash value (cached) */ +} TupleHashKey; + typedef struct TupleHashEntryData { MinimalTuple firstTuple; /* copy of first tuple in this group */ - void *additional; /* user data */ - uint32 status; /* hash status */ uint32 hash; /* hash value (cached) */ + uint32 status; /* hash status */ + void *additional; /* user data */ } TupleHashEntryData; /* define parameters necessary to generate the tuple hash table interface */ @@ -646,6 +652,7 @@ typedef struct TupleHashTableData FmgrInfo *cur_eq_funcs; /* equality functions for input vs. table */ uint32 hash_iv; /* hash-function IV */ ExprState *eq_func; /* tuple equality comparator */ + ExprState *hash_func; /* tuple hash function */ ExprContext *exprcontext; /* expression context */ } TupleHashTableData; |