Skip to content

Commit 044695d

Browse files
committed
[ORC] Implement basic reoptimization.
1 parent 6059562 commit 044695d

File tree

8 files changed

+619
-10
lines changed

8 files changed

+619
-10
lines changed

compiler-rt/lib/orc/common.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@
1919

2020
/// This macro should be used to define tags that will be associated with
2121
/// handlers in the JIT process, and call can be used to define tags f
22-
#define ORC_RT_JIT_DISPATCH_TAG(X) \
23-
extern "C" char X; \
24-
char X = 0;
22+
#define ORC_RT_JIT_DISPATCH_TAG(X) \
23+
ORC_RT_INTERFACE char X; \
24+
char X = 0;
2525

2626
/// Opaque struct for external symbols.
2727
struct __orc_rt_Opaque {};

compiler-rt/lib/orc/elfnix_platform.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ using namespace __orc_rt;
2828
using namespace __orc_rt::elfnix;
2929

3030
// Declare function tags for functions in the JIT process.
31+
ORC_RT_JIT_DISPATCH_TAG(__orc_rt_reoptimize_tag)
3132
ORC_RT_JIT_DISPATCH_TAG(__orc_rt_elfnix_get_initializers_tag)
3233
ORC_RT_JIT_DISPATCH_TAG(__orc_rt_elfnix_get_deinitializers_tag)
3334
ORC_RT_JIT_DISPATCH_TAG(__orc_rt_elfnix_symbol_lookup_tag)
Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
//===- ReOptimizeLayer.h - Re-optimization layer interface ------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// Re-optimization layer interface.
10+
//
11+
//===----------------------------------------------------------------------===//
12+
#ifndef LLVM_EXECUTIONENGINE_ORC_REOPTLAYER_H
13+
#define LLVM_EXECUTIONENGINE_ORC_REOPTLAYER_H
14+
15+
#include "llvm/ExecutionEngine/Orc/Core.h"
16+
#include "llvm/ExecutionEngine/Orc/Layer.h"
17+
#include "llvm/ExecutionEngine/Orc/RedirectionManager.h"
18+
#include "llvm/ExecutionEngine/Orc/ThreadSafeModule.h"
19+
#include "llvm/IR/IRBuilder.h"
20+
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
21+
#include "llvm/Transforms/Utils/Cloning.h"
22+
23+
namespace llvm {
24+
namespace orc {
25+
26+
using ReOptMaterializationUnitID = uint64_t;
27+
28+
class ReOptimizeLayer : public IRLayer, public ResourceManager {
29+
public:
30+
/// AddProfilerFunc will be called when ReOptimizeLayer emits the first
31+
/// version of a materialization unit in order to inject profiling code and
32+
/// reoptimization request code.
33+
using AddProfilerFunc = unique_function<Error(
34+
ReOptimizeLayer &Parent, ReOptMaterializationUnitID MUID,
35+
unsigned CurVersion, ThreadSafeModule &TSM)>;
36+
37+
/// ReOptimizeFunc will be called when ReOptimizeLayer reoptimization of a
38+
/// materialization unit was requested in order to reoptimize the IR module
39+
/// based on profile data. OldRT is the ResourceTracker that tracks the old
40+
/// function definitions. The OldRT must be kept alive until it can be
41+
/// guaranteed that every invocation of the old function definitions has been
42+
/// terminated.
43+
using ReOptimizeFunc = unique_function<Error(
44+
ReOptimizeLayer &Parent, ReOptMaterializationUnitID MUID,
45+
unsigned CurVersion, ResourceTrackerSP OldRT, ThreadSafeModule &TSM)>;
46+
47+
ReOptimizeLayer(ExecutionSession &ES, IRLayer &BaseLayer,
48+
RedirectableSymbolManager &RM)
49+
: IRLayer(ES, BaseLayer.getManglingOptions()), ES(ES),
50+
BaseLayer(BaseLayer), RSManager(RM), ReOptFunc(identity),
51+
ProfilerFunc(reoptimizeIfCallFrequent) {}
52+
53+
void setReoptimizeFunc(ReOptimizeFunc ReOptFunc) {
54+
this->ReOptFunc = std::move(ReOptFunc);
55+
}
56+
57+
void setAddProfilerFunc(AddProfilerFunc ProfilerFunc) {
58+
this->ProfilerFunc = std::move(ProfilerFunc);
59+
}
60+
61+
/// Registers reoptimize runtime dispatch handlers to given PlatformJD. The
62+
/// reoptimization request will not be handled if dispatch handler is not
63+
/// registered by using this function.
64+
Error reigsterRuntimeFunctions(JITDylib &PlatformJD);
65+
66+
/// Emits the given module. This should not be called by clients: it will be
67+
/// called by the JIT when a definition added via the add method is requested.
68+
void emit(std::unique_ptr<MaterializationResponsibility> R,
69+
ThreadSafeModule TSM) override;
70+
71+
static const uint64_t CallCountThreshold = 10;
72+
73+
/// Basic AddProfilerFunc that reoptimizes the function when the call count
74+
/// exceeds CallCountThreshold.
75+
static Error reoptimizeIfCallFrequent(ReOptimizeLayer &Parent,
76+
ReOptMaterializationUnitID MUID,
77+
unsigned CurVersion,
78+
ThreadSafeModule &TSM);
79+
80+
static Error identity(ReOptimizeLayer &Parent,
81+
ReOptMaterializationUnitID MUID, unsigned CurVersion,
82+
ResourceTrackerSP OldRT, ThreadSafeModule &TSM) {
83+
return Error::success();
84+
}
85+
86+
// Create IR reoptimize request fucntion call.
87+
static void createReoptimizeCall(Module &M, Instruction &IP,
88+
GlobalVariable *ArgBuffer);
89+
90+
Error handleRemoveResources(JITDylib &JD, ResourceKey K) override;
91+
void handleTransferResources(JITDylib &JD, ResourceKey DstK,
92+
ResourceKey SrcK) override;
93+
94+
private:
95+
class ReOptMaterializationUnitState {
96+
public:
97+
ReOptMaterializationUnitState() = default;
98+
ReOptMaterializationUnitState(ReOptMaterializationUnitID ID,
99+
ThreadSafeModule TSM)
100+
: ID(ID), TSM(std::move(TSM)) {}
101+
ReOptMaterializationUnitState(ReOptMaterializationUnitState &&Other)
102+
: ID(Other.ID), TSM(std::move(Other.TSM)), RT(std::move(Other.RT)),
103+
Reoptimizing(std::move(Other.Reoptimizing)),
104+
CurVersion(Other.CurVersion) {}
105+
106+
ReOptMaterializationUnitID getID() { return ID; }
107+
108+
const ThreadSafeModule &getThreadSafeModule() { return TSM; }
109+
110+
ResourceTrackerSP getResourceTracker() {
111+
std::unique_lock<std::mutex> Lock(Mutex);
112+
return RT;
113+
}
114+
115+
void setResourceTracker(ResourceTrackerSP RT) {
116+
std::unique_lock<std::mutex> Lock(Mutex);
117+
this->RT = RT;
118+
}
119+
120+
uint32_t getCurVersion() {
121+
std::unique_lock<std::mutex> Lock(Mutex);
122+
return CurVersion;
123+
}
124+
125+
bool tryStartReoptimize();
126+
void reoptimizeSucceeded();
127+
void reoptimizeFailed();
128+
129+
private:
130+
std::mutex Mutex;
131+
ReOptMaterializationUnitID ID;
132+
ThreadSafeModule TSM;
133+
ResourceTrackerSP RT;
134+
bool Reoptimizing = false;
135+
uint32_t CurVersion = 0;
136+
};
137+
138+
using SPSReoptimizeArgList =
139+
shared::SPSArgList<ReOptMaterializationUnitID, uint32_t>;
140+
using SendErrorFn = unique_function<void(Error)>;
141+
142+
Expected<SymbolMap> emitMUImplSymbols(ReOptMaterializationUnitState &MUState,
143+
uint32_t Version, JITDylib &JD,
144+
ThreadSafeModule TSM);
145+
146+
void rt_reoptimize(SendErrorFn SendResult, ReOptMaterializationUnitID MUID,
147+
uint32_t CurVersion);
148+
149+
static Expected<Constant *>
150+
createReoptimizeArgBuffer(Module &M, ReOptMaterializationUnitID MUID,
151+
uint32_t CurVersion);
152+
153+
ReOptMaterializationUnitState &
154+
createMaterializationUnitState(const ThreadSafeModule &TSM);
155+
156+
void
157+
registerMaterializationUnitResource(ResourceKey Key,
158+
ReOptMaterializationUnitState &State);
159+
160+
ReOptMaterializationUnitState &
161+
getMaterializationUnitState(ReOptMaterializationUnitID MUID);
162+
163+
ExecutionSession &ES;
164+
IRLayer &BaseLayer;
165+
RedirectableSymbolManager &RSManager;
166+
167+
ReOptimizeFunc ReOptFunc;
168+
AddProfilerFunc ProfilerFunc;
169+
170+
std::mutex Mutex;
171+
std::map<ReOptMaterializationUnitID, ReOptMaterializationUnitState> MUStates;
172+
DenseMap<ResourceKey, DenseSet<ReOptMaterializationUnitID>> MUResources;
173+
ReOptMaterializationUnitID NextID = 1;
174+
};
175+
176+
} // namespace orc
177+
} // namespace llvm
178+
179+
#endif

llvm/lib/ExecutionEngine/Orc/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ add_llvm_component_library(LLVMOrcJIT
5252
ThreadSafeModule.cpp
5353
RedirectionManager.cpp
5454
JITLinkRedirectableSymbolManager.cpp
55+
ReOptimizeLayer.cpp
5556
ADDITIONAL_HEADER_DIRS
5657
${LLVM_MAIN_INCLUDE_DIR}/llvm/ExecutionEngine/Orc
5758

llvm/lib/ExecutionEngine/Orc/JITLinkRedirectableSymbolManager.cpp

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,21 +37,21 @@ void JITLinkRedirectableSymbolManager::emitRedirectableSymbols(
3737
R->failMaterialization();
3838
return;
3939
}
40-
dbgs() << *K << "\n";
4140
SymbolToStubs[&TargetJD][K] = StubID;
4241
NewSymbolDefs[K] = JumpStubs[StubID];
4342
NewSymbolDefs[K].setFlags(V.getFlags());
4443
Symbols.push_back(K);
4544
AvailableStubs.pop_back();
4645
}
4746

48-
if (auto Err = R->replace(absoluteSymbols(NewSymbolDefs))) {
47+
// FIXME: when this fails we can return stubs to the pool
48+
if (auto Err = redirectInner(TargetJD, InitialDests)) {
4949
ES.reportError(std::move(Err));
5050
R->failMaterialization();
5151
return;
5252
}
5353

54-
if (auto Err = redirectInner(TargetJD, InitialDests)) {
54+
if (auto Err = R->replace(absoluteSymbols(NewSymbolDefs))) {
5555
ES.reportError(std::move(Err));
5656
R->failMaterialization();
5757
return;
@@ -85,10 +85,8 @@ Error JITLinkRedirectableSymbolManager::redirectInner(
8585
StubHandle StubID = SymbolToStubs[&TargetJD].at(K);
8686
PtrWrites.push_back({StubPointers[StubID].getAddress(), V.getAddress()});
8787
}
88-
if (auto Err = ES.getExecutorProcessControl().getMemoryAccess().writePointers(
89-
PtrWrites))
90-
return Err;
91-
return Error::success();
88+
return ES.getExecutorProcessControl().getMemoryAccess().writePointers(
89+
PtrWrites);
9290
}
9391

9492
Error JITLinkRedirectableSymbolManager::grow(unsigned Need) {
@@ -113,6 +111,7 @@ Error JITLinkRedirectableSymbolManager::grow(unsigned Need) {
113111
auto &StubsSection =
114112
G->createSection(JumpStubTableName, MemProt::Exec | MemProt::Read);
115113

114+
// FIXME: We can batch the stubs into one block and use address to access them
116115
for (size_t I = OldSize; I < NewSize; I++) {
117116
auto Pointer = AnonymousPtrCreator(*G, PointerSection, nullptr, 0);
118117
if (auto Err = Pointer.takeError())

0 commit comments

Comments
 (0)