Skip to content

Commit bb27e45

Browse files
committed
[ORC] Add SimpleRemoteEPC: ExecutorProcessControl over SPS + abstract transport.
SimpleRemoteEPC is an ExecutorProcessControl implementation (with corresponding new server class) that uses ORC SimplePackedSerialization (SPS) to serialize and deserialize EPC-messages to/from byte-buffers. The byte-buffers are sent and received via a new SimpleRemoteEPCTransport interface that can be implemented to run SimpleRemoteEPC over whatever underlying transport system (IPC, RPC, network sockets, etc.) best suits your use case. The SimpleRemoteEPCServer class provides executor-side support. It uses a customizable SimpleRemoteEPCServer::Dispatcher object to dispatch wrapper function calls to prevent the RPC thread from being blocked (a problem in some earlier remote-JIT server implementations). Almost all functionality (beyond the bare basics needed to bootstrap) is implemented as wrapper functions to keep the implementation simple and uniform. Compared to previous remote JIT utilities (OrcRemoteTarget*, OrcRPCExecutorProcessControl), more consideration has been given to disconnection and error handling behavior: Graceful disconnection is now always initiated by the ORC side of the connection, and failure at either end (or in the transport) will result in Errors being delivered to both ends to enable controlled tear-down of the JIT and Executor (in the Executor's case this means "as controlled as the JIT'd code allows"). The introduction of SimpleRemoteEPC will allow us to remove other remote-JIT support from ORC (including the legacy OrcRemoteTarget* code used by lli, and the OrcRPCExecutorProcessControl and OrcRPCEPCServer classes), and then remove ORC RPC itself. The llvm-jitlink and llvm-jitlink-executor tools have been updated to use SimpleRemoteEPC over file descriptors. Future commits will move lli and other tools and example code to this system, and remove ORC RPC.
1 parent c6bf8b8 commit bb27e45

File tree

17 files changed

+1516
-218
lines changed

17 files changed

+1516
-218
lines changed

llvm/include/llvm/ExecutionEngine/Orc/Core.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1302,7 +1302,8 @@ class ExecutionSession {
13021302
/// object.
13031303
ExecutionSession(std::unique_ptr<ExecutorProcessControl> EPC);
13041304

1305-
/// End the session. Closes all JITDylibs.
1305+
/// End the session. Closes all JITDylibs and disconnects from the
1306+
/// executor.
13061307
Error endSession();
13071308

13081309
/// Get the ExecutorProcessControl object associated with this

llvm/include/llvm/ExecutionEngine/Orc/EPCGenericJITLinkMemoryManager.h

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,6 @@ class EPCGenericJITLinkMemoryManager : public jitlink::JITLinkMemoryManager {
3838
EPCGenericJITLinkMemoryManager(ExecutorProcessControl &EPC, FuncAddrs FAs)
3939
: EPC(EPC), FAs(FAs) {}
4040

41-
/// Create using the standard memory allocation function names from the
42-
/// ORCTargetProcess library.
43-
static Expected<std::unique_ptr<EPCGenericJITLinkMemoryManager>>
44-
CreateUsingOrcRTFuncs(ExecutorProcessControl &EPC);
45-
4641
Expected<std::unique_ptr<Allocation>>
4742
allocate(const jitlink::JITLinkDylib *JD,
4843
const SegmentsRequestMap &Request) override;

llvm/include/llvm/ExecutionEngine/Orc/EPCGenericMemoryAccess.h

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,6 @@ class EPCGenericMemoryAccess : public ExecutorProcessControl::MemoryAccess {
3939
EPCGenericMemoryAccess(ExecutorProcessControl &EPC, FuncAddrs FAs)
4040
: EPC(EPC), FAs(FAs) {}
4141

42-
/// Create using the standard memory access function names from the
43-
/// ORCTargetProcess library.
44-
static Expected<std::unique_ptr<EPCGenericMemoryAccess>>
45-
CreateUsingOrcRTFuncs(ExecutorProcessControl &EPC);
46-
4742
void writeUInt8sAsync(ArrayRef<tpctypes::UInt8Write> Ws,
4843
WriteResultFn OnWriteComplete) override {
4944
using namespace shared;
Lines changed: 249 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,249 @@
1+
//===--- SimpleRemoteEPCUtils.h - Utils for Simple Remote EPC ---*- 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+
// Message definitions and other utilities for SimpleRemoteEPC and
10+
// SimpleRemoteEPCServer.
11+
//
12+
//===----------------------------------------------------------------------===//
13+
14+
#ifndef LLVM_EXECUTIONENGINE_ORC_SHARED_SIMPLEREMOTEEPCUTILS_H
15+
#define LLVM_EXECUTIONENGINE_ORC_SHARED_SIMPLEREMOTEEPCUTILS_H
16+
17+
#include "llvm/ADT/ArrayRef.h"
18+
#include "llvm/ADT/SmallVector.h"
19+
#include "llvm/ADT/StringMap.h"
20+
#include "llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h"
21+
#include "llvm/ExecutionEngine/Orc/Shared/SimplePackedSerialization.h"
22+
#include "llvm/Support/Error.h"
23+
24+
#include <string>
25+
#include <thread>
26+
27+
namespace llvm {
28+
namespace orc {
29+
30+
namespace SimpleRemoteEPCDefaultBootstrapSymbolNames {
31+
extern const char *ExecutorSessionObjectName;
32+
extern const char *DispatchFnName;
33+
} // end namespace SimpleRemoteEPCDefaultBootstrapSymbolNames
34+
35+
enum class SimpleRemoteEPCOpcode : uint8_t {
36+
FirstOpC,
37+
Setup = FirstOpC,
38+
Hangup,
39+
Result,
40+
CallWrapper,
41+
LastOpC = CallWrapper
42+
};
43+
44+
struct SimpleRemoteEPCExecutorInfo {
45+
std::string TargetTriple;
46+
uint64_t PageSize;
47+
StringMap<ExecutorAddress> BootstrapSymbols;
48+
49+
Expected<ExecutorAddress> getBootstrapSymbol(StringRef Name) const {
50+
auto I = BootstrapSymbols.find(Name);
51+
if (I == BootstrapSymbols.end())
52+
return make_error<StringError>("Symbol \"" + Name +
53+
"\" not found in "
54+
"bootstrap symbols map",
55+
inconvertibleErrorCode());
56+
return I->second;
57+
}
58+
59+
Error getBootstrapSymbols(
60+
ArrayRef<std::pair<ExecutorAddress &, StringRef>> Pairs) const {
61+
for (auto &KV : Pairs) {
62+
if (auto A = getBootstrapSymbol(KV.second))
63+
KV.first = *A;
64+
else
65+
return A.takeError();
66+
}
67+
return Error::success();
68+
}
69+
};
70+
71+
using SimpleRemoteEPCArgBytesVector = SmallVector<char, 128>;
72+
73+
class SimpleRemoteEPCTransportClient {
74+
public:
75+
enum HandleMessageAction { ContinueSession, EndSession };
76+
77+
virtual ~SimpleRemoteEPCTransportClient();
78+
79+
/// Handle receipt of a message.
80+
///
81+
/// Returns an Error if the message cannot be handled, 'EndSession' if the
82+
/// client will not accept any further messages, and 'ContinueSession'
83+
/// otherwise.
84+
virtual Expected<HandleMessageAction>
85+
handleMessage(SimpleRemoteEPCOpcode OpC, uint64_t SeqNo,
86+
ExecutorAddress TagAddr,
87+
SimpleRemoteEPCArgBytesVector ArgBytes) = 0;
88+
89+
/// Handle a disconnection from the underlying transport. No further messages
90+
/// should be sent to handleMessage after this is called.
91+
/// Err may contain an Error value indicating unexpected disconnection. This
92+
/// allows clients to log such errors, but no attempt should be made at
93+
/// recovery (which should be handled inside the transport class, if it is
94+
/// supported at all).
95+
virtual void handleDisconnect(Error Err) = 0;
96+
};
97+
98+
class SimpleRemoteEPCTransport {
99+
public:
100+
virtual ~SimpleRemoteEPCTransport();
101+
102+
/// Send a SimpleRemoteEPC message.
103+
///
104+
/// This function may be called concurrently. Subclasses should implement
105+
/// locking if required for the underlying transport.
106+
virtual Error sendMessage(SimpleRemoteEPCOpcode OpC, uint64_t SeqNo,
107+
ExecutorAddress TagAddr,
108+
ArrayRef<char> ArgBytes) = 0;
109+
110+
/// Trigger disconnection from the transport. The implementation should
111+
/// respond by calling handleDisconnect on the client once disconnection
112+
/// is complete.
113+
virtual void disconnect() = 0;
114+
};
115+
116+
/// Uses read/write on FileDescriptors for transport.
117+
class FDSimpleRemoteEPCTransport : public SimpleRemoteEPCTransport {
118+
public:
119+
/// Create a FDSimpleRemoteEPCTransport using the given FDs for
120+
/// reading (InFD) and writing (OutFD).
121+
static Expected<std::unique_ptr<FDSimpleRemoteEPCTransport>>
122+
Create(SimpleRemoteEPCTransportClient &C, int InFD, int OutFD);
123+
124+
/// Create a FDSimpleRemoteEPCTransport using the given FD for both
125+
/// reading and writing.
126+
static Expected<std::unique_ptr<FDSimpleRemoteEPCTransport>>
127+
Create(SimpleRemoteEPCTransportClient &C, int FD) {
128+
return Create(C, FD, FD);
129+
}
130+
131+
~FDSimpleRemoteEPCTransport() override;
132+
133+
Error sendMessage(SimpleRemoteEPCOpcode OpC, uint64_t SeqNo,
134+
ExecutorAddress TagAddr, ArrayRef<char> ArgBytes) override;
135+
136+
void disconnect() override;
137+
138+
private:
139+
FDSimpleRemoteEPCTransport(SimpleRemoteEPCTransportClient &C, int InFD,
140+
int OutFD);
141+
142+
Error readBytes(char *Dst, size_t Size, bool *IsEOF = nullptr);
143+
int writeBytes(const char *Src, size_t Size);
144+
void listenLoop();
145+
146+
std::mutex M;
147+
SimpleRemoteEPCTransportClient &C;
148+
std::thread ListenerThread;
149+
int InFD, OutFD;
150+
};
151+
152+
struct RemoteSymbolLookupSetElement {
153+
std::string Name;
154+
bool Required;
155+
};
156+
157+
using RemoteSymbolLookupSet = std::vector<RemoteSymbolLookupSetElement>;
158+
159+
struct RemoteSymbolLookup {
160+
uint64_t H;
161+
RemoteSymbolLookupSet Symbols;
162+
};
163+
164+
namespace shared {
165+
166+
using SPSRemoteSymbolLookupSetElement = SPSTuple<SPSString, bool>;
167+
168+
using SPSRemoteSymbolLookupSet = SPSSequence<SPSRemoteSymbolLookupSetElement>;
169+
170+
using SPSRemoteSymbolLookup = SPSTuple<uint64_t, SPSRemoteSymbolLookupSet>;
171+
172+
/// Tuple containing target triple, page size, and bootstrap symbols.
173+
using SPSSimpleRemoteEPCExecutorInfo =
174+
SPSTuple<SPSString, uint64_t,
175+
SPSSequence<SPSTuple<SPSString, SPSExecutorAddress>>>;
176+
177+
template <>
178+
class SPSSerializationTraits<SPSRemoteSymbolLookupSetElement,
179+
RemoteSymbolLookupSetElement> {
180+
public:
181+
static size_t size(const RemoteSymbolLookupSetElement &V) {
182+
return SPSArgList<SPSString, bool>::size(V.Name, V.Required);
183+
}
184+
185+
static size_t serialize(SPSOutputBuffer &OB,
186+
const RemoteSymbolLookupSetElement &V) {
187+
return SPSArgList<SPSString, bool>::serialize(OB, V.Name, V.Required);
188+
}
189+
190+
static size_t deserialize(SPSInputBuffer &IB,
191+
RemoteSymbolLookupSetElement &V) {
192+
return SPSArgList<SPSString, bool>::deserialize(IB, V.Name, V.Required);
193+
}
194+
};
195+
196+
template <>
197+
class SPSSerializationTraits<SPSRemoteSymbolLookup, RemoteSymbolLookup> {
198+
public:
199+
static size_t size(const RemoteSymbolLookup &V) {
200+
return SPSArgList<uint64_t, SPSRemoteSymbolLookupSet>::size(V.H, V.Symbols);
201+
}
202+
203+
static size_t serialize(SPSOutputBuffer &OB, const RemoteSymbolLookup &V) {
204+
return SPSArgList<uint64_t, SPSRemoteSymbolLookupSet>::serialize(OB, V.H,
205+
V.Symbols);
206+
}
207+
208+
static size_t deserialize(SPSInputBuffer &IB, RemoteSymbolLookup &V) {
209+
return SPSArgList<uint64_t, SPSRemoteSymbolLookupSet>::deserialize(
210+
IB, V.H, V.Symbols);
211+
}
212+
};
213+
214+
template <>
215+
class SPSSerializationTraits<SPSSimpleRemoteEPCExecutorInfo,
216+
SimpleRemoteEPCExecutorInfo> {
217+
public:
218+
static size_t size(const SimpleRemoteEPCExecutorInfo &SI) {
219+
return SPSSimpleRemoteEPCExecutorInfo::AsArgList ::size(
220+
SI.TargetTriple, SI.PageSize, SI.BootstrapSymbols);
221+
}
222+
223+
static bool serialize(SPSOutputBuffer &OB,
224+
const SimpleRemoteEPCExecutorInfo &SI) {
225+
return SPSSimpleRemoteEPCExecutorInfo::AsArgList ::serialize(
226+
OB, SI.TargetTriple, SI.PageSize, SI.BootstrapSymbols);
227+
}
228+
229+
static bool deserialize(SPSInputBuffer &IB, SimpleRemoteEPCExecutorInfo &SI) {
230+
return SPSSimpleRemoteEPCExecutorInfo::AsArgList ::deserialize(
231+
IB, SI.TargetTriple, SI.PageSize, SI.BootstrapSymbols);
232+
}
233+
};
234+
235+
using SPSRunAsMainSignature = int64_t(SPSExecutorAddress,
236+
SPSSequence<SPSString>);
237+
238+
using SPSLoadDylibSignature =
239+
SPSExpected<SPSExecutorAddress>(SPSExecutorAddress, SPSString, uint64_t);
240+
241+
using SPSLookupSymbolsSignature =
242+
SPSExpected<SPSSequence<SPSSequence<SPSExecutorAddress>>>(
243+
SPSExecutorAddress, SPSSequence<SPSRemoteSymbolLookup>);
244+
245+
} // end namespace shared
246+
} // end namespace orc
247+
} // end namespace llvm
248+
249+
#endif // LLVM_EXECUTIONENGINE_ORC_SHARED_SIMPLEREMOTEEPCUTILS_H

0 commit comments

Comments
 (0)