Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit3b991f8

Browse files
llvmjit: Use explicit LLVMContextRef for inlining
When performing inlining LLVM unfortunately "leaks" types (thetypes survive and are usable, but a new round of inlining willrecreate new structurally equivalent types). This accumulationwill over time amount to a memory leak which for some queriescan be large enough to trigger the OOM process killer.To avoid accumulation of types, all IR related data is storedin an LLVMContextRef which is dropped and recreated in orderto release all types. Dropping and recreating incurs overhead,so it will be done only after 100 queries. This is a heuristicwhich might be revisited, but until we can get the size of thecontext from LLVM we are flying a bit blind.This issue has been reported several times, there may be morereferences to it in the archives on top of the threads linkedbelow.This is a backpatch of9dce220 to all supported branches.Reported-By: Justin Pryzby <pryzby@telsasoft.com>Reported-By: Kurt Roeckx <kurt@roeckx.be>Reported-By: Jaime Casanova <jcasanov@systemguards.com.ec>Reported-By: Lauri Laanmets <pcspets@gmail.com>Author: Andres Freund and Daniel GustafssonDiscussion:https://postgr.es/m/7acc8678-df5f-4923-9cf6-e843131ae89d@www.fastmail.comDiscussion:https://postgr.es/m/20201218235607.GC30237@telsasoft.comDiscussion:https://postgr.es/m/CAPH-tTxLf44s3CvUUtQpkDr1D8Hxqc2NGDzGXS1ODsfiJ6WSqA@mail.gmail.comBackpatch-through: v12
1 parentc980eed commit3b991f8

File tree

6 files changed

+252
-109
lines changed

6 files changed

+252
-109
lines changed

‎src/backend/jit/llvm/llvmjit.c

Lines changed: 124 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@
5151
#endif
5252

5353

54+
#defineLLVMJIT_LLVM_CONTEXT_REUSE_MAX 100
55+
5456
/* Handle of a module emitted via ORC JIT */
5557
typedefstructLLVMJitHandle
5658
{
@@ -103,8 +105,15 @@ LLVMModuleRef llvm_types_module = NULL;
103105

104106
staticboolllvm_session_initialized= false;
105107
staticsize_tllvm_generation=0;
108+
109+
/* number of LLVMJitContexts that currently are in use */
110+
staticsize_tllvm_jit_context_in_use_count=0;
111+
112+
/* how many times has the current LLVMContextRef been used */
113+
staticsize_tllvm_llvm_context_reuse_count=0;
106114
staticconstchar*llvm_triple=NULL;
107115
staticconstchar*llvm_layout=NULL;
116+
staticLLVMContextRefllvm_context;
108117

109118

110119
staticLLVMTargetRefllvm_targetref;
@@ -125,6 +134,8 @@ static void llvm_compile_module(LLVMJitContext *context);
125134
staticvoidllvm_optimize_module(LLVMJitContext*context,LLVMModuleRefmodule);
126135

127136
staticvoidllvm_create_types(void);
137+
staticvoidllvm_set_target(void);
138+
staticvoidllvm_recreate_llvm_context(void);
128139
staticuint64_tllvm_resolve_symbol(constchar*name,void*ctx);
129140

130141
#ifLLVM_VERSION_MAJOR>11
@@ -146,6 +157,63 @@ _PG_jit_provider_init(JitProviderCallbacks *cb)
146157
cb->compile_expr=llvm_compile_expr;
147158
}
148159

160+
161+
/*
162+
* Every now and then create a new LLVMContextRef. Unfortunately, during every
163+
* round of inlining, types may "leak" (they can still be found/used via the
164+
* context, but new types will be created the next time in inlining is
165+
* performed). To prevent that from slowly accumulating problematic amounts of
166+
* memory, recreate the LLVMContextRef we use. We don't want to do so too
167+
* often, as that implies some overhead (particularly re-loading the module
168+
* summaries / modules is fairly expensive). A future TODO would be to make
169+
* this more finegrained and only drop/recreate the LLVMContextRef when we know
170+
* there has been inlining. If we can get the size of the context from LLVM
171+
* then that might be a better way to determine when to drop/recreate rather
172+
* then the usagecount heuristic currently employed.
173+
*/
174+
staticvoid
175+
llvm_recreate_llvm_context(void)
176+
{
177+
if (!llvm_context)
178+
elog(ERROR,"Trying to recreate a non-existing context");
179+
180+
/*
181+
* We can only safely recreate the LLVM context if no other code is being
182+
* JITed, otherwise we'd release the types in use for that.
183+
*/
184+
if (llvm_jit_context_in_use_count>0)
185+
{
186+
llvm_llvm_context_reuse_count++;
187+
return;
188+
}
189+
190+
if (llvm_llvm_context_reuse_count <=LLVMJIT_LLVM_CONTEXT_REUSE_MAX)
191+
{
192+
llvm_llvm_context_reuse_count++;
193+
return;
194+
}
195+
196+
/*
197+
* Need to reset the modules that the inlining code caches before
198+
* disposing of the context. LLVM modules exist within a specific LLVM
199+
* context, therefore disposing of the context before resetting the cache
200+
* would lead to dangling pointers to modules.
201+
*/
202+
llvm_inline_reset_caches();
203+
204+
LLVMContextDispose(llvm_context);
205+
llvm_context=LLVMContextCreate();
206+
llvm_llvm_context_reuse_count=0;
207+
208+
/*
209+
* Re-build cached type information, so code generation code can rely on
210+
* that information to be present (also prevents the variables to be
211+
* dangling references).
212+
*/
213+
llvm_create_types();
214+
}
215+
216+
149217
/*
150218
* Create a context for JITing work.
151219
*
@@ -162,6 +230,8 @@ llvm_create_context(int jitFlags)
162230

163231
llvm_session_initialize();
164232

233+
llvm_recreate_llvm_context();
234+
165235
ResourceOwnerEnlargeJIT(CurrentResourceOwner);
166236

167237
context=MemoryContextAllocZero(TopMemoryContext,
@@ -172,6 +242,8 @@ llvm_create_context(int jitFlags)
172242
context->base.resowner=CurrentResourceOwner;
173243
ResourceOwnerRememberJIT(CurrentResourceOwner,PointerGetDatum(context));
174244

245+
llvm_jit_context_in_use_count++;
246+
175247
returncontext;
176248
}
177249

@@ -181,7 +253,13 @@ llvm_create_context(int jitFlags)
181253
staticvoid
182254
llvm_release_context(JitContext*context)
183255
{
184-
LLVMJitContext*llvm_context= (LLVMJitContext*)context;
256+
LLVMJitContext*llvm_jit_context= (LLVMJitContext*)context;
257+
258+
/*
259+
* Consider as cleaned up even if we skip doing so below, that way we can
260+
* verify the tracking is correct (see llvm_shutdown()).
261+
*/
262+
llvm_jit_context_in_use_count--;
185263

186264
/*
187265
* When this backend is exiting, don't clean up LLVM. As an error might
@@ -193,18 +271,18 @@ llvm_release_context(JitContext *context)
193271

194272
llvm_enter_fatal_on_oom();
195273

196-
if (llvm_context->module)
274+
if (llvm_jit_context->module)
197275
{
198-
LLVMDisposeModule(llvm_context->module);
199-
llvm_context->module=NULL;
276+
LLVMDisposeModule(llvm_jit_context->module);
277+
llvm_jit_context->module=NULL;
200278
}
201279

202-
while (llvm_context->handles!=NIL)
280+
while (llvm_jit_context->handles!=NIL)
203281
{
204282
LLVMJitHandle*jit_handle;
205283

206-
jit_handle= (LLVMJitHandle*)linitial(llvm_context->handles);
207-
llvm_context->handles=list_delete_first(llvm_context->handles);
284+
jit_handle= (LLVMJitHandle*)linitial(llvm_jit_context->handles);
285+
llvm_jit_context->handles=list_delete_first(llvm_jit_context->handles);
208286

209287
#ifLLVM_VERSION_MAJOR>11
210288
{
@@ -232,6 +310,8 @@ llvm_release_context(JitContext *context)
232310

233311
pfree(jit_handle);
234312
}
313+
list_free(llvm_jit_context->handles);
314+
llvm_jit_context->handles=NIL;
235315

236316
llvm_leave_fatal_on_oom();
237317
}
@@ -251,7 +331,7 @@ llvm_mutable_module(LLVMJitContext *context)
251331
{
252332
context->compiled= false;
253333
context->module_generation=llvm_generation++;
254-
context->module=LLVMModuleCreateWithName("pg");
334+
context->module=LLVMModuleCreateWithNameInContext("pg",llvm_context);
255335
LLVMSetTarget(context->module,llvm_triple);
256336
LLVMSetDataLayout(context->module,llvm_layout);
257337
}
@@ -835,6 +915,14 @@ llvm_session_initialize(void)
835915
LLVMInitializeNativeAsmPrinter();
836916
LLVMInitializeNativeAsmParser();
837917

918+
if (llvm_context==NULL)
919+
{
920+
llvm_context=LLVMContextCreate();
921+
922+
llvm_jit_context_in_use_count=0;
923+
llvm_llvm_context_reuse_count=0;
924+
}
925+
838926
/*
839927
* When targeting LLVM 15, turn off opaque pointers for the context we
840928
* build our code in. We don't need to do so for other contexts (e.g.
@@ -854,6 +942,11 @@ llvm_session_initialize(void)
854942
*/
855943
llvm_create_types();
856944

945+
/*
946+
* Extract target information from loaded module.
947+
*/
948+
llvm_set_target();
949+
857950
if (LLVMGetTargetFromTriple(llvm_triple,&llvm_targetref,&error)!=0)
858951
{
859952
elog(FATAL,"failed to query triple %s",error);
@@ -949,6 +1042,10 @@ llvm_shutdown(int code, Datum arg)
9491042
return;
9501043
}
9511044

1045+
if (llvm_jit_context_in_use_count!=0)
1046+
elog(PANIC,"LLVMJitContext in use count not 0 at exit (is %zu)",
1047+
llvm_jit_context_in_use_count);
1048+
9521049
#ifLLVM_VERSION_MAJOR>11
9531050
{
9541051
if (llvm_opt3_orc)
@@ -1011,6 +1108,23 @@ load_return_type(LLVMModuleRef mod, const char *name)
10111108
returntyp;
10121109
}
10131110

1111+
/*
1112+
* Load triple & layout from clang emitted file so we're guaranteed to be
1113+
* compatible.
1114+
*/
1115+
staticvoid
1116+
llvm_set_target(void)
1117+
{
1118+
if (!llvm_types_module)
1119+
elog(ERROR,"failed to extract target information, llvmjit_types.c not loaded");
1120+
1121+
if (llvm_triple==NULL)
1122+
llvm_triple=pstrdup(LLVMGetTarget(llvm_types_module));
1123+
1124+
if (llvm_layout==NULL)
1125+
llvm_layout=pstrdup(LLVMGetDataLayoutStr(llvm_types_module));
1126+
}
1127+
10141128
/*
10151129
* Load required information, types, function signatures from llvmjit_types.c
10161130
* and make them available in global variables.
@@ -1034,19 +1148,12 @@ llvm_create_types(void)
10341148
}
10351149

10361150
/* eagerly load contents, going to need it all */
1037-
if (LLVMParseBitcode2(buf,&llvm_types_module))
1151+
if (LLVMParseBitcodeInContext2(llvm_context,buf,&llvm_types_module))
10381152
{
1039-
elog(ERROR,"LLVMParseBitcode2 of %s failed",path);
1153+
elog(ERROR,"LLVMParseBitcodeInContext2 of %s failed",path);
10401154
}
10411155
LLVMDisposeMemoryBuffer(buf);
10421156

1043-
/*
1044-
* Load triple & layout from clang emitted file so we're guaranteed to be
1045-
* compatible.
1046-
*/
1047-
llvm_triple=pstrdup(LLVMGetTarget(llvm_types_module));
1048-
llvm_layout=pstrdup(LLVMGetDataLayoutStr(llvm_types_module));
1049-
10501157
TypeSizeT=llvm_pg_var_type("TypeSizeT");
10511158
TypeParamBool=load_return_type(llvm_types_module,"FunctionReturningBool");
10521159
TypeStorageBool=llvm_pg_var_type("TypeStorageBool");

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp