Skip to content

Commit 4d02f43

Browse files
committed
Don't reuse passmanagers across compilations
1 parent b1f954c commit 4d02f43

File tree

5 files changed

+44
-47
lines changed

5 files changed

+44
-47
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: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1032,7 +1032,7 @@ static AOTOutputs add_output_impl(Module &M, TargetMachine &SourceTM, ShardTimer
10321032
SourceTM.getCodeModel(),
10331033
SourceTM.getOptLevel()));
10341034
fixupTM(*PMTM);
1035-
NewPM optimizer{std::move(PMTM), getOptLevel(jl_options.opt_level), OptimizationOptions::defaults(true, true)};
1035+
NewPM optimizer{std::move(PMTM), getOptLevel(jl_options.opt_level), M.getContext(), OptimizationOptions::defaults(true, true)};
10361036
optimizer.run(M);
10371037
assert(!verifyLLVMIR(M));
10381038
bool inject_aliases = false;
@@ -1909,7 +1909,7 @@ void jl_get_llvmf_defn_impl(jl_llvmf_dump_t* dump, jl_method_instance_t *mi, siz
19091909
}
19101910
assert(!verifyLLVMIR(*m.getModuleUnlocked()));
19111911
if (optimize) {
1912-
NewPM PM{jl_ExecutionEngine->cloneTargetMachine(), getOptLevel(jl_options.opt_level)};
1912+
NewPM PM{jl_ExecutionEngine->cloneTargetMachine(), getOptLevel(jl_options.opt_level), output.getContext()};
19131913
//Safe b/c context lock is held by output
19141914
PM.run(*m.getModuleUnlocked());
19151915
assert(!verifyLLVMIR(*m.getModuleUnlocked()));

src/jitlayers.cpp

Lines changed: 34 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1245,37 +1245,20 @@ namespace {
12451245
}
12461246
};
12471247

1248-
struct PMCreator {
1249-
orc::JITTargetMachineBuilder JTMB;
1250-
OptimizationLevel O;
1251-
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) {}
1254-
1255-
auto operator()() JL_NOTSAFEPOINT {
1256-
auto TM = cantFail(JTMB.createTargetMachine());
1257-
fixupTM(*TM);
1258-
auto NPM = std::make_unique<NewPM>(std::move(TM), O);
1259-
// 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-
});
1263-
return NPM;
1264-
}
1265-
};
12661248

12671249
template<size_t N>
12681250
struct OptimizerT {
1269-
OptimizerT(TargetMachine &TM, SmallVector<std::function<void()>, 0> &printers) JL_NOTSAFEPOINT {
1251+
OptimizerT(TargetMachine &TM, SmallSet<std::function<void()>*, 4> &printers, std::mutex &print_mutex) JL_NOTSAFEPOINT
1252+
:TM(TM), printers(printers), print_mutex(print_mutex) {
12701253
for (size_t i = 0; i < N; i++) {
1271-
PMs[i] = std::make_unique<JuliaOJIT::ResourcePool<std::unique_ptr<PassManager>>>(PMCreator(TM, i, printers));
1254+
JTMBs.push_back(createJTMBFromTM(TM, i));
12721255
}
1273-
}
1256+
}
12741257

12751258
OptimizerResultT operator()(orc::ThreadSafeModule TSM, orc::MaterializationResponsibility &R) JL_NOTSAFEPOINT {
12761259
TSM.withModuleDo([&](Module &M) JL_NOTSAFEPOINT {
1277-
auto PoolIdx = cast<ConstantInt>(cast<ConstantAsMetadata>(M.getModuleFlag("julia.optlevel"))->getValue())->getZExtValue();
1278-
assert(PoolIdx < N && "Invalid optimization pool index");
1260+
auto optlevel = cast<ConstantInt>(cast<ConstantAsMetadata>(M.getModuleFlag("julia.optlevel"))->getValue())->getZExtValue();
1261+
assert(optlevel < N && "Invalid optimization pool index");
12791262

12801263
uint64_t start_time = 0;
12811264

@@ -1312,7 +1295,22 @@ namespace {
13121295
{
13131296
JL_TIMING(LLVM_JIT, JIT_Opt);
13141297
//Run the optimization
1315-
(****PMs[PoolIdx]).run(M);
1298+
auto TM = cantFail(JTMBs[optlevel].createTargetMachine());
1299+
fixupTM(*TM);
1300+
NewPM NPM(std::move(TM), getOptLevel(optlevel), M.getContext());
1301+
// TODO this needs to be locked, as different resource pools may add to the printer vector at the same time
1302+
std::function<void()> printfun = [&]() JL_NOTSAFEPOINT {
1303+
NPM.printTimers();
1304+
};
1305+
{
1306+
std::lock_guard<std::mutex> lock(print_mutex);
1307+
printers.insert(&printfun);
1308+
}
1309+
NPM.run(M);
1310+
{
1311+
std::lock_guard<std::mutex> lock(print_mutex);
1312+
printers.erase(&printfun);
1313+
}
13161314
assert(!verifyLLVMIR(M));
13171315
}
13181316

@@ -1346,7 +1344,7 @@ namespace {
13461344
s.dump(stream);
13471345
}
13481346
ios_printf(stream, " time_ns: %" PRIu64 "\n", end_time - start_time);
1349-
ios_printf(stream, " optlevel: %d\n", PoolIdx);
1347+
ios_printf(stream, " optlevel: %d\n", optlevel);
13501348

13511349
// Print LLVM function statistics _after_ optimization
13521350
ios_printf(stream, " after: \n");
@@ -1359,7 +1357,7 @@ namespace {
13591357
}
13601358
}
13611359
++ModulesOptimized;
1362-
switch (PoolIdx) {
1360+
switch (optlevel) {
13631361
case 0:
13641362
++OptO0;
13651363
break;
@@ -1380,7 +1378,10 @@ namespace {
13801378
return Expected<orc::ThreadSafeModule>{std::move(TSM)};
13811379
}
13821380
private:
1383-
std::array<std::unique_ptr<JuliaOJIT::ResourcePool<std::unique_ptr<PassManager>>>, N> PMs;
1381+
TargetMachine &TM;
1382+
SmallSet<std::function<void()>*, 4> &printers;
1383+
std::mutex &print_mutex;
1384+
SmallVector<orc::JITTargetMachineBuilder, 4> JTMBs;
13841385
};
13851386

13861387
template<size_t N>
@@ -1697,7 +1698,7 @@ JuliaOJIT::JuliaOJIT()
16971698
LockLayer(ObjectLayer),
16981699
CompileLayer(ES, LockLayer, std::make_unique<CompilerT<N_optlevels>>(orc::irManglingOptionsFromTargetOptions(TM->Options), *TM)),
16991700
JITPointersLayer(ES, CompileLayer, orc::IRTransformLayer::TransformFunction(JITPointersT(ES))),
1700-
OptimizeLayer(ES, JITPointersLayer, orc::IRTransformLayer::TransformFunction(OptimizerT<N_optlevels>(*TM, PrintLLVMTimers))),
1701+
OptimizeLayer(ES, JITPointersLayer, orc::IRTransformLayer::TransformFunction(OptimizerT<N_optlevels>(*TM, PrintLLVMTimers, llvm_printing_mutex))),
17011702
OptSelLayer(ES, OptimizeLayer, orc::IRTransformLayer::TransformFunction(selectOptLevel)),
17021703
DepsVerifyLayer(ES, OptSelLayer, orc::IRTransformLayer::TransformFunction(validateExternRelocations)),
17031704
ExternalCompileLayer(ES, LockLayer,
@@ -2043,8 +2044,11 @@ size_t JuliaOJIT::getTotalBytes() const
20432044

20442045
void JuliaOJIT::printTimers()
20452046
{
2046-
for (auto &printer : PrintLLVMTimers) {
2047-
printer();
2047+
{
2048+
std::lock_guard<std::mutex> lock(llvm_printing_mutex);
2049+
for (auto printer : PrintLLVMTimers) {
2050+
(*printer)();
2051+
}
20482052
}
20492053
reportAndResetTimings();
20502054
}

src/jitlayers.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// This file is a part of Julia. License is MIT: https://julialang.org/license
22

33
#include <llvm/ADT/MapVector.h>
4+
#include "llvm/ADT/SmallSet.h"
45

56
#include <llvm/IR/LLVMContext.h>
67
#include <llvm/IR/Constants.h>
@@ -99,15 +100,13 @@ struct OptimizationOptions {
99100

100101
struct NewPM {
101102
std::unique_ptr<TargetMachine> TM;
102-
#if JL_LLVM_VERSION < 160000
103103
StandardInstrumentations SI;
104-
#endif
105104
std::unique_ptr<PassInstrumentationCallbacks> PIC;
106105
PassBuilder PB;
107106
ModulePassManager MPM;
108107
OptimizationLevel O;
109108

110-
NewPM(std::unique_ptr<TargetMachine> TM, OptimizationLevel O, OptimizationOptions options = OptimizationOptions::defaults()) JL_NOTSAFEPOINT;
109+
NewPM(std::unique_ptr<TargetMachine> TM, OptimizationLevel O, LLVMContext &ctx, OptimizationOptions options = OptimizationOptions::defaults()) JL_NOTSAFEPOINT;
111110
~NewPM() JL_NOTSAFEPOINT;
112111

113112
void run(Module &M) JL_NOTSAFEPOINT;
@@ -537,7 +536,8 @@ class JuliaOJIT {
537536
jl_locked_stream dump_compiles_stream;
538537
jl_locked_stream dump_llvm_opt_stream;
539538

540-
SmallVector<std::function<void()>, 0> PrintLLVMTimers;
539+
std::mutex llvm_printing_mutex{};
540+
SmallSet<std::function<void()>*, 4> PrintLLVMTimers;
541541

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

src/pipeline.cpp

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -701,20 +701,12 @@ 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
711704
auto createPIC(StandardInstrumentations &SI) JL_NOTSAFEPOINT {
712705
auto PIC = std::make_unique<PassInstrumentationCallbacks>();
713706
adjustPIC(*PIC);
714707
SI.registerCallbacks(*PIC);
715708
return PIC;
716709
}
717-
#endif
718710

719711
FunctionAnalysisManager createFAM(OptimizationLevel O, TargetMachine &TM) JL_NOTSAFEPOINT {
720712

@@ -743,14 +735,14 @@ PIC.addClassToPassName(decltype(CREATE_PASS)::name(), NAME);
743735
}
744736
}
745737

746-
NewPM::NewPM(std::unique_ptr<TargetMachine> TM, OptimizationLevel O, OptimizationOptions options) :
738+
NewPM::NewPM(std::unique_ptr<TargetMachine> TM, OptimizationLevel O, LLVMContext &ctx, OptimizationOptions options) :
747739
TM(std::move(TM)),
748740
#if JL_LLVM_VERSION < 160000
749741
SI(false),
750-
PIC(createPIC(SI)),
751742
#else
752-
PIC(createPIC()),
743+
SI(ctx, false),
753744
#endif
745+
PIC(createPIC(SI)),
754746
PB(this->TM.get(), PipelineTuningOptions(), None, PIC.get()),
755747
MPM(createMPM(PB, O, options)), O(O) {}
756748

0 commit comments

Comments
 (0)