Skip to content

Commit 91a118e

Browse files
authored
track-allocation: charge entry cost to caller (#34391)
Don't include one-time costs (JIT compilation) so that warm-up isn't generally required. And adjust codegen emission to charge call entry costs to the caller. fixes #11753 fixes #19981 fixes #21871 fixes #34054 close #18595
1 parent c5da9de commit 91a118e

File tree

6 files changed

+76
-20
lines changed

6 files changed

+76
-20
lines changed

src/codegen.cpp

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,7 @@ Function *juliapersonality_func;
320320
#endif
321321
#endif
322322
static Function *diff_gc_total_bytes_func;
323+
static Function *sync_gc_total_bytes_func;
323324
static Function *jlarray_data_owner_func;
324325
static GlobalVariable *jlgetworld_global;
325326

@@ -1799,17 +1800,18 @@ static void coverageAllocLine(StringRef filename, int line)
17991800

18001801
static logdata_t mallocData;
18011802

1802-
static void mallocVisitLine(jl_codectx_t &ctx, StringRef filename, int line)
1803+
static void mallocVisitLine(jl_codectx_t &ctx, StringRef filename, int line, Value *sync)
18031804
{
18041805
assert(!imaging_mode);
18051806
if (filename == "" || filename == "none" || filename == "no file" || filename == "<missing>" || line < 0)
18061807
return;
1807-
Value *addend = ctx.builder.CreateCall(prepare_call(diff_gc_total_bytes_func), {});
1808+
Value *addend = sync
1809+
? ctx.builder.CreateCall(prepare_call(sync_gc_total_bytes_func), {sync})
1810+
: ctx.builder.CreateCall(prepare_call(diff_gc_total_bytes_func), {});
18081811
visitLine(ctx, mallocData[filename], line, addend, "bytecnt");
18091812
}
18101813

1811-
// Resets the malloc counts. Needed to avoid including memory usage
1812-
// from JITting.
1814+
// Resets the malloc counts.
18131815
extern "C" JL_DLLEXPORT void jl_clear_malloc_data(void)
18141816
{
18151817
logdata_t::iterator it = mallocData.begin();
@@ -1826,7 +1828,7 @@ extern "C" JL_DLLEXPORT void jl_clear_malloc_data(void)
18261828
}
18271829
}
18281830
}
1829-
jl_gc_sync_total_bytes();
1831+
jl_gc_sync_total_bytes(0);
18301832
}
18311833

18321834
extern "C" int isabspath(const char *in);
@@ -6374,12 +6376,15 @@ static std::unique_ptr<Module> emit_function(
63746376
}
63756377
new_lineinfo.clear();
63766378
};
6377-
auto mallocVisitStmt = [&] (unsigned dbg) {
6378-
if (!do_malloc_log(mod_is_user_mod) || dbg == 0)
6379+
auto mallocVisitStmt = [&] (unsigned dbg, Value *sync) {
6380+
if (!do_malloc_log(mod_is_user_mod) || dbg == 0) {
6381+
if (do_malloc_log(true) && sync)
6382+
ctx.builder.CreateCall(prepare_call(sync_gc_total_bytes_func), {sync});
63796383
return;
6384+
}
63806385
while (linetable.at(dbg).inlined_at)
63816386
dbg = linetable.at(dbg).inlined_at;
6382-
mallocVisitLine(ctx, ctx.file, linetable.at(dbg).line);
6387+
mallocVisitLine(ctx, ctx.file, linetable.at(dbg).line, sync);
63836388
};
63846389
if (coverage_mode != JL_LOG_NONE) {
63856390
// record all lines that could be covered
@@ -6450,8 +6455,10 @@ static std::unique_ptr<Module> emit_function(
64506455
current_lineinfo.push_back(1);
64516456
}
64526457
}
6453-
if (do_malloc_log(mod_is_user_mod))
6454-
mallocVisitLine(ctx, ctx.file, toplineno);
6458+
Value *sync_bytes = nullptr;
6459+
if (do_malloc_log(true))
6460+
sync_bytes = ctx.builder.CreateCall(prepare_call(diff_gc_total_bytes_func), {});
6461+
64556462
find_next_stmt(0);
64566463
while (cursor != -1) {
64576464
int32_t debuginfoloc = ((int32_t*)jl_array_data(src->codelocs))[cursor];
@@ -6563,7 +6570,7 @@ static std::unique_ptr<Module> emit_function(
65636570
}
65646571
}
65656572

6566-
mallocVisitStmt(debuginfoloc);
6573+
mallocVisitStmt(debuginfoloc, sync_bytes);
65676574
if (toplevel)
65686575
ctx.builder.CreateStore(last_age, ctx.world_age_field);
65696576
assert(type_is_ghost(retty) || returninfo.cc == jl_returninfo_t::SRet ||
@@ -6605,7 +6612,7 @@ static std::unique_ptr<Module> emit_function(
66056612
jl_value_t *cond = args[0];
66066613
int lname = jl_unbox_long(args[1]);
66076614
Value *isfalse = emit_condition(ctx, cond, "if");
6608-
mallocVisitStmt(debuginfoloc);
6615+
mallocVisitStmt(debuginfoloc, nullptr);
66096616
come_from_bb[cursor+1] = ctx.builder.GetInsertBlock();
66106617
workstack.push_back(lname - 1);
66116618
BasicBlock *ifnot = BB[lname];
@@ -6643,7 +6650,7 @@ static std::unique_ptr<Module> emit_function(
66436650
}
66446651
else {
66456652
emit_stmtpos(ctx, stmt, cursor);
6646-
mallocVisitStmt(debuginfoloc);
6653+
mallocVisitStmt(debuginfoloc, nullptr);
66476654
}
66486655
find_next_stmt(cursor + 1);
66496656
}
@@ -7683,6 +7690,13 @@ static void init_julia_llvm_env(Module *m)
76837690
"jl_gc_diff_total_bytes", m);
76847691
add_named_global(diff_gc_total_bytes_func, &jl_gc_diff_total_bytes);
76857692

7693+
sync_gc_total_bytes_func =
7694+
Function::Create(FunctionType::get(T_int64, {T_int64}, false),
7695+
Function::ExternalLinkage,
7696+
"jl_gc_sync_total_bytes", m);
7697+
add_named_global(sync_gc_total_bytes_func, &jl_gc_sync_total_bytes);
7698+
7699+
76867700
std::vector<Type*> array_owner_args(0);
76877701
array_owner_args.push_back(T_prjlvalue);
76887702
jlarray_data_owner_func =

src/gc.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2789,9 +2789,13 @@ JL_DLLEXPORT int64_t jl_gc_diff_total_bytes(void)
27892789
return newtb - oldtb;
27902790
}
27912791

2792-
void jl_gc_sync_total_bytes(void)
2792+
JL_DLLEXPORT int64_t jl_gc_sync_total_bytes(int64_t offset)
27932793
{
2794-
jl_gc_get_total_bytes(&last_gc_total_bytes);
2794+
int64_t oldtb = last_gc_total_bytes;
2795+
int64_t newtb;
2796+
jl_gc_get_total_bytes(&newtb);
2797+
last_gc_total_bytes = newtb - offset;
2798+
return newtb - oldtb;
27952799
}
27962800

27972801
JL_DLLEXPORT int64_t jl_gc_live_bytes(void)

src/gf.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2146,6 +2146,7 @@ STATIC_INLINE jl_value_t *_jl_invoke(jl_value_t *F, jl_value_t **args, uint32_t
21462146
}
21472147
codeinst = codeinst->next;
21482148
}
2149+
int64_t last_alloc = jl_options.malloc_log ? jl_gc_diff_total_bytes() : 0;
21492150
int last_errno = errno;
21502151
#ifdef _OS_WINDOWS_
21512152
DWORD last_error = GetLastError();
@@ -2155,6 +2156,8 @@ STATIC_INLINE jl_value_t *_jl_invoke(jl_value_t *F, jl_value_t **args, uint32_t
21552156
SetLastError(last_error);
21562157
#endif
21572158
errno = last_errno;
2159+
if (jl_options.malloc_log)
2160+
jl_gc_sync_total_bytes(last_alloc); // discard allocation count from compilation
21582161
jl_value_t *res = codeinst->invoke(F, args, nargs, codeinst);
21592162
return verify_type(res);
21602163
}
@@ -2281,6 +2284,7 @@ STATIC_INLINE jl_method_instance_t *jl_lookup_generic_(jl_value_t *F, jl_value_t
22812284
mfunc = entry->func.linfo;
22822285
}
22832286
else {
2287+
int64_t last_alloc = jl_options.malloc_log ? jl_gc_diff_total_bytes() : 0;
22842288
JL_LOCK(&mt->writelock);
22852289
// cache miss case
22862290
JL_TIMING(METHOD_LOOKUP_SLOW);
@@ -2289,6 +2293,8 @@ STATIC_INLINE jl_method_instance_t *jl_lookup_generic_(jl_value_t *F, jl_value_t
22892293
mfunc = jl_mt_assoc_by_type(mt, tt, /*cache*/1, world);
22902294
JL_GC_POP();
22912295
JL_UNLOCK(&mt->writelock);
2296+
if (jl_options.malloc_log)
2297+
jl_gc_sync_total_bytes(last_alloc); // discard allocation count from compilation
22922298
if (mfunc == NULL) {
22932299
#ifdef JL_TRACE
22942300
if (error_en)
@@ -2382,6 +2388,7 @@ static jl_value_t *jl_gf_invoke_by_method(jl_method_t *method, jl_value_t *gf, j
23822388
mfunc = tm->func.linfo;
23832389
}
23842390
else {
2391+
int64_t last_alloc = jl_options.malloc_log ? jl_gc_diff_total_bytes() : 0;
23852392
jl_svec_t *tpenv = jl_emptysvec;
23862393
jl_tupletype_t *tt = NULL;
23872394
JL_GC_PUSH2(&tpenv, &tt);
@@ -2398,6 +2405,8 @@ static jl_value_t *jl_gf_invoke_by_method(jl_method_t *method, jl_value_t *gf, j
23982405
mfunc = cache_method(NULL, &method->invokes, (jl_value_t*)method, tt, method, 1, tpenv);
23992406
JL_UNLOCK(&method->writelock);
24002407
JL_GC_POP();
2408+
if (jl_options.malloc_log)
2409+
jl_gc_sync_total_bytes(last_alloc); // discard allocation count from compilation
24012410
}
24022411
JL_GC_PROMISE_ROOTED(mfunc);
24032412
size_t world = jl_get_ptls_states()->world_age;

src/julia_internal.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,7 @@ JL_DLLEXPORT void *jl_gc_counted_malloc(size_t sz);
315315
JL_DLLEXPORT void JL_NORETURN jl_throw_out_of_memory_error(void);
316316

317317
JL_DLLEXPORT int64_t jl_gc_diff_total_bytes(void);
318-
void jl_gc_sync_total_bytes(void);
318+
JL_DLLEXPORT int64_t jl_gc_sync_total_bytes(int64_t offset);
319319
void jl_gc_track_malloced_array(jl_ptls_t ptls, jl_array_t *a) JL_NOTSAFEPOINT;
320320
void jl_gc_count_allocd(size_t sz) JL_NOTSAFEPOINT;
321321
void jl_gc_run_all_finalizers(jl_ptls_t ptls);

test/cmdlineargs.jl

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -264,10 +264,31 @@ let exename = `$(Base.julia_cmd()) --startup-file=no`
264264
@test readchomp(`$exename -E "Base.JLOptions().malloc_log != 0"`) == "false"
265265
@test readchomp(`$exename -E "Base.JLOptions().malloc_log != 0" --track-allocation=none`) == "false"
266266

267-
@test readchomp(`$exename -E "Base.JLOptions().malloc_log != 0"
268-
--track-allocation`) == "true"
269-
@test readchomp(`$exename -E "Base.JLOptions().malloc_log != 0"
270-
--track-allocation=user`) == "true"
267+
@test readchomp(`$exename -E "Base.JLOptions().malloc_log != 0" --track-allocation`) == "true"
268+
@test readchomp(`$exename -E "Base.JLOptions().malloc_log != 0" --track-allocation=user`) == "true"
269+
mktempdir() do dir
270+
helperdir = joinpath(@__DIR__, "testhelpers")
271+
inputfile = joinpath(helperdir, "allocation_file.jl")
272+
pid = readchomp(`$exename -E "getpid()" -L $inputfile --track-allocation=user`)
273+
memfile = "$inputfile.$pid.mem"
274+
got = readlines(memfile)
275+
rm(memfile)
276+
@test popfirst!(got) == " 0 g(x) = x + 123456"
277+
@test popfirst!(got) == " - function f(x)"
278+
@test popfirst!(got) == " 80 []"
279+
if Sys.WORD_SIZE == 64
280+
@test popfirst!(got) == " 32 Base.invokelatest(g, 0)"
281+
@test popfirst!(got) == " 48 Base.invokelatest(g, x)"
282+
else
283+
@test popfirst!(got) == " 24 Base.invokelatest(g, 0)"
284+
@test popfirst!(got) == " 36 Base.invokelatest(g, x)"
285+
end
286+
@test popfirst!(got) == " 80 []"
287+
@test popfirst!(got) == " - end"
288+
@test popfirst!(got) == " - f(1.23)"
289+
@test isempty(got) || got
290+
end
291+
271292

272293
# --optimize
273294
@test readchomp(`$exename -E "Base.JLOptions().opt_level"`) == "2"

test/testhelpers/allocation_file.jl

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
g(x) = x + 123456
2+
function f(x)
3+
[]
4+
Base.invokelatest(g, 0)
5+
Base.invokelatest(g, x)
6+
[]
7+
end
8+
f(1.23)

0 commit comments

Comments
 (0)