Skip to content

Commit b991db1

Browse files
committed
Merge pull request #15860 from JuliaLang/kf/tracing
RFC: Add API for programatic tracing of specializations/new methods
2 parents 9492c53 + 79b2dd8 commit b991db1

File tree

8 files changed

+76
-5
lines changed

8 files changed

+76
-5
lines changed

base/reflection.jl

+1-1
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,7 @@ uncompressed_ast(l::LambdaInfo) =
254254
# Printing code representations in IR and assembly
255255
function _dump_function(f, t::ANY, native, wrapper, strip_ir_metadata, dump_module)
256256
t = tt_cons(Core.Typeof(f), to_tuple_type(t))
257-
llvmf = ccall(:jl_get_llvmf, Ptr{Void}, (Any, Any, Bool, Bool), f, t, wrapper, native)
257+
llvmf = ccall(:jl_get_llvmf, Ptr{Void}, (Any, Bool, Bool), t, wrapper, native)
258258

259259
if llvmf == C_NULL
260260
error("no method found for the specified argument types")

src/alloc.c

+1
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,7 @@ jl_lambda_info_t *jl_new_lambda_info(jl_value_t *ast, jl_svec_t *tvars, jl_svec_
373373
li->pure = 0;
374374
li->called = 0xff;
375375
li->needs_sparam_vals_ducttape = 2;
376+
li->traced = 0;
376377
if (ast != NULL) {
377378
JL_GC_PUSH1(&li);
378379
jl_lambda_info_set_ast(li, ast);

src/codegen.cpp

+3-2
Original file line numberDiff line numberDiff line change
@@ -1174,14 +1174,15 @@ void jl_extern_c(jl_function_t *f, jl_value_t *rt, jl_value_t *argt, char *name)
11741174
// this is paired with jl_dump_function_ir and jl_dump_function_asm in particular ways:
11751175
// misuse will leak memory or cause read-after-free
11761176
extern "C" JL_DLLEXPORT
1177-
void *jl_get_llvmf(jl_function_t *f, jl_tupletype_t *tt, bool getwrapper, bool getdeclarations)
1177+
void *jl_get_llvmf(jl_tupletype_t *tt, bool getwrapper, bool getdeclarations)
11781178
{
11791179
jl_lambda_info_t *linfo = NULL;
11801180
JL_GC_PUSH2(&linfo, &tt);
11811181
if (tt != NULL) {
11821182
linfo = jl_get_specialization1(tt);
11831183
if (linfo == NULL) {
1184-
linfo = jl_method_lookup_by_type(jl_gf_mtable(f), tt, 0, 0);
1184+
linfo = jl_method_lookup_by_type(
1185+
((jl_datatype_t*)jl_tparam0(tt))->name->mt, tt, 0, 0);
11851186
if (linfo == NULL) {
11861187
JL_GC_POP();
11871188
return NULL;

src/dump.c

+1
Original file line numberDiff line numberDiff line change
@@ -1475,6 +1475,7 @@ static jl_value_t *jl_deserialize_value_(ios_t *s, jl_value_t *vtag, jl_value_t
14751475
jl_delayed_fptrs(li, func_llvm, cfunc_llvm);
14761476
li->jlcall_api = func_llvm ? read_int8(s) : 0;
14771477
li->needs_sparam_vals_ducttape = read_int8(s);
1478+
li->traced = 0;
14781479
return (jl_value_t*)li;
14791480
}
14801481
else if (vtag == (jl_value_t*)jl_module_type) {

src/gf.c

+9-1
Original file line numberDiff line numberDiff line change
@@ -465,6 +465,8 @@ static int is_kind(jl_value_t *v)
465465
static jl_value_t *ml_matches(jl_methlist_t *ml, jl_value_t *type,
466466
jl_sym_t *name, int lim);
467467

468+
extern void (*jl_linfo_tracer)(jl_lambda_info_t *tracee);
469+
468470
static jl_lambda_info_t *cache_method(jl_methtable_t *mt, jl_tupletype_t *type,
469471
jl_lambda_info_t *method, jl_methlist_t *m,
470472
jl_svec_t *sparams)
@@ -839,6 +841,8 @@ static jl_lambda_info_t *cache_method(jl_methtable_t *mt, jl_tupletype_t *type,
839841
}
840842
JL_GC_POP();
841843
JL_UNLOCK(codegen);
844+
if (method->traced)
845+
jl_linfo_tracer(newmeth);
842846
return newmeth;
843847
}
844848

@@ -2020,6 +2024,8 @@ JL_DLLEXPORT jl_function_t *jl_new_generic_function(jl_sym_t *name, jl_module_t
20202024
return jl_new_generic_function_with_supertype(name, module, jl_function_type, 0);
20212025
}
20222026

2027+
2028+
extern void (*jl_newmeth_tracer)(jl_methlist_t *tracee);
20232029
void jl_add_method_to_table(jl_methtable_t *mt, jl_tupletype_t *types, jl_lambda_info_t *meth,
20242030
jl_svec_t *tvars, int8_t isstaged)
20252031
{
@@ -2035,7 +2041,9 @@ void jl_add_method_to_table(jl_methtable_t *mt, jl_tupletype_t *types, jl_lambda
20352041
meth->unspecialized = NULL;
20362042
}
20372043
meth->name = n;
2038-
(void)jl_method_table_insert(mt, types, meth, tvars, isstaged);
2044+
jl_methlist_t *newmeth = jl_method_table_insert(mt, types, meth, tvars, isstaged);
2045+
if (jl_newmeth_tracer)
2046+
jl_newmeth_tracer(newmeth);
20392047
JL_GC_POP();
20402048
}
20412049

src/jlapi.c

+25
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,31 @@ JL_DLLEXPORT const char *jl_git_commit(void)
308308
return commit;
309309
}
310310

311+
JL_DLLEXPORT void jl_trace_linfo(jl_lambda_info_t *li)
312+
{
313+
assert(jl_is_lambda_info(li));
314+
li->traced = 1;
315+
}
316+
317+
JL_DLLEXPORT void jl_untrace_linfo(jl_lambda_info_t *li)
318+
{
319+
assert(jl_is_lambda_info(li));
320+
li->traced = 0;
321+
}
322+
323+
void (*jl_linfo_tracer)(jl_lambda_info_t *tracee) = 0;
324+
JL_DLLEXPORT void jl_register_tracer(void (*callback)(jl_lambda_info_t *tracee))
325+
{
326+
jl_linfo_tracer = callback;
327+
}
328+
329+
void (*jl_newmeth_tracer)(jl_methlist_t *tracee) = 0;
330+
JL_DLLEXPORT void jl_register_newmeth_tracer(void (*callback)(jl_methlist_t *tracee))
331+
{
332+
jl_newmeth_tracer = callback;
333+
}
334+
335+
311336
// Create function versions of some useful macros
312337
JL_DLLEXPORT jl_taggedvalue_t *(jl_astaggedvalue)(jl_value_t *v)
313338
{

src/julia.h

+9
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,9 @@ typedef struct _jl_lambda_info_t {
210210
// and so unspecialized will be created for each linfo instead of once in linfo->def.
211211
// 0 = no, 1 = yes, 2 = not yet known
212212
uint8_t needs_sparam_vals_ducttape : 2;
213+
// If this flag is set, the system will call a callback if a specialization
214+
// is added to this lambda info. See jl_register_tracer below.
215+
uint8_t traced : 1;
213216
jl_fptr_t fptr; // jlcall entry point
214217

215218
// On the old JIT, handles to all Functions generated for this linfo
@@ -1243,6 +1246,12 @@ JL_DLLEXPORT jl_value_t *jl_interpret_toplevel_expr_in(jl_module_t *m, jl_value_
12431246
jl_lambda_info_t *lam);
12441247
JL_DLLEXPORT jl_module_t *jl_base_relative_to(jl_module_t *m);
12451248

1249+
// tracing
1250+
JL_DLLEXPORT void jl_trace_linfo(jl_lambda_info_t *li);
1251+
JL_DLLEXPORT void jl_untrace_linfo(jl_lambda_info_t *li);
1252+
JL_DLLEXPORT void jl_register_tracer(void (*callback)(jl_lambda_info_t *tracee));
1253+
JL_DLLEXPORT void jl_register_newmeth_tracer(void (*callback)(jl_methlist_t *tracee));
1254+
12461255
// AST access
12471256
JL_DLLEXPORT int jl_is_rest_arg(jl_value_t *ex);
12481257

test/reflection.jl

+27-1
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,7 @@ definitely_not_in_sysimg() = nothing
276276
for (f,t) in ((definitely_not_in_sysimg,Tuple{}),
277277
(Base.throw_boundserror,Tuple{UnitRange{Int64},Int64}))
278278
t = Base.tt_cons(Core.Typeof(f), Base.to_tuple_type(t))
279-
llvmf = ccall(:jl_get_llvmf, Ptr{Void}, (Any, Any, Bool, Bool), f, t, false, true)
279+
llvmf = ccall(:jl_get_llvmf, Ptr{Void}, (Any, Bool, Bool), t, false, true)
280280
@test llvmf != C_NULL
281281
@test ccall(:jl_get_llvm_fptr, Ptr{Void}, (Ptr{Void},), llvmf) != C_NULL
282282
end
@@ -374,3 +374,29 @@ test_typed_ast_printing(g15714, Tuple{Vector{Float32}},
374374
[:array_var15714, :index_var15714])
375375
@test used_dup_var_tested15714
376376
@test used_unique_var_tested15714
377+
378+
# Linfo Tracing test
379+
tracefoo(x, y) = x+y
380+
didtrace = false
381+
tracer(x::Ptr{Void}) = (@test isa(unsafe_pointer_to_objref(x), LambdaInfo); global didtrace = true; nothing)
382+
ccall(:jl_register_tracer, Void, (Ptr{Void},), cfunction(tracer, Void, (Ptr{Void},)))
383+
mlinfo = first(methods(tracefoo)).func
384+
ccall(:jl_trace_linfo, Void, (Any,), mlinfo)
385+
@test tracefoo(1, 2) == 3
386+
ccall(:jl_untrace_linfo, Void, (Any,), mlinfo)
387+
@test didtrace
388+
didtrace = false
389+
@test tracefoo(1.0, 2.0) == 3.0
390+
@test !didtrace
391+
ccall(:jl_register_tracer, Void, (Ptr{Void},), C_NULL)
392+
393+
# Method Tracing test
394+
methtracer(x::Ptr{Void}) = (@test isa(unsafe_pointer_to_objref(x), Method); global didtrace = true; nothing)
395+
ccall(:jl_register_newmeth_tracer, Void, (Ptr{Void},), cfunction(methtracer, Void, (Ptr{Void},)))
396+
tracefoo2(x, y) = x*y
397+
@test didtrace
398+
didtrace = false
399+
tracefoo(x::Int64, y::Int64) = x*y
400+
@test didtrace
401+
didtrace = false
402+
ccall(:jl_register_newmeth_tracer, Void, (Ptr{Void},), C_NULL)

0 commit comments

Comments
 (0)