Skip to content

Commit 9c456e5

Browse files
authored
[ORC] Add SimpleRemoteMemoryMapper (new MemoryMapper implementation). (#163707)
SimpleRemoteMemoryMapper is a MemoryMapper implementation that manages remote memory via EPC-calls to reserve, initialize, deinitialize, and release operations. It is compatible with the SimpleExecutorMemoryManager backend, and its introduction allows MapperJITLinkMemoryManager to use this backend. It is also intended to be compatible with the orc_rt::SimpleNativeMemoryMap backend.
1 parent cf55dfb commit 9c456e5

File tree

4 files changed

+242
-8
lines changed

4 files changed

+242
-8
lines changed
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
//===- SimpleRemoteMemoryMapper.h - Remote memory mapper --------*- 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+
// A simple memory mapper that uses EPC calls to implement reserve, initialize,
10+
// deinitialize, and release.
11+
//
12+
//===----------------------------------------------------------------------===//
13+
14+
#ifndef LLVM_EXECUTIONENGINE_ORC_SIMPLEREMOTEMEMORYMAPPER_H
15+
#define LLVM_EXECUTIONENGINE_ORC_SIMPLEREMOTEMEMORYMAPPER_H
16+
17+
#include "llvm/ExecutionEngine/Orc/MemoryMapper.h"
18+
19+
namespace llvm::orc {
20+
21+
/// Manages remote memory by making SPS-based EPC calls.
22+
class LLVM_ABI SimpleRemoteMemoryMapper final : public MemoryMapper {
23+
public:
24+
struct SymbolAddrs {
25+
ExecutorAddr Instance;
26+
ExecutorAddr Reserve;
27+
ExecutorAddr Initialize;
28+
ExecutorAddr Deinitialize;
29+
ExecutorAddr Release;
30+
};
31+
32+
SimpleRemoteMemoryMapper(ExecutorProcessControl &EPC, SymbolAddrs SAs);
33+
34+
static Expected<std::unique_ptr<SimpleRemoteMemoryMapper>>
35+
Create(ExecutorProcessControl &EPC, SymbolAddrs SAs) {
36+
return std::make_unique<SimpleRemoteMemoryMapper>(EPC, SAs);
37+
}
38+
39+
unsigned int getPageSize() override { return EPC.getPageSize(); }
40+
41+
/// Reserves memory in the remote process by calling a remote
42+
/// SPS-wrapper-function with signature
43+
///
44+
/// SPSExpected<SPSExecutorAddr>(uint64_t Size).
45+
///
46+
/// On success, returns the base address of the reserved range.
47+
void reserve(size_t NumBytes, OnReservedFunction OnReserved) override;
48+
49+
char *prepare(jitlink::LinkGraph &G, ExecutorAddr Addr,
50+
size_t ContentSize) override;
51+
52+
/// Initializes memory within a previously reserved region (applying
53+
/// protections and running any finalization actions) by calling a remote
54+
/// SPS-wrapper-function with signature
55+
///
56+
/// SPSExpected<SPSExecutorAddr>(SPSFinalizeRequest)
57+
///
58+
/// On success, returns a key that can be used to deinitialize the region.
59+
void initialize(AllocInfo &AI, OnInitializedFunction OnInitialized) override;
60+
61+
/// Given a series of keys from previous initialize calls, deinitialize
62+
/// previously initialized memory regions (running dealloc actions, resetting
63+
/// permissions and decommitting if possible) by calling a remote
64+
/// SPS-wrapper-function with signature
65+
///
66+
/// SPSError(SPSSequence<SPSExecutorAddr> Keys)
67+
///
68+
void deinitialize(ArrayRef<ExecutorAddr> Allocations,
69+
OnDeinitializedFunction OnDeInitialized) override;
70+
71+
/// Given a sequence of base addresses from previous reserve calls, release
72+
/// the underlying ranges (deinitializing any remaining regions within them)
73+
/// by calling a remote SPS-wrapper-function with signature
74+
///
75+
/// SPSError(SPSSequence<SPSExecutorAddr> Bases)
76+
///
77+
void release(ArrayRef<ExecutorAddr> Reservations,
78+
OnReleasedFunction OnRelease) override;
79+
80+
private:
81+
ExecutorProcessControl &EPC;
82+
SymbolAddrs SAs;
83+
};
84+
85+
} // namespace llvm::orc
86+
87+
#endif // LLVM_EXECUTIONENGINE_ORC_SIMPLEREMOTEMEMORYMAPPER_H

llvm/lib/ExecutionEngine/Orc/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ add_llvm_component_library(LLVMOrcJIT
5656
SectCreate.cpp
5757
SelfExecutorProcessControl.cpp
5858
SimpleRemoteEPC.cpp
59+
SimpleRemoteMemoryMapper.cpp
5960
Speculation.cpp
6061
SpeculateAnalyses.cpp
6162
ExecutorProcessControl.cpp
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
//===---- SimpleRemoteMemoryMapper.cpp - Remote memory mapper ----*- 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+
#include "llvm/ExecutionEngine/Orc/SimpleRemoteMemoryMapper.h"
10+
11+
#include "llvm/ExecutionEngine/JITLink/JITLink.h"
12+
#include "llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h"
13+
14+
namespace llvm::orc {
15+
16+
SimpleRemoteMemoryMapper::SimpleRemoteMemoryMapper(ExecutorProcessControl &EPC,
17+
SymbolAddrs SAs)
18+
: EPC(EPC), SAs(SAs) {}
19+
20+
void SimpleRemoteMemoryMapper::reserve(size_t NumBytes,
21+
OnReservedFunction OnReserved) {
22+
EPC.callSPSWrapperAsync<rt::SPSSimpleRemoteMemoryMapReserveSignature>(
23+
SAs.Reserve,
24+
[NumBytes, OnReserved = std::move(OnReserved)](
25+
Error SerializationErr, Expected<ExecutorAddr> Result) mutable {
26+
if (SerializationErr) {
27+
cantFail(Result.takeError());
28+
return OnReserved(std::move(SerializationErr));
29+
}
30+
31+
if (Result)
32+
OnReserved(ExecutorAddrRange(*Result, NumBytes));
33+
else
34+
OnReserved(Result.takeError());
35+
},
36+
SAs.Instance, static_cast<uint64_t>(NumBytes));
37+
}
38+
39+
char *SimpleRemoteMemoryMapper::prepare(jitlink::LinkGraph &G,
40+
ExecutorAddr Addr, size_t ContentSize) {
41+
return G.allocateBuffer(ContentSize).data();
42+
}
43+
44+
void SimpleRemoteMemoryMapper::initialize(MemoryMapper::AllocInfo &AI,
45+
OnInitializedFunction OnInitialized) {
46+
47+
tpctypes::FinalizeRequest FR;
48+
49+
std::swap(FR.Actions, AI.Actions);
50+
FR.Segments.reserve(AI.Segments.size());
51+
52+
for (auto Seg : AI.Segments)
53+
FR.Segments.push_back({Seg.AG, AI.MappingBase + Seg.Offset,
54+
Seg.ContentSize + Seg.ZeroFillSize,
55+
ArrayRef<char>(Seg.WorkingMem, Seg.ContentSize)});
56+
57+
EPC.callSPSWrapperAsync<rt::SPSSimpleRemoteMemoryMapInitializeSignature>(
58+
SAs.Initialize,
59+
[OnInitialized = std::move(OnInitialized)](
60+
Error SerializationErr, Expected<ExecutorAddr> Result) mutable {
61+
if (SerializationErr) {
62+
cantFail(Result.takeError());
63+
return OnInitialized(std::move(SerializationErr));
64+
}
65+
66+
OnInitialized(std::move(Result));
67+
},
68+
SAs.Instance, std::move(FR));
69+
}
70+
71+
void SimpleRemoteMemoryMapper::deinitialize(
72+
ArrayRef<ExecutorAddr> Allocations,
73+
MemoryMapper::OnDeinitializedFunction OnDeinitialized) {
74+
EPC.callSPSWrapperAsync<rt::SPSSimpleRemoteMemoryMapDeinitializeSignature>(
75+
SAs.Deinitialize,
76+
[OnDeinitialized = std::move(OnDeinitialized)](Error SerializationErr,
77+
Error Result) mutable {
78+
if (SerializationErr) {
79+
cantFail(std::move(Result));
80+
return OnDeinitialized(std::move(SerializationErr));
81+
}
82+
83+
OnDeinitialized(std::move(Result));
84+
},
85+
SAs.Instance, Allocations);
86+
}
87+
88+
void SimpleRemoteMemoryMapper::release(ArrayRef<ExecutorAddr> Bases,
89+
OnReleasedFunction OnReleased) {
90+
EPC.callSPSWrapperAsync<rt::SPSSimpleRemoteMemoryMapReleaseSignature>(
91+
SAs.Release,
92+
[OnReleased = std::move(OnReleased)](Error SerializationErr,
93+
Error Result) mutable {
94+
if (SerializationErr) {
95+
cantFail(std::move(Result));
96+
return OnReleased(std::move(SerializationErr));
97+
}
98+
99+
return OnReleased(std::move(Result));
100+
},
101+
SAs.Instance, Bases);
102+
}
103+
104+
} // namespace llvm::orc

llvm/tools/llvm-jitlink/llvm-jitlink.cpp

Lines changed: 50 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
#include "llvm/ExecutionEngine/Orc/SectCreate.h"
4141
#include "llvm/ExecutionEngine/Orc/SelfExecutorProcessControl.h"
4242
#include "llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h"
43+
#include "llvm/ExecutionEngine/Orc/SimpleRemoteMemoryMapper.h"
4344
#include "llvm/ExecutionEngine/Orc/TargetProcess/JITLoaderGDB.h"
4445
#include "llvm/ExecutionEngine/Orc/TargetProcess/JITLoaderPerf.h"
4546
#include "llvm/ExecutionEngine/Orc/TargetProcess/JITLoaderVTune.h"
@@ -312,10 +313,19 @@ static cl::opt<bool>
312313
cl::desc("Show FailedToMaterialize errors"),
313314
cl::init(false), cl::cat(JITLinkCategory));
314315

315-
static cl::opt<bool> UseSharedMemory(
316-
"use-shared-memory",
317-
cl::desc("Use shared memory to transfer generated code and data"),
318-
cl::init(false), cl::cat(JITLinkCategory));
316+
enum class MemMgr { Default, Generic, SimpleRemote, Shared };
317+
318+
static cl::opt<MemMgr> UseMemMgr(
319+
"use-memmgr", cl::desc("Choose memory manager"), cl::init(MemMgr::Generic),
320+
cl::values(clEnumValN(MemMgr::Default, "default",
321+
"Use setup default (InProcess or EPCGeneric)"),
322+
clEnumValN(MemMgr::Generic, "generic",
323+
"Generic remote memory manager"),
324+
clEnumValN(MemMgr::SimpleRemote, "simple-remote",
325+
"Mapper memory manager with simple-remote backend"),
326+
clEnumValN(MemMgr::Shared, "shared",
327+
"Mapper memory manager with shared-memory manager")),
328+
cl::cat(JITLinkCategory));
319329

320330
static cl::opt<std::string>
321331
OverrideTriple("triple", cl::desc("Override target triple detection"),
@@ -717,6 +727,27 @@ static std::unique_ptr<JITLinkMemoryManager> createInProcessMemoryManager() {
717727
SlabSize));
718728
}
719729

730+
Expected<std::unique_ptr<jitlink::JITLinkMemoryManager>>
731+
createSimpleRemoteMemoryManager(SimpleRemoteEPC &SREPC) {
732+
SimpleRemoteMemoryMapper::SymbolAddrs SAs;
733+
if (auto Err = SREPC.getBootstrapSymbols(
734+
{{SAs.Instance, rt::SimpleExecutorMemoryManagerInstanceName},
735+
{SAs.Reserve, rt::SimpleExecutorMemoryManagerReserveWrapperName},
736+
{SAs.Initialize,
737+
rt::SimpleExecutorMemoryManagerInitializeWrapperName},
738+
{SAs.Deinitialize,
739+
rt::SimpleExecutorMemoryManagerDeinitializeWrapperName},
740+
{SAs.Release, rt::SimpleExecutorMemoryManagerReleaseWrapperName}}))
741+
return std::move(Err);
742+
#ifdef _WIN32
743+
size_t SlabSize = 1024 * 1024;
744+
#else
745+
size_t SlabSize = 1024 * 1024 * 1024;
746+
#endif
747+
return MapperJITLinkMemoryManager::CreateWithMapper<SimpleRemoteMemoryMapper>(
748+
SlabSize, SREPC, SAs);
749+
}
750+
720751
Expected<std::unique_ptr<jitlink::JITLinkMemoryManager>>
721752
createSharedMemoryManager(SimpleRemoteEPC &SREPC) {
722753
SharedMemoryMapper::SymbolAddrs SAs;
@@ -745,6 +776,19 @@ createSharedMemoryManager(SimpleRemoteEPC &SREPC) {
745776
SlabSize, SREPC, SAs);
746777
}
747778

779+
static void setupEPCRemoteMemoryManager(SimpleRemoteEPC::Setup &S) {
780+
switch (UseMemMgr) {
781+
case MemMgr::Default:
782+
case MemMgr::Generic:
783+
break;
784+
case MemMgr::SimpleRemote:
785+
S.CreateMemoryManager = createSimpleRemoteMemoryManager;
786+
break;
787+
case MemMgr::Shared:
788+
S.CreateMemoryManager = createSharedMemoryManager;
789+
break;
790+
}
791+
}
748792

749793
static Expected<MaterializationUnit::Interface>
750794
getTestObjectFileInterface(Session &S, MemoryBufferRef O) {
@@ -904,8 +948,7 @@ static Expected<std::unique_ptr<ExecutorProcessControl>> launchExecutor() {
904948
close(FromExecutor[WriteEnd]);
905949

906950
auto S = SimpleRemoteEPC::Setup();
907-
if (UseSharedMemory)
908-
S.CreateMemoryManager = createSharedMemoryManager;
951+
setupEPCRemoteMemoryManager(S);
909952

910953
return SimpleRemoteEPC::Create<FDSimpleRemoteEPCTransport>(
911954
std::make_unique<DynamicThreadPoolTaskDispatcher>(MaterializationThreads),
@@ -994,8 +1037,7 @@ static Expected<std::unique_ptr<ExecutorProcessControl>> connectToExecutor() {
9941037
return SockFD.takeError();
9951038

9961039
auto S = SimpleRemoteEPC::Setup();
997-
if (UseSharedMemory)
998-
S.CreateMemoryManager = createSharedMemoryManager;
1040+
setupEPCRemoteMemoryManager(S);
9991041

10001042
return SimpleRemoteEPC::Create<FDSimpleRemoteEPCTransport>(
10011043
std::make_unique<DynamicThreadPoolTaskDispatcher>(std::nullopt),

0 commit comments

Comments
 (0)