Skip to content

Commit

Permalink
jl_debug_method_invalidation: return a list of instances, signatures,…
Browse files Browse the repository at this point in the history
… and tags (#35768)

Rather than print debug info, this stores the relevant entities to an
array.  This facilitates easier analysis of the causes, for example
making it possible to automatically walk the hierarchy of related code
objects (methods, functions, signature types), perform
type-intersection, etc.

Analysis code will live outside Julia proper (SnoopCompile and MethodAnalysis
are two early "consumers").
  • Loading branch information
timholy authored Jun 3, 2020
1 parent 2855625 commit 65c2a03
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 26 deletions.
13 changes: 8 additions & 5 deletions src/dump.c
Original file line number Diff line number Diff line change
Expand Up @@ -1830,7 +1830,7 @@ static void jl_insert_methods(jl_array_t *list)
}
}

extern int jl_debug_method_invalidation;
extern jl_array_t *_jl_debug_method_invalidation JL_GLOBALLY_ROOTED;

// verify that these edges intersect with the same methods as before
static void jl_verify_edges(jl_array_t *targets, jl_array_t **pvalids)
Expand Down Expand Up @@ -1884,7 +1884,8 @@ static void jl_insert_backedges(jl_array_t *list, jl_array_t *targets)
// map(enable, ((list[i] => targets[list[i + 1] .* 2]) for i in 1:2:length(list) if all(valids[list[i + 1]])))
size_t i, l = jl_array_len(list);
jl_array_t *valids = NULL;
JL_GC_PUSH1(&valids);
jl_value_t *loctag = NULL;
JL_GC_PUSH2(&valids, &loctag);
jl_verify_edges(targets, &valids);
for (i = 0; i < l; i += 2) {
jl_method_instance_t *caller = (jl_method_instance_t*)jl_array_ptr_ref(list, i);
Expand Down Expand Up @@ -1922,9 +1923,11 @@ static void jl_insert_backedges(jl_array_t *list, jl_array_t *targets)
}
}
else {
if (jl_debug_method_invalidation) {
jl_static_show(JL_STDOUT, (jl_value_t*)caller);
jl_uv_puts(JL_STDOUT, "<<<\n", 4);
if (_jl_debug_method_invalidation) {
jl_array_ptr_1d_push(_jl_debug_method_invalidation, (jl_value_t*)caller);
loctag = jl_cstr_to_string("insert_backedges");
jl_gc_wb(_jl_debug_method_invalidation, loctag);
jl_array_ptr_1d_push(_jl_debug_method_invalidation, loctag);
}
}
}
Expand Down
96 changes: 75 additions & 21 deletions src/gf.c
Original file line number Diff line number Diff line change
Expand Up @@ -1485,17 +1485,33 @@ static void update_max_args(jl_methtable_t *mt, jl_value_t *type)
mt->max_args = na;
}

JL_DLLEXPORT int jl_debug_method_invalidation = 0;
jl_array_t *_jl_debug_method_invalidation JL_GLOBALLY_ROOTED = NULL;
JL_DLLEXPORT jl_value_t *jl_debug_method_invalidation(int state)
{
/* After calling with `state = 1`, caller is responsible for
holding a reference to the returned array until this is called
again with `state = 0`. */
if (state) {
if (_jl_debug_method_invalidation)
return (jl_value_t*) _jl_debug_method_invalidation;
_jl_debug_method_invalidation = jl_alloc_array_1d(jl_array_any_type, 0);
return (jl_value_t*) _jl_debug_method_invalidation;
}
_jl_debug_method_invalidation = NULL;
return jl_nothing;
}

// recursively invalidate cached methods that had an edge to a replaced method
static void invalidate_method_instance(jl_method_instance_t *replaced, size_t max_world, int depth)
{
if (jl_debug_method_invalidation) {
int d0 = depth;
while (d0-- > 0)
jl_uv_puts(JL_STDOUT, " ", 1);
jl_static_show(JL_STDOUT, (jl_value_t*)replaced);
jl_uv_puts(JL_STDOUT, "\n", 1);
if (_jl_debug_method_invalidation) {
jl_value_t *boxeddepth = NULL;
JL_GC_PUSH1(&boxeddepth);
jl_array_ptr_1d_push(_jl_debug_method_invalidation, (jl_value_t*)replaced);
boxeddepth = jl_box_int32(depth);
jl_array_ptr_1d_push(_jl_debug_method_invalidation, boxeddepth);
jl_gc_wb(_jl_debug_method_invalidation, boxeddepth);
JL_GC_POP();
}
if (!jl_is_method(replaced->def.method))
return; // shouldn't happen, but better to be safe
Expand Down Expand Up @@ -1622,10 +1638,14 @@ static int invalidate_mt_cache(jl_typemap_entry_t *oldentry, void *closure0)
}
}
if (intersects) {
if (jl_debug_method_invalidation) {
jl_uv_puts(JL_STDOUT, "-- ", 3);
jl_static_show(JL_STDOUT, (jl_value_t*)mi);
jl_uv_puts(JL_STDOUT, "\n", 1);
if (_jl_debug_method_invalidation) {
jl_value_t *loctag = NULL;
JL_GC_PUSH1(&loctag);
jl_array_ptr_1d_push(_jl_debug_method_invalidation, (jl_value_t*)mi);
loctag = jl_cstr_to_string("invalidate_mt_cache");
jl_gc_wb(_jl_debug_method_invalidation, loctag);
jl_array_ptr_1d_push(_jl_debug_method_invalidation, loctag);
JL_GC_POP();
}
oldentry->max_world = env->max_world;
}
Expand Down Expand Up @@ -1673,12 +1693,33 @@ JL_DLLEXPORT void jl_method_table_disable(jl_methtable_t *mt, jl_method_t *metho
jl_typemap_visitor(mt->cache, invalidate_mt_cache, (void*)&mt_cache_env);
// Invalidate the backedges
jl_svec_t *specializations = methodentry->func.method->specializations;
int invalidated = 0;
jl_value_t *loctag = NULL;
JL_GC_PUSH1(&loctag);
size_t i, l = jl_svec_len(specializations);
for (i = 0; i < l; i++) {
jl_method_instance_t *mi = (jl_method_instance_t*)jl_svecref(specializations, i);
if (mi)
invalidate_backedges(mi, methodentry->max_world);
if (mi) {
invalidated = 1;
if (invalidate_backedges(mi, methodentry->max_world))
if (_jl_debug_method_invalidation) {
if (!loctag) {
loctag = jl_cstr_to_string("jl_method_table_disable");
jl_gc_wb(_jl_debug_method_invalidation, loctag);
}
jl_array_ptr_1d_push(_jl_debug_method_invalidation, loctag);
}
}
}
if (invalidated && _jl_debug_method_invalidation) {
jl_array_ptr_1d_push(_jl_debug_method_invalidation, (jl_value_t*)method);
if (!loctag) {
loctag = jl_cstr_to_string("jl_method_table_disable");
jl_gc_wb(_jl_debug_method_invalidation, loctag);
}
jl_array_ptr_1d_push(_jl_debug_method_invalidation, loctag);
}
JL_GC_POP();
JL_UNLOCK(&mt->writelock);
}

Expand All @@ -1693,7 +1734,8 @@ JL_DLLEXPORT void jl_method_table_insert(jl_methtable_t *mt, jl_method_t *method
method->primary_world = ++jl_world_counter;
size_t max_world = method->primary_world - 1;
int invalidated = 0;
JL_GC_PUSH1(&oldvalue);
jl_value_t *loctag = NULL; // debug info for invalidation
JL_GC_PUSH2(&oldvalue, &loctag);
JL_LOCK(&mt->writelock);
// first delete the existing entry (we'll disable it later)
struct jl_typemap_assoc search = {(jl_value_t*)type, method->primary_world, NULL, 0, ~(size_t)0};
Expand Down Expand Up @@ -1722,6 +1764,8 @@ JL_DLLEXPORT void jl_method_table_insert(jl_methtable_t *mt, jl_method_t *method
jl_method_instance_t *backedge = (jl_method_instance_t*)backedges[i];
invalidate_method_instance(backedge, max_world, 0);
invalidated = 1;
if (_jl_debug_method_invalidation)
jl_array_ptr_1d_push(_jl_debug_method_invalidation, (jl_value_t*)backedgetyp);
}
else {
backedges[ins++] = backedges[i - 1];
Expand Down Expand Up @@ -1767,17 +1811,27 @@ JL_DLLEXPORT void jl_method_table_insert(jl_methtable_t *mt, jl_method_t *method
for (i = 0; i < l; i++) {
jl_method_instance_t *mi = (jl_method_instance_t*)jl_svecref(specializations, i);
if (mi != NULL && !jl_has_empty_intersection(type, (jl_value_t*)mi->specTypes))
if (invalidate_backedges(mi, max_world))
if (invalidate_backedges(mi, max_world)) {
invalidated = 1;
if (_jl_debug_method_invalidation) {
jl_array_ptr_1d_push(_jl_debug_method_invalidation, (jl_value_t*)mi);
if (!loctag) {
loctag = jl_cstr_to_string("jl_method_table_insert");
jl_gc_wb(_jl_debug_method_invalidation, loctag);
}
jl_array_ptr_1d_push(_jl_debug_method_invalidation, loctag);
}
}
}
}
}
if (invalidated && jl_debug_method_invalidation) {
jl_uv_puts(JL_STDOUT, ">> ", 3);
jl_static_show(JL_STDOUT, (jl_value_t*)method);
jl_uv_puts(JL_STDOUT, " ", 1);
jl_static_show(JL_STDOUT, (jl_value_t*)type);
jl_uv_puts(JL_STDOUT, "\n", 1);
if (invalidated && _jl_debug_method_invalidation) {
jl_array_ptr_1d_push(_jl_debug_method_invalidation, (jl_value_t*)method);
if (!loctag) {
loctag = jl_cstr_to_string("jl_method_table_insert");
jl_gc_wb(_jl_debug_method_invalidation, loctag);
}
jl_array_ptr_1d_push(_jl_debug_method_invalidation, loctag);
}
update_max_args(mt, type);
JL_UNLOCK(&mt->writelock);
Expand Down

0 comments on commit 65c2a03

Please sign in to comment.