Skip to content

Commit

Permalink
add option for codecov and alloc tracking by path
Browse files Browse the repository at this point in the history
  • Loading branch information
IanButterworth committed Feb 26, 2022
1 parent 5ac0020 commit 642a644
Show file tree
Hide file tree
Showing 7 changed files with 76 additions and 16 deletions.
1 change: 1 addition & 0 deletions base/options.jl
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ struct JLOptions
compile_enabled::Int8
code_coverage::Int8
malloc_log::Int8
tracked_path::Ptr{UInt8}
opt_level::Int8
opt_level_min::Int8
debug_level::Int8
Expand Down
4 changes: 4 additions & 0 deletions base/util.jl
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,8 @@ function julia_cmd(julia=joinpath(Sys.BINDIR, julia_exename()))
push!(addflags, "--code-coverage=user")
elseif opts.code_coverage == 2
push!(addflags, "--code-coverage=all")
elseif opts.code_coverage == 3
push!(addflags, "--code-coverage=@$(opts.tracked_path)")
end
isempty(coverage_file) || push!(addflags, "--code-coverage=$coverage_file")
end
Expand All @@ -204,6 +206,8 @@ function julia_cmd(julia=joinpath(Sys.BINDIR, julia_exename()))
push!(addflags, "--track-allocation=user")
elseif opts.malloc_log == 2
push!(addflags, "--track-allocation=all")
elseif opts.malloc_log == 3
push!(addflags, "--track-allocation=@$(opts.tracked_path)")
end
if opts.color == 1
push!(addflags, "--color=yes")
Expand Down
41 changes: 26 additions & 15 deletions src/codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6977,15 +6977,20 @@ static std::pair<std::unique_ptr<Module>, jl_llvm_functions_t>
return (!jl_is_submodule(mod, jl_base_module) &&
!jl_is_submodule(mod, jl_core_module));
};
auto in_tracked_path = [] (StringRef file) {
return (jl_options.tracked_path != NULL && file.rfind(jl_options.tracked_path) == 0);
};
bool mod_is_user_mod = in_user_mod(ctx.module);
bool mod_is_tracked = in_tracked_path(ctx.file);
struct DebugLineTable {
DebugLoc loc;
StringRef file;
ssize_t line;
bool is_user_code;
bool is_tracked; // If file falls within an explicitly set directory
unsigned inlined_at;
bool operator ==(const DebugLineTable &other) const {
return other.loc == loc && other.file == file && other.line == line && other.is_user_code == is_user_code && other.inlined_at == inlined_at;
return other.loc == loc && other.file == file && other.line == line && other.is_user_code == is_user_code && other.is_tracked == is_tracked && other.inlined_at == inlined_at;
}
};
std::vector<DebugLineTable> linetable;
Expand All @@ -6998,6 +7003,7 @@ static std::pair<std::unique_ptr<Module>, jl_llvm_functions_t>
topinfo.file = ctx.file;
topinfo.line = toplineno;
topinfo.is_user_code = mod_is_user_mod;
topinfo.is_tracked = mod_is_tracked;
topinfo.inlined_at = 0;
topinfo.loc = topdebugloc;
for (size_t i = 0; i < nlocs; i++) {
Expand All @@ -7011,13 +7017,16 @@ static std::pair<std::unique_ptr<Module>, jl_llvm_functions_t>
info.line = jl_unbox_long(jl_fieldref(locinfo, 3));
info.inlined_at = jl_unbox_long(jl_fieldref(locinfo, 4));
assert(info.inlined_at <= i);
if (module == ctx.module)
info.is_user_code = mod_is_user_mod;
else
info.is_user_code = in_user_mod(module);
info.file = jl_symbol_name(filesym);
if (info.file.empty())
info.file = "<missing>";
if (module == ctx.module) {
info.is_user_code = mod_is_user_mod;
info.is_tracked = mod_is_tracked;
} else {
info.is_user_code = in_user_mod(module);
info.is_tracked = in_tracked_path(info.file);
}
if (ctx.debug_enabled) {
StringRef fname;
if (jl_is_method_instance(method))
Expand Down Expand Up @@ -7131,13 +7140,15 @@ static std::pair<std::unique_ptr<Module>, jl_llvm_functions_t>
cursor = -1;
};

auto do_coverage = [&] (bool in_user_code) {
auto do_coverage = [&] (bool in_user_code, bool is_tracked) {
return (coverage_mode == JL_LOG_ALL ||
(coverage_mode == JL_LOG_USER && in_user_code));
(in_user_code && coverage_mode == JL_LOG_USER) ||
(is_tracked && coverage_mode == JL_LOG_PATH));
};
auto do_malloc_log = [&] (bool in_user_code) {
auto do_malloc_log = [&] (bool in_user_code, bool is_tracked) {
return (malloc_log_mode == JL_LOG_ALL ||
(malloc_log_mode == JL_LOG_USER && in_user_code));
(in_user_code && malloc_log_mode == JL_LOG_USER) ||
(is_tracked && malloc_log_mode == JL_LOG_PATH));
};
std::vector<unsigned> current_lineinfo, new_lineinfo;
auto coverageVisitStmt = [&] (size_t dbg) {
Expand All @@ -7156,15 +7167,15 @@ static std::pair<std::unique_ptr<Module>, jl_llvm_functions_t>
if (newdbg != current_lineinfo[dbg]) {
current_lineinfo[dbg] = newdbg;
const auto &info = linetable.at(newdbg);
if (do_coverage(info.is_user_code))
if (do_coverage(info.is_user_code, info.is_tracked))
coverageVisitLine(ctx, info.file, info.line);
}
}
new_lineinfo.clear();
};
auto mallocVisitStmt = [&] (unsigned dbg, Value *sync) {
if (!do_malloc_log(mod_is_user_mod) || dbg == 0) {
if (do_malloc_log(true) && sync)
if (!do_malloc_log(mod_is_user_mod, mod_is_tracked) || dbg == 0) {
if (do_malloc_log(true, mod_is_tracked) && sync)
ctx.builder.CreateCall(prepare_call(sync_gc_total_bytes_func), {sync});
return;
}
Expand All @@ -7175,7 +7186,7 @@ static std::pair<std::unique_ptr<Module>, jl_llvm_functions_t>
if (coverage_mode != JL_LOG_NONE) {
// record all lines that could be covered
for (const auto &info : linetable)
if (do_coverage(info.is_user_code))
if (do_coverage(info.is_user_code, info.is_tracked))
jl_coverage_alloc_line(info.file, info.line);
}

Expand Down Expand Up @@ -7230,15 +7241,15 @@ static std::pair<std::unique_ptr<Module>, jl_llvm_functions_t>
}

Value *sync_bytes = nullptr;
if (do_malloc_log(true))
if (do_malloc_log(true, mod_is_tracked))
sync_bytes = ctx.builder.CreateCall(prepare_call(diff_gc_total_bytes_func), {});
{ // coverage for the function definition line number
const auto &topinfo = linetable.at(0);
if (linetable.size() > 1) {
if (topinfo == linetable.at(1))
current_lineinfo.push_back(1);
}
if (do_coverage(topinfo.is_user_code))
if (do_coverage(topinfo.is_user_code, topinfo.is_tracked))
coverageVisitLine(ctx, topinfo.file, topinfo.line);
}

Expand Down
13 changes: 13 additions & 0 deletions src/jloptions.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ JL_DLLEXPORT void jl_init_options(void)
JL_OPTIONS_COMPILE_DEFAULT, // compile_enabled
0, // code_coverage
0, // malloc_log
NULL, // tracked_path
2, // opt_level
0, // opt_level_min
#ifdef JL_DEBUG_BUILD
Expand Down Expand Up @@ -154,11 +155,15 @@ static const char opts[] =
// instrumentation options
" --code-coverage[={none*|user|all}]\n"
" Count executions of source lines (omitting setting is equivalent to `user`)\n"
" --code-coverage@/abspath\n"
" Count executions but only in files that fall under the given absolute file path/directory\n"
" --code-coverage=tracefile.info\n"
" Append coverage information to the LCOV tracefile (filename supports format tokens)\n"
// TODO: These TOKENS are defined in `runtime_ccall.cpp`. A more verbose `--help` should include that list here.
" --track-allocation[={none*|user|all}]\n"
" Count bytes allocated by each source line (omitting setting is equivalent to `user`)\n"
" --track-allocation@/abspath\n"
" Count bytes but only in files that fall under the given absolute file path/directory\n"
" --bug-report=KIND Launch a bug report session. It can be used to start a REPL, run a script, or evaluate\n"
" expressions. It first tries to use BugReporting.jl installed in current environment and\n"
" fallbacks to the latest compatible BugReporting.jl if not. For more information, see\n"
Expand Down Expand Up @@ -520,6 +525,10 @@ JL_DLLEXPORT void jl_parse_opts(int *argcp, char ***argvp)
codecov = JL_LOG_ALL;
jl_options.output_code_coverage = optarg;
}
else if (!strncmp(optarg, "@", 1)) {
codecov = JL_LOG_PATH;
jl_options.tracked_path = memmove(optarg, optarg+1, strlen(optarg)); // remove `@`
}
else
jl_errorf("julia: invalid argument to --code-coverage (%s)", optarg);
break;
Expand All @@ -536,6 +545,10 @@ JL_DLLEXPORT void jl_parse_opts(int *argcp, char ***argvp)
malloclog = JL_LOG_ALL;
else if (!strcmp(optarg,"none"))
malloclog = JL_LOG_NONE;
else if (!strncmp(optarg, "@", 1)) {
malloclog = JL_LOG_PATH;
jl_options.tracked_path = memmove(optarg, optarg+1, strlen(optarg)); // remove `@`
}
else
jl_errorf("julia: invalid argument to --track-allocation (%s)", optarg);
break;
Expand Down
1 change: 1 addition & 0 deletions src/jloptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ typedef struct {
int8_t compile_enabled;
int8_t code_coverage;
int8_t malloc_log;
const char *tracked_path;
int8_t opt_level;
int8_t opt_level_min;
int8_t debug_level;
Expand Down
1 change: 1 addition & 0 deletions src/julia.h
Original file line number Diff line number Diff line change
Expand Up @@ -2075,6 +2075,7 @@ JL_DLLEXPORT int jl_generating_output(void) JL_NOTSAFEPOINT;
#define JL_LOG_NONE 0
#define JL_LOG_USER 1
#define JL_LOG_ALL 2
#define JL_LOG_PATH 3

#define JL_OPTIONS_CHECK_BOUNDS_DEFAULT 0
#define JL_OPTIONS_CHECK_BOUNDS_ON 1
Expand Down
31 changes: 30 additions & 1 deletion test/cmdlineargs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -326,8 +326,37 @@ let exename = `$(Base.julia_cmd()) --startup-file=no --color=no`
rm(covfile)
@test occursin(expected, got) || (expected, got)
@test_broken occursin(expected_good, got)
end

# Ask for coverage in specific file
tfile = realpath(inputfile)
@test readchomp(`$exename -E "(Base.JLOptions().code_coverage, unsafe_string(Base.JLOptions().tracked_path))" -L $inputfile
--code-coverage=$covfile --code-coverage=@$tfile`) == "(3, $(repr(tfile)))"
@test isfile(covfile)
got = read(covfile, String)
rm(covfile)
@test occursin(expected, got) || (expected, got)
@test_broken occursin(expected_good, got)

# Ask for coverage in directory
tdir = dirname(realpath(inputfile))
@test readchomp(`$exename -E "(Base.JLOptions().code_coverage, unsafe_string(Base.JLOptions().tracked_path))" -L $inputfile
--code-coverage=$covfile --code-coverage=@$tdir`) == "(3, $(repr(tdir)))"
@test isfile(covfile)
got = read(covfile, String)
rm(covfile)
@test occursin(expected, got) || (expected, got)
@test_broken occursin(expected_good, got)

# Ask for coverage in a different directory
tdir = mktempdir() # a dir that contains no code
@test readchomp(`$exename -E "(Base.JLOptions().code_coverage, unsafe_string(Base.JLOptions().tracked_path))" -L $inputfile
--code-coverage=$covfile --code-coverage=@$tdir`) == "(3, $(repr(tdir)))"
@test isfile(covfile)
got = read(covfile, String)
@test isempty(got)
rm(covfile)
end
error("done")
# --track-allocation
@test readchomp(`$exename -E "Base.JLOptions().malloc_log != 0"`) == "false"
@test readchomp(`$exename -E "Base.JLOptions().malloc_log != 0" --track-allocation=none`) == "false"
Expand Down

0 comments on commit 642a644

Please sign in to comment.