Skip to content

Commit c615a49

Browse files
pchintalapudiKristofferC
authored andcommitted
Remove typeinfer lock altogether (#46825)
* Remove typeinfer lock altogether * Don't remove the typeinf lock functions * Track reentrancy in current task state * Fix up some git status * Initialize task variables * Promise that jl_typeinf_func is rooted somewhere (cherry picked from commit 113efb6)
1 parent 0f271d7 commit c615a49

File tree

10 files changed

+65
-42
lines changed

10 files changed

+65
-42
lines changed

base/compiler/typeinfer.jl

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -404,9 +404,7 @@ function cache_result!(interp::AbstractInterpreter, result::InferenceResult)
404404
if track_newly_inferred[]
405405
m = linfo.def
406406
if isa(m, Method) && m.module != Core
407-
ccall(:jl_typeinf_lock_begin, Cvoid, ())
408-
push!(newly_inferred, linfo)
409-
ccall(:jl_typeinf_lock_end, Cvoid, ())
407+
ccall(:jl_push_newly_inferred, Cvoid, (Any,), linfo)
410408
end
411409
end
412410
end

base/loading.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1662,6 +1662,7 @@ function include_package_for_output(pkg::PkgId, input::String, depot_path::Vecto
16621662
task_local_storage()[:SOURCE_PATH] = source
16631663
end
16641664

1665+
ccall(:jl_set_newly_inferred, Cvoid, (Any,), Core.Compiler.newly_inferred)
16651666
Core.Compiler.track_newly_inferred.x = true
16661667
try
16671668
Base.include(Base.__toplevel__, input)
@@ -1672,7 +1673,6 @@ function include_package_for_output(pkg::PkgId, input::String, depot_path::Vecto
16721673
finally
16731674
Core.Compiler.track_newly_inferred.x = false
16741675
end
1675-
ccall(:jl_set_newly_inferred, Cvoid, (Any,), Core.Compiler.newly_inferred)
16761676
end
16771677

16781678
const PRECOMPILE_TRACE_COMPILE = Ref{String}()

doc/src/devdocs/locks.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ The following is a leaf lock (level 2), and only acquires level 1 locks (safepoi
4242
> * typecache
4343
> * Module->lock
4444
> * JLDebuginfoPlugin::PluginMutex
45+
> * newly_inferred_mutex
4546
4647
The following is a level 3 lock, which can only acquire level 1 or level 2 locks internally:
4748

src/aotcompile.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,8 @@ void *jl_create_native_impl(jl_array_t *methods, LLVMOrcThreadSafeModuleRef llvm
274274
jl_code_info_t *src = NULL;
275275
JL_GC_PUSH1(&src);
276276
JL_LOCK(&jl_codegen_lock);
277+
auto ct = jl_current_task;
278+
ct->reentrant_codegen++;
277279
orc::ThreadSafeContext ctx;
278280
orc::ThreadSafeModule backing;
279281
if (!llvmmod) {
@@ -425,6 +427,7 @@ void *jl_create_native_impl(jl_array_t *methods, LLVMOrcThreadSafeModuleRef llvm
425427
if (ctx.getContext()) {
426428
jl_ExecutionEngine->releaseContext(std::move(ctx));
427429
}
430+
ct->reentrant_codegen--;
428431
JL_UNLOCK(&jl_codegen_lock); // Might GC
429432
return (void*)data;
430433
}

src/dump.c

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,8 @@ static htable_t external_mis;
158158
// Inference tracks newly-inferred MethodInstances during precompilation
159159
// and registers them by calling jl_set_newly_inferred
160160
static jl_array_t *newly_inferred JL_GLOBALLY_ROOTED;
161+
// Mutex for newly_inferred
162+
static jl_mutex_t newly_inferred_mutex;
161163

162164
// New roots to add to Methods. These can't be added until after
163165
// recaching is complete, so we have to hold on to them separately
@@ -2894,14 +2896,23 @@ JL_DLLEXPORT void jl_init_restored_modules(jl_array_t *init_order)
28942896

28952897
// --- entry points ---
28962898

2897-
// Register all newly-inferred MethodInstances
2898-
// This gets called as the final step of Base.include_package_for_output
2899+
// Register array of newly-inferred MethodInstances
2900+
// This gets called as the first step of Base.include_package_for_output
28992901
JL_DLLEXPORT void jl_set_newly_inferred(jl_value_t* _newly_inferred)
29002902
{
29012903
assert(_newly_inferred == NULL || jl_is_array(_newly_inferred));
29022904
newly_inferred = (jl_array_t*) _newly_inferred;
29032905
}
29042906

2907+
JL_DLLEXPORT void jl_push_newly_inferred(jl_value_t* linfo)
2908+
{
2909+
JL_LOCK(&newly_inferred_mutex);
2910+
size_t end = jl_array_len(newly_inferred);
2911+
jl_array_grow_end(newly_inferred, 1);
2912+
jl_arrayset(newly_inferred, linfo, end);
2913+
JL_UNLOCK(&newly_inferred_mutex);
2914+
}
2915+
29052916
// Serialize the modules in `worklist` to file `fname`
29062917
JL_DLLEXPORT int jl_save_incremental(const char *fname, jl_array_t *worklist)
29072918
{

src/gf.c

Lines changed: 18 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -279,8 +279,8 @@ jl_code_info_t *jl_type_infer(jl_method_instance_t *mi, size_t world, int force)
279279
JL_TIMING(INFERENCE);
280280
if (jl_typeinf_func == NULL)
281281
return NULL;
282-
static int in_inference;
283-
if (in_inference > 2)
282+
jl_task_t *ct = jl_current_task;
283+
if (ct->reentrant_inference > 2)
284284
return NULL;
285285

286286
jl_code_info_t *src = NULL;
@@ -300,15 +300,14 @@ jl_code_info_t *jl_type_infer(jl_method_instance_t *mi, size_t world, int force)
300300
jl_printf(JL_STDERR, "\n");
301301
}
302302
#endif
303-
jl_task_t *ct = jl_current_task;
304303
int last_errno = errno;
305304
#ifdef _OS_WINDOWS_
306305
DWORD last_error = GetLastError();
307306
#endif
308307
size_t last_age = ct->world_age;
309308
ct->world_age = jl_typeinf_world;
310309
mi->inInference = 1;
311-
in_inference++;
310+
ct->reentrant_inference++;
312311
JL_TRY {
313312
src = (jl_code_info_t*)jl_apply(fargs, 3);
314313
}
@@ -329,7 +328,7 @@ jl_code_info_t *jl_type_infer(jl_method_instance_t *mi, size_t world, int force)
329328
src = NULL;
330329
}
331330
ct->world_age = last_age;
332-
in_inference--;
331+
ct->reentrant_inference--;
333332
mi->inInference = 0;
334333
#ifdef _OS_WINDOWS_
335334
SetLastError(last_error);
@@ -544,7 +543,7 @@ static int reset_mt_caches(jl_methtable_t *mt, void *env)
544543
}
545544

546545

547-
jl_function_t *jl_typeinf_func = NULL;
546+
jl_function_t *jl_typeinf_func JL_GLOBALLY_ROOTED = NULL;
548547
JL_DLLEXPORT size_t jl_typeinf_world = 1;
549548

550549
JL_DLLEXPORT void jl_set_typeinf_func(jl_value_t *f)
@@ -3416,44 +3415,39 @@ int jl_has_concrete_subtype(jl_value_t *typ)
34163415
return ((jl_datatype_t*)typ)->has_concrete_subtype;
34173416
}
34183417

3419-
// TODO: separate the codegen and typeinf locks
3420-
// currently using a coarser lock seems like
3421-
// the best way to avoid acquisition priority
3422-
// ordering violations
3423-
//static jl_mutex_t typeinf_lock;
34243418
#define typeinf_lock jl_codegen_lock
34253419

3426-
static jl_mutex_t inference_timing_mutex;
3427-
static uint64_t inference_start_time = 0;
3428-
static uint8_t inference_is_measuring_compile_time = 0;
3429-
34303420
JL_DLLEXPORT void jl_typeinf_timing_begin(void)
34313421
{
34323422
if (jl_atomic_load_relaxed(&jl_measure_compile_time_enabled)) {
3433-
JL_LOCK_NOGC(&inference_timing_mutex);
3434-
if (inference_is_measuring_compile_time++ == 0) {
3435-
inference_start_time = jl_hrtime();
3436-
}
3437-
JL_UNLOCK_NOGC(&inference_timing_mutex);
3423+
jl_task_t *ct = jl_current_task;
3424+
if (ct->inference_start_time == 0 && ct->reentrant_inference == 1)
3425+
ct->inference_start_time = jl_hrtime();
34383426
}
34393427
}
34403428

34413429
JL_DLLEXPORT void jl_typeinf_timing_end(void)
34423430
{
3443-
JL_LOCK_NOGC(&inference_timing_mutex);
3444-
if (--inference_is_measuring_compile_time == 0) {
3445-
jl_atomic_fetch_add_relaxed(&jl_cumulative_compile_time, (jl_hrtime() - inference_start_time));
3431+
jl_task_t *ct = jl_current_task;
3432+
if (ct->inference_start_time != 0 && ct->reentrant_inference == 1) {
3433+
jl_atomic_fetch_add_relaxed(&jl_cumulative_compile_time, (jl_hrtime() - ct->inference_start_time));
3434+
ct->inference_start_time = 0;
34463435
}
3447-
JL_UNLOCK_NOGC(&inference_timing_mutex);
34483436
}
34493437

34503438
JL_DLLEXPORT void jl_typeinf_lock_begin(void)
34513439
{
34523440
JL_LOCK(&typeinf_lock);
3441+
//Although this is claiming to be a typeinfer lock, it is actually
3442+
//affecting the codegen lock count, not type inference's inferencing count
3443+
jl_task_t *ct = jl_current_task;
3444+
ct->reentrant_codegen++;
34533445
}
34543446

34553447
JL_DLLEXPORT void jl_typeinf_lock_end(void)
34563448
{
3449+
jl_task_t *ct = jl_current_task;
3450+
ct->reentrant_codegen--;
34573451
JL_UNLOCK(&typeinf_lock);
34583452
}
34593453

src/jitlayers.cpp

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -295,7 +295,8 @@ const char *jl_generate_ccallable(LLVMOrcThreadSafeModuleRef llvmmod, void *sysi
295295
extern "C" JL_DLLEXPORT
296296
int jl_compile_extern_c_impl(LLVMOrcThreadSafeModuleRef llvmmod, void *p, void *sysimg, jl_value_t *declrt, jl_value_t *sigt)
297297
{
298-
JL_LOCK(&jl_codegen_lock);
298+
auto ct = jl_current_task;
299+
ct->reentrant_codegen++;
299300
uint64_t compiler_start_time = 0;
300301
uint8_t measure_compile_time_enabled = jl_atomic_load_relaxed(&jl_measure_compile_time_enabled);
301302
if (measure_compile_time_enabled)
@@ -311,6 +312,7 @@ int jl_compile_extern_c_impl(LLVMOrcThreadSafeModuleRef llvmmod, void *p, void *
311312
backing = jl_create_llvm_module("cextern", pparams ? pparams->tsctx : ctx, pparams ? pparams->imaging : imaging_default());
312313
into = &backing;
313314
}
315+
JL_LOCK(&jl_codegen_lock);
314316
jl_codegen_params_t params(into->getContext());
315317
if (pparams == NULL)
316318
pparams = &params;
@@ -330,12 +332,12 @@ int jl_compile_extern_c_impl(LLVMOrcThreadSafeModuleRef llvmmod, void *p, void *
330332
if (success && llvmmod == NULL)
331333
jl_ExecutionEngine->addModule(std::move(*into));
332334
}
333-
if (jl_codegen_lock.count == 1 && measure_compile_time_enabled)
335+
JL_UNLOCK(&jl_codegen_lock);
336+
if (!--ct->reentrant_codegen && measure_compile_time_enabled)
334337
jl_atomic_fetch_add_relaxed(&jl_cumulative_compile_time, (jl_hrtime() - compiler_start_time));
335338
if (ctx.getContext()) {
336339
jl_ExecutionEngine->releaseContext(std::move(ctx));
337340
}
338-
JL_UNLOCK(&jl_codegen_lock);
339341
return success;
340342
}
341343

@@ -386,7 +388,8 @@ void jl_extern_c_impl(jl_value_t *declrt, jl_tupletype_t *sigt)
386388
extern "C" JL_DLLEXPORT
387389
jl_code_instance_t *jl_generate_fptr_impl(jl_method_instance_t *mi JL_PROPAGATES_ROOT, size_t world)
388390
{
389-
JL_LOCK(&jl_codegen_lock); // also disables finalizers, to prevent any unexpected recursion
391+
auto ct = jl_current_task;
392+
ct->reentrant_codegen++;
390393
uint64_t compiler_start_time = 0;
391394
uint8_t measure_compile_time_enabled = jl_atomic_load_relaxed(&jl_measure_compile_time_enabled);
392395
bool is_recompile = false;
@@ -395,6 +398,7 @@ jl_code_instance_t *jl_generate_fptr_impl(jl_method_instance_t *mi JL_PROPAGATES
395398
// if we don't have any decls already, try to generate it now
396399
jl_code_info_t *src = NULL;
397400
JL_GC_PUSH1(&src);
401+
JL_LOCK(&jl_codegen_lock); // also disables finalizers, to prevent any unexpected recursion
398402
jl_value_t *ci = jl_rettype_inferred(mi, world, world);
399403
jl_code_instance_t *codeinst = (ci == jl_nothing ? NULL : (jl_code_instance_t*)ci);
400404
if (codeinst) {
@@ -437,13 +441,13 @@ jl_code_instance_t *jl_generate_fptr_impl(jl_method_instance_t *mi JL_PROPAGATES
437441
else {
438442
codeinst = NULL;
439443
}
440-
if (jl_codegen_lock.count == 1 && measure_compile_time_enabled) {
444+
JL_UNLOCK(&jl_codegen_lock);
445+
if (!--ct->reentrant_codegen && measure_compile_time_enabled) {
441446
uint64_t t_comp = jl_hrtime() - compiler_start_time;
442447
if (is_recompile)
443448
jl_atomic_fetch_add_relaxed(&jl_cumulative_recompile_time, t_comp);
444449
jl_atomic_fetch_add_relaxed(&jl_cumulative_compile_time, t_comp);
445450
}
446-
JL_UNLOCK(&jl_codegen_lock);
447451
JL_GC_POP();
448452
return codeinst;
449453
}
@@ -454,11 +458,13 @@ void jl_generate_fptr_for_unspecialized_impl(jl_code_instance_t *unspec)
454458
if (jl_atomic_load_relaxed(&unspec->invoke) != NULL) {
455459
return;
456460
}
457-
JL_LOCK(&jl_codegen_lock);
461+
auto ct = jl_current_task;
462+
ct->reentrant_codegen++;
458463
uint64_t compiler_start_time = 0;
459464
uint8_t measure_compile_time_enabled = jl_atomic_load_relaxed(&jl_measure_compile_time_enabled);
460465
if (measure_compile_time_enabled)
461466
compiler_start_time = jl_hrtime();
467+
JL_LOCK(&jl_codegen_lock);
462468
if (jl_atomic_load_relaxed(&unspec->invoke) == NULL) {
463469
jl_code_info_t *src = NULL;
464470
JL_GC_PUSH1(&src);
@@ -486,9 +492,9 @@ void jl_generate_fptr_for_unspecialized_impl(jl_code_instance_t *unspec)
486492
}
487493
JL_GC_POP();
488494
}
489-
if (jl_codegen_lock.count == 1 && measure_compile_time_enabled)
490-
jl_atomic_fetch_add_relaxed(&jl_cumulative_compile_time, (jl_hrtime() - compiler_start_time));
491495
JL_UNLOCK(&jl_codegen_lock); // Might GC
496+
if (!--ct->reentrant_codegen && measure_compile_time_enabled)
497+
jl_atomic_fetch_add_relaxed(&jl_cumulative_compile_time, (jl_hrtime() - compiler_start_time));
492498
}
493499

494500

@@ -508,11 +514,13 @@ jl_value_t *jl_dump_method_asm_impl(jl_method_instance_t *mi, size_t world,
508514
// normally we prevent native code from being generated for these functions,
509515
// (using sentinel value `1` instead)
510516
// so create an exception here so we can print pretty our lies
511-
JL_LOCK(&jl_codegen_lock); // also disables finalizers, to prevent any unexpected recursion
517+
auto ct = jl_current_task;
518+
ct->reentrant_codegen++;
512519
uint64_t compiler_start_time = 0;
513520
uint8_t measure_compile_time_enabled = jl_atomic_load_relaxed(&jl_measure_compile_time_enabled);
514521
if (measure_compile_time_enabled)
515522
compiler_start_time = jl_hrtime();
523+
JL_LOCK(&jl_codegen_lock); // also disables finalizers, to prevent any unexpected recursion
516524
specfptr = (uintptr_t)jl_atomic_load_relaxed(&codeinst->specptr.fptr);
517525
if (specfptr == 0) {
518526
jl_code_info_t *src = jl_type_infer(mi, world, 0);
@@ -536,7 +544,7 @@ jl_value_t *jl_dump_method_asm_impl(jl_method_instance_t *mi, size_t world,
536544
}
537545
JL_GC_POP();
538546
}
539-
if (measure_compile_time_enabled)
547+
if (!--ct->reentrant_codegen && measure_compile_time_enabled)
540548
jl_atomic_fetch_add_relaxed(&jl_cumulative_compile_time, (jl_hrtime() - compiler_start_time));
541549
JL_UNLOCK(&jl_codegen_lock);
542550
}

src/julia.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1765,6 +1765,7 @@ JL_DLLEXPORT void jl_save_system_image(const char *fname);
17651765
JL_DLLEXPORT void jl_restore_system_image(const char *fname);
17661766
JL_DLLEXPORT void jl_restore_system_image_data(const char *buf, size_t len);
17671767
JL_DLLEXPORT void jl_set_newly_inferred(jl_value_t *newly_inferred);
1768+
JL_DLLEXPORT void jl_push_newly_inferred(jl_value_t *linfo);
17681769
JL_DLLEXPORT int jl_save_incremental(const char *fname, jl_array_t *worklist);
17691770
JL_DLLEXPORT jl_value_t *jl_restore_incremental(const char *fname, jl_array_t *depmods);
17701771
JL_DLLEXPORT jl_value_t *jl_restore_incremental_from_buf(const char *buf, size_t sz, jl_array_t *depmods);
@@ -1935,6 +1936,9 @@ typedef struct _jl_task_t {
19351936
jl_ucontext_t ctx;
19361937
void *stkbuf; // malloc'd memory (either copybuf or stack)
19371938
size_t bufsz; // actual sizeof stkbuf
1939+
uint64_t inference_start_time; // time when inference started
1940+
unsigned int reentrant_inference; // How many times we've reentered inference
1941+
unsigned int reentrant_codegen; // How many times we've reentered codegen
19381942
unsigned int copy_stack:31; // sizeof stack for copybuf
19391943
unsigned int started:1;
19401944
} jl_task_t;

src/julia_internal.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,7 @@ void print_func_loc(JL_STREAM *s, jl_method_t *m);
292292
extern jl_array_t *_jl_debug_method_invalidation JL_GLOBALLY_ROOTED;
293293

294294
extern JL_DLLEXPORT size_t jl_page_size;
295-
extern jl_function_t *jl_typeinf_func;
295+
extern jl_function_t *jl_typeinf_func JL_GLOBALLY_ROOTED;
296296
extern JL_DLLEXPORT size_t jl_typeinf_world;
297297
extern _Atomic(jl_typemap_entry_t*) call_cache[N_CALL_CACHE] JL_GLOBALLY_ROOTED;
298298
extern jl_array_t *jl_all_methods JL_GLOBALLY_ROOTED;

src/task.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -938,6 +938,8 @@ JL_DLLEXPORT jl_task_t *jl_new_task(jl_function_t *start, jl_value_t *completion
938938
t->threadpoolid = ct->threadpoolid;
939939
t->ptls = NULL;
940940
t->world_age = ct->world_age;
941+
t->reentrant_codegen = 0;
942+
t->reentrant_inference = 0;
941943

942944
#ifdef COPY_STACKS
943945
if (!t->copy_stack) {
@@ -1523,6 +1525,8 @@ jl_task_t *jl_init_root_task(jl_ptls_t ptls, void *stack_lo, void *stack_hi)
15231525
ct->sticky = 1;
15241526
ct->ptls = ptls;
15251527
ct->world_age = 1; // OK to run Julia code on this task
1528+
ct->reentrant_codegen = 0;
1529+
ct->reentrant_inference = 0;
15261530
ptls->root_task = ct;
15271531
jl_atomic_store_relaxed(&ptls->current_task, ct);
15281532
JL_GC_PROMISE_ROOTED(ct);

0 commit comments

Comments
 (0)