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

Commit2cf5058

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 parentf07a303 commit2cf5058

File tree

6 files changed

+244
-103
lines changed

6 files changed

+244
-103
lines changed

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

Lines changed: 122 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@
4747
#include"utils/memutils.h"
4848
#include"utils/resowner_private.h"
4949

50+
#defineLLVMJIT_LLVM_CONTEXT_REUSE_MAX 100
51+
5052
/* Handle of a module emitted via ORC JIT */
5153
typedefstructLLVMJitHandle
5254
{
@@ -100,8 +102,15 @@ LLVMModuleRef llvm_types_module = NULL;
100102

101103
staticboolllvm_session_initialized= false;
102104
staticsize_tllvm_generation=0;
105+
106+
/* number of LLVMJitContexts that currently are in use */
107+
staticsize_tllvm_jit_context_in_use_count=0;
108+
109+
/* how many times has the current LLVMContextRef been used */
110+
staticsize_tllvm_llvm_context_reuse_count=0;
103111
staticconstchar*llvm_triple=NULL;
104112
staticconstchar*llvm_layout=NULL;
113+
staticLLVMContextRefllvm_context;
105114

106115

107116
staticLLVMTargetRefllvm_targetref;
@@ -122,6 +131,8 @@ static void llvm_compile_module(LLVMJitContext *context);
122131
staticvoidllvm_optimize_module(LLVMJitContext*context,LLVMModuleRefmodule);
123132

124133
staticvoidllvm_create_types(void);
134+
staticvoidllvm_set_target(void);
135+
staticvoidllvm_recreate_llvm_context(void);
125136
staticuint64_tllvm_resolve_symbol(constchar*name,void*ctx);
126137

127138
#ifLLVM_VERSION_MAJOR>11
@@ -143,6 +154,63 @@ _PG_jit_provider_init(JitProviderCallbacks *cb)
143154
cb->compile_expr=llvm_compile_expr;
144155
}
145156

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

160228
llvm_session_initialize();
161229

230+
llvm_recreate_llvm_context();
231+
162232
ResourceOwnerEnlargeJIT(CurrentResourceOwner);
163233

164234
context=MemoryContextAllocZero(TopMemoryContext,
@@ -169,6 +239,8 @@ llvm_create_context(int jitFlags)
169239
context->base.resowner=CurrentResourceOwner;
170240
ResourceOwnerRememberJIT(CurrentResourceOwner,PointerGetDatum(context));
171241

242+
llvm_jit_context_in_use_count++;
243+
172244
returncontext;
173245
}
174246

@@ -178,9 +250,15 @@ llvm_create_context(int jitFlags)
178250
staticvoid
179251
llvm_release_context(JitContext*context)
180252
{
181-
LLVMJitContext*llvm_context= (LLVMJitContext*)context;
253+
LLVMJitContext*llvm_jit_context= (LLVMJitContext*)context;
182254
ListCell*lc;
183255

256+
/*
257+
* Consider as cleaned up even if we skip doing so below, that way we can
258+
* verify the tracking is correct (see llvm_shutdown()).
259+
*/
260+
llvm_jit_context_in_use_count--;
261+
184262
/*
185263
* When this backend is exiting, don't clean up LLVM. As an error might
186264
* have occurred from within LLVM, we do not want to risk reentering. All
@@ -191,13 +269,13 @@ llvm_release_context(JitContext *context)
191269

192270
llvm_enter_fatal_on_oom();
193271

194-
if (llvm_context->module)
272+
if (llvm_jit_context->module)
195273
{
196-
LLVMDisposeModule(llvm_context->module);
197-
llvm_context->module=NULL;
274+
LLVMDisposeModule(llvm_jit_context->module);
275+
llvm_jit_context->module=NULL;
198276
}
199277

200-
foreach(lc,llvm_context->handles)
278+
foreach(lc,llvm_jit_context->handles)
201279
{
202280
LLVMJitHandle*jit_handle= (LLVMJitHandle*)lfirst(lc);
203281

@@ -227,8 +305,8 @@ llvm_release_context(JitContext *context)
227305

228306
pfree(jit_handle);
229307
}
230-
list_free(llvm_context->handles);
231-
llvm_context->handles=NIL;
308+
list_free(llvm_jit_context->handles);
309+
llvm_jit_context->handles=NIL;
232310

233311
llvm_leave_fatal_on_oom();
234312
}
@@ -248,7 +326,7 @@ llvm_mutable_module(LLVMJitContext *context)
248326
{
249327
context->compiled= false;
250328
context->module_generation=llvm_generation++;
251-
context->module=LLVMModuleCreateWithName("pg");
329+
context->module=LLVMModuleCreateWithNameInContext("pg",llvm_context);
252330
LLVMSetTarget(context->module,llvm_triple);
253331
LLVMSetDataLayout(context->module,llvm_layout);
254332
}
@@ -832,6 +910,14 @@ llvm_session_initialize(void)
832910
LLVMInitializeNativeAsmPrinter();
833911
LLVMInitializeNativeAsmParser();
834912

913+
if (llvm_context==NULL)
914+
{
915+
llvm_context=LLVMContextCreate();
916+
917+
llvm_jit_context_in_use_count=0;
918+
llvm_llvm_context_reuse_count=0;
919+
}
920+
835921
/*
836922
* When targeting LLVM 15, turn off opaque pointers for the context we
837923
* build our code in. We don't need to do so for other contexts (e.g.
@@ -851,6 +937,11 @@ llvm_session_initialize(void)
851937
*/
852938
llvm_create_types();
853939

940+
/*
941+
* Extract target information from loaded module.
942+
*/
943+
llvm_set_target();
944+
854945
if (LLVMGetTargetFromTriple(llvm_triple,&llvm_targetref,&error)!=0)
855946
{
856947
elog(FATAL,"failed to query triple %s",error);
@@ -946,6 +1037,10 @@ llvm_shutdown(int code, Datum arg)
9461037
return;
9471038
}
9481039

1040+
if (llvm_jit_context_in_use_count!=0)
1041+
elog(PANIC,"LLVMJitContext in use count not 0 at exit (is %zu)",
1042+
llvm_jit_context_in_use_count);
1043+
9491044
#ifLLVM_VERSION_MAJOR>11
9501045
{
9511046
if (llvm_opt3_orc)
@@ -1008,6 +1103,23 @@ load_return_type(LLVMModuleRef mod, const char *name)
10081103
returntyp;
10091104
}
10101105

1106+
/*
1107+
* Load triple & layout from clang emitted file so we're guaranteed to be
1108+
* compatible.
1109+
*/
1110+
staticvoid
1111+
llvm_set_target(void)
1112+
{
1113+
if (!llvm_types_module)
1114+
elog(ERROR,"failed to extract target information, llvmjit_types.c not loaded");
1115+
1116+
if (llvm_triple==NULL)
1117+
llvm_triple=pstrdup(LLVMGetTarget(llvm_types_module));
1118+
1119+
if (llvm_layout==NULL)
1120+
llvm_layout=pstrdup(LLVMGetDataLayoutStr(llvm_types_module));
1121+
}
1122+
10111123
/*
10121124
* Load required information, types, function signatures from llvmjit_types.c
10131125
* and make them available in global variables.
@@ -1031,19 +1143,12 @@ llvm_create_types(void)
10311143
}
10321144

10331145
/* eagerly load contents, going to need it all */
1034-
if (LLVMParseBitcode2(buf,&llvm_types_module))
1146+
if (LLVMParseBitcodeInContext2(llvm_context,buf,&llvm_types_module))
10351147
{
1036-
elog(ERROR,"LLVMParseBitcode2 of %s failed",path);
1148+
elog(ERROR,"LLVMParseBitcodeInContext2 of %s failed",path);
10371149
}
10381150
LLVMDisposeMemoryBuffer(buf);
10391151

1040-
/*
1041-
* Load triple & layout from clang emitted file so we're guaranteed to be
1042-
* compatible.
1043-
*/
1044-
llvm_triple=pstrdup(LLVMGetTarget(llvm_types_module));
1045-
llvm_layout=pstrdup(LLVMGetDataLayoutStr(llvm_types_module));
1046-
10471152
TypeSizeT=llvm_pg_var_type("TypeSizeT");
10481153
TypeParamBool=load_return_type(llvm_types_module,"FunctionReturningBool");
10491154
TypeStorageBool=llvm_pg_var_type("TypeStorageBool");

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp