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-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 = false;
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
2967 andres@anarazel.de 57 :UBC 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
2967 andres@anarazel.de 68 :LBC (4553) : provider_init(void)
69 : : {
70 : : char path[MAXPGPATH];
71 : : JitProviderInit init;
72 : :
73 : : /* don't even try to load if not enabled */
74 [ # # ]: (4553) : if (!jit_enabled)
2967 andres@anarazel.de 75 :UBC 0 : return false;
76 : :
77 : : /*
78 : : * Don't retry loading after failing - attempting to load JIT provider
79 : : * isn't cheap.
80 : : */
2967 andres@anarazel.de 81 [ # # ]:LBC (4553) : if (provider_failed_loading)
82 : (4317) : return false;
83 [ # # ]: (236) : if (provider_successfully_loaded)
2967 andres@anarazel.de 84 :UBC 0 : 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 : : */
2967 andres@anarazel.de 91 :LBC (236) : snprintf(path, MAXPGPATH, "%s/%s%s", pkglib_path, jit_provider, DLSUFFIX);
92 [ # # ]: (236) : elog(DEBUG1, "probing availability of JIT provider at %s", path);
844 michael@paquier.xyz 93 [ # # ]: (236) : if (!pg_file_exists(path))
94 : : {
2967 andres@anarazel.de 95 [ # # ]: (236) : elog(DEBUG1,
96 : : "provider not available, disabling JIT for current session");
97 : (236) : provider_failed_loading = true;
98 : (236) : 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 : : */
2967 andres@anarazel.de 108 :UBC 0 : provider_failed_loading = true;
109 : :
110 : : /* and initialize */
111 : 0 : init = (JitProviderInit)
112 : 0 : load_external_function(path, "_PG_jit_provider_init", true, NULL);
113 : 0 : init(&provider);
114 : :
115 : 0 : provider_successfully_loaded = true;
116 : 0 : provider_failed_loading = false;
117 : :
118 [ # # ]: 0 : elog(DEBUG1, "successfully loaded JIT provider in current session");
119 : :
120 : 0 : 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
2967 andres@anarazel.de 128 :CBC 31096 : jit_reset_after_error(void)
129 : : {
130 [ - + ]: 31096 : if (provider_successfully_loaded)
2967 andres@anarazel.de 131 :UBC 0 : provider.reset_after_error();
2967 andres@anarazel.de 132 :CBC 31096 : }
133 : :
134 : : /*
135 : : * Release resources required by one JIT context.
136 : : */
137 : : void
2967 andres@anarazel.de 138 :UBC 0 : jit_release_context(JitContext *context)
139 : : {
140 [ # # ]: 0 : if (provider_successfully_loaded)
141 : 0 : provider.release_context(context);
142 : :
143 : 0 : pfree(context);
144 : 0 : }
145 : :
146 : : /*
147 : : * Ask provider to JIT compile an expression.
148 : : *
149 : : * Returns true if successful, false if not.
150 : : */
151 : : bool
2968 andres@anarazel.de 152 :CBC 1615967 : 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 [ + + ]: 1615967 : if (!state->parent)
164 : 448684 : return false;
165 : :
166 : : /* if no jitting should be performed at all */
167 [ + - ]: 1167283 : if (!(state->parent->state->es_jit_flags & PGJIT_PERFORM))
168 : 1167283 : return false;
169 : :
170 : : /* or if expressions aren't JITed */
2968 andres@anarazel.de 171 [ # # ]:LBC (4553) : if (!(state->parent->state->es_jit_flags & PGJIT_EXPR))
2968 andres@anarazel.de 172 :UBC 0 : return false;
173 : :
174 : : /* this also takes !jit_enabled into account */
2968 andres@anarazel.de 175 [ # # ]:LBC (4553) : if (provider_init())
2968 andres@anarazel.de 176 :UBC 0 : return provider.compile_expr(state);
177 : :
2968 andres@anarazel.de 178 :LBC (4553) : return false;
179 : : }
180 : :
181 : : /* Aggregate JIT instrumentation information */
182 : : void
2779 183 : (36) : InstrJitAgg(JitInstrumentation *dst, JitInstrumentation *add)
184 : : {
185 : (36) : dst->created_functions += add->created_functions;
186 : (36) : INSTR_TIME_ADD(dst->generation_counter, add->generation_counter);
970 dgustafsson@postgres 187 : (36) : INSTR_TIME_ADD(dst->deform_counter, add->deform_counter);
2779 andres@anarazel.de 188 : (36) : INSTR_TIME_ADD(dst->inlining_counter, add->inlining_counter);
189 : (36) : INSTR_TIME_ADD(dst->optimization_counter, add->optimization_counter);
190 : (36) : INSTR_TIME_ADD(dst->emission_counter, add->emission_counter);
191 : (36) : }
|