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