summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndres Freund2018-01-29 08:51:11 +0000
committerAndres Freund2018-01-29 09:44:57 +0000
commitfdc6c7a6dddbd6df63717f2375637660bcd00fc6 (patch)
treee34a636274325a796015cc123202bde1ae2a68e2
parentfff9076c8ec5fd870e6ed338e7b7e91b71b4396c (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.c75
-rw-r--r--src/backend/executor/execExprCompile.c62
-rw-r--r--src/backend/executor/execExprInterp.c22
-rw-r--r--src/backend/executor/execGrouping.c51
-rw-r--r--src/include/executor/execExpr.h4
-rw-r--r--src/include/executor/executor.h5
-rw-r--r--src/include/nodes/execnodes.h11
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;