Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * jit.c
4 : * Provider independent JIT infrastructure.
5 : *
6 : * Code related to loading JIT providers, redirecting calls into JIT providers
7 : * and error handling. No code specific to a specific JIT implementation
8 : * should end up here.
9 : *
10 : *
11 : * Copyright (c) 2016-2026, PostgreSQL Global Development Group
12 : *
13 : * IDENTIFICATION
14 : * src/backend/jit/jit.c
15 : *
16 : *-------------------------------------------------------------------------
17 : */
18 : #include "postgres.h"
19 :
20 : #include <sys/types.h>
21 : #include <sys/stat.h>
22 : #include <unistd.h>
23 :
24 : #include "fmgr.h"
25 : #include "jit/jit.h"
26 : #include "miscadmin.h"
27 : #include "nodes/execnodes.h"
28 : #include "portability/instr_time.h"
29 : #include "storage/fd.h"
30 : #include "utils/fmgrprotos.h"
31 :
32 : /* GUCs */
33 : bool jit_enabled = true;
34 : char *jit_provider = NULL;
35 : bool jit_debugging_support = false;
36 : bool jit_dump_bitcode = false;
37 : bool jit_expressions = true;
38 : bool jit_profiling_support = false;
39 : bool jit_tuple_deforming = true;
40 : double jit_above_cost = 100000;
41 : double jit_inline_above_cost = 500000;
42 : double jit_optimize_above_cost = 500000;
43 :
44 : static JitProviderCallbacks provider;
45 : static bool provider_successfully_loaded = false;
46 : static bool provider_failed_loading = false;
47 :
48 :
49 : static bool provider_init(void);
50 :
51 :
52 : /*
53 : * SQL level function returning whether JIT is available in the current
54 : * backend. Will attempt to load JIT provider if necessary.
55 : */
56 : Datum
57 0 : pg_jit_available(PG_FUNCTION_ARGS)
58 : {
59 0 : PG_RETURN_BOOL(provider_init());
60 : }
61 :
62 :
63 : /*
64 : * Return whether a JIT provider has successfully been loaded, caching the
65 : * result.
66 : */
67 : static bool
68 5192 : provider_init(void)
69 : {
70 : char path[MAXPGPATH];
71 : JitProviderInit init;
72 :
73 : /* don't even try to load if not enabled */
74 5192 : if (!jit_enabled)
75 0 : return false;
76 :
77 : /*
78 : * Don't retry loading after failing - attempting to load JIT provider
79 : * isn't cheap.
80 : */
81 5192 : if (provider_failed_loading)
82 0 : return false;
83 5192 : if (provider_successfully_loaded)
84 5048 : return true;
85 :
86 : /*
87 : * Check whether shared library exists. We do that check before actually
88 : * attempting to load the shared library (via load_external_function()),
89 : * because that'd error out in case the shlib isn't available.
90 : */
91 144 : snprintf(path, MAXPGPATH, "%s/%s%s", pkglib_path, jit_provider, DLSUFFIX);
92 144 : elog(DEBUG1, "probing availability of JIT provider at %s", path);
93 144 : if (!pg_file_exists(path))
94 : {
95 0 : elog(DEBUG1,
96 : "provider not available, disabling JIT for current session");
97 0 : provider_failed_loading = true;
98 0 : return false;
99 : }
100 :
101 : /*
102 : * If loading functions fails, signal failure. We do so because
103 : * load_external_function() might error out despite the above check if
104 : * e.g. the library's dependencies aren't installed. We want to signal
105 : * ERROR in that case, so the user is notified, but we don't want to
106 : * continually retry.
107 : */
108 144 : provider_failed_loading = true;
109 :
110 : /* and initialize */
111 144 : init = (JitProviderInit)
112 144 : load_external_function(path, "_PG_jit_provider_init", true, NULL);
113 144 : init(&provider);
114 :
115 144 : provider_successfully_loaded = true;
116 144 : provider_failed_loading = false;
117 :
118 144 : elog(DEBUG1, "successfully loaded JIT provider in current session");
119 :
120 144 : return true;
121 : }
122 :
123 : /*
124 : * Reset JIT provider's error handling. This'll be called after an error has
125 : * been thrown and the main-loop has re-established control.
126 : */
127 : void
128 30329 : jit_reset_after_error(void)
129 : {
130 30329 : if (provider_successfully_loaded)
131 2722 : provider.reset_after_error();
132 30329 : }
133 :
134 : /*
135 : * Release resources required by one JIT context.
136 : */
137 : void
138 663 : jit_release_context(JitContext *context)
139 : {
140 663 : if (provider_successfully_loaded)
141 663 : provider.release_context(context);
142 :
143 663 : pfree(context);
144 663 : }
145 :
146 : /*
147 : * Ask provider to JIT compile an expression.
148 : *
149 : * Returns true if successful, false if not.
150 : */
151 : bool
152 2508519 : jit_compile_expr(struct ExprState *state)
153 : {
154 : /*
155 : * We can easily create a one-off context for functions without an
156 : * associated PlanState (and thus EState). But because there's no executor
157 : * shutdown callback that could deallocate the created function, they'd
158 : * live to the end of the transactions, where they'd be cleaned up by the
159 : * resowner machinery. That can lead to a noticeable amount of memory
160 : * usage, and worse, trigger some quadratic behaviour in gdb. Therefore,
161 : * at least for now, don't create a JITed function in those circumstances.
162 : */
163 2508519 : if (!state->parent)
164 441169 : return false;
165 :
166 : /* if no jitting should be performed at all */
167 2067350 : if (!(state->parent->state->es_jit_flags & PGJIT_PERFORM))
168 2062158 : return false;
169 :
170 : /* or if expressions aren't JITed */
171 5192 : if (!(state->parent->state->es_jit_flags & PGJIT_EXPR))
172 0 : return false;
173 :
174 : /* this also takes !jit_enabled into account */
175 5192 : if (provider_init())
176 5192 : return provider.compile_expr(state);
177 :
178 0 : return false;
179 : }
180 :
181 : /* Aggregate JIT instrumentation information */
182 : void
183 0 : InstrJitAgg(JitInstrumentation *dst, JitInstrumentation *add)
184 : {
185 0 : dst->created_functions += add->created_functions;
186 0 : INSTR_TIME_ADD(dst->generation_counter, add->generation_counter);
187 0 : INSTR_TIME_ADD(dst->deform_counter, add->deform_counter);
188 0 : INSTR_TIME_ADD(dst->inlining_counter, add->inlining_counter);
189 0 : INSTR_TIME_ADD(dst->optimization_counter, add->optimization_counter);
190 0 : INSTR_TIME_ADD(dst->emission_counter, add->emission_counter);
191 0 : }
|