Skip to content

Commit 65c2a03

Browse files
authored
jl_debug_method_invalidation: return a list of instances, signatures, 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").
1 parent 2855625 commit 65c2a03

File tree

2 files changed

+83
-26
lines changed

2 files changed

+83
-26
lines changed

src/dump.c

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1830,7 +1830,7 @@ static void jl_insert_methods(jl_array_t *list)
18301830
}
18311831
}
18321832

1833-
extern int jl_debug_method_invalidation;
1833+
extern jl_array_t *_jl_debug_method_invalidation JL_GLOBALLY_ROOTED;
18341834

18351835
// verify that these edges intersect with the same methods as before
18361836
static void jl_verify_edges(jl_array_t *targets, jl_array_t **pvalids)
@@ -1884,7 +1884,8 @@ static void jl_insert_backedges(jl_array_t *list, jl_array_t *targets)
18841884
// map(enable, ((list[i] => targets[list[i + 1] .* 2]) for i in 1:2:length(list) if all(valids[list[i + 1]])))
18851885
size_t i, l = jl_array_len(list);
18861886
jl_array_t *valids = NULL;
1887-
JL_GC_PUSH1(&valids);
1887+
jl_value_t *loctag = NULL;
1888+
JL_GC_PUSH2(&valids, &loctag);
18881889
jl_verify_edges(targets, &valids);
18891890
for (i = 0; i < l; i += 2) {
18901891
jl_method_instance_t *caller = (jl_method_instance_t*)jl_array_ptr_ref(list, i);
@@ -1922,9 +1923,11 @@ static void jl_insert_backedges(jl_array_t *list, jl_array_t *targets)
19221923
}
19231924
}
19241925
else {
1925-
if (jl_debug_method_invalidation) {
1926-
jl_static_show(JL_STDOUT, (jl_value_t*)caller);
1927-
jl_uv_puts(JL_STDOUT, "<<<\n", 4);
1926+
if (_jl_debug_method_invalidation) {
1927+
jl_array_ptr_1d_push(_jl_debug_method_invalidation, (jl_value_t*)caller);
1928+
loctag = jl_cstr_to_string("insert_backedges");
1929+
jl_gc_wb(_jl_debug_method_invalidation, loctag);
1930+
jl_array_ptr_1d_push(_jl_debug_method_invalidation, loctag);
19281931
}
19291932
}
19301933
}

src/gf.c

Lines changed: 75 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1485,17 +1485,33 @@ static void update_max_args(jl_methtable_t *mt, jl_value_t *type)
14851485
mt->max_args = na;
14861486
}
14871487

1488-
JL_DLLEXPORT int jl_debug_method_invalidation = 0;
1488+
jl_array_t *_jl_debug_method_invalidation JL_GLOBALLY_ROOTED = NULL;
1489+
JL_DLLEXPORT jl_value_t *jl_debug_method_invalidation(int state)
1490+
{
1491+
/* After calling with `state = 1`, caller is responsible for
1492+
holding a reference to the returned array until this is called
1493+
again with `state = 0`. */
1494+
if (state) {
1495+
if (_jl_debug_method_invalidation)
1496+
return (jl_value_t*) _jl_debug_method_invalidation;
1497+
_jl_debug_method_invalidation = jl_alloc_array_1d(jl_array_any_type, 0);
1498+
return (jl_value_t*) _jl_debug_method_invalidation;
1499+
}
1500+
_jl_debug_method_invalidation = NULL;
1501+
return jl_nothing;
1502+
}
14891503

14901504
// recursively invalidate cached methods that had an edge to a replaced method
14911505
static void invalidate_method_instance(jl_method_instance_t *replaced, size_t max_world, int depth)
14921506
{
1493-
if (jl_debug_method_invalidation) {
1494-
int d0 = depth;
1495-
while (d0-- > 0)
1496-
jl_uv_puts(JL_STDOUT, " ", 1);
1497-
jl_static_show(JL_STDOUT, (jl_value_t*)replaced);
1498-
jl_uv_puts(JL_STDOUT, "\n", 1);
1507+
if (_jl_debug_method_invalidation) {
1508+
jl_value_t *boxeddepth = NULL;
1509+
JL_GC_PUSH1(&boxeddepth);
1510+
jl_array_ptr_1d_push(_jl_debug_method_invalidation, (jl_value_t*)replaced);
1511+
boxeddepth = jl_box_int32(depth);
1512+
jl_array_ptr_1d_push(_jl_debug_method_invalidation, boxeddepth);
1513+
jl_gc_wb(_jl_debug_method_invalidation, boxeddepth);
1514+
JL_GC_POP();
14991515
}
15001516
if (!jl_is_method(replaced->def.method))
15011517
return; // shouldn't happen, but better to be safe
@@ -1622,10 +1638,14 @@ static int invalidate_mt_cache(jl_typemap_entry_t *oldentry, void *closure0)
16221638
}
16231639
}
16241640
if (intersects) {
1625-
if (jl_debug_method_invalidation) {
1626-
jl_uv_puts(JL_STDOUT, "-- ", 3);
1627-
jl_static_show(JL_STDOUT, (jl_value_t*)mi);
1628-
jl_uv_puts(JL_STDOUT, "\n", 1);
1641+
if (_jl_debug_method_invalidation) {
1642+
jl_value_t *loctag = NULL;
1643+
JL_GC_PUSH1(&loctag);
1644+
jl_array_ptr_1d_push(_jl_debug_method_invalidation, (jl_value_t*)mi);
1645+
loctag = jl_cstr_to_string("invalidate_mt_cache");
1646+
jl_gc_wb(_jl_debug_method_invalidation, loctag);
1647+
jl_array_ptr_1d_push(_jl_debug_method_invalidation, loctag);
1648+
JL_GC_POP();
16291649
}
16301650
oldentry->max_world = env->max_world;
16311651
}
@@ -1673,12 +1693,33 @@ JL_DLLEXPORT void jl_method_table_disable(jl_methtable_t *mt, jl_method_t *metho
16731693
jl_typemap_visitor(mt->cache, invalidate_mt_cache, (void*)&mt_cache_env);
16741694
// Invalidate the backedges
16751695
jl_svec_t *specializations = methodentry->func.method->specializations;
1696+
int invalidated = 0;
1697+
jl_value_t *loctag = NULL;
1698+
JL_GC_PUSH1(&loctag);
16761699
size_t i, l = jl_svec_len(specializations);
16771700
for (i = 0; i < l; i++) {
16781701
jl_method_instance_t *mi = (jl_method_instance_t*)jl_svecref(specializations, i);
1679-
if (mi)
1680-
invalidate_backedges(mi, methodentry->max_world);
1702+
if (mi) {
1703+
invalidated = 1;
1704+
if (invalidate_backedges(mi, methodentry->max_world))
1705+
if (_jl_debug_method_invalidation) {
1706+
if (!loctag) {
1707+
loctag = jl_cstr_to_string("jl_method_table_disable");
1708+
jl_gc_wb(_jl_debug_method_invalidation, loctag);
1709+
}
1710+
jl_array_ptr_1d_push(_jl_debug_method_invalidation, loctag);
1711+
}
1712+
}
1713+
}
1714+
if (invalidated && _jl_debug_method_invalidation) {
1715+
jl_array_ptr_1d_push(_jl_debug_method_invalidation, (jl_value_t*)method);
1716+
if (!loctag) {
1717+
loctag = jl_cstr_to_string("jl_method_table_disable");
1718+
jl_gc_wb(_jl_debug_method_invalidation, loctag);
1719+
}
1720+
jl_array_ptr_1d_push(_jl_debug_method_invalidation, loctag);
16811721
}
1722+
JL_GC_POP();
16821723
JL_UNLOCK(&mt->writelock);
16831724
}
16841725

@@ -1693,7 +1734,8 @@ JL_DLLEXPORT void jl_method_table_insert(jl_methtable_t *mt, jl_method_t *method
16931734
method->primary_world = ++jl_world_counter;
16941735
size_t max_world = method->primary_world - 1;
16951736
int invalidated = 0;
1696-
JL_GC_PUSH1(&oldvalue);
1737+
jl_value_t *loctag = NULL; // debug info for invalidation
1738+
JL_GC_PUSH2(&oldvalue, &loctag);
16971739
JL_LOCK(&mt->writelock);
16981740
// first delete the existing entry (we'll disable it later)
16991741
struct jl_typemap_assoc search = {(jl_value_t*)type, method->primary_world, NULL, 0, ~(size_t)0};
@@ -1722,6 +1764,8 @@ JL_DLLEXPORT void jl_method_table_insert(jl_methtable_t *mt, jl_method_t *method
17221764
jl_method_instance_t *backedge = (jl_method_instance_t*)backedges[i];
17231765
invalidate_method_instance(backedge, max_world, 0);
17241766
invalidated = 1;
1767+
if (_jl_debug_method_invalidation)
1768+
jl_array_ptr_1d_push(_jl_debug_method_invalidation, (jl_value_t*)backedgetyp);
17251769
}
17261770
else {
17271771
backedges[ins++] = backedges[i - 1];
@@ -1767,17 +1811,27 @@ JL_DLLEXPORT void jl_method_table_insert(jl_methtable_t *mt, jl_method_t *method
17671811
for (i = 0; i < l; i++) {
17681812
jl_method_instance_t *mi = (jl_method_instance_t*)jl_svecref(specializations, i);
17691813
if (mi != NULL && !jl_has_empty_intersection(type, (jl_value_t*)mi->specTypes))
1770-
if (invalidate_backedges(mi, max_world))
1814+
if (invalidate_backedges(mi, max_world)) {
17711815
invalidated = 1;
1816+
if (_jl_debug_method_invalidation) {
1817+
jl_array_ptr_1d_push(_jl_debug_method_invalidation, (jl_value_t*)mi);
1818+
if (!loctag) {
1819+
loctag = jl_cstr_to_string("jl_method_table_insert");
1820+
jl_gc_wb(_jl_debug_method_invalidation, loctag);
1821+
}
1822+
jl_array_ptr_1d_push(_jl_debug_method_invalidation, loctag);
1823+
}
1824+
}
17721825
}
17731826
}
17741827
}
1775-
if (invalidated && jl_debug_method_invalidation) {
1776-
jl_uv_puts(JL_STDOUT, ">> ", 3);
1777-
jl_static_show(JL_STDOUT, (jl_value_t*)method);
1778-
jl_uv_puts(JL_STDOUT, " ", 1);
1779-
jl_static_show(JL_STDOUT, (jl_value_t*)type);
1780-
jl_uv_puts(JL_STDOUT, "\n", 1);
1828+
if (invalidated && _jl_debug_method_invalidation) {
1829+
jl_array_ptr_1d_push(_jl_debug_method_invalidation, (jl_value_t*)method);
1830+
if (!loctag) {
1831+
loctag = jl_cstr_to_string("jl_method_table_insert");
1832+
jl_gc_wb(_jl_debug_method_invalidation, loctag);
1833+
}
1834+
jl_array_ptr_1d_push(_jl_debug_method_invalidation, loctag);
17811835
}
17821836
update_max_args(mt, type);
17831837
JL_UNLOCK(&mt->writelock);

0 commit comments

Comments
 (0)