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

Commit9dce220

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.Backpatching of this fix will be handled once it has maturedin master for a bit.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.com
1 parentef668d8 commit9dce220

File tree

6 files changed

+234
-94
lines changed

6 files changed

+234
-94
lines changed

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

Lines changed: 122 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@
4242
#include"utils/memutils.h"
4343
#include"utils/resowner_private.h"
4444

45+
#defineLLVMJIT_LLVM_CONTEXT_REUSE_MAX 100
46+
4547
/* Handle of a module emitted via ORC JIT */
4648
typedefstructLLVMJitHandle
4749
{
@@ -81,8 +83,15 @@ static LLVMModuleRef llvm_types_module = NULL;
8183

8284
staticboolllvm_session_initialized= false;
8385
staticsize_tllvm_generation=0;
86+
87+
/* number of LLVMJitContexts that currently are in use */
88+
staticsize_tllvm_jit_context_in_use_count=0;
89+
90+
/* how many times has the current LLVMContextRef been used */
91+
staticsize_tllvm_llvm_context_reuse_count=0;
8492
staticconstchar*llvm_triple=NULL;
8593
staticconstchar*llvm_layout=NULL;
94+
staticLLVMContextRefllvm_context;
8695

8796

8897
staticLLVMTargetRefllvm_targetref;
@@ -103,6 +112,8 @@ static void llvm_compile_module(LLVMJitContext *context);
103112
staticvoidllvm_optimize_module(LLVMJitContext*context,LLVMModuleRefmodule);
104113

105114
staticvoidllvm_create_types(void);
115+
staticvoidllvm_set_target(void);
116+
staticvoidllvm_recreate_llvm_context(void);
106117
staticuint64_tllvm_resolve_symbol(constchar*name,void*ctx);
107118

108119
#ifLLVM_VERSION_MAJOR>11
@@ -124,6 +135,63 @@ _PG_jit_provider_init(JitProviderCallbacks *cb)
124135
cb->compile_expr=llvm_compile_expr;
125136
}
126137

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

141209
llvm_session_initialize();
142210

211+
llvm_recreate_llvm_context();
212+
143213
ResourceOwnerEnlargeJIT(CurrentResourceOwner);
144214

145215
context=MemoryContextAllocZero(TopMemoryContext,
@@ -150,6 +220,8 @@ llvm_create_context(int jitFlags)
150220
context->base.resowner=CurrentResourceOwner;
151221
ResourceOwnerRememberJIT(CurrentResourceOwner,PointerGetDatum(context));
152222

223+
llvm_jit_context_in_use_count++;
224+
153225
returncontext;
154226
}
155227

@@ -159,9 +231,15 @@ llvm_create_context(int jitFlags)
159231
staticvoid
160232
llvm_release_context(JitContext*context)
161233
{
162-
LLVMJitContext*llvm_context= (LLVMJitContext*)context;
234+
LLVMJitContext*llvm_jit_context= (LLVMJitContext*)context;
163235
ListCell*lc;
164236

237+
/*
238+
* Consider as cleaned up even if we skip doing so below, that way we can
239+
* verify the tracking is correct (see llvm_shutdown()).
240+
*/
241+
llvm_jit_context_in_use_count--;
242+
165243
/*
166244
* When this backend is exiting, don't clean up LLVM. As an error might
167245
* have occurred from within LLVM, we do not want to risk reentering. All
@@ -172,13 +250,13 @@ llvm_release_context(JitContext *context)
172250

173251
llvm_enter_fatal_on_oom();
174252

175-
if (llvm_context->module)
253+
if (llvm_jit_context->module)
176254
{
177-
LLVMDisposeModule(llvm_context->module);
178-
llvm_context->module=NULL;
255+
LLVMDisposeModule(llvm_jit_context->module);
256+
llvm_jit_context->module=NULL;
179257
}
180258

181-
foreach(lc,llvm_context->handles)
259+
foreach(lc,llvm_jit_context->handles)
182260
{
183261
LLVMJitHandle*jit_handle= (LLVMJitHandle*)lfirst(lc);
184262

@@ -208,8 +286,8 @@ llvm_release_context(JitContext *context)
208286

209287
pfree(jit_handle);
210288
}
211-
list_free(llvm_context->handles);
212-
llvm_context->handles=NIL;
289+
list_free(llvm_jit_context->handles);
290+
llvm_jit_context->handles=NIL;
213291

214292
llvm_leave_fatal_on_oom();
215293
}
@@ -229,7 +307,7 @@ llvm_mutable_module(LLVMJitContext *context)
229307
{
230308
context->compiled= false;
231309
context->module_generation=llvm_generation++;
232-
context->module=LLVMModuleCreateWithName("pg");
310+
context->module=LLVMModuleCreateWithNameInContext("pg",llvm_context);
233311
LLVMSetTarget(context->module,llvm_triple);
234312
LLVMSetDataLayout(context->module,llvm_layout);
235313
}
@@ -787,6 +865,14 @@ llvm_session_initialize(void)
787865
LLVMInitializeNativeAsmPrinter();
788866
LLVMInitializeNativeAsmParser();
789867

868+
if (llvm_context==NULL)
869+
{
870+
llvm_context=LLVMContextCreate();
871+
872+
llvm_jit_context_in_use_count=0;
873+
llvm_llvm_context_reuse_count=0;
874+
}
875+
790876
/*
791877
* When targeting an LLVM version with opaque pointers enabled by default,
792878
* turn them off for the context we build our code in. We don't need to
@@ -803,6 +889,11 @@ llvm_session_initialize(void)
803889
*/
804890
llvm_create_types();
805891

892+
/*
893+
* Extract target information from loaded module.
894+
*/
895+
llvm_set_target();
896+
806897
if (LLVMGetTargetFromTriple(llvm_triple,&llvm_targetref,&error)!=0)
807898
{
808899
elog(FATAL,"failed to query triple %s",error);
@@ -898,6 +989,10 @@ llvm_shutdown(int code, Datum arg)
898989
return;
899990
}
900991

992+
if (llvm_jit_context_in_use_count!=0)
993+
elog(PANIC,"LLVMJitContext in use count not 0 at exit (is %zu)",
994+
llvm_jit_context_in_use_count);
995+
901996
#ifLLVM_VERSION_MAJOR>11
902997
{
903998
if (llvm_opt3_orc)
@@ -968,6 +1063,23 @@ load_return_type(LLVMModuleRef mod, const char *name)
9681063
returntyp;
9691064
}
9701065

1066+
/*
1067+
* Load triple & layout from clang emitted file so we're guaranteed to be
1068+
* compatible.
1069+
*/
1070+
staticvoid
1071+
llvm_set_target(void)
1072+
{
1073+
if (!llvm_types_module)
1074+
elog(ERROR,"failed to extract target information, llvmjit_types.c not loaded");
1075+
1076+
if (llvm_triple==NULL)
1077+
llvm_triple=pstrdup(LLVMGetTarget(llvm_types_module));
1078+
1079+
if (llvm_layout==NULL)
1080+
llvm_layout=pstrdup(LLVMGetDataLayoutStr(llvm_types_module));
1081+
}
1082+
9711083
/*
9721084
* Load required information, types, function signatures from llvmjit_types.c
9731085
* and make them available in global variables.
@@ -991,19 +1103,12 @@ llvm_create_types(void)
9911103
}
9921104

9931105
/* eagerly load contents, going to need it all */
994-
if (LLVMParseBitcode2(buf,&llvm_types_module))
1106+
if (LLVMParseBitcodeInContext2(llvm_context,buf,&llvm_types_module))
9951107
{
996-
elog(ERROR,"LLVMParseBitcode2 of %s failed",path);
1108+
elog(ERROR,"LLVMParseBitcodeInContext2 of %s failed",path);
9971109
}
9981110
LLVMDisposeMemoryBuffer(buf);
9991111

1000-
/*
1001-
* Load triple & layout from clang emitted file so we're guaranteed to be
1002-
* compatible.
1003-
*/
1004-
llvm_triple=pstrdup(LLVMGetTarget(llvm_types_module));
1005-
llvm_layout=pstrdup(LLVMGetDataLayoutStr(llvm_types_module));
1006-
10071112
TypeSizeT=llvm_pg_var_type("TypeSizeT");
10081113
TypeParamBool=load_return_type(llvm_types_module,"FunctionReturningBool");
10091114
TypeStorageBool=llvm_pg_var_type("TypeStorageBool");

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp