Skip to content

Commit bedccaf

Browse files
Add option for codecov and allocation tracking to be restricted by path (#44359)
(cherry picked from commit 166b829)
1 parent 901ad02 commit bedccaf

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
@@ -185,6 +185,11 @@ Disallow or enable unsafe floating point optimizations (overrides @fastmath decl
185185
--code-coverage[={none*|user|all}]
186186
Count executions of source lines (omitting setting is equivalent to `user`)
187187

188+
.TP
189+
--code-coverage=@<path>
190+
Count executions of source lines in a file or files under a given directory. A `@` must
191+
be placed before the path to indicate this option. A `@` with no path will track the current directory.
192+
188193
.TP
189194
--code-coverage=tracefile.info
190195
Append coverage information to the LCOV tracefile (filename supports format tokens)
@@ -193,6 +198,11 @@ Count executions of source lines (omitting setting is equivalent to `user`)
193198
--track-allocation[={none*|user|all}]
194199
Count bytes allocated by each source line (omitting setting is equivalent to `user`)
195200

201+
.TP
202+
--track-allocation=@<path>
203+
Count bytes allocated by each source line in a file or files under a given directory. A `@`
204+
must be placed before the path to indicate this option. A `@` with no path will track the current directory.
205+
196206
.TP
197207
--bug-report=KIND
198208
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
@@ -6956,15 +6956,20 @@ static std::pair<std::unique_ptr<Module>, jl_llvm_functions_t>
69566956
return (!jl_is_submodule(mod, jl_base_module) &&
69576957
!jl_is_submodule(mod, jl_core_module));
69586958
};
6959+
auto in_tracked_path = [] (StringRef file) {
6960+
return jl_options.tracked_path != NULL && file.startswith(jl_options.tracked_path);
6961+
};
69596962
bool mod_is_user_mod = in_user_mod(ctx.module);
6963+
bool mod_is_tracked = in_tracked_path(ctx.file);
69606964
struct DebugLineTable {
69616965
DebugLoc loc;
69626966
StringRef file;
69636967
ssize_t line;
69646968
bool is_user_code;
6969+
bool is_tracked; // falls within an explicitly set file or directory
69656970
unsigned inlined_at;
69666971
bool operator ==(const DebugLineTable &other) const {
6967-
return other.loc == loc && other.file == file && other.line == line && other.is_user_code == is_user_code && other.inlined_at == inlined_at;
6972+
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;
69686973
}
69696974
};
69706975
std::vector<DebugLineTable> linetable;
@@ -6977,6 +6982,7 @@ static std::pair<std::unique_ptr<Module>, jl_llvm_functions_t>
69776982
topinfo.file = ctx.file;
69786983
topinfo.line = toplineno;
69796984
topinfo.is_user_code = mod_is_user_mod;
6985+
topinfo.is_tracked = mod_is_tracked;
69806986
topinfo.inlined_at = 0;
69816987
topinfo.loc = topdebugloc;
69826988
for (size_t i = 0; i < nlocs; i++) {
@@ -6990,13 +6996,14 @@ static std::pair<std::unique_ptr<Module>, jl_llvm_functions_t>
69906996
info.line = jl_unbox_long(jl_fieldref(locinfo, 3));
69916997
info.inlined_at = jl_unbox_long(jl_fieldref(locinfo, 4));
69926998
assert(info.inlined_at <= i);
6999+
info.file = jl_symbol_name(filesym);
7000+
if (info.file.empty())
7001+
info.file = "<missing>";
69937002
if (module == ctx.module)
69947003
info.is_user_code = mod_is_user_mod;
69957004
else
69967005
info.is_user_code = in_user_mod(module);
6997-
info.file = jl_symbol_name(filesym);
6998-
if (info.file.empty())
6999-
info.file = "<missing>";
7006+
info.is_tracked = in_tracked_path(info.file);
70007007
if (ctx.debug_enabled) {
70017008
StringRef fname;
70027009
if (jl_is_method_instance(method))
@@ -7110,13 +7117,15 @@ static std::pair<std::unique_ptr<Module>, jl_llvm_functions_t>
71107117
cursor = -1;
71117118
};
71127119

7113-
auto do_coverage = [&] (bool in_user_code) {
7120+
auto do_coverage = [&] (bool in_user_code, bool is_tracked) {
71147121
return (coverage_mode == JL_LOG_ALL ||
7115-
(coverage_mode == JL_LOG_USER && in_user_code));
7122+
(in_user_code && coverage_mode == JL_LOG_USER) ||
7123+
(is_tracked && coverage_mode == JL_LOG_PATH));
71167124
};
7117-
auto do_malloc_log = [&] (bool in_user_code) {
7125+
auto do_malloc_log = [&] (bool in_user_code, bool is_tracked) {
71187126
return (malloc_log_mode == JL_LOG_ALL ||
7119-
(malloc_log_mode == JL_LOG_USER && in_user_code));
7127+
(in_user_code && malloc_log_mode == JL_LOG_USER) ||
7128+
(is_tracked && malloc_log_mode == JL_LOG_PATH));
71207129
};
71217130
std::vector<unsigned> current_lineinfo, new_lineinfo;
71227131
auto coverageVisitStmt = [&] (size_t dbg) {
@@ -7135,15 +7144,15 @@ static std::pair<std::unique_ptr<Module>, jl_llvm_functions_t>
71357144
if (newdbg != current_lineinfo[dbg]) {
71367145
current_lineinfo[dbg] = newdbg;
71377146
const auto &info = linetable.at(newdbg);
7138-
if (do_coverage(info.is_user_code))
7147+
if (do_coverage(info.is_user_code, info.is_tracked))
71397148
coverageVisitLine(ctx, info.file, info.line);
71407149
}
71417150
}
71427151
new_lineinfo.clear();
71437152
};
71447153
auto mallocVisitStmt = [&] (unsigned dbg, Value *sync) {
7145-
if (!do_malloc_log(mod_is_user_mod) || dbg == 0) {
7146-
if (do_malloc_log(true) && sync)
7154+
if (!do_malloc_log(mod_is_user_mod, mod_is_tracked) || dbg == 0) {
7155+
if (do_malloc_log(true, mod_is_tracked) && sync)
71477156
ctx.builder.CreateCall(prepare_call(sync_gc_total_bytes_func), {sync});
71487157
return;
71497158
}
@@ -7154,7 +7163,7 @@ static std::pair<std::unique_ptr<Module>, jl_llvm_functions_t>
71547163
if (coverage_mode != JL_LOG_NONE) {
71557164
// record all lines that could be covered
71567165
for (const auto &info : linetable)
7157-
if (do_coverage(info.is_user_code))
7166+
if (do_coverage(info.is_user_code, info.is_tracked))
71587167
jl_coverage_alloc_line(info.file, info.line);
71597168
}
71607169

@@ -7209,15 +7218,15 @@ static std::pair<std::unique_ptr<Module>, jl_llvm_functions_t>
72097218
}
72107219

72117220
Value *sync_bytes = nullptr;
7212-
if (do_malloc_log(true))
7221+
if (do_malloc_log(true, mod_is_tracked))
72137222
sync_bytes = ctx.builder.CreateCall(prepare_call(diff_gc_total_bytes_func), {});
72147223
{ // coverage for the function definition line number
72157224
const auto &topinfo = linetable.at(0);
72167225
if (linetable.size() > 1) {
72177226
if (topinfo == linetable.at(1))
72187227
current_lineinfo.push_back(1);
72197228
}
7220-
if (do_coverage(topinfo.is_user_code))
7229+
if (do_coverage(topinfo.is_user_code, topinfo.is_tracked))
72217230
coverageVisitLine(ctx, topinfo.file, topinfo.line);
72227231
}
72237232

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
@@ -149,11 +150,20 @@ static const char opts[] =
149150
// instrumentation options
150151
" --code-coverage[={none*|user|all}]\n"
151152
" Count executions of source lines (omitting setting is equivalent to `user`)\n"
153+
" --code-coverage=@<path>\n"
154+
" Count executions but only in files that fall under the given file path/directory.\n"
155+
" The `@` prefix is required to select this option. A `@` with no path will track the\n"
156+
" current directory.\n"
157+
152158
" --code-coverage=tracefile.info\n"
153159
" Append coverage information to the LCOV tracefile (filename supports format tokens)\n"
154160
// TODO: These TOKENS are defined in `runtime_ccall.cpp`. A more verbose `--help` should include that list here.
155161
" --track-allocation[={none*|user|all}]\n"
156162
" Count bytes allocated by each source line (omitting setting is equivalent to `user`)\n"
163+
" --track-allocation=@<path>\n"
164+
" Count bytes but only in files that fall under the given file path/directory.\n"
165+
" The `@` prefix is required to select this option. A `@` with no path will track the\n"
166+
" current directory.\n"
157167
" --bug-report=KIND Launch a bug report session. It can be used to start a REPL, run a script, or evaluate\n"
158168
" expressions. It first tries to use BugReporting.jl installed in current environment and\n"
159169
" fallbacks to the latest compatible BugReporting.jl if not. For more information, see\n"
@@ -515,6 +525,10 @@ JL_DLLEXPORT void jl_parse_opts(int *argcp, char ***argvp)
515525
codecov = JL_LOG_ALL;
516526
jl_options.output_code_coverage = optarg;
517527
}
528+
else if (!strncmp(optarg, "@", 1)) {
529+
codecov = JL_LOG_PATH;
530+
jl_options.tracked_path = optarg + 1; // skip `@`
531+
}
518532
else
519533
jl_errorf("julia: invalid argument to --code-coverage (%s)", optarg);
520534
break;
@@ -531,6 +545,10 @@ JL_DLLEXPORT void jl_parse_opts(int *argcp, char ***argvp)
531545
malloclog = JL_LOG_ALL;
532546
else if (!strcmp(optarg,"none"))
533547
malloclog = JL_LOG_NONE;
548+
else if (!strncmp(optarg, "@", 1)) {
549+
malloclog = JL_LOG_PATH;
550+
jl_options.tracked_path = optarg + 1; // skip `@`
551+
}
534552
else
535553
jl_errorf("julia: invalid argument to --track-allocation (%s)", optarg);
536554
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
@@ -2077,6 +2077,7 @@ JL_DLLEXPORT int jl_generating_output(void) JL_NOTSAFEPOINT;
20772077
#define JL_LOG_NONE 0
20782078
#define JL_LOG_USER 1
20792079
#define JL_LOG_ALL 2
2080+
#define JL_LOG_PATH 3
20802081

20812082
#define JL_OPTIONS_CHECK_BOUNDS_DEFAULT 0
20822083
#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)