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

Commit10912f7

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 parent2db84c2 commit10912f7

File tree

6 files changed

+245
-104
lines changed

6 files changed

+245
-104
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
{
@@ -99,8 +101,15 @@ LLVMModuleRef llvm_types_module = NULL;
99101

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

105114

106115
staticLLVMTargetRefllvm_targetref;
@@ -121,6 +130,8 @@ static void llvm_compile_module(LLVMJitContext *context);
121130
staticvoidllvm_optimize_module(LLVMJitContext*context,LLVMModuleRefmodule);
122131

123132
staticvoidllvm_create_types(void);
133+
staticvoidllvm_set_target(void);
134+
staticvoidllvm_recreate_llvm_context(void);
124135
staticuint64_tllvm_resolve_symbol(constchar*name,void*ctx);
125136

126137
#ifLLVM_VERSION_MAJOR>11
@@ -142,6 +153,63 @@ _PG_jit_provider_init(JitProviderCallbacks *cb)
142153
cb->compile_expr=llvm_compile_expr;
143154
}
144155

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

159227
llvm_session_initialize();
160228

229+
llvm_recreate_llvm_context();
230+
161231
ResourceOwnerEnlargeJIT(CurrentResourceOwner);
162232

163233
context=MemoryContextAllocZero(TopMemoryContext,
@@ -168,6 +238,8 @@ llvm_create_context(int jitFlags)
168238
context->base.resowner=CurrentResourceOwner;
169239
ResourceOwnerRememberJIT(CurrentResourceOwner,PointerGetDatum(context));
170240

241+
llvm_jit_context_in_use_count++;
242+
171243
returncontext;
172244
}
173245

@@ -177,9 +249,15 @@ llvm_create_context(int jitFlags)
177249
staticvoid
178250
llvm_release_context(JitContext*context)
179251
{
180-
LLVMJitContext*llvm_context= (LLVMJitContext*)context;
252+
LLVMJitContext*llvm_jit_context= (LLVMJitContext*)context;
181253
ListCell*lc;
182254

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

191269
llvm_enter_fatal_on_oom();
192270

193-
if (llvm_context->module)
271+
if (llvm_jit_context->module)
194272
{
195-
LLVMDisposeModule(llvm_context->module);
196-
llvm_context->module=NULL;
273+
LLVMDisposeModule(llvm_jit_context->module);
274+
llvm_jit_context->module=NULL;
197275
}
198276

199-
foreach(lc,llvm_context->handles)
277+
foreach(lc,llvm_jit_context->handles)
200278
{
201279
LLVMJitHandle*jit_handle= (LLVMJitHandle*)lfirst(lc);
202280

@@ -226,8 +304,8 @@ llvm_release_context(JitContext *context)
226304

227305
pfree(jit_handle);
228306
}
229-
list_free(llvm_context->handles);
230-
llvm_context->handles=NIL;
307+
list_free(llvm_jit_context->handles);
308+
llvm_jit_context->handles=NIL;
231309

232310
llvm_leave_fatal_on_oom();
233311
}
@@ -247,7 +325,7 @@ llvm_mutable_module(LLVMJitContext *context)
247325
{
248326
context->compiled= false;
249327
context->module_generation=llvm_generation++;
250-
context->module=LLVMModuleCreateWithName("pg");
328+
context->module=LLVMModuleCreateWithNameInContext("pg",llvm_context);
251329
LLVMSetTarget(context->module,llvm_triple);
252330
LLVMSetDataLayout(context->module,llvm_layout);
253331
}
@@ -831,6 +909,14 @@ llvm_session_initialize(void)
831909
LLVMInitializeNativeAsmPrinter();
832910
LLVMInitializeNativeAsmParser();
833911

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

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

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

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

10321144
/* eagerly load contents, going to need it all */
1033-
if (LLVMParseBitcode2(buf,&llvm_types_module))
1145+
if (LLVMParseBitcodeInContext2(llvm_context,buf,&llvm_types_module))
10341146
{
1035-
elog(ERROR,"LLVMParseBitcode2 of %s failed",path);
1147+
elog(ERROR,"LLVMParseBitcodeInContext2 of %s failed",path);
10361148
}
10371149
LLVMDisposeMemoryBuffer(buf);
10381150

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

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp