Commit cc415a56 authored by Andres Freund's avatar Andres Freund

Basic planner and executor integration for JIT.

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
parent 7ec0d80c
......@@ -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
*/
......
......@@ -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 */
......
......@@ -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
*/
......
......@@ -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;
......
......@@ -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);
......
......@@ -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);
......
......@@ -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);
......
......@@ -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;
}
......
......@@ -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 "
......
......@@ -318,6 +318,12 @@
#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
......
......@@ -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);
......
......@@ -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;
......
......@@ -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 */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment