Skip to content

Commit 32293c4

Browse files
add "project" mode to code coverage and allocation tracking
1 parent ad129a9 commit 32293c4

File tree

13 files changed

+152
-62
lines changed

13 files changed

+152
-62
lines changed

base/reflection.jl

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,50 @@ Foo
245245
parentmodule(t::DataType) = t.name.module
246246
parentmodule(t::UnionAll) = parentmodule(unwrap_unionall(t))
247247

248+
"""
249+
setprojectmodule(m::Module)
250+
251+
Set a given module and its recursive submodules as "project modules",
252+
marking them for inclusion when code coverage and allocation tracking is
253+
set to `project` mode.
254+
255+
For instance, when starting julia with code coverage, and similarly for allocation
256+
tracking (`--track-allocation`):
257+
```
258+
\$ julia --code-coverage=project -e `using Foo; Base.setprojectmodule(Foo); Foo.bar()`
259+
```
260+
261+
!!! compat "Julia 1.8"
262+
This function requires at least Julia 1.8.
263+
"""
264+
function setprojectmodule(m::Module)
265+
function _setchildmods(m)
266+
for name in names(m; all = true, imported = false)
267+
if name isa Module
268+
setprojectmod(name, false)
269+
_setchildmods(name)
270+
end
271+
end
272+
nothing
273+
end
274+
setprojectmodule(m, true)
275+
_setchildmods(m)
276+
return
277+
end
278+
setprojectmodule(m::Module, isprimary::Bool) = ccall(:jl_set_isprojmod, Cvoid, (Any, Bool), m, isprimary)
279+
280+
"""
281+
isprojectmodule(m::Module)
282+
283+
Check whether a given module is marked as a "project module",
284+
which marks it for inclusion when code coverage and allocation tracking is
285+
set to `project` mode.
286+
287+
!!! compat "Julia 1.8"
288+
This function requires at least Julia 1.8.
289+
"""
290+
isprojectmodule(m::Module) = ccall(:jl_isprojmod, Cint, (Any,), m) == 1
291+
248292
"""
249293
isconst(m::Module, s::Symbol) -> Bool
250294

base/util.jl

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -192,16 +192,20 @@ function julia_cmd(julia=joinpath(Sys.BINDIR::String, julia_exename()))
192192
coverage_file = (opts.output_code_coverage != C_NULL) ? unsafe_string(opts.output_code_coverage) : ""
193193
if isempty(coverage_file) || occursin("%p", coverage_file)
194194
if opts.code_coverage == 1
195-
push!(addflags, "--code-coverage=user")
195+
push!(addflags, "--code-coverage=project")
196196
elseif opts.code_coverage == 2
197+
push!(addflags, "--code-coverage=user")
198+
elseif opts.code_coverage == 3
197199
push!(addflags, "--code-coverage=all")
198200
end
199201
isempty(coverage_file) || push!(addflags, "--code-coverage=$coverage_file")
200202
end
201203
end
202204
if opts.malloc_log == 1
203-
push!(addflags, "--track-allocation=user")
205+
push!(addflags, "--track-allocation=project")
204206
elseif opts.malloc_log == 2
207+
push!(addflags, "--track-allocation=user")
208+
elseif opts.malloc_log == 3
205209
push!(addflags, "--track-allocation=all")
206210
end
207211
if opts.color == 1

doc/man/julia.1

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -195,11 +195,11 @@ Generate LLVM bitcode (.bc)
195195
Generate an incremental output file (rather than complete)
196196

197197
.TP
198-
--code-coverage={none|user|all}, --code-coverage
198+
--code-coverage={none|project|user|all}, --code-coverage
199199
Count executions of source lines (omitting setting is equivalent to 'user')
200200

201201
.TP
202-
--track-allocation={none|user|all}, --track-allocation
202+
--track-allocation={none|project|user|all}, --track-allocation
203203
Count bytes allocated by each source line
204204

205205
.SH FILES

doc/src/manual/command-line-options.md

Lines changed: 35 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -75,41 +75,41 @@ julia [switches] -- [programfile] [args...]
7575
The following is a complete list of command-line switches available when launching julia, e.g.
7676

7777

78-
|Switch |Description|
79-
|:--- |:---|
80-
|`-v`, `--version` |Display version information|
81-
|`-h`, `--help` |Print command-line options (this message).|
82-
|`--project[={<dir>\|@.}]` |Set `<dir>` as the home project/environment. The default `@.` option will search through parent directories until a `Project.toml` or `JuliaProject.toml` file is found.|
83-
|`-J`, `--sysimage <file>` |Start up with the given system image file|
84-
|`-H`, `--home <dir>` |Set location of `julia` executable|
85-
|`--startup-file={yes\|no}` |Load `~/.julia/config/startup.jl`|
86-
|`--handle-signals={yes\|no}` |Enable or disable Julia's default signal handlers|
87-
|`--sysimage-native-code={yes\|no}` |Use native code from system image if available|
88-
|`--compiled-modules={yes\|no}` |Enable or disable incremental precompilation of modules|
89-
|`-e`, `--eval <expr>` |Evaluate `<expr>`|
90-
|`-E`, `--print <expr>` |Evaluate `<expr>` and display the result|
91-
|`-L`, `--load <file>` |Load `<file>` immediately on all processors|
92-
|`-t`, `--threads {N\|auto`} |Enable N threads; `auto` currently sets N to the number of local CPU threads but this might change in the future|
93-
|`-p`, `--procs {N\|auto`} |Integer value N launches N additional local worker processes; `auto` launches as many workers as the number of local CPU threads (logical cores)|
94-
|`--machine-file <file>` |Run processes on hosts listed in `<file>`|
95-
|`-i` |Interactive mode; REPL runs and `isinteractive()` is true|
96-
|`-q`, `--quiet` |Quiet startup: no banner, suppress REPL warnings|
97-
|`--banner={yes\|no\|auto}` |Enable or disable startup banner|
98-
|`--color={yes\|no\|auto}` |Enable or disable color text|
99-
|`--history-file={yes\|no}` |Load or save history|
100-
|`--depwarn={yes\|no\|error}` |Enable or disable syntax and method deprecation warnings (`error` turns warnings into errors)|
101-
|`--warn-overwrite={yes\|no}` |Enable or disable method overwrite warnings|
102-
|`-C`, `--cpu-target <target>` |Limit usage of CPU features up to `<target>`; set to `help` to see the available options|
103-
|`-O`, `--optimize={0,1,2,3}` |Set the optimization level (default level is 2 if unspecified or 3 if used without a level)|
104-
|`--min-optlevel={0,1,2,3}` |Set the lower bound on per-module optimization (default is 0)|
105-
|`-g`, `-g <level>` |Enable or set the level of debug info generation (default level is 1 if unspecified or 2 if used without a level)|
106-
|`--inline={yes\|no}` |Control whether inlining is permitted, including overriding `@inline` declarations|
107-
|`--check-bounds={yes\|no\|auto}` |Emit bounds checks always, never, or respect `@inbounds` declarations|
108-
|`--math-mode={ieee,fast}` |Disallow or enable unsafe floating point optimizations (overrides `@fastmath` declaration)|
109-
|`--code-coverage={none\|user\|all}` |Count executions of source lines|
110-
|`--code-coverage` |equivalent to `--code-coverage=user`|
111-
|`--track-allocation={none\|user\|all}` |Count bytes allocated by each source line|
112-
|`--track-allocation` |equivalent to `--track-allocation=user`|
78+
|Switch |Description|
79+
|:--- |:---|
80+
|`-v`, `--version` |Display version information|
81+
|`-h`, `--help` |Print command-line options (this message).|
82+
|`--project[={<dir>\|@.}]` |Set `<dir>` as the home project/environment. The default `@.` option will search through parent directories until a `Project.toml` or `JuliaProject.toml` file is found.|
83+
|`-J`, `--sysimage <file>` |Start up with the given system image file|
84+
|`-H`, `--home <dir>` |Set location of `julia` executable|
85+
|`--startup-file={yes\|no}` |Load `~/.julia/config/startup.jl`|
86+
|`--handle-signals={yes\|no}` |Enable or disable Julia's default signal handlers|
87+
|`--sysimage-native-code={yes\|no}` |Use native code from system image if available|
88+
|`--compiled-modules={yes\|no}` |Enable or disable incremental precompilation of modules|
89+
|`-e`, `--eval <expr>` |Evaluate `<expr>`|
90+
|`-E`, `--print <expr>` |Evaluate `<expr>` and display the result|
91+
|`-L`, `--load <file>` |Load `<file>` immediately on all processors|
92+
|`-t`, `--threads {N\|auto`} |Enable N threads; `auto` currently sets N to the number of local CPU threads but this might change in the future|
93+
|`-p`, `--procs {N\|auto`} |Integer value N launches N additional local worker processes; `auto` launches as many workers as the number of local CPU threads (logical cores)|
94+
|`--machine-file <file>` |Run processes on hosts listed in `<file>`|
95+
|`-i` |Interactive mode; REPL runs and `isinteractive()` is true|
96+
|`-q`, `--quiet` |Quiet startup: no banner, suppress REPL warnings|
97+
|`--banner={yes\|no\|auto}` |Enable or disable startup banner|
98+
|`--color={yes\|no\|auto}` |Enable or disable color text|
99+
|`--history-file={yes\|no}` |Load or save history|
100+
|`--depwarn={yes\|no\|error}` |Enable or disable syntax and method deprecation warnings (`error` turns warnings into errors)|
101+
|`--warn-overwrite={yes\|no}` |Enable or disable method overwrite warnings|
102+
|`-C`, `--cpu-target <target>` |Limit usage of CPU features up to `<target>`; set to `help` to see the available options|
103+
|`-O`, `--optimize={0,1,2,3}` |Set the optimization level (default level is 2 if unspecified or 3 if used without a level)|
104+
|`--min-optlevel={0,1,2,3}` |Set the lower bound on per-module optimization (default is 0)|
105+
|`-g`, `-g <level>` |Enable or set the level of debug info generation (default level is 1 if unspecified or 2 if used without a level)|
106+
|`--inline={yes\|no}` |Control whether inlining is permitted, including overriding `@inline` declarations|
107+
|`--check-bounds={yes\|no\|auto}` |Emit bounds checks always, never, or respect `@inbounds` declarations|
108+
|`--math-mode={ieee,fast}` |Disallow or enable unsafe floating point optimizations (overrides `@fastmath` declaration)|
109+
|`--code-coverage={none\|project\|user\|all}` |Count executions of source lines|
110+
|`--code-coverage` |equivalent to `--code-coverage=user`|
111+
|`--track-allocation={none\|project\|user\|all}` |Count bytes allocated by each source line|
112+
|`--track-allocation` |equivalent to `--track-allocation=user`|
113113

114114
!!! compat "Julia 1.1"
115115
In Julia 1.0, the default `--project=@.` option did not search up from the root

src/codegen.cpp

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6698,14 +6698,17 @@ static std::pair<std::unique_ptr<Module>, jl_llvm_functions_t>
66986698
!jl_is_submodule(mod, jl_core_module));
66996699
};
67006700
bool mod_is_user_mod = in_user_mod(ctx.module);
6701+
bool mod_is_project_mod = ctx.module->isprojmod;
67016702
struct DebugLineTable {
67026703
DebugLoc loc;
67036704
StringRef file;
67046705
ssize_t line;
67056706
bool is_user_code;
6707+
bool is_project_code;
67066708
unsigned inlined_at;
67076709
bool operator ==(const DebugLineTable &other) const {
6708-
return other.loc == loc && other.file == file && other.line == line && other.is_user_code == is_user_code && other.inlined_at == inlined_at;
6710+
return other.loc == loc && other.file == file && other.line == line && other.is_user_code == is_user_code &&
6711+
other.is_project_code == is_project_code && other.inlined_at == inlined_at;
67096712
}
67106713
};
67116714
std::vector<DebugLineTable> linetable;
@@ -6718,6 +6721,7 @@ static std::pair<std::unique_ptr<Module>, jl_llvm_functions_t>
67186721
topinfo.file = ctx.file;
67196722
topinfo.line = toplineno;
67206723
topinfo.is_user_code = mod_is_user_mod;
6724+
topinfo.is_project_code = mod_is_project_mod;
67216725
topinfo.inlined_at = 0;
67226726
topinfo.loc = topdebugloc;
67236727
for (size_t i = 0; i < nlocs; i++) {
@@ -6731,10 +6735,13 @@ static std::pair<std::unique_ptr<Module>, jl_llvm_functions_t>
67316735
info.line = jl_unbox_long(jl_fieldref(locinfo, 3));
67326736
info.inlined_at = jl_unbox_long(jl_fieldref(locinfo, 4));
67336737
assert(info.inlined_at <= i);
6734-
if (module == ctx.module)
6738+
if (module == ctx.module) {
67356739
info.is_user_code = mod_is_user_mod;
6736-
else
6740+
info.is_project_code = mod_is_project_mod;
6741+
} else {
67376742
info.is_user_code = in_user_mod(module);
6743+
info.is_project_code = module->isprojmod;
6744+
}
67386745
info.file = jl_symbol_name(filesym);
67396746
if (info.file.empty())
67406747
info.file = "<missing>";
@@ -6851,13 +6858,15 @@ static std::pair<std::unique_ptr<Module>, jl_llvm_functions_t>
68516858
cursor = -1;
68526859
};
68536860

6854-
auto do_coverage = [&] (bool in_user_code) {
6861+
auto do_coverage = [&] (bool in_user_code, bool in_project_code) {
68556862
return (coverage_mode == JL_LOG_ALL ||
6856-
(coverage_mode == JL_LOG_USER && in_user_code));
6863+
(coverage_mode == JL_LOG_USER && in_user_code) ||
6864+
(coverage_mode == JL_LOG_PROJECT && in_project_code));
68576865
};
6858-
auto do_malloc_log = [&] (bool in_user_code) {
6866+
auto do_malloc_log = [&] (bool in_user_code, bool in_project_code) {
68596867
return (malloc_log_mode == JL_LOG_ALL ||
6860-
(malloc_log_mode == JL_LOG_USER && in_user_code));
6868+
(malloc_log_mode == JL_LOG_USER && in_user_code) ||
6869+
(malloc_log_mode == JL_LOG_PROJECT && in_project_code));
68616870
};
68626871
std::vector<unsigned> current_lineinfo, new_lineinfo;
68636872
auto coverageVisitStmt = [&] (size_t dbg) {
@@ -6876,15 +6885,15 @@ static std::pair<std::unique_ptr<Module>, jl_llvm_functions_t>
68766885
if (newdbg != current_lineinfo[dbg]) {
68776886
current_lineinfo[dbg] = newdbg;
68786887
const auto &info = linetable.at(newdbg);
6879-
if (do_coverage(info.is_user_code))
6888+
if (do_coverage(info.is_user_code, info.is_project_code))
68806889
coverageVisitLine(ctx, info.file, info.line);
68816890
}
68826891
}
68836892
new_lineinfo.clear();
68846893
};
68856894
auto mallocVisitStmt = [&] (unsigned dbg, Value *sync) {
6886-
if (!do_malloc_log(mod_is_user_mod) || dbg == 0) {
6887-
if (do_malloc_log(true) && sync)
6895+
if (!do_malloc_log(mod_is_user_mod, mod_is_project_mod) || dbg == 0) {
6896+
if (do_malloc_log(true, true) && sync)
68886897
ctx.builder.CreateCall(prepare_call(sync_gc_total_bytes_func), {sync});
68896898
return;
68906899
}
@@ -6895,7 +6904,7 @@ static std::pair<std::unique_ptr<Module>, jl_llvm_functions_t>
68956904
if (coverage_mode != JL_LOG_NONE) {
68966905
// record all lines that could be covered
68976906
for (const auto &info : linetable)
6898-
if (do_coverage(info.is_user_code))
6907+
if (do_coverage(info.is_user_code, info.is_project_code))
68996908
jl_coverage_alloc_line(info.file, info.line);
69006909
}
69016910

@@ -6950,15 +6959,15 @@ static std::pair<std::unique_ptr<Module>, jl_llvm_functions_t>
69506959
}
69516960

69526961
Value *sync_bytes = nullptr;
6953-
if (do_malloc_log(true))
6962+
if (do_malloc_log(true,true))
69546963
sync_bytes = ctx.builder.CreateCall(prepare_call(diff_gc_total_bytes_func), {});
69556964
{ // coverage for the function definition line number
69566965
const auto &topinfo = linetable.at(0);
69576966
if (linetable.size() > 1) {
69586967
if (topinfo == linetable.at(1))
69596968
current_lineinfo.push_back(1);
69606969
}
6961-
if (do_coverage(topinfo.is_user_code))
6970+
if (do_coverage(topinfo.is_user_code, topinfo.is_project_code))
69626971
coverageVisitLine(ctx, topinfo.file, topinfo.line);
69636972
}
69646973

src/dump.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,7 @@ static void jl_serialize_module(jl_serializer_state *s, jl_module_t *m)
363363
jl_serialize_value(s, (jl_value_t*)m->usings.items[i]);
364364
}
365365
write_uint8(s->s, m->istopmod);
366+
write_uint8(s->s, m->isprojmod);
366367
write_uint64(s->s, m->uuid.hi);
367368
write_uint64(s->s, m->uuid.lo);
368369
write_uint64(s->s, m->build_id);
@@ -1675,6 +1676,7 @@ static jl_value_t *jl_deserialize_value_module(jl_serializer_state *s) JL_GC_DIS
16751676
i++;
16761677
}
16771678
m->istopmod = read_uint8(s->s);
1679+
m->isprojmod = read_uint8(s->s);
16781680
m->uuid.hi = read_uint64(s->s);
16791681
m->uuid.lo = read_uint64(s->s);
16801682
m->build_id = read_uint64(s->s);

src/jl_exported_data.inc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@
8484
XX(jl_pinode_type) \
8585
XX(jl_pointer_type) \
8686
XX(jl_pointer_typename) \
87+
XX(jl_project_module) \
8788
XX(jl_quotenode_type) \
8889
XX(jl_readonlymemory_exception) \
8990
XX(jl_ref_type) \

src/jl_exported_funcs.inc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,7 @@
412412
XX(jl_set_const) \
413413
XX(jl_set_errno) \
414414
XX(jl_set_global) \
415+
XX(jl_set_isprojmod) \
415416
XX(jl_set_istopmod) \
416417
XX(jl_set_module_compile) \
417418
XX(jl_set_module_infer) \

src/jloptions.c

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -145,12 +145,12 @@ static const char opts[] =
145145
" --math-mode={ieee,fast} Disallow or enable unsafe floating point optimizations (overrides @fastmath declaration)\n\n"
146146

147147
// instrumentation options
148-
" --code-coverage={none|user|all}, --code-coverage\n"
148+
" --code-coverage={none|project|user|all}, --code-coverage\n"
149149
" Count executions of source lines (omitting setting is equivalent to \"user\")\n"
150150
" --code-coverage=tracefile.info\n"
151151
" Append coverage information to the LCOV tracefile (filename supports format tokens).\n"
152152
// TODO: These TOKENS are defined in `runtime_ccall.cpp`. A more verbose `--help` should include that list here.
153-
" --track-allocation={none|user|all}, --track-allocation\n"
153+
" --track-allocation={none|project|user|all}, --track-allocation\n"
154154
" Count bytes allocated by each source line (omitting setting is equivalent to \"user\")\n"
155155
" --bug-report=KIND Launch a bug report session. It can be used to start a REPL, run a script, or evaluate\n"
156156
" expressions. It first tries to use BugReporting.jl installed in current environment and\n"
@@ -499,7 +499,9 @@ JL_DLLEXPORT void jl_parse_opts(int *argcp, char ***argvp)
499499
case opt_code_coverage:
500500
if (optarg != NULL) {
501501
size_t endof = strlen(optarg);
502-
if (!strcmp(optarg, "user"))
502+
if (!strcmp(optarg,"project"))
503+
codecov = JL_LOG_PROJECT;
504+
else if (!strcmp(optarg, "user"))
503505
codecov = JL_LOG_USER;
504506
else if (!strcmp(optarg, "all"))
505507
codecov = JL_LOG_ALL;
@@ -520,7 +522,9 @@ JL_DLLEXPORT void jl_parse_opts(int *argcp, char ***argvp)
520522
break;
521523
case opt_track_allocation:
522524
if (optarg != NULL) {
523-
if (!strcmp(optarg,"user"))
525+
if (!strcmp(optarg,"project"))
526+
malloclog = JL_LOG_PROJECT;
527+
else if (!strcmp(optarg,"user"))
524528
malloclog = JL_LOG_USER;
525529
else if (!strcmp(optarg,"all"))
526530
malloclog = JL_LOG_ALL;

0 commit comments

Comments
 (0)