Skip to content

Commit 79a845c

Browse files
authored
Don't reuse passmanagers across compilations (#52054)
1 parent 9884e44 commit 79a845c

File tree

6 files changed

+52
-45
lines changed

6 files changed

+52
-45
lines changed

doc/src/devdocs/locks.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ The following are definitely leaf locks (level 1), and must not try to acquire a
3030
> * jl_in_stackwalk (Win32)
3131
> * ResourcePool<?>::mutex
3232
> * RLST_mutex
33+
> * llvm_printing_mutex
3334
> * jl_locked_stream::mutex
3435
> * debuginfo_asyncsafe
3536
> * inference_timing_mutex

src/aotcompile.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1414,12 +1414,15 @@ static SmallVector<AOTOutputs, 16> add_output(Module &M, TargetMachine &TM, Stri
14141414
return outputs;
14151415
}
14161416

1417+
extern int jl_is_timing_passes;
14171418
static unsigned compute_image_thread_count(const ModuleInfo &info) {
14181419
// 32-bit systems are very memory-constrained
14191420
#ifdef _P32
14201421
LLVM_DEBUG(dbgs() << "32-bit systems are restricted to a single thread\n");
14211422
return 1;
14221423
#endif
1424+
if (jl_is_timing_passes) // LLVM isn't thread safe when timing the passes https://github.com/llvm/llvm-project/issues/44417
1425+
return 1;
14231426
// COFF has limits on external symbols (even hidden) up to 65536. We reserve the last few
14241427
// for any of our other symbols that we insert during compilation.
14251428
if (info.triple.isOSBinFormatCOFF() && info.globals > 64000) {

src/codegen.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9483,6 +9483,8 @@ char jl_using_oprofile_jitevents = 0; // Non-zero if running under OProfile
94839483
char jl_using_perf_jitevents = 0;
94849484
#endif
94859485

9486+
int jl_is_timing_passes = 0;
9487+
94869488
extern "C" void jl_init_llvm(void)
94879489
{
94889490
jl_page_size = jl_getpagesize();
@@ -9541,6 +9543,11 @@ extern "C" void jl_init_llvm(void)
95419543
if (clopt && clopt->getNumOccurrences() == 0) {
95429544
clopt->addOccurrence(1, clopt->ArgStr, "false", true);
95439545
}
9546+
9547+
clopt = llvmopts.lookup("time-passes");
9548+
if (clopt && clopt->getNumOccurrences() > 0)
9549+
jl_is_timing_passes = 1;
9550+
95449551
jl_ExecutionEngine = new JuliaOJIT();
95459552

95469553
bool jl_using_gdb_jitevents = false;

src/jitlayers.cpp

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1249,26 +1249,30 @@ namespace {
12491249
orc::JITTargetMachineBuilder JTMB;
12501250
OptimizationLevel O;
12511251
SmallVector<std::function<void()>, 0> &printers;
1252-
PMCreator(TargetMachine &TM, int optlevel, SmallVector<std::function<void()>, 0> &printers) JL_NOTSAFEPOINT
1253-
: JTMB(createJTMBFromTM(TM, optlevel)), O(getOptLevel(optlevel)), printers(printers) {}
1252+
std::mutex &llvm_printing_mutex;
1253+
PMCreator(TargetMachine &TM, int optlevel, SmallVector<std::function<void()>, 0> &printers, std::mutex &llvm_printing_mutex) JL_NOTSAFEPOINT
1254+
: JTMB(createJTMBFromTM(TM, optlevel)), O(getOptLevel(optlevel)), printers(printers), llvm_printing_mutex(llvm_printing_mutex) {}
12541255

12551256
auto operator()() JL_NOTSAFEPOINT {
12561257
auto TM = cantFail(JTMB.createTargetMachine());
12571258
fixupTM(*TM);
12581259
auto NPM = std::make_unique<NewPM>(std::move(TM), O);
12591260
// TODO this needs to be locked, as different resource pools may add to the printer vector at the same time
1260-
printers.push_back([NPM = NPM.get()]() JL_NOTSAFEPOINT {
1261-
NPM->printTimers();
1262-
});
1261+
{
1262+
std::lock_guard<std::mutex> lock(llvm_printing_mutex);
1263+
printers.push_back([NPM = NPM.get()]() JL_NOTSAFEPOINT {
1264+
NPM->printTimers();
1265+
});
1266+
}
12631267
return NPM;
12641268
}
12651269
};
12661270

12671271
template<size_t N>
12681272
struct OptimizerT {
1269-
OptimizerT(TargetMachine &TM, SmallVector<std::function<void()>, 0> &printers) JL_NOTSAFEPOINT {
1273+
OptimizerT(TargetMachine &TM, SmallVector<std::function<void()>, 0> &printers, std::mutex &llvm_printing_mutex) JL_NOTSAFEPOINT {
12701274
for (size_t i = 0; i < N; i++) {
1271-
PMs[i] = std::make_unique<JuliaOJIT::ResourcePool<std::unique_ptr<PassManager>>>(PMCreator(TM, i, printers));
1275+
PMs[i] = std::make_unique<JuliaOJIT::ResourcePool<std::unique_ptr<PassManager>>>(PMCreator(TM, i, printers, llvm_printing_mutex));
12721276
}
12731277
}
12741278

@@ -1706,7 +1710,7 @@ JuliaOJIT::JuliaOJIT()
17061710
LockLayer(ObjectLayer),
17071711
CompileLayer(ES, LockLayer, std::make_unique<CompilerT<N_optlevels>>(orc::irManglingOptionsFromTargetOptions(TM->Options), *TM)),
17081712
JITPointersLayer(ES, CompileLayer, orc::IRTransformLayer::TransformFunction(JITPointersT(SharedBytes, RLST_mutex))),
1709-
OptimizeLayer(ES, JITPointersLayer, orc::IRTransformLayer::TransformFunction(OptimizerT<N_optlevels>(*TM, PrintLLVMTimers))),
1713+
OptimizeLayer(ES, JITPointersLayer, orc::IRTransformLayer::TransformFunction(OptimizerT<N_optlevels>(*TM, PrintLLVMTimers, llvm_printing_mutex))),
17101714
OptSelLayer(ES, OptimizeLayer, orc::IRTransformLayer::TransformFunction(selectOptLevel)),
17111715
DepsVerifyLayer(ES, OptSelLayer, orc::IRTransformLayer::TransformFunction(validateExternRelocations)),
17121716
ExternalCompileLayer(ES, LockLayer,

src/jitlayers.h

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <llvm/IR/Value.h>
1111
#include <llvm/IR/PassManager.h>
1212
#include <llvm/IR/LegacyPassManager.h>
13+
#include <llvm/IR/PassTimingInfo.h>
1314

1415
#include <llvm/ExecutionEngine/Orc/IRCompileLayer.h>
1516
#include <llvm/ExecutionEngine/Orc/IRTransformLayer.h>
@@ -101,14 +102,9 @@ struct OptimizationOptions {
101102

102103
struct NewPM {
103104
std::unique_ptr<TargetMachine> TM;
104-
#if JL_LLVM_VERSION < 160000
105-
StandardInstrumentations SI;
106-
#endif
107-
std::unique_ptr<PassInstrumentationCallbacks> PIC;
108-
PassBuilder PB;
109-
ModulePassManager MPM;
110105
OptimizationLevel O;
111-
106+
OptimizationOptions options;
107+
TimePassesHandler TimePasses;
112108
NewPM(std::unique_ptr<TargetMachine> TM, OptimizationLevel O, OptimizationOptions options = OptimizationOptions::defaults()) JL_NOTSAFEPOINT;
113109
~NewPM() JL_NOTSAFEPOINT;
114110

@@ -582,6 +578,7 @@ class JuliaOJIT {
582578
jl_locked_stream dump_compiles_stream;
583579
jl_locked_stream dump_llvm_opt_stream;
584580

581+
std::mutex llvm_printing_mutex{};
585582
SmallVector<std::function<void()>, 0> PrintLLVMTimers;
586583

587584
ResourcePool<orc::ThreadSafeContext, 0, std::queue<orc::ThreadSafeContext>> ContextPool;

src/pipeline.cpp

Lines changed: 25 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -701,21 +701,6 @@ PIC.addClassToPassName(decltype(CREATE_PASS)::name(), NAME);
701701
PIC.addClassToPassName("AfterOptimizationMarkerPass", "AfterOptimization");
702702
}
703703

704-
#if JL_LLVM_VERSION >= 160000
705-
auto createPIC() JL_NOTSAFEPOINT {
706-
auto PIC = std::make_unique<PassInstrumentationCallbacks>();
707-
adjustPIC(*PIC);
708-
return PIC;
709-
}
710-
#else
711-
auto createPIC(StandardInstrumentations &SI) JL_NOTSAFEPOINT {
712-
auto PIC = std::make_unique<PassInstrumentationCallbacks>();
713-
adjustPIC(*PIC);
714-
SI.registerCallbacks(*PIC);
715-
return PIC;
716-
}
717-
#endif
718-
719704
FunctionAnalysisManager createFAM(OptimizationLevel O, TargetMachine &TM) JL_NOTSAFEPOINT {
720705

721706
FunctionAnalysisManager FAM;
@@ -744,15 +729,8 @@ PIC.addClassToPassName(decltype(CREATE_PASS)::name(), NAME);
744729
}
745730

746731
NewPM::NewPM(std::unique_ptr<TargetMachine> TM, OptimizationLevel O, OptimizationOptions options) :
747-
TM(std::move(TM)),
748-
#if JL_LLVM_VERSION < 160000
749-
SI(false),
750-
PIC(createPIC(SI)),
751-
#else
752-
PIC(createPIC()),
753-
#endif
754-
PB(this->TM.get(), PipelineTuningOptions(), None, PIC.get()),
755-
MPM(createMPM(PB, O, options)), O(O) {}
732+
TM(std::move(TM)), O(O), options(options), TimePasses() {}
733+
756734

757735
NewPM::~NewPM() = default;
758736

@@ -778,17 +756,34 @@ void NewPM::run(Module &M) {
778756
//We must recreate the analysis managers every time
779757
//so that analyses from previous runs of the pass manager
780758
//do not hang around for the next run
781-
AnalysisManagers AM{*TM, PB, O};
782-
759+
#if JL_LLVM_VERSION >= 160000
760+
StandardInstrumentations SI(M.getContext(),false);
761+
#else
762+
StandardInstrumentations SI(false);
763+
#endif
764+
FunctionAnalysisManager FAM(createFAM(O, *TM.get()));
765+
PassInstrumentationCallbacks PIC;
766+
adjustPIC(PIC);
767+
TimePasses.registerCallbacks(PIC);
768+
SI.registerCallbacks(PIC, &FAM);
769+
SI.getTimePasses().setOutStream(nulls()); //TODO: figure out a better way of doing this
770+
LoopAnalysisManager LAM;
771+
CGSCCAnalysisManager CGAM;
772+
ModuleAnalysisManager MAM;
773+
PassBuilder PB(TM.get(), PipelineTuningOptions(), None, &PIC);
774+
PB.registerLoopAnalyses(LAM);
775+
PB.registerFunctionAnalyses(FAM);
776+
PB.registerCGSCCAnalyses(CGAM);
777+
PB.registerModuleAnalyses(MAM);
778+
PB.crossRegisterProxies(LAM, FAM, CGAM, MAM);
779+
ModulePassManager MPM = createMPM(PB, O, options);
783780
#ifndef __clang_gcanalyzer__ /* the analyzer cannot prove we have not added instrumentation callbacks with safepoints */
784-
MPM.run(M, AM.MAM);
781+
MPM.run(M, MAM);
785782
#endif
786783
}
787784

788785
void NewPM::printTimers() {
789-
#if JL_LLVM_VERSION < 160000
790-
SI.getTimePasses().print();
791-
#endif
786+
TimePasses.print();
792787
}
793788

794789
OptimizationLevel getOptLevel(int optlevel) {

0 commit comments

Comments
 (0)