YugabyteDB (2.13.1.0-b60, 21121d69985fbf76aa6958d8f04a9bfa936293b5)

Coverage Report

Created: 2022-03-22 16:43

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