Skip to content

Commit a60de70

Browse files
committed
Merge pull request #7464 from JuliaLang/teh/malloclog
More instrumentation (memory allocation, also fixes #7259)
2 parents b43b391 + 196dfbc commit a60de70

File tree

8 files changed

+176
-23
lines changed

8 files changed

+176
-23
lines changed

base/exports.jl

+1
Original file line numberDiff line numberDiff line change
@@ -1072,6 +1072,7 @@ export
10721072
gc_disable,
10731073
gc_enable,
10741074
precompile,
1075+
clear_malloc_data,
10751076

10761077
# misc
10771078
atexit,

base/util.jl

+3
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ gc_time_ns() = ccall(:jl_gc_total_hrtime, Uint64, ())
1212
# total number of bytes allocated so far
1313
gc_bytes() = ccall(:jl_gc_total_bytes, Int64, ())
1414

15+
# reset the malloc log. Used to avoid counting memory allocated during compilation.
16+
clear_malloc_data() = ccall(:jl_clear_malloc_data, Void, ())
17+
1518
function tic()
1619
t0 = time_ns()
1720
task_local_storage(:TIMERS, (t0, get(task_local_storage(), :TIMERS, ())))

src/codegen.cpp

+33-4
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,8 @@ static Function *jlgetnthfieldchecked_func;
322322
#ifdef _OS_WINDOWS_
323323
static Function *resetstkoflw_func;
324324
#endif
325+
static Function *diff_gc_total_bytes_func;
326+
static Function *show_execution_point_func;
325327

326328
// --- code generation ---
327329

@@ -3367,8 +3369,9 @@ static Function *emit_function(jl_lambda_info_t *lam, bool cstyle)
33673369
ctx.f = f;
33683370

33693371
// step 5. set up debug info context and create first basic block
3370-
bool do_coverage =
3371-
jl_compileropts.code_coverage && lam->module != jl_base_module && lam->module != jl_core_module;
3372+
bool in_user_code = lam->module != jl_base_module && lam->module != jl_core_module;
3373+
bool do_coverage = jl_compileropts.code_coverage == JL_LOG_ALL || (jl_compileropts.code_coverage == JL_LOG_USER && in_user_code);
3374+
bool do_malloc_log = jl_compileropts.malloc_log == JL_LOG_ALL || (jl_compileropts.malloc_log == JL_LOG_USER && in_user_code);
33723375
jl_value_t *stmt = jl_cellref(stmts,0);
33733376
std::string filename = "no file";
33743377
char *dbgFuncName = lam->name->name;
@@ -3414,6 +3417,7 @@ static Function *emit_function(jl_lambda_info_t *lam, bool cstyle)
34143417
builder.SetCurrentDebugLocation(noDbg);
34153418
debug_enabled = false;
34163419
do_coverage = false;
3420+
do_malloc_log = false;
34173421
}
34183422
else {
34193423
// TODO: Fix when moving to new LLVM version
@@ -3716,18 +3720,20 @@ static Function *emit_function(jl_lambda_info_t *lam, bool cstyle)
37163720

37173721
// step 15. compile body statements
37183722
bool prevlabel = false;
3723+
lno = -1;
3724+
int prevlno = -1;
37193725
for(i=0; i < stmtslen; i++) {
37203726
jl_value_t *stmt = jl_cellref(stmts,i);
37213727
if (jl_is_linenode(stmt)) {
3722-
int lno = jl_linenode_line(stmt);
3728+
lno = jl_linenode_line(stmt);
37233729
if (debug_enabled)
37243730
builder.SetCurrentDebugLocation(DebugLoc::get(lno, 1, (MDNode*)SP, NULL));
37253731
if (do_coverage)
37263732
coverageVisitLine(filename, lno);
37273733
ctx.lineno = lno;
37283734
}
37293735
else if (jl_is_expr(stmt) && ((jl_expr_t*)stmt)->head == line_sym) {
3730-
int lno = jl_unbox_long(jl_exprarg(stmt, 0));
3736+
lno = jl_unbox_long(jl_exprarg(stmt, 0));
37313737
if (debug_enabled)
37323738
builder.SetCurrentDebugLocation(DebugLoc::get(lno, 1, (MDNode*)SP, NULL));
37333739
if (do_coverage)
@@ -3741,6 +3747,12 @@ static Function *emit_function(jl_lambda_info_t *lam, bool cstyle)
37413747
else {
37423748
prevlabel = false;
37433749
}
3750+
if (do_malloc_log && lno != prevlno) {
3751+
// Check memory allocation only after finishing a line
3752+
if (prevlno != -1)
3753+
mallocVisitLine(filename, prevlno);
3754+
prevlno = lno;
3755+
}
37443756
if (jl_is_expr(stmt) && ((jl_expr_t*)stmt)->head == return_sym) {
37453757
jl_expr_t *ex = (jl_expr_t*)stmt;
37463758
Value *retval;
@@ -3761,6 +3773,8 @@ static Function *emit_function(jl_lambda_info_t *lam, bool cstyle)
37613773
builder.CreateStore(builder.CreateBitCast(builder.CreateLoad(gcpop, false), jl_ppvalue_llvmt),
37623774
prepare_global(jlpgcstack_var));
37633775
#endif
3776+
if (do_malloc_log && lno != -1)
3777+
mallocVisitLine(filename, lno);
37643778
if (builder.GetInsertBlock()->getTerminator() == NULL) {
37653779
if (retty == T_void)
37663780
builder.CreateRetVoid();
@@ -4254,6 +4268,21 @@ static void init_julia_llvm_env(Module *m)
42544268
"jl_get_nth_field_checked", m);
42554269
add_named_global(jlgetnthfieldchecked_func, (void*)*jl_get_nth_field_checked);
42564270

4271+
diff_gc_total_bytes_func =
4272+
Function::Create(FunctionType::get(T_int64, false),
4273+
Function::ExternalLinkage,
4274+
"diff_gc_total_bytes", m);
4275+
add_named_global(diff_gc_total_bytes_func, (void*)*diff_gc_total_bytes);
4276+
4277+
std::vector<Type *> execpoint_args(0);
4278+
execpoint_args.push_back(T_pint8);
4279+
execpoint_args.push_back(T_int32);
4280+
show_execution_point_func =
4281+
Function::Create(FunctionType::get(T_void, execpoint_args, false),
4282+
Function::ExternalLinkage,
4283+
"show_execution_point", m);
4284+
add_named_global(show_execution_point_func, (void*)*show_execution_point);
4285+
42574286
// set up optimization passes
42584287
FPM = new FunctionPassManager(m);
42594288

src/debuginfo.cpp

+80-16
Original file line numberDiff line numberDiff line change
@@ -541,14 +541,14 @@ void* CALLBACK jl_getUnwindInfo(HANDLE hProcess, ULONG64 AddrBase, ULONG64 UserC
541541

542542
// Code coverage
543543

544-
typedef std::map<std::string,std::vector<GlobalVariable*> > coveragedata_t;
545-
static coveragedata_t coverageData;
544+
typedef std::map<std::string,std::vector<GlobalVariable*> > logdata_t;
545+
static logdata_t coverageData;
546546

547547
static void coverageVisitLine(std::string filename, int line)
548548
{
549549
if (filename == "" || filename == "none" || filename == "no file")
550550
return;
551-
coveragedata_t::iterator it = coverageData.find(filename);
551+
logdata_t::iterator it = coverageData.find(filename);
552552
if (it == coverageData.end()) {
553553
coverageData[filename] = std::vector<GlobalVariable*>(0);
554554
}
@@ -564,39 +564,43 @@ static void coverageVisitLine(std::string filename, int line)
564564
v);
565565
}
566566

567-
extern "C" void jl_write_coverage_data(void)
567+
void write_log_data(logdata_t logData, const char* extension)
568568
{
569-
coveragedata_t::iterator it = coverageData.begin();
570-
for (; it != coverageData.end(); it++) {
569+
std::string base = std::string(julia_home);
570+
base = base + "/../share/julia/base/";
571+
logdata_t::iterator it = logData.begin();
572+
for (; it != logData.end(); it++) {
571573
std::string filename = (*it).first;
572-
std::string outfile = filename + ".cov";
573-
std::vector<GlobalVariable*> &counts = (*it).second;
574-
if (counts.size() > 1) {
574+
std::vector<GlobalVariable*> &values = (*it).second;
575+
if (values.size() > 1) {
576+
if (filename[0] != '/')
577+
filename = base + filename;
575578
std::ifstream inf(filename.c_str());
576579
if (inf.is_open()) {
580+
std::string outfile = filename + extension;
577581
std::ofstream outf(outfile.c_str(), std::ofstream::trunc | std::ofstream::out);
578582
char line[1024];
579583
int l = 1;
580584
while (!inf.eof()) {
581585
inf.getline(line, sizeof(line));
582586
if (inf.fail() && !inf.bad()) {
583-
// Read through lines longer than 1024
587+
// Read through lines longer than sizeof(line)
584588
inf.clear();
585589
inf.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
586590
}
587-
int count = -1;
588-
if ((size_t)l < counts.size()) {
589-
GlobalVariable *gv = counts[l];
591+
int value = -1;
592+
if ((size_t)l < values.size()) {
593+
GlobalVariable *gv = values[l];
590594
if (gv) {
591595
int *p = (int*)jl_ExecutionEngine->getPointerToGlobal(gv);
592-
count = *p;
596+
value = *p;
593597
}
594598
}
595599
outf.width(9);
596-
if (count == -1)
600+
if (value == -1)
597601
outf<<'-';
598602
else
599-
outf<<count;
603+
outf<<value;
600604
outf.width(0);
601605
outf<<" "<<line<<std::endl;
602606
l++;
@@ -607,3 +611,63 @@ extern "C" void jl_write_coverage_data(void)
607611
}
608612
}
609613
}
614+
615+
extern "C" void jl_write_coverage_data(void)
616+
{
617+
write_log_data(coverageData, ".cov");
618+
}
619+
620+
// Memory allocation log (malloc_log)
621+
622+
static logdata_t mallocData;
623+
624+
static void mallocVisitLine(std::string filename, int line)
625+
{
626+
if (filename == "" || filename == "none" || filename == "no file") {
627+
sync_gc_total_bytes();
628+
return;
629+
}
630+
logdata_t::iterator it = mallocData.find(filename);
631+
if (it == mallocData.end()) {
632+
mallocData[filename] = std::vector<GlobalVariable*>(0);
633+
}
634+
std::vector<GlobalVariable*> &vec = mallocData[filename];
635+
if (vec.size() <= (size_t)line)
636+
vec.resize(line+1, NULL);
637+
if (vec[line] == NULL)
638+
vec[line] = new GlobalVariable(*jl_Module, T_int64, false,
639+
GlobalVariable::InternalLinkage,
640+
ConstantInt::get(T_int64,0), "bytecnt");
641+
GlobalVariable *v = vec[line];
642+
builder.CreateStore(builder.CreateAdd(builder.CreateLoad(v, true),
643+
builder.CreateCall(prepare_call(diff_gc_total_bytes_func))),
644+
v, true);
645+
}
646+
647+
// Resets the malloc counts. Needed to avoid including memory usage
648+
// from JITting.
649+
extern "C" DLLEXPORT void jl_clear_malloc_data(void)
650+
{
651+
logdata_t::iterator it = mallocData.begin();
652+
for (; it != mallocData.end(); it++) {
653+
std::vector<GlobalVariable*> &bytes = (*it).second;
654+
std::vector<GlobalVariable*>::iterator itb;
655+
for (itb = bytes.begin(); itb != bytes.end(); itb++) {
656+
if (*itb) {
657+
int64_t *p = (int64_t*) jl_ExecutionEngine->getPointerToGlobal(*itb);
658+
*p = 0;
659+
}
660+
}
661+
}
662+
sync_gc_total_bytes();
663+
}
664+
665+
extern "C" void jl_write_malloc_log(void)
666+
{
667+
write_log_data(mallocData, ".mlc");
668+
}
669+
670+
void show_execution_point(char *filename, int lno)
671+
{
672+
jl_printf(JL_STDOUT, "executing file %s, line %d\n", filename, lno);
673+
}

src/gc.c

+10
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ typedef struct _bigval_t {
8080
// GC knobs and self-measurement variables
8181
static size_t allocd_bytes = 0;
8282
static int64_t total_allocd_bytes = 0;
83+
static int64_t last_gc_total_bytes = 0;
8384
static size_t freed_bytes = 0;
8485
static uint64_t total_gc_time=0;
8586
#ifdef _P64
@@ -917,6 +918,15 @@ DLLEXPORT int jl_gc_is_enabled(void) { return is_gc_enabled; }
917918
DLLEXPORT int64_t jl_gc_total_bytes(void) { return total_allocd_bytes + allocd_bytes; }
918919
DLLEXPORT uint64_t jl_gc_total_hrtime(void) { return total_gc_time; }
919920

921+
int64_t diff_gc_total_bytes(void)
922+
{
923+
int64_t oldtb = last_gc_total_bytes;
924+
int64_t newtb = jl_gc_total_bytes();
925+
last_gc_total_bytes = newtb;
926+
return newtb - oldtb;
927+
}
928+
void sync_gc_total_bytes(void) {last_gc_total_bytes = jl_gc_total_bytes();}
929+
920930
void jl_gc_ephemeral_on(void) { pools = &ephe_pools[0]; }
921931
void jl_gc_ephemeral_off(void) { pools = &norm_pools[0]; }
922932

src/init.c

+4
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ extern BOOL (WINAPI *hSymRefreshModuleList)(HANDLE);
6767
char *julia_home = NULL;
6868
jl_compileropts_t jl_compileropts = { NULL, // build_path
6969
0, // code_coverage
70+
0, // malloc_log
7071
JL_COMPILEROPT_CHECK_BOUNDS_DEFAULT,
7172
0 // int32_literals
7273
};
@@ -378,6 +379,7 @@ static void jl_uv_exitcleanup_walk(uv_handle_t* handle, void *arg)
378379
}
379380

380381
void jl_write_coverage_data(void);
382+
void jl_write_malloc_log(void);
381383

382384
DLLEXPORT void uv_atexit_hook()
383385
{
@@ -386,6 +388,8 @@ DLLEXPORT void uv_atexit_hook()
386388
#endif
387389
if (jl_compileropts.code_coverage)
388390
jl_write_coverage_data();
391+
if (jl_compileropts.malloc_log)
392+
jl_write_malloc_log();
389393
if (jl_base_module) {
390394
jl_value_t *f = jl_get_global(jl_base_module, jl_symbol("_atexit"));
391395
if (f!=NULL && jl_is_function(f)) {

src/julia.h

+13
Original file line numberDiff line numberDiff line change
@@ -1054,6 +1054,8 @@ DLLEXPORT void jl_gc_disable(void);
10541054
DLLEXPORT int jl_gc_is_enabled(void);
10551055
DLLEXPORT int64_t jl_gc_total_bytes(void);
10561056
DLLEXPORT uint64_t jl_gc_total_hrtime(void);
1057+
int64_t diff_gc_total_bytes(void);
1058+
void sync_gc_total_bytes(void);
10571059
void jl_gc_ephemeral_on(void);
10581060
void jl_gc_ephemeral_off(void);
10591061
DLLEXPORT void jl_gc_collect(void);
@@ -1073,6 +1075,8 @@ DLLEXPORT void *alloc_4w(void);
10731075
void *allocb(size_t sz);
10741076
DLLEXPORT void *allocobj(size_t sz);
10751077

1078+
DLLEXPORT void jl_clear_malloc_data(void);
1079+
10761080
#else
10771081

10781082
#define JL_GC_PUSH(...) ;
@@ -1308,17 +1312,26 @@ DLLEXPORT size_t jl_static_show(JL_STREAM *out, jl_value_t *v);
13081312
void jl_print_gc_stats(JL_STREAM *s);
13091313
#endif
13101314

1315+
// debugging
1316+
void show_execution_point(char *filename, int lno);
1317+
13111318
// compiler options -----------------------------------------------------------
13121319

13131320
typedef struct {
13141321
char *build_path;
13151322
int8_t code_coverage;
1323+
int8_t malloc_log;
13161324
int8_t check_bounds;
13171325
int int_literals;
13181326
} jl_compileropts_t;
13191327

13201328
extern DLLEXPORT jl_compileropts_t jl_compileropts;
13211329

1330+
// Settings for code_coverage and mallog_log
1331+
#define JL_LOG_NONE 0
1332+
#define JL_LOG_USER 1
1333+
#define JL_LOG_ALL 2
1334+
13221335
#define JL_COMPILEROPT_CHECK_BOUNDS_DEFAULT 0
13231336
#define JL_COMPILEROPT_CHECK_BOUNDS_ON 1
13241337
#define JL_COMPILEROPT_CHECK_BOUNDS_OFF 2

0 commit comments

Comments
 (0)