From 1ef12c3385235529840e2c8302b88848c07e09b2 Mon Sep 17 00:00:00 2001 From: Andres Freund Date: Mon, 13 Mar 2017 20:22:10 -0700 Subject: [PATCH] WIP ORC and ResOwner. Author: Reviewed-By: Discussion: https://postgr.es/m/ Backpatch: --- configure | 2 +- configure.in | 2 +- src/backend/executor/execCompileExpr.c | 25 +++++-- src/backend/executor/execExpr.c | 18 ++--- src/backend/executor/execInterpExpr.c | 2 +- src/backend/executor/execMain.c | 2 + src/backend/executor/execTuples.c | 13 ++++ src/backend/lib/llvmjit.c | 99 +++++++++++++++++++++++++- src/backend/utils/resowner/resowner.c | 32 +++++++++ src/include/executor/execExpr.h | 4 +- src/include/executor/tuptable.h | 1 + src/include/lib/llvmjit.h | 9 +++ src/include/nodes/execnodes.h | 5 +- src/include/utils/resowner_private.h | 7 ++ 14 files changed, 201 insertions(+), 20 deletions(-) diff --git a/configure b/configure index 466b712f99..2049001ab4 100755 --- a/configure +++ b/configure @@ -6227,7 +6227,7 @@ done -L*) LDFLAGS="$LDFLAGS $pgac_option";; esac done - for pgac_option in `$LLVM_CONFIG --libs --system-libs engine debuginfodwarf perfjitevents`; do + for pgac_option in `$LLVM_CONFIG --libs --system-libs engine debuginfodwarf orcjit passes perfjitevents`; do case $pgac_option in -l*) LLVM_LIBS="$LLVM_LIBS $pgac_option";; esac diff --git a/configure.in b/configure.in index cc86756849..54d7643f7b 100644 --- a/configure.in +++ b/configure.in @@ -863,7 +863,7 @@ if test "$with_llvm" = yes ; then -L*) LDFLAGS="$LDFLAGS $pgac_option";; esac done - for pgac_option in `$LLVM_CONFIG --libs --system-libs engine debuginfodwarf perfjitevents`; do + for pgac_option in `$LLVM_CONFIG --libs --system-libs engine debuginfodwarf orcjit passes perfjitevents`; do case $pgac_option in -l*) LLVM_LIBS="$LLVM_LIBS $pgac_option";; esac diff --git a/src/backend/executor/execCompileExpr.c b/src/backend/executor/execCompileExpr.c index ba0d11d2c7..3477a0f088 100644 --- a/src/backend/executor/execCompileExpr.c +++ b/src/backend/executor/execCompileExpr.c @@ -185,7 +185,7 @@ create_EvalArrayRefCheckSubscript(LLVMModuleRef mod) } void -ExecInstantiateCompiledExpr(ExprState *state) +ExecInstantiateCompiledExpr(ExprState *state, PlanState *parent) { ExprEvalStep *op; int i = 0; @@ -277,8 +277,12 @@ ExecInstantiateCompiledExpr(ExprState *state) builder = LLVMCreateBuilder(); /* Create the signature and function */ - mod = LLVMModuleCreateWithName(funcname); + mod = LLVMModuleCreateWithName("frak"); + LLVMSetTarget(mod, "x86_64-unknown-linux-gnu"); + +#if 0 LLVMAddModule(llvm_engine, mod); +#endif { LLVMTypeRef param_types[] = { @@ -288,7 +292,8 @@ ExecInstantiateCompiledExpr(ExprState *state) eval_sig = LLVMFunctionType(TypeSizeT, param_types, lengthof(param_types), 0); } eval_fn = LLVMAddFunction(mod, funcname, eval_sig); - LLVMSetLinkage(eval_fn, LLVMInternalLinkage); + LLVMSetLinkage(eval_fn, LLVMExternalLinkage); + LLVMSetVisibility(eval_fn, LLVMDefaultVisibility); entry = LLVMAppendBasicBlock(eval_fn, "entry"); /* build referenced functions */ @@ -2327,12 +2332,24 @@ ExecInstantiateCompiledExpr(ExprState *state) } } +#if 0 llvm_add_module(mod, funcname); - state->cb = (ExecEvalExprCB) llvm_get_function(funcname); + state->cb = (ExprStateEvalFunc) llvm_get_function(funcname); LLVMDisposeBuilder(builder); llvm_dispose_module(mod, funcname); +#else + { + int handle; + state->cb = (ExprStateEvalFunc) llvm_get_function2(mod, funcname, &handle); + if (parent && parent->state) + { + parent->state->es_handles = lappend_int(parent->state->es_handles, handle); + } + LLVMDisposeBuilder(builder); + } +#endif } #endif diff --git a/src/backend/executor/execExpr.c b/src/backend/executor/execExpr.c index d6e5337bf2..a043c8d06e 100644 --- a/src/backend/executor/execExpr.c +++ b/src/backend/executor/execExpr.c @@ -78,9 +78,9 @@ /* * Support for building execution state. */ -static void ExecInstantiateExpr(ExprState *state); -static void ExecInitExprRec(Expr *node, PlanState *parent, ExprState *state, - Datum *resv, bool *resnull); +static void ExecInstantiateExpr(ExprState *state, PlanState *parent); +static void ExecInitExprRec(Expr *node, PlanState *parent, + ExprState *state, Datum *resv, bool *resnull); static void ExprEvalPushStep(ExprState *es, ExprEvalStep *s); static void ExecInitFunc(ExprEvalStep *scratch, Expr *node, List *args, Oid funcid, Oid inputcollid, PlanState *parent, @@ -144,7 +144,7 @@ ExecInitExpr(Expr *node, PlanState *parent) scratch.opcode = EEO_DONE; ExprEvalPushStep(state, &scratch); - ExecInstantiateExpr(state); + ExecInstantiateExpr(state, parent); return state; } @@ -215,7 +215,7 @@ ExecInitQual(List *qual, PlanState *parent) scratch.opcode = EEO_DONE; ExprEvalPushStep(state, &scratch); - ExecInstantiateExpr(state); + ExecInstantiateExpr(state, parent); return state; } @@ -370,7 +370,7 @@ ExecBuildProjectionInfo(List *targetList, scratch.opcode = EEO_DONE; ExprEvalPushStep(state, &scratch); - ExecInstantiateExpr(state); + ExecInstantiateExpr(state, parent); return projInfo; } @@ -521,15 +521,15 @@ ExecCheck(ExprState *state, ExprContext *econtext) * Therefore this should be used instead of ExecInstantiateInterpretedExpr(). */ static void -ExecInstantiateExpr(ExprState *state) +ExecInstantiateExpr(ExprState *state, PlanState *parent) { #ifdef USE_LLVM - ExecInstantiateCompiledExpr(state); + ExecInstantiateCompiledExpr(state, parent); if (!state->cb) #endif { - ExecInstantiateInterpretedExpr(state); + ExecInstantiateInterpretedExpr(state, parent); } } diff --git a/src/backend/executor/execInterpExpr.c b/src/backend/executor/execInterpExpr.c index 21388f4086..d1d714bf85 100644 --- a/src/backend/executor/execInterpExpr.c +++ b/src/backend/executor/execInterpExpr.c @@ -125,7 +125,7 @@ static Datum ExecJustAssignScanVar(ExprState *state, ExprContext *econtext, bool * Prepare ExprState for interpreted execution. */ void -ExecInstantiateInterpretedExpr(ExprState *state) +ExecInstantiateInterpretedExpr(ExprState *state, PlanState *parent) { ExecPrepareInterp(); diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c index ede675fa61..f19b9b26a7 100644 --- a/src/backend/executor/execMain.c +++ b/src/backend/executor/execMain.c @@ -1519,6 +1519,8 @@ ExecEndPlan(PlanState *planstate, EState *estate) */ ExecResetTupleTable(estate->es_tupleTable, false); + ExecResetExpressions(estate->es_handles); + /* * close the result relation(s) if any, but hold locks until xact commit. */ diff --git a/src/backend/executor/execTuples.c b/src/backend/executor/execTuples.c index f002ee2561..e6d8ab86f5 100644 --- a/src/backend/executor/execTuples.c +++ b/src/backend/executor/execTuples.c @@ -186,6 +186,19 @@ ExecResetTupleTable(List *tupleTable, /* tuple table */ list_free(tupleTable); } +#include "lib/llvmjit.h" + +void +ExecResetExpressions(List *exprTable) +{ + ListCell *lc; + + foreach(lc, exprTable) + { + llvm_release_handle(CurrentResourceOwner, lfirst_int(lc)); + } +} + /* -------------------------------- * MakeSingleTupleTableSlot * diff --git a/src/backend/lib/llvmjit.c b/src/backend/lib/llvmjit.c index a70fe8a5eb..801598efc0 100644 --- a/src/backend/lib/llvmjit.c +++ b/src/backend/lib/llvmjit.c @@ -8,6 +8,9 @@ #include "lib/llvmjit.h" +#include "utils/memutils.h" +#include "utils/resowner_private.h" + #include #include #include @@ -19,8 +22,10 @@ #include #include #include +#include +#include +#include -#include "utils/memutils.h" /* GUCs */ bool jit_log_ir = 0; @@ -39,6 +44,11 @@ LLVMTypeRef StructItemPointerData; LLVMTypeRef StructBlockId; LLVMTypeRef StructTupleTableSlot; +static char *llvm_triple = NULL; +static LLVMTargetRef llvm_targetref; +static LLVMTargetMachineRef llvm_targetmachine; +static LLVMOrcJITStackRef llvm_orc; + static void shutdown_perf(void) { @@ -63,6 +73,32 @@ llvm_initialize(void) LLVMInitializeNativeAsmPrinter(); LLVMInitializeNativeAsmParser(); + llvm_triple = LLVMGetDefaultTargetTriple(); + + if (LLVMGetTargetFromTriple(llvm_triple, &llvm_targetref, &error) != 0) + { + fprintf(stderr, "failed to create targetref: %s\n", error); + abort(); + } + + llvm_targetmachine = + LLVMCreateTargetMachine(llvm_targetref, llvm_triple, NULL, NULL, + LLVMCodeGenLevelAggressive, + LLVMRelocDefault, + LLVMCodeModelJITDefault); + + { + LLVMPassManagerRef pm = LLVMCreatePassManager(); + LLVMPassManagerBuilderRef pmb = LLVMPassManagerBuilderCreate(); + LLVMPassManagerBuilderSetOptLevel(pmb, 3); + + LLVMPassManagerBuilderPopulateModulePassManager(pmb, pm); + + LLVMAddAnalysisPasses(llvm_targetmachine, pm); + } + + llvm_orc = LLVMOrcCreateInstance(llvm_targetmachine); + llvm_mod = LLVMModuleCreateWithName("top_module"); LLVMSetTarget(llvm_mod, "x86_64-unknown-linux-gnu"); @@ -224,4 +260,65 @@ llvm_dispose_module(LLVMModuleRef mod, const char *funcname) } } +#include "executor/tuptable.h" +static uint64_t +resolver(const char *name, void *ctx) +{ + return (uint64_t) LLVMSearchForAddressOfSymbol(name); + if (strcmp(name, "slot_getsomeattrs") == 0) + return (uint64_t) slot_getsomeattrs; + //elog(ERROR, "resolvin %s", name); + return 0; +} + +void * +llvm_get_function2(LLVMModuleRef mod, const char *funcname, int *handle) +{ + void *addr; + char *mangled; + + if (jit_log_ir) + { + LLVMDumpModule(mod); + } + + + LLVMOrcGetMangledSymbol(llvm_orc, &mangled, funcname); + + *handle = + LLVMOrcAddEagerlyCompiledIR(llvm_orc, mod, + resolver, NULL); + + ResourceOwnerEnlargeJIT(CurrentResourceOwner); + ResourceOwnerRememberJIT(CurrentResourceOwner, *handle); + + addr = (void *) LLVMOrcGetSymbolAddress(llvm_orc, mangled); + + if (!addr) + elog(ERROR, "failed to JIT: %s %s", funcname, mangled); + + return addr; +} + #endif /* USE_LLVM */ + + +#ifdef USE_LLVM + +extern void +llvm_release_handle(ResourceOwner resowner, Datum handle) +{ + LLVMOrcRemoveModule(llvm_orc, handle); + + ResourceOwnerForgetJIT(resowner, handle); + +} + +#else + +extern void +llvm_release_handle(ResourceOwner resowner, Datum handle) +{ +} + +#endif diff --git a/src/backend/utils/resowner/resowner.c b/src/backend/utils/resowner/resowner.c index af46d78125..8f51b21ec6 100644 --- a/src/backend/utils/resowner/resowner.c +++ b/src/backend/utils/resowner/resowner.c @@ -27,6 +27,7 @@ #include "utils/rel.h" #include "utils/resowner_private.h" #include "utils/snapmgr.h" +#include "lib/llvmjit.h" /* @@ -124,6 +125,7 @@ typedef struct ResourceOwnerData ResourceArray snapshotarr; /* snapshot references */ ResourceArray filearr; /* open temporary files */ ResourceArray dsmarr; /* dynamic shmem segments */ + ResourceArray jitarr; /* JIT handles */ /* We can remember up to MAX_RESOWNER_LOCKS references to local locks. */ int nlocks; /* number of owned locks */ @@ -437,6 +439,7 @@ ResourceOwnerCreate(ResourceOwner parent, const char *name) ResourceArrayInit(&(owner->snapshotarr), PointerGetDatum(NULL)); ResourceArrayInit(&(owner->filearr), FileGetDatum(-1)); ResourceArrayInit(&(owner->dsmarr), PointerGetDatum(NULL)); + ResourceArrayInit(&(owner->jitarr), Int32GetDatum(-1)); return owner; } @@ -552,6 +555,13 @@ ResourceOwnerReleaseInternal(ResourceOwner owner, PrintDSMLeakWarning(res); dsm_detach(res); } + + /* Ditto for dynamic shared memory segments */ + while (ResourceArrayGetAny(&(owner->jitarr), &foundres)) + { + llvm_release_handle(owner, foundres); + } + } else if (phase == RESOURCE_RELEASE_LOCKS) { @@ -699,6 +709,7 @@ ResourceOwnerDelete(ResourceOwner owner) Assert(owner->snapshotarr.nitems == 0); Assert(owner->filearr.nitems == 0); Assert(owner->dsmarr.nitems == 0); + Assert(owner->jitarr.nitems == 0); Assert(owner->nlocks == 0 || owner->nlocks == MAX_RESOWNER_LOCKS + 1); /* @@ -725,6 +736,7 @@ ResourceOwnerDelete(ResourceOwner owner) ResourceArrayFree(&(owner->snapshotarr)); ResourceArrayFree(&(owner->filearr)); ResourceArrayFree(&(owner->dsmarr)); + ResourceArrayFree(&(owner->jitarr)); pfree(owner); } @@ -1267,3 +1279,23 @@ PrintDSMLeakWarning(dsm_segment *seg) elog(WARNING, "dynamic shared memory leak: segment %u still referenced", dsm_segment_handle(seg)); } + +void +ResourceOwnerEnlargeJIT(ResourceOwner owner) +{ + ResourceArrayEnlarge(&(owner->jitarr)); +} + +void +ResourceOwnerRememberJIT(ResourceOwner owner, Datum handle) +{ + ResourceArrayAdd(&(owner->jitarr), handle); +} + +void +ResourceOwnerForgetJIT(ResourceOwner owner, Datum handle) +{ + if (!ResourceArrayRemove(&(owner->jitarr), handle)) + elog(ERROR, "jit %lu is not owned by resource owner %s", + handle, owner->name); +} diff --git a/src/include/executor/execExpr.h b/src/include/executor/execExpr.h index 62adc5bfdf..7843d77e6f 100644 --- a/src/include/executor/execExpr.h +++ b/src/include/executor/execExpr.h @@ -417,8 +417,8 @@ typedef struct ArrayRefState bool prevnull; } ArrayRefState; -extern void ExecInstantiateInterpretedExpr(ExprState *state); -extern void ExecInstantiateCompiledExpr(ExprState *state); +extern void ExecInstantiateInterpretedExpr(ExprState *state, PlanState *parent); +extern void ExecInstantiateCompiledExpr(ExprState *state, PlanState *parent); extern ExprEvalOp ExecEvalStepOp(ExprState *state, ExprEvalStep *op); diff --git a/src/include/executor/tuptable.h b/src/include/executor/tuptable.h index 32489ef9bd..e1a2a2d1a3 100644 --- a/src/include/executor/tuptable.h +++ b/src/include/executor/tuptable.h @@ -142,6 +142,7 @@ typedef struct TupleTableSlot extern TupleTableSlot *MakeTupleTableSlot(void); extern TupleTableSlot *ExecAllocTableSlot(List **tupleTable); extern void ExecResetTupleTable(List *tupleTable, bool shouldFree); +extern void ExecResetExpressions(List *exprTable); extern TupleTableSlot *MakeSingleTupleTableSlot(TupleDesc tupdesc); extern void ExecDropSingleTupleTableSlot(TupleTableSlot *slot); extern void ExecSetSlotDescriptor(TupleTableSlot *slot, TupleDesc tupdesc); diff --git a/src/include/lib/llvmjit.h b/src/include/lib/llvmjit.h index 678320485a..79ce569390 100644 --- a/src/include/lib/llvmjit.h +++ b/src/include/lib/llvmjit.h @@ -1,5 +1,8 @@ #ifndef LLVMJIT_H #define LLVMJIT_H + +#include "utils/resowner.h" + #ifdef USE_LLVM #undef PM @@ -29,8 +32,14 @@ extern void llvm_add_module(LLVMModuleRef mod, const char *funcname); extern void * llvm_get_function(const char *funcname); extern void llvm_dispose_module(LLVMModuleRef mod, const char *funcname); +extern void * llvm_get_function2(LLVMModuleRef mod, const char *funcname, int *handle); + + extern void llvm_perf_support(LLVMExecutionEngineRef EE); extern void llvm_shutdown_perf_support(LLVMExecutionEngineRef EE); #endif /* USE_LLVM */ + +extern void llvm_release_handle(ResourceOwner resowner, Datum handle); + #endif /* LLVMJIT_H */ diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h index 8d30382746..b08ba73749 100644 --- a/src/include/nodes/execnodes.h +++ b/src/include/nodes/execnodes.h @@ -445,7 +445,10 @@ typedef struct EState bool *es_epqScanDone; /* true if EPQ tuple has been fetched */ /* The per-query shared memory area to use for parallel execution. */ - struct dsa_area *es_query_dsa; + struct dsa_area *es_query_dsa; + + List *es_handles; + } EState; diff --git a/src/include/utils/resowner_private.h b/src/include/utils/resowner_private.h index 411d08ff0b..e45d3b0aa9 100644 --- a/src/include/utils/resowner_private.h +++ b/src/include/utils/resowner_private.h @@ -88,4 +88,11 @@ extern void ResourceOwnerRememberDSM(ResourceOwner owner, extern void ResourceOwnerForgetDSM(ResourceOwner owner, dsm_segment *); +/* support for JITed functions */ +extern void ResourceOwnerEnlargeJIT(ResourceOwner owner); +extern void ResourceOwnerRememberJIT(ResourceOwner owner, + Datum handle); +extern void ResourceOwnerForgetJIT(ResourceOwner owner, + Datum handle); + #endif /* RESOWNER_PRIVATE_H */ -- 2.39.5