Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 48 additions & 7 deletions src/gf.c
Original file line number Diff line number Diff line change
Expand Up @@ -2373,20 +2373,40 @@ jl_code_instance_t *jl_method_compiled(jl_method_instance_t *mi, size_t world)

jl_mutex_t precomp_statement_out_lock;

_Atomic(uint8_t) jl_force_trace_compile_timing_enabled = 0;

/**
* @brief Enable force trace compile to stderr with timing.
*/
JL_DLLEXPORT void jl_force_trace_compile_timing_enable(void)
{
// Increment the flag to allow reentrant callers to `@trace_compile`.
jl_atomic_fetch_add(&jl_force_trace_compile_timing_enabled, 1);
}
/**
* @brief Disable force trace compile to stderr with timing.
*/
JL_DLLEXPORT void jl_force_trace_compile_timing_disable(void)
{
// Increment the flag to allow reentrant callers to `@trace_compile`.
jl_atomic_fetch_add(&jl_force_trace_compile_timing_enabled, -1);
}

static void record_precompile_statement(jl_method_instance_t *mi, double compilation_time)
{
static ios_t f_precompile;
static JL_STREAM* s_precompile = NULL;
jl_method_t *def = mi->def.method;
if (jl_options.trace_compile == NULL)
uint8_t force_trace_compile = jl_atomic_load_relaxed(&jl_force_trace_compile_timing_enabled);
if (force_trace_compile == 0 && jl_options.trace_compile == NULL)
return;
if (!jl_is_method(def))
return;

JL_LOCK(&precomp_statement_out_lock);
if (s_precompile == NULL) {
const char *t = jl_options.trace_compile;
if (!strncmp(t, "stderr", 6)) {
if (force_trace_compile || !strncmp(t, "stderr", 6)) {
s_precompile = JL_STDERR;
}
else {
Expand All @@ -2396,7 +2416,7 @@ static void record_precompile_statement(jl_method_instance_t *mi, double compila
}
}
if (!jl_has_free_typevars(mi->specTypes)) {
if (jl_options.trace_compile_timing)
if (force_trace_compile || jl_options.trace_compile_timing)
jl_printf(s_precompile, "#= %6.1f =# ", compilation_time / 1e6);
jl_printf(s_precompile, "precompile(");
jl_static_show(s_precompile, mi->specTypes);
Expand All @@ -2409,6 +2429,25 @@ static void record_precompile_statement(jl_method_instance_t *mi, double compila

jl_mutex_t dispatch_statement_out_lock;

_Atomic(uint8_t) jl_force_trace_dispatch_enabled = 0;

/**
* @brief Enable force trace dispatch to stderr.
*/
JL_DLLEXPORT void jl_force_trace_dispatch_enable(void)
{
// Increment the flag to allow reentrant callers to `@trace_dispatch`.
jl_atomic_fetch_add(&jl_force_trace_dispatch_enabled, 1);
}
/**
* @brief Disable force trace dispatch to stderr.
*/
JL_DLLEXPORT void jl_force_trace_dispatch_disable(void)
{
// Increment the flag to allow reentrant callers to `@trace_dispatch`.
jl_atomic_fetch_add(&jl_force_trace_dispatch_enabled, -1);
}

static void record_dispatch_statement(jl_method_instance_t *mi)
{
static ios_t f_dispatch;
Expand All @@ -2417,10 +2456,11 @@ static void record_dispatch_statement(jl_method_instance_t *mi)
if (!jl_is_method(def))
return;

uint8_t force_trace_dispatch = jl_atomic_load_relaxed(&jl_force_trace_dispatch_enabled);
JL_LOCK(&dispatch_statement_out_lock);
if (s_dispatch == NULL) {
const char *t = jl_options.trace_dispatch;
if (!strncmp(t, "stderr", 6)) {
if (force_trace_dispatch || !strncmp(t, "stderr", 6)) {
s_dispatch = JL_STDERR;
}
else {
Expand Down Expand Up @@ -3140,7 +3180,8 @@ STATIC_INLINE jl_method_instance_t *jl_lookup_generic_(jl_value_t *F, jl_value_t
// unreachable
}
// mfunc is about to be dispatched
if (jl_options.trace_dispatch != NULL) {
uint8_t force_trace_dispatch = jl_atomic_load_relaxed(&jl_force_trace_dispatch_enabled);
if (force_trace_dispatch || jl_options.trace_dispatch != NULL) {
uint8_t miflags = jl_atomic_load_relaxed(&mfunc->flags);
uint8_t was_dispatched = miflags & JL_MI_FLAGS_MASK_DISPATCHED;
if (!was_dispatched) {
Expand Down Expand Up @@ -3271,7 +3312,8 @@ jl_value_t *jl_gf_invoke_by_method(jl_method_t *method, jl_value_t *gf, jl_value
jl_gc_sync_total_bytes(last_alloc); // discard allocation count from compilation
}
JL_GC_PROMISE_ROOTED(mfunc);
if (jl_options.trace_dispatch != NULL) {
uint8_t force_trace_dispatch = jl_atomic_load_relaxed(&jl_force_trace_dispatch_enabled);
if (force_trace_dispatch || jl_options.trace_dispatch != NULL) {
uint8_t miflags = jl_atomic_load_relaxed(&mfunc->flags);
uint8_t was_dispatched = miflags & JL_MI_FLAGS_MASK_DISPATCHED;
if (!was_dispatched) {
Expand Down Expand Up @@ -3668,7 +3710,6 @@ static int sort_mlmatches(jl_array_t *t, size_t idx, arraylist_t *visited, array
}



// This is the collect form of calling jl_typemap_intersection_visitor
// with optimizations to skip fully shadowed methods.
//
Expand Down
6 changes: 6 additions & 0 deletions src/julia_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -1112,6 +1112,12 @@ JL_DLLEXPORT void jl_mi_cache_insert(jl_method_instance_t *mi JL_ROOTING_ARGUMEN
jl_code_instance_t *ci JL_ROOTED_ARGUMENT JL_MAYBE_UNROOTED);
JL_DLLEXPORT extern jl_value_t *(*const jl_rettype_inferred_addr)(jl_method_instance_t *mi JL_PROPAGATES_ROOT, size_t min_world, size_t max_world) JL_NOTSAFEPOINT;

JL_DLLEXPORT void jl_force_trace_compile_timing_enable(void);
JL_DLLEXPORT void jl_force_trace_compile_timing_disable(void);

JL_DLLEXPORT void jl_force_trace_dispatch_enable(void);
JL_DLLEXPORT void jl_force_trace_dispatch_disable(void);

uint32_t jl_module_next_counter(jl_module_t *m) JL_NOTSAFEPOINT;
jl_tupletype_t *arg_type_tuple(jl_value_t *arg1, jl_value_t **args, size_t nargs);

Expand Down
2 changes: 2 additions & 0 deletions stdlib/InteractiveUtils/docs/src/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,7 @@ InteractiveUtils.@code_llvm
InteractiveUtils.code_native
InteractiveUtils.@code_native
InteractiveUtils.@time_imports
InteractiveUtils.@trace_compile
InteractiveUtils.@trace_dispatch
InteractiveUtils.clipboard
```
2 changes: 1 addition & 1 deletion stdlib/InteractiveUtils/src/InteractiveUtils.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Base.Experimental.@optlevel 1

export apropos, edit, less, code_warntype, code_llvm, code_native, methodswith, varinfo,
versioninfo, subtypes, supertypes, @which, @edit, @less, @functionloc, @code_warntype,
@code_typed, @code_lowered, @code_llvm, @code_native, @time_imports, clipboard
@code_typed, @code_lowered, @code_llvm, @code_native, @time_imports, clipboard, @trace_compile, @trace_dispatch

import Base.Docs.apropos

Expand Down
55 changes: 55 additions & 0 deletions stdlib/InteractiveUtils/src/macros.jl
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,28 @@ macro time_imports(ex)
end
end

macro trace_compile(ex)
quote
try
ccall(:jl_force_trace_compile_timing_enable, Cvoid, ())
$(esc(ex))
finally
ccall(:jl_force_trace_compile_timing_disable, Cvoid, ())
end
end
end

macro trace_dispatch(ex)
quote
try
ccall(:jl_force_trace_dispatch_enable, Cvoid, ())
$(esc(ex))
finally
ccall(:jl_force_trace_dispatch_disable, Cvoid, ())
end
end
end

"""
@functionloc

Expand Down Expand Up @@ -392,3 +414,36 @@ julia> @time_imports using CSV

"""
:@time_imports

"""
@trace_compile

A macro to execute an expression and show any methods that were compiled (or recompiled in yellow),
like the julia args `--trace-compile=stderr --trace-compile-timing` but specifically for a call.

```julia-repl
julia> @trace_compile rand(2,2) * rand(2,2)
#= 39.1 ms =# precompile(Tuple{typeof(Base.rand), Int64, Int64})
#= 102.0 ms =# precompile(Tuple{typeof(Base.:(*)), Array{Float64, 2}, Array{Float64, 2}})
2×2 Matrix{Float64}:
0.421704 0.864841
0.211262 0.444366
```

!!! compat "Julia 1.12"
This macro requires at least Julia 1.12

"""
:@trace_compile

"""
@trace_dispatch

A macro to execute an expression and report methods that were compiled via dynamic dispatch,
like the julia arg `--trace-dispatch=stderr` but specifically for a call.

!!! compat "Julia 1.12"
This macro requires at least Julia 1.12

"""
:@trace_dispatch
34 changes: 32 additions & 2 deletions stdlib/InteractiveUtils/test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -643,7 +643,7 @@ let
@test !(first(@code_typed optimize=opt sum(1:10)).inferred)
end

@testset "@time_imports" begin
@testset "@time_imports, @trace_compile, @trace_dispatch" begin
mktempdir() do dir
cd(dir) do
try
Expand All @@ -652,7 +652,16 @@ end
write(foo_file,
"""
module Foo3242
foo() = 1
function foo()
Base.Experimental.@force_compile
foo(1)
end
foo(x) = x
function bar()
Base.Experimental.@force_compile
bar(1)
end
bar(x) = x
end
""")

Expand All @@ -669,6 +678,27 @@ end

@test occursin("ms Foo3242", String(buf))

fname = tempname()
f = open(fname, "w")
redirect_stderr(f) do
@trace_compile @eval Foo3242.foo()
end
close(f)
buf = read(fname)
rm(fname)

@test occursin("ms =# precompile(", String(buf))

fname = tempname()
f = open(fname, "w")
redirect_stderr(f) do
@trace_dispatch @eval Foo3242.bar()
end
close(f)
buf = read(fname)
rm(fname)

@test occursin("precompile(", String(buf))
finally
filter!((≠)(dir), LOAD_PATH)
end
Expand Down