diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c
index 16a80a0..8959a2b 100644
--- a/src/backend/commands/explain.c
+++ b/src/backend/commands/explain.c
@@ -564,7 +564,7 @@ ExplainOnePlan(PlannedStmt *plannedstmt, IntoClause *into, ExplainState *es,
 	 * at a later stage.
 	 */
 	if (queryDesc->estate->es_jit && es->costs &&
-		queryDesc->estate->es_jit->created_functions > 0)
+		queryDesc->estate->es_jit->jit_instr.created_functions > 0)
 		ExplainPrintJIT(es, queryDesc);
 
 	/*
@@ -705,28 +705,28 @@ ExplainPrintJIT(ExplainState *es, QueryDesc *queryDesc)
 		appendStringInfo(es->str, "JIT:\n");
 	}
 
-	ExplainPropertyInteger("Functions", NULL, jc->created_functions, es);
+	ExplainPropertyInteger("Functions", NULL, jc->jit_instr.created_functions, es);
 	if (es->analyze && es->timing)
 		ExplainPropertyFloat("Generation Time", "ms",
-							 1000.0 * INSTR_TIME_GET_DOUBLE(jc->generation_counter),
+							 1000.0 * INSTR_TIME_GET_DOUBLE(jc->jit_instr.generation_counter),
 							 3, es);
 
 	ExplainPropertyBool("Inlining", jc->flags & PGJIT_INLINE, es);
 
 	if (es->analyze && es->timing)
 		ExplainPropertyFloat("Inlining Time", "ms",
-							 1000.0 * INSTR_TIME_GET_DOUBLE(jc->inlining_counter),
+							 1000.0 * INSTR_TIME_GET_DOUBLE(jc->jit_instr.inlining_counter),
 							 3, es);
 
 	ExplainPropertyBool("Optimization", jc->flags & PGJIT_OPT3, es);
 	if (es->analyze && es->timing)
 		ExplainPropertyFloat("Optimization Time", "ms",
-							 1000.0 * INSTR_TIME_GET_DOUBLE(jc->optimization_counter),
+							 1000.0 * INSTR_TIME_GET_DOUBLE(jc->jit_instr.optimization_counter),
 							 3, es);
 
 	if (es->analyze && es->timing)
 		ExplainPropertyFloat("Emission Time", "ms",
-							 1000.0 * INSTR_TIME_GET_DOUBLE(jc->emission_counter),
+							 1000.0 * INSTR_TIME_GET_DOUBLE(jc->jit_instr.emission_counter),
 							 3, es);
 
 	ExplainCloseGroup("JIT", "JIT", true, es);
diff --git a/src/backend/executor/execParallel.c b/src/backend/executor/execParallel.c
index ee0f07a..1d8182b 100644
--- a/src/backend/executor/execParallel.c
+++ b/src/backend/executor/execParallel.c
@@ -37,6 +37,7 @@
 #include "executor/nodeSeqscan.h"
 #include "executor/nodeSort.h"
 #include "executor/tqueue.h"
+#include "jit/jit.h"
 #include "nodes/nodeFuncs.h"
 #include "optimizer/planmain.h"
 #include "optimizer/planner.h"
@@ -62,6 +63,7 @@
 #define PARALLEL_KEY_INSTRUMENTATION	UINT64CONST(0xE000000000000006)
 #define PARALLEL_KEY_DSA				UINT64CONST(0xE000000000000007)
 #define PARALLEL_KEY_QUERY_TEXT		UINT64CONST(0xE000000000000008)
+#define PARALLEL_KEY_JIT_INSTRUMENTATION UINT64CONST(0xE000000000000009)
 
 #define PARALLEL_TUPLE_QUEUE_SIZE		65536
 
@@ -105,6 +107,18 @@ struct SharedExecutorInstrumentation
 	(AssertVariableIsOfTypeMacro(sei, SharedExecutorInstrumentation *), \
 	 (Instrumentation *) (((char *) sei) + sei->instrument_offset))
 
+/*
+ * DSM structure for accumulating jit instrumentation of all workers.
+ *
+ * num_workers: Number of workers.
+ */
+struct SharedJitInstrumentation
+{
+	int			num_workers;
+	JitInstrumentation jit_instr[FLEXIBLE_ARRAY_MEMBER];
+	/* array of JitInstrumentation objects * num_workers follows */
+};
+
 /* Context object for ExecParallelEstimate. */
 typedef struct ExecParallelEstimateContext
 {
@@ -573,9 +587,11 @@ ExecInitParallelPlan(PlanState *planstate, EState *estate,
 	char	   *paramlistinfo_space;
 	BufferUsage *bufusage_space;
 	SharedExecutorInstrumentation *instrumentation = NULL;
+	SharedJitInstrumentation *jit_instrumentation = NULL;
 	int			pstmt_len;
 	int			paramlistinfo_len;
 	int			instrumentation_len = 0;
+	int			jit_instrumentation_len;
 	int			instrument_offset = 0;
 	Size		dsa_minsize = dsa_minimum_size();
 	char	   *query_string;
@@ -661,6 +677,17 @@ ExecInitParallelPlan(PlanState *planstate, EState *estate,
 		shm_toc_estimate_keys(&pcxt->estimator, 1);
 	}
 
+	/* Estimate space for JIT instrumentation, if required. */
+	if (estate->es_jit_flags != PGJIT_NONE)
+	{
+		jit_instrumentation_len =
+			offsetof(SharedJitInstrumentation, jit_instr) +
+			sizeof(JitInstrumentation) * nworkers;
+		jit_instrumentation_len = MAXALIGN(jit_instrumentation_len);
+		shm_toc_estimate_chunk(&pcxt->estimator, jit_instrumentation_len);
+		shm_toc_estimate_keys(&pcxt->estimator, 1);
+	}
+
 	/* Estimate space for DSA area. */
 	shm_toc_estimate_chunk(&pcxt->estimator, dsa_minsize);
 	shm_toc_estimate_keys(&pcxt->estimator, 1);
@@ -734,6 +761,17 @@ ExecInitParallelPlan(PlanState *planstate, EState *estate,
 		pei->instrumentation = instrumentation;
 	}
 
+	if (estate->es_jit_flags != PGJIT_NONE)
+	{
+		jit_instrumentation = shm_toc_allocate(pcxt->toc, jit_instrumentation_len);
+		jit_instrumentation->num_workers = nworkers;
+		memset(jit_instrumentation->jit_instr, 0,
+			   sizeof(JitInstrumentation) * nworkers);
+		shm_toc_insert(pcxt->toc, PARALLEL_KEY_JIT_INSTRUMENTATION,
+					   jit_instrumentation);
+		pei->jit_instrumentation = jit_instrumentation;
+	}
+
 	/*
 	 * Create a DSA area that can be used by the leader and all workers.
 	 * (However, if we failed to create a DSM and are using private memory
@@ -990,6 +1028,35 @@ ExecParallelRetrieveInstrumentation(PlanState *planstate,
 }
 
 /*
+ * Add up the workers' JIT instrumentation from dynamic shared memory.
+ */
+static void
+ExecParallelRetrieveJitInstrumentation(PlanState *planstate,
+									   SharedJitInstrumentation *shared_jit)
+{
+	int			n;
+	JitContext *jit = planstate->state->es_jit;
+
+	/* If the leader hasn't yet created a jit context, allocate one now. */
+	if (!jit)
+	{
+		planstate->state->es_jit = jit =
+			jit_create_context(planstate->state->es_jit_flags);
+	}
+
+	/*
+	 * It may happen that we couldn't create a context, possibly because
+	 * the jit provider could not be loaded. In that case, don't bother about
+	 * retrieving from the workers.
+	 */
+	if (jit != NULL)
+	{
+		for (n = 0; n < shared_jit->num_workers; ++n)
+			InstrJitAgg(&jit->jit_instr, &shared_jit->jit_instr[n]);
+	}
+}
+
+/*
  * Finish parallel execution.  We wait for parallel workers to finish, and
  * accumulate their buffer usage.
  */
@@ -1054,6 +1121,11 @@ ExecParallelCleanup(ParallelExecutorInfo *pei)
 		ExecParallelRetrieveInstrumentation(pei->planstate,
 											pei->instrumentation);
 
+	/* Accumulate JIT instrumentation, if any. */
+	if (pei->jit_instrumentation)
+		ExecParallelRetrieveJitInstrumentation(pei->planstate,
+											pei->jit_instrumentation);
+
 	/* Free any serialized parameters. */
 	if (DsaPointerIsValid(pei->param_exec))
 	{
@@ -1260,6 +1332,7 @@ ParallelQueryMain(dsm_segment *seg, shm_toc *toc)
 	DestReceiver *receiver;
 	QueryDesc  *queryDesc;
 	SharedExecutorInstrumentation *instrumentation;
+	SharedJitInstrumentation *jit_instrumentation;
 	int			instrument_options = 0;
 	void	   *area_space;
 	dsa_area   *area;
@@ -1273,6 +1346,8 @@ ParallelQueryMain(dsm_segment *seg, shm_toc *toc)
 	instrumentation = shm_toc_lookup(toc, PARALLEL_KEY_INSTRUMENTATION, true);
 	if (instrumentation != NULL)
 		instrument_options = instrumentation->instrument_options;
+	jit_instrumentation = shm_toc_lookup(toc, PARALLEL_KEY_JIT_INSTRUMENTATION,
+										 true);
 	queryDesc = ExecParallelGetQueryDesc(toc, receiver, instrument_options);
 
 	/* Setting debug_query_string for individual workers */
@@ -1336,6 +1411,14 @@ ParallelQueryMain(dsm_segment *seg, shm_toc *toc)
 		ExecParallelReportInstrumentation(queryDesc->planstate,
 										  instrumentation);
 
+	/* Report JIT instrumentation data if any */
+	if (queryDesc->estate->es_jit && jit_instrumentation != NULL)
+	{
+		Assert(ParallelWorkerNumber < jit_instrumentation->num_workers);
+		jit_instrumentation->jit_instr[ParallelWorkerNumber] =
+			queryDesc->estate->es_jit->jit_instr;
+	}
+
 	/* Must do this after capturing instrumentation. */
 	ExecutorEnd(queryDesc);
 
diff --git a/src/backend/jit/jit.c b/src/backend/jit/jit.c
index c170309..8513d86 100644
--- a/src/backend/jit/jit.c
+++ b/src/backend/jit/jit.c
@@ -182,6 +182,34 @@ jit_compile_expr(struct ExprState *state)
 	return false;
 }
 
+/*
+ * Ask provider to create a JIT context.
+ *
+ * Returns the jit context if successful, NULL if not.
+ */
+JitContext *
+jit_create_context(int flags)
+{
+	/* this also takes !jit_enabled into account */
+	if (provider_init())
+		return provider.create_context(flags);
+	else
+		return NULL;
+}
+
+/* Aggregate JIT instrumentation information */
+void
+InstrJitAgg(JitInstrumentation *dst, JitInstrumentation *add)
+{
+	dst->created_functions = add_size(dst->created_functions,
+									  add->created_functions);
+
+	INSTR_TIME_ADD(dst->generation_counter, add->generation_counter);
+	INSTR_TIME_ADD(dst->inlining_counter, add->inlining_counter);
+	INSTR_TIME_ADD(dst->optimization_counter, add->optimization_counter);
+	INSTR_TIME_ADD(dst->emission_counter, add->emission_counter);
+}
+
 static bool
 file_exists(const char *name)
 {
diff --git a/src/backend/jit/llvm/llvmjit.c b/src/backend/jit/llvm/llvmjit.c
index 640c27f..5a1c67d 100644
--- a/src/backend/jit/llvm/llvmjit.c
+++ b/src/backend/jit/llvm/llvmjit.c
@@ -122,6 +122,7 @@ void
 _PG_jit_provider_init(JitProviderCallbacks *cb)
 {
 	cb->reset_after_error = llvm_reset_after_error;
+	cb->create_context = llvm_create_context;
 	cb->release_context = llvm_release_context;
 	cb->compile_expr = llvm_compile_expr;
 }
@@ -133,7 +134,7 @@ _PG_jit_provider_init(JitProviderCallbacks *cb)
  * the context is explicitly released, or when the lifetime of
  * CurrentResourceOwner ends (usually the end of the current [sub]xact).
  */
-LLVMJitContext *
+JitContext *
 llvm_create_context(int jitFlags)
 {
 	LLVMJitContext *context;
@@ -152,7 +153,7 @@ llvm_create_context(int jitFlags)
 	context->base.resowner = CurrentResourceOwner;
 	ResourceOwnerRememberJIT(CurrentResourceOwner, PointerGetDatum(context));
 
-	return context;
+	return (JitContext *) context;
 }
 
 /*
@@ -224,7 +225,7 @@ llvm_expand_funcname(struct LLVMJitContext *context, const char *basename)
 {
 	Assert(context->module != NULL);
 
-	context->base.created_functions++;
+	context->base.jit_instr.created_functions++;
 
 	/*
 	 * Previously we used dots to separate, but turns out some tools, e.g.
@@ -504,7 +505,7 @@ llvm_compile_module(LLVMJitContext *context)
 		INSTR_TIME_SET_CURRENT(starttime);
 		llvm_inline(context->module);
 		INSTR_TIME_SET_CURRENT(endtime);
-		INSTR_TIME_ACCUM_DIFF(context->base.inlining_counter,
+		INSTR_TIME_ACCUM_DIFF(context->base.jit_instr.inlining_counter,
 							  endtime, starttime);
 	}
 
@@ -524,7 +525,7 @@ llvm_compile_module(LLVMJitContext *context)
 	INSTR_TIME_SET_CURRENT(starttime);
 	llvm_optimize_module(context, context->module);
 	INSTR_TIME_SET_CURRENT(endtime);
-	INSTR_TIME_ACCUM_DIFF(context->base.optimization_counter,
+	INSTR_TIME_ACCUM_DIFF(context->base.jit_instr.optimization_counter,
 						  endtime, starttime);
 
 	if (jit_dump_bitcode)
@@ -575,7 +576,7 @@ llvm_compile_module(LLVMJitContext *context)
 	}
 #endif
 	INSTR_TIME_SET_CURRENT(endtime);
-	INSTR_TIME_ACCUM_DIFF(context->base.emission_counter,
+	INSTR_TIME_ACCUM_DIFF(context->base.jit_instr.emission_counter,
 						  endtime, starttime);
 
 	context->module = NULL;
@@ -596,9 +597,9 @@ llvm_compile_module(LLVMJitContext *context)
 
 	ereport(DEBUG1,
 			(errmsg("time to inline: %.3fs, opt: %.3fs, emit: %.3fs",
-					INSTR_TIME_GET_DOUBLE(context->base.inlining_counter),
-					INSTR_TIME_GET_DOUBLE(context->base.optimization_counter),
-					INSTR_TIME_GET_DOUBLE(context->base.emission_counter)),
+					INSTR_TIME_GET_DOUBLE(context->base.jit_instr.inlining_counter),
+					INSTR_TIME_GET_DOUBLE(context->base.jit_instr.optimization_counter),
+					INSTR_TIME_GET_DOUBLE(context->base.jit_instr.emission_counter)),
 			 errhidestmt(true),
 			 errhidecontext(true)));
 }
diff --git a/src/backend/jit/llvm/llvmjit_expr.c b/src/backend/jit/llvm/llvmjit_expr.c
index 0f31093..96f4a9d 100644
--- a/src/backend/jit/llvm/llvmjit_expr.c
+++ b/src/backend/jit/llvm/llvmjit_expr.c
@@ -129,7 +129,8 @@ llvm_compile_expr(ExprState *state)
 	}
 	else
 	{
-		context = llvm_create_context(parent->state->es_jit_flags);
+		context = (LLVMJitContext *)
+				  llvm_create_context(parent->state->es_jit_flags);
 
 		if (parent)
 		{
@@ -2557,7 +2558,7 @@ llvm_compile_expr(ExprState *state)
 	llvm_leave_fatal_on_oom();
 
 	INSTR_TIME_SET_CURRENT(endtime);
-	INSTR_TIME_ACCUM_DIFF(context->base.generation_counter,
+	INSTR_TIME_ACCUM_DIFF(context->base.jit_instr.generation_counter,
 						  endtime, starttime);
 
 	return true;
diff --git a/src/include/executor/execParallel.h b/src/include/executor/execParallel.h
index 626a66c..35dad58 100644
--- a/src/include/executor/execParallel.h
+++ b/src/include/executor/execParallel.h
@@ -20,6 +20,7 @@
 #include "utils/dsa.h"
 
 typedef struct SharedExecutorInstrumentation SharedExecutorInstrumentation;
+typedef struct SharedJitInstrumentation SharedJitInstrumentation;
 
 typedef struct ParallelExecutorInfo
 {
@@ -27,6 +28,7 @@ typedef struct ParallelExecutorInfo
 	ParallelContext *pcxt;		/* parallel context we're using */
 	BufferUsage *buffer_usage;	/* points to bufusage area in DSM */
 	SharedExecutorInstrumentation *instrumentation; /* optional */
+	SharedJitInstrumentation *jit_instrumentation; /* optional */
 	dsa_area   *area;			/* points to DSA area in DSM */
 	dsa_pointer param_exec;		/* serialized PARAM_EXEC parameters */
 	bool		finished;		/* set true by ExecParallelFinish */
diff --git a/src/include/jit/jit.h b/src/include/jit/jit.h
index b451f40..1a6c1b2 100644
--- a/src/include/jit/jit.h
+++ b/src/include/jit/jit.h
@@ -23,14 +23,8 @@
 #define PGJIT_EXPR	   (1 << 3)
 #define PGJIT_DEFORM   (1 << 4)
 
-
-typedef struct JitContext
+typedef struct JitInstrumentation
 {
-	/* see PGJIT_* above */
-	int			flags;
-
-	ResourceOwner resowner;
-
 	/* number of emitted functions */
 	size_t		created_functions;
 
@@ -45,6 +39,14 @@ typedef struct JitContext
 
 	/* accumulated time for code emission */
 	instr_time	emission_counter;
+} JitInstrumentation;
+
+typedef struct JitContext
+{
+	/* see PGJIT_* above */
+	int			flags;
+	ResourceOwner resowner;
+	JitInstrumentation jit_instr;
 } JitContext;
 
 typedef struct JitProviderCallbacks JitProviderCallbacks;
@@ -52,6 +54,7 @@ typedef struct JitProviderCallbacks JitProviderCallbacks;
 extern void _PG_jit_provider_init(JitProviderCallbacks *cb);
 typedef void (*JitProviderInit) (JitProviderCallbacks *cb);
 typedef void (*JitProviderResetAfterErrorCB) (void);
+typedef JitContext * (*JitProviderCreateContextCB) (int flags);
 typedef void (*JitProviderReleaseContextCB) (JitContext *context);
 struct ExprState;
 typedef bool (*JitProviderCompileExprCB) (struct ExprState *state);
@@ -59,6 +62,7 @@ typedef bool (*JitProviderCompileExprCB) (struct ExprState *state);
 struct JitProviderCallbacks
 {
 	JitProviderResetAfterErrorCB reset_after_error;
+	JitProviderCreateContextCB create_context;
 	JitProviderReleaseContextCB release_context;
 	JitProviderCompileExprCB compile_expr;
 };
@@ -85,6 +89,8 @@ extern void jit_release_context(JitContext *context);
  * not be able to perform JIT (i.e. return false).
  */
 extern bool jit_compile_expr(struct ExprState *state);
+extern JitContext *jit_create_context(int flags);
+extern void InstrJitAgg(JitInstrumentation *dst, JitInstrumentation *add);
 
 
 #endif							/* JIT_H */
diff --git a/src/include/jit/llvmjit.h b/src/include/jit/llvmjit.h
index c81cff8..be1c7ce 100644
--- a/src/include/jit/llvmjit.h
+++ b/src/include/jit/llvmjit.h
@@ -91,7 +91,7 @@ extern void llvm_leave_fatal_on_oom(void);
 extern void llvm_reset_after_error(void);
 extern void llvm_assert_in_fatal_section(void);
 
-extern LLVMJitContext *llvm_create_context(int jitFlags);
+extern JitContext * llvm_create_context(int jitFlags);
 extern LLVMModuleRef llvm_mutable_module(LLVMJitContext *context);
 extern char *llvm_expand_funcname(LLVMJitContext *context, const char *basename);
 extern void *llvm_get_function(LLVMJitContext *context, const char *funcname);
