]> granicus.if.org Git - postgresql/commitdiff
Basic planner and executor integration for JIT.
authorAndres Freund <andres@anarazel.de>
Thu, 22 Mar 2018 18:45:07 +0000 (11:45 -0700)
committerAndres Freund <andres@anarazel.de>
Thu, 22 Mar 2018 18:51:58 +0000 (11:51 -0700)
This adds simple cost based plan time decision about whether JIT
should be performed. jit_above_cost, jit_optimize_above_cost are
compared with the total cost of a plan, and if the cost is above them
JIT is performed / optimization is performed respectively.

For that PlannedStmt and EState have a jitFlags (es_jit_flags) field
that stores information about what JIT operations should be performed.

EState now also has a new es_jit field, which can store a
JitContext. When there are no errors the context is released in
standard_ExecutorEnd().

It is likely that the default values for jit_[optimize_]above_cost
will need to be adapted further, but in my test these values seem to
work reasonably.

Author: Andres Freund, with feedback by Peter Eisentraut
Discussion: https://postgr.es/m/20170901064131.tazjxwus3k2w3ybh@alap3.anarazel.de

13 files changed:
src/backend/executor/execMain.c
src/backend/executor/execParallel.c
src/backend/executor/execUtils.c
src/backend/jit/jit.c
src/backend/nodes/copyfuncs.c
src/backend/nodes/outfuncs.c
src/backend/nodes/readfuncs.c
src/backend/optimizer/plan/planner.c
src/backend/utils/misc/guc.c
src/backend/utils/misc/postgresql.conf.sample
src/include/jit/jit.h
src/include/nodes/execnodes.h
src/include/nodes/plannodes.h

index 91ba939bdcade9e58db4f246abdcc215b89da908..890067757c0c8f71de5b7511e0ecf17155481847 100644 (file)
@@ -48,6 +48,7 @@
 #include "commands/trigger.h"
 #include "executor/execdebug.h"
 #include "foreign/fdwapi.h"
+#include "jit/jit.h"
 #include "mb/pg_wchar.h"
 #include "miscadmin.h"
 #include "optimizer/clauses.h"
@@ -249,6 +250,9 @@ standard_ExecutorStart(QueryDesc *queryDesc, int eflags)
        estate->es_top_eflags = eflags;
        estate->es_instrument = queryDesc->instrument_options;
 
+       if (queryDesc->plannedstmt)
+               estate->es_jit_flags = queryDesc->plannedstmt->jitFlags;
+
        /*
         * Set up an AFTER-trigger statement context, unless told not to, or
         * unless it's EXPLAIN-only mode (when ExecutorFinish won't be called).
@@ -496,6 +500,10 @@ standard_ExecutorEnd(QueryDesc *queryDesc)
        UnregisterSnapshot(estate->es_snapshot);
        UnregisterSnapshot(estate->es_crosscheck_snapshot);
 
+       /* release JIT context, if allocated */
+       if (estate->es_jit)
+               jit_release_context(estate->es_jit);
+
        /*
         * Must switch out of context before destroying it
         */
index 14b0b89463cd67fb0a21147301a299bb58620806..52f1a96db5faf24c7c954a9f7182a8929c2e0511 100644 (file)
@@ -73,6 +73,7 @@ typedef struct FixedParallelExecutorState
        int64           tuples_needed;  /* tuple bound, see ExecSetTupleBound */
        dsa_pointer param_exec;
        int                     eflags;
+       int                     jit_flags;
 } FixedParallelExecutorState;
 
 /*
@@ -680,6 +681,7 @@ ExecInitParallelPlan(PlanState *planstate, EState *estate,
        fpes->tuples_needed = tuples_needed;
        fpes->param_exec = InvalidDsaPointer;
        fpes->eflags = estate->es_top_eflags;
+       fpes->jit_flags = estate->es_jit_flags;
        shm_toc_insert(pcxt->toc, PARALLEL_KEY_EXECUTOR_FIXED, fpes);
 
        /* Store query string */
@@ -1287,6 +1289,7 @@ ParallelQueryMain(dsm_segment *seg, shm_toc *toc)
        area = dsa_attach_in_place(area_space, seg);
 
        /* Start up the executor */
+       queryDesc->plannedstmt->jitFlags = fpes->jit_flags;
        ExecutorStart(queryDesc, fpes->eflags);
 
        /* Special executor initialization steps for parallel workers */
index a8ae37ebc80c2af75f3e255e67d77737ae3cd1ed..14b07b5d449ce0d2f3975d2b85ecf61bd45d3545 100644 (file)
@@ -158,6 +158,9 @@ CreateExecutorState(void)
 
        estate->es_use_parallel_mode = false;
 
+       estate->es_jit_flags = 0;
+       estate->es_jit = NULL;
+
        /*
         * Return the executor state structure
         */
index c17df1c985e1eeafb26ed7f7c2eabfea5854f190..1d74ec8c91a3c21cd94998934a19baa011b3dcfc 100644 (file)
@@ -36,6 +36,8 @@ char     *jit_provider = "llvmjit";
 bool           jit_debugging_support = false;
 bool           jit_dump_bitcode = false;
 bool           jit_profiling_support = false;
+double         jit_above_cost = 100000;
+double         jit_optimize_above_cost = 500000;
 
 static JitProviderCallbacks provider;
 static bool provider_successfully_loaded = false;
index 3ad4da64aafd8ce4ada56652ddf2009dfb826968..c7293a60d7863abd4ea05b05729610d8409ae6ee 100644 (file)
@@ -87,6 +87,7 @@ _copyPlannedStmt(const PlannedStmt *from)
        COPY_SCALAR_FIELD(transientPlan);
        COPY_SCALAR_FIELD(dependsOnRole);
        COPY_SCALAR_FIELD(parallelModeNeeded);
+       COPY_SCALAR_FIELD(jitFlags);
        COPY_NODE_FIELD(planTree);
        COPY_NODE_FIELD(rtable);
        COPY_NODE_FIELD(resultRelations);
index fd8089195484f3536cc56a479ac698e246bac7c3..f61ae03ac505b475bcb7ee54941bf880bf289607 100644 (file)
@@ -272,6 +272,7 @@ _outPlannedStmt(StringInfo str, const PlannedStmt *node)
        WRITE_BOOL_FIELD(transientPlan);
        WRITE_BOOL_FIELD(dependsOnRole);
        WRITE_BOOL_FIELD(parallelModeNeeded);
+       WRITE_BOOL_FIELD(jitFlags);
        WRITE_NODE_FIELD(planTree);
        WRITE_NODE_FIELD(rtable);
        WRITE_NODE_FIELD(resultRelations);
index 068db353d70c590dfabae793cf15b5061e804580..fd4586e73d52d3a6fe865adf0dc6b95129e7270d 100644 (file)
@@ -1475,6 +1475,7 @@ _readPlannedStmt(void)
        READ_BOOL_FIELD(transientPlan);
        READ_BOOL_FIELD(dependsOnRole);
        READ_BOOL_FIELD(parallelModeNeeded);
+       READ_BOOL_FIELD(jitFlags);
        READ_NODE_FIELD(planTree);
        READ_NODE_FIELD(rtable);
        READ_NODE_FIELD(resultRelations);
index 54f2da70cb1c49b70f32e81a343a69a736221547..3668db4e09ee87cd96454a741a5eb69d2d922662 100644 (file)
@@ -29,6 +29,7 @@
 #include "executor/nodeAgg.h"
 #include "foreign/fdwapi.h"
 #include "miscadmin.h"
+#include "jit/jit.h"
 #include "lib/bipartite_match.h"
 #include "lib/knapsack.h"
 #include "nodes/makefuncs.h"
@@ -531,6 +532,20 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
        result->stmt_location = parse->stmt_location;
        result->stmt_len = parse->stmt_len;
 
+       result->jitFlags = PGJIT_NONE;
+       if (jit_enabled && jit_above_cost >= 0 &&
+               top_plan->total_cost > jit_above_cost)
+       {
+               result->jitFlags |= PGJIT_PERFORM;
+
+               /*
+                * Decide how much effort should be put into generating better code.
+                */
+               if (jit_optimize_above_cost >= 0 &&
+                       top_plan->total_cost > jit_optimize_above_cost)
+                       result->jitFlags |= PGJIT_OPT3;
+       }
+
        return result;
 }
 
index 8e09e083069402d66b73b91ee3edff11e673a7a9..978c8757c64bc805f65f0cc94eeb39c020529801 100644 (file)
@@ -3075,6 +3075,26 @@ static struct config_real ConfigureNamesReal[] =
                NULL, NULL, NULL
        },
 
+       {
+               {"jit_above_cost", PGC_USERSET, QUERY_TUNING_COST,
+                       gettext_noop("Perform JIT compilation if query is more expensive."),
+                       gettext_noop("-1 disables JIT compilation.")
+               },
+               &jit_above_cost,
+               100000, -1, DBL_MAX,
+               NULL, NULL, NULL
+       },
+
+       {
+               {"jit_optimize_above_cost", PGC_USERSET, QUERY_TUNING_COST,
+                       gettext_noop("Optimize JITed functions if query is more expensive."),
+                       gettext_noop("-1 disables optimization.")
+               },
+               &jit_optimize_above_cost,
+               500000, -1, DBL_MAX,
+               NULL, NULL, NULL
+       },
+
        {
                {"cursor_tuple_fraction", PGC_USERSET, QUERY_TUNING_OTHER,
                        gettext_noop("Sets the planner's estimate of the fraction of "
index 1e0f411c4024fc2035aea48ae59ace67142af2b1..4b692dc3e5d1d992803f2166d7bc78816eef2d73 100644 (file)
 #cpu_operator_cost = 0.0025            # same scale as above
 #parallel_tuple_cost = 0.1             # same scale as above
 #parallel_setup_cost = 1000.0  # same scale as above
+
+#jit_above_cost = 100000               # perform JIT compilation if available
+                                       # and query more expensive, -1 disables
+#jit_optimize_above_cost = 500000      # optimize JITed functions if query is
+                                       # more expensive, -1 disables
+
 #min_parallel_table_scan_size = 8MB
 #min_parallel_index_scan_size = 512kB
 #effective_cache_size = 4GB
index 2c21c2d27b7a5fdb8eb870378ece30a73e70ccde..dac8d593eb08cdf2caefc3d3dc9f47969ad4fe94 100644 (file)
@@ -61,6 +61,8 @@ extern char *jit_provider;
 extern bool jit_debugging_support;
 extern bool jit_dump_bitcode;
 extern bool jit_profiling_support;
+extern double jit_above_cost;
+extern double jit_optimize_above_cost;
 
 
 extern void jit_reset_after_error(void);
index d9e591802fefafa8291d2119088b540fc34ba8ae..7b752560c60fdbad4fabdda6eed3593387d9f1d8 100644 (file)
@@ -528,6 +528,14 @@ typedef struct EState
 
        /* The per-query shared memory area to use for parallel execution. */
        struct dsa_area *es_query_dsa;
+
+       /*
+        * JIT information. es_jit_flags indicates whether JIT should be performed
+        * and with which options.  es_jit is created on-demand when JITing is
+        * performed.
+        */
+       int                     es_jit_flags;
+       struct JitContext *es_jit;
 } EState;
 
 
index f2e19eae68fceca81e12600e8c914d62eceb880e..c922216b7d152ecb2ef0f6771c2ea9e226bd9209 100644 (file)
@@ -58,6 +58,8 @@ typedef struct PlannedStmt
 
        bool            parallelModeNeeded; /* parallel mode required to execute? */
 
+       int                     jitFlags;               /* which forms of JIT should be performed */
+
        struct Plan *planTree;          /* tree of Plan nodes */
 
        List       *rtable;                     /* list of RangeTblEntry nodes */