Skip to content

Commit 166b829

Browse files
Add option for codecov and allocation tracking to be restricted by path (#44359)
1 parent 694110d commit 166b829

File tree

10 files changed

+113
-14
lines changed

10 files changed

+113
-14
lines changed

base/options.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ struct JLOptions
2020
compile_enabled::Int8
2121
code_coverage::Int8
2222
malloc_log::Int8
23+
tracked_path::Ptr{UInt8}
2324
opt_level::Int8
2425
opt_level_min::Int8
2526
debug_level::Int8

base/util.jl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,8 @@ function julia_cmd(julia=joinpath(Sys.BINDIR, julia_exename()))
196196
push!(addflags, "--code-coverage=user")
197197
elseif opts.code_coverage == 2
198198
push!(addflags, "--code-coverage=all")
199+
elseif opts.code_coverage == 3
200+
push!(addflags, "--code-coverage=@$(unsafe_string(opts.tracked_path))")
199201
end
200202
isempty(coverage_file) || push!(addflags, "--code-coverage=$coverage_file")
201203
end
@@ -204,6 +206,8 @@ function julia_cmd(julia=joinpath(Sys.BINDIR, julia_exename()))
204206
push!(addflags, "--track-allocation=user")
205207
elseif opts.malloc_log == 2
206208
push!(addflags, "--track-allocation=all")
209+
elseif opts.malloc_log == 3
210+
push!(addflags, "--track-allocation=@$(unsafe_string(opts.tracked_path))")
207211
end
208212
if opts.color == 1
209213
push!(addflags, "--color=yes")

doc/man/julia.1

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,11 @@ Disallow or enable unsafe floating point optimizations (overrides @fastmath decl
191191
--code-coverage[={none*|user|all}]
192192
Count executions of source lines (omitting setting is equivalent to `user`)
193193

194+
.TP
195+
--code-coverage=@<path>
196+
Count executions of source lines in a file or files under a given directory. A `@` must
197+
be placed before the path to indicate this option. A `@` with no path will track the current directory.
198+
194199
.TP
195200
--code-coverage=tracefile.info
196201
Append coverage information to the LCOV tracefile (filename supports format tokens)
@@ -199,6 +204,11 @@ Count executions of source lines (omitting setting is equivalent to `user`)
199204
--track-allocation[={none*|user|all}]
200205
Count bytes allocated by each source line (omitting setting is equivalent to `user`)
201206

207+
.TP
208+
--track-allocation=@<path>
209+
Count bytes allocated by each source line in a file or files under a given directory. A `@`
210+
must be placed before the path to indicate this option. A `@` with no path will track the current directory.
211+
202212
.TP
203213
--bug-report=KIND
204214
Launch a bug report session. It can be used to start a REPL, run a script, or evaluate

src/codegen.cpp

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6976,15 +6976,20 @@ static std::pair<std::unique_ptr<Module>, jl_llvm_functions_t>
69766976
return (!jl_is_submodule(mod, jl_base_module) &&
69776977
!jl_is_submodule(mod, jl_core_module));
69786978
};
6979+
auto in_tracked_path = [] (StringRef file) {
6980+
return jl_options.tracked_path != NULL && file.startswith(jl_options.tracked_path);
6981+
};
69796982
bool mod_is_user_mod = in_user_mod(ctx.module);
6983+
bool mod_is_tracked = in_tracked_path(ctx.file);
69806984
struct DebugLineTable {
69816985
DebugLoc loc;
69826986
StringRef file;
69836987
ssize_t line;
69846988
bool is_user_code;
6989+
bool is_tracked; // falls within an explicitly set file or directory
69856990
unsigned inlined_at;
69866991
bool operator ==(const DebugLineTable &other) const {
6987-
return other.loc == loc && other.file == file && other.line == line && other.is_user_code == is_user_code && other.inlined_at == inlined_at;
6992+
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;
69886993
}
69896994
};
69906995
std::vector<DebugLineTable> linetable;
@@ -6997,6 +7002,7 @@ static std::pair<std::unique_ptr<Module>, jl_llvm_functions_t>
69977002
topinfo.file = ctx.file;
69987003
topinfo.line = toplineno;
69997004
topinfo.is_user_code = mod_is_user_mod;
7005+
topinfo.is_tracked = mod_is_tracked;
70007006
topinfo.inlined_at = 0;
70017007
topinfo.loc = topdebugloc;
70027008
for (size_t i = 0; i < nlocs; i++) {
@@ -7010,13 +7016,14 @@ static std::pair<std::unique_ptr<Module>, jl_llvm_functions_t>
70107016
info.line = jl_unbox_long(jl_fieldref(locinfo, 3));
70117017
info.inlined_at = jl_unbox_long(jl_fieldref(locinfo, 4));
70127018
assert(info.inlined_at <= i);
7019+
info.file = jl_symbol_name(filesym);
7020+
if (info.file.empty())
7021+
info.file = "<missing>";
70137022
if (module == ctx.module)
70147023
info.is_user_code = mod_is_user_mod;
70157024
else
70167025
info.is_user_code = in_user_mod(module);
7017-
info.file = jl_symbol_name(filesym);
7018-
if (info.file.empty())
7019-
info.file = "<missing>";
7026+
info.is_tracked = in_tracked_path(info.file);
70207027
if (ctx.debug_enabled) {
70217028
StringRef fname;
70227029
if (jl_is_method_instance(method))
@@ -7130,13 +7137,15 @@ static std::pair<std::unique_ptr<Module>, jl_llvm_functions_t>
71307137
cursor = -1;
71317138
};
71327139

7133-
auto do_coverage = [&] (bool in_user_code) {
7140+
auto do_coverage = [&] (bool in_user_code, bool is_tracked) {
71347141
return (coverage_mode == JL_LOG_ALL ||
7135-
(coverage_mode == JL_LOG_USER && in_user_code));
7142+
(in_user_code && coverage_mode == JL_LOG_USER) ||
7143+
(is_tracked && coverage_mode == JL_LOG_PATH));
71367144
};
7137-
auto do_malloc_log = [&] (bool in_user_code) {
7145+
auto do_malloc_log = [&] (bool in_user_code, bool is_tracked) {
71387146
return (malloc_log_mode == JL_LOG_ALL ||
7139-
(malloc_log_mode == JL_LOG_USER && in_user_code));
7147+
(in_user_code && malloc_log_mode == JL_LOG_USER) ||
7148+
(is_tracked && malloc_log_mode == JL_LOG_PATH));
71407149
};
71417150
std::vector<unsigned> current_lineinfo, new_lineinfo;
71427151
auto coverageVisitStmt = [&] (size_t dbg) {
@@ -7155,15 +7164,15 @@ static std::pair<std::unique_ptr<Module>, jl_llvm_functions_t>
71557164
if (newdbg != current_lineinfo[dbg]) {
71567165
current_lineinfo[dbg] = newdbg;
71577166
const auto &info = linetable.at(newdbg);
7158-
if (do_coverage(info.is_user_code))
7167+
if (do_coverage(info.is_user_code, info.is_tracked))
71597168
coverageVisitLine(ctx, info.file, info.line);
71607169
}
71617170
}
71627171
new_lineinfo.clear();
71637172
};
71647173
auto mallocVisitStmt = [&] (unsigned dbg, Value *sync) {
7165-
if (!do_malloc_log(mod_is_user_mod) || dbg == 0) {
7166-
if (do_malloc_log(true) && sync)
7174+
if (!do_malloc_log(mod_is_user_mod, mod_is_tracked) || dbg == 0) {
7175+
if (do_malloc_log(true, mod_is_tracked) && sync)
71677176
ctx.builder.CreateCall(prepare_call(sync_gc_total_bytes_func), {sync});
71687177
return;
71697178
}
@@ -7174,7 +7183,7 @@ static std::pair<std::unique_ptr<Module>, jl_llvm_functions_t>
71747183
if (coverage_mode != JL_LOG_NONE) {
71757184
// record all lines that could be covered
71767185
for (const auto &info : linetable)
7177-
if (do_coverage(info.is_user_code))
7186+
if (do_coverage(info.is_user_code, info.is_tracked))
71787187
jl_coverage_alloc_line(info.file, info.line);
71797188
}
71807189

@@ -7229,15 +7238,15 @@ static std::pair<std::unique_ptr<Module>, jl_llvm_functions_t>
72297238
}
72307239

72317240
Value *sync_bytes = nullptr;
7232-
if (do_malloc_log(true))
7241+
if (do_malloc_log(true, mod_is_tracked))
72337242
sync_bytes = ctx.builder.CreateCall(prepare_call(diff_gc_total_bytes_func), {});
72347243
{ // coverage for the function definition line number
72357244
const auto &topinfo = linetable.at(0);
72367245
if (linetable.size() > 1) {
72377246
if (topinfo == linetable.at(1))
72387247
current_lineinfo.push_back(1);
72397248
}
7240-
if (do_coverage(topinfo.is_user_code))
7249+
if (do_coverage(topinfo.is_user_code, topinfo.is_tracked))
72417250
coverageVisitLine(ctx, topinfo.file, topinfo.line);
72427251
}
72437252

src/init.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -583,6 +583,8 @@ static void jl_resolve_sysimg_location(JL_IMAGE_SEARCH rel)
583583
jl_options.machine_file = abspath(jl_options.machine_file, 0);
584584
if (jl_options.output_code_coverage)
585585
jl_options.output_code_coverage = absformat(jl_options.output_code_coverage);
586+
if (jl_options.tracked_path)
587+
jl_options.tracked_path = absformat(jl_options.tracked_path);
586588

587589
const char **cmdp = jl_options.cmds;
588590
if (cmdp) {

src/jloptions.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ JL_DLLEXPORT void jl_init_options(void)
4949
JL_OPTIONS_COMPILE_DEFAULT, // compile_enabled
5050
0, // code_coverage
5151
0, // malloc_log
52+
NULL, // tracked_path
5253
2, // opt_level
5354
0, // opt_level_min
5455
#ifdef JL_DEBUG_BUILD
@@ -154,11 +155,20 @@ static const char opts[] =
154155
// instrumentation options
155156
" --code-coverage[={none*|user|all}]\n"
156157
" Count executions of source lines (omitting setting is equivalent to `user`)\n"
158+
" --code-coverage=@<path>\n"
159+
" Count executions but only in files that fall under the given file path/directory.\n"
160+
" The `@` prefix is required to select this option. A `@` with no path will track the\n"
161+
" current directory.\n"
162+
157163
" --code-coverage=tracefile.info\n"
158164
" Append coverage information to the LCOV tracefile (filename supports format tokens)\n"
159165
// TODO: These TOKENS are defined in `runtime_ccall.cpp`. A more verbose `--help` should include that list here.
160166
" --track-allocation[={none*|user|all}]\n"
161167
" Count bytes allocated by each source line (omitting setting is equivalent to `user`)\n"
168+
" --track-allocation=@<path>\n"
169+
" Count bytes but only in files that fall under the given file path/directory.\n"
170+
" The `@` prefix is required to select this option. A `@` with no path will track the\n"
171+
" current directory.\n"
162172
" --bug-report=KIND Launch a bug report session. It can be used to start a REPL, run a script, or evaluate\n"
163173
" expressions. It first tries to use BugReporting.jl installed in current environment and\n"
164174
" fallbacks to the latest compatible BugReporting.jl if not. For more information, see\n"
@@ -520,6 +530,10 @@ JL_DLLEXPORT void jl_parse_opts(int *argcp, char ***argvp)
520530
codecov = JL_LOG_ALL;
521531
jl_options.output_code_coverage = optarg;
522532
}
533+
else if (!strncmp(optarg, "@", 1)) {
534+
codecov = JL_LOG_PATH;
535+
jl_options.tracked_path = optarg + 1; // skip `@`
536+
}
523537
else
524538
jl_errorf("julia: invalid argument to --code-coverage (%s)", optarg);
525539
break;
@@ -536,6 +550,10 @@ JL_DLLEXPORT void jl_parse_opts(int *argcp, char ***argvp)
536550
malloclog = JL_LOG_ALL;
537551
else if (!strcmp(optarg,"none"))
538552
malloclog = JL_LOG_NONE;
553+
else if (!strncmp(optarg, "@", 1)) {
554+
malloclog = JL_LOG_PATH;
555+
jl_options.tracked_path = optarg + 1; // skip `@`
556+
}
539557
else
540558
jl_errorf("julia: invalid argument to --track-allocation (%s)", optarg);
541559
break;

src/jloptions.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ typedef struct {
2424
int8_t compile_enabled;
2525
int8_t code_coverage;
2626
int8_t malloc_log;
27+
const char *tracked_path;
2728
int8_t opt_level;
2829
int8_t opt_level_min;
2930
int8_t debug_level;

src/julia.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2075,6 +2075,7 @@ JL_DLLEXPORT int jl_generating_output(void) JL_NOTSAFEPOINT;
20752075
#define JL_LOG_NONE 0
20762076
#define JL_LOG_USER 1
20772077
#define JL_LOG_ALL 2
2078+
#define JL_LOG_PATH 3
20782079

20792080
#define JL_OPTIONS_CHECK_BOUNDS_DEFAULT 0
20802081
#define JL_OPTIONS_CHECK_BOUNDS_ON 1

test/cmdlineargs.jl

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,39 @@ let exename = `$(Base.julia_cmd()) --startup-file=no --color=no`
326326
rm(covfile)
327327
@test occursin(expected, got) || (expected, got)
328328
@test_broken occursin(expected_good, got)
329+
330+
# Ask for coverage in specific file
331+
# TODO: Figure out why asking for a specific file/dir means some lines are under-counted
332+
# NOTE that a different expected reference is loaded here
333+
expected = replace(read(joinpath(helperdir, "coverage_file.info.bad2"), String),
334+
"<FILENAME>" => realpath(inputfile))
335+
tfile = realpath(inputfile)
336+
@test readchomp(`$exename -E "(Base.JLOptions().code_coverage, unsafe_string(Base.JLOptions().tracked_path))" -L $inputfile
337+
--code-coverage=$covfile --code-coverage=@$tfile`) == "(3, $(repr(tfile)))"
338+
@test isfile(covfile)
339+
got = read(covfile, String)
340+
rm(covfile)
341+
@test occursin(expected, got) || (expected, got)
342+
@test_broken occursin(expected_good, got)
343+
344+
# Ask for coverage in directory
345+
tdir = dirname(realpath(inputfile))
346+
@test readchomp(`$exename -E "(Base.JLOptions().code_coverage, unsafe_string(Base.JLOptions().tracked_path))" -L $inputfile
347+
--code-coverage=$covfile --code-coverage=@$tdir`) == "(3, $(repr(tdir)))"
348+
@test isfile(covfile)
349+
got = read(covfile, String)
350+
rm(covfile)
351+
@test occursin(expected, got) || (expected, got)
352+
@test_broken occursin(expected_good, got)
353+
354+
# Ask for coverage in a different directory
355+
tdir = mktempdir() # a dir that contains no code
356+
@test readchomp(`$exename -E "(Base.JLOptions().code_coverage, unsafe_string(Base.JLOptions().tracked_path))" -L $inputfile
357+
--code-coverage=$covfile --code-coverage=@$tdir`) == "(3, $(repr(tdir)))"
358+
@test isfile(covfile)
359+
got = read(covfile, String)
360+
@test isempty(got)
361+
rm(covfile)
329362
end
330363

331364
# --track-allocation
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
SF:<FILENAME>
2+
DA:3,1
3+
DA:4,1
4+
DA:5,0
5+
DA:7,1
6+
DA:8,1
7+
DA:9,3
8+
DA:10,5
9+
DA:11,0
10+
DA:12,1
11+
DA:14,0
12+
DA:17,1
13+
DA:18,0
14+
DA:19,0
15+
DA:20,0
16+
DA:22,1
17+
DA:1234,0
18+
LH:9
19+
LF:16
20+
end_of_record

0 commit comments

Comments
 (0)