[orc-rt] Add multi-addr dealloc/release to SimpleNativeMemoryMap. (#163025)
In an ORC JIT it's common for multiple memory regions to be deallocated
at once, e.g. when a ResourceTracker covering multiple object files is
removed. This commit adds SimpleNativeMemoryMap::deallocateMultiple and
SimpleNativeMemoryMap::releaseMultiple APIs that can be used to reduce
the number of calls (and consequently IPC messages in cross-process
setups) in these cases.
Adding these operations will make it easier to write an
llvm::orc::MemoryMapper class that can use SimpleNativeMemoryMap as a
backend.
diff --git a/orc-rt/include/orc-rt/SimpleNativeMemoryMap.h b/orc-rt/include/orc-rt/SimpleNativeMemoryMap.h
index 6dbc0c0..0e516ee 100644
--- a/orc-rt/include/orc-rt/SimpleNativeMemoryMap.h
+++ b/orc-rt/include/orc-rt/SimpleNativeMemoryMap.h
@@ -50,7 +50,13 @@
/// Release a slab of contiguous address space back to the system.
using OnReleaseCompleteFn = move_only_function<void(Error)>;
- void release(OnReleaseCompleteFn &&OnComplete, void *Addr);
+ void release(OnReleaseCompleteFn &&OnComplete, void *Addrs);
+
+ /// Convenience method to release multiple slabs with one call. This can be
+ /// used to save on interprocess communication at the cost of less expressive
+ /// errors.
+ void releaseMultiple(OnReleaseCompleteFn &&OnComplete,
+ std::vector<void *> Addrs);
struct FinalizeRequest {
struct Segment {
@@ -74,6 +80,12 @@
using OnDeallocateCompleteFn = move_only_function<void(Error)>;
void deallocate(OnDeallocateCompleteFn &&OnComplete, void *Base);
+ /// Convenience method to deallocate multiple regions with one call. This can
+ /// be used to save on interprocess communication at the cost of less
+ /// expressive errors.
+ void deallocateMultiple(OnDeallocateCompleteFn &&OnComplete,
+ std::vector<void *> Bases);
+
void detach(ResourceManager::OnCompleteFn OnComplete) override;
void shutdown(ResourceManager::OnCompleteFn OnComplete) override;
@@ -84,6 +96,10 @@
std::unordered_map<void *, std::vector<AllocAction>> DeallocActions;
};
+ void releaseNext(OnReleaseCompleteFn &&OnComplete, std::vector<void *> Addrs,
+ bool AnyError, Error LastErr);
+ void deallocateNext(OnDeallocateCompleteFn &&OnComplete,
+ std::vector<void *> Bases, bool AnyError, Error LastErr);
void shutdownNext(OnCompleteFn OnComplete, std::vector<void *> Bases);
Error makeBadSlabError(void *Base, const char *Op);
SlabInfo *findSlabInfoFor(void *Base);
@@ -100,7 +116,8 @@
orc_rt_SessionRef Session, void *CallCtx,
orc_rt_WrapperFunctionReturn Return, orc_rt_WrapperFunctionBuffer ArgBytes);
-ORC_RT_SPS_INTERFACE void orc_rt_SimpleNativeMemoryMap_release_sps_wrapper(
+ORC_RT_SPS_INTERFACE void
+orc_rt_SimpleNativeMemoryMap_releaseMultiple_sps_wrapper(
orc_rt_SessionRef Session, void *CallCtx,
orc_rt_WrapperFunctionReturn Return, orc_rt_WrapperFunctionBuffer ArgBytes);
@@ -108,7 +125,8 @@
orc_rt_SessionRef Session, void *CallCtx,
orc_rt_WrapperFunctionReturn Return, orc_rt_WrapperFunctionBuffer ArgBytes);
-ORC_RT_SPS_INTERFACE void orc_rt_SimpleNativeMemoryMap_deallocate_sps_wrapper(
+ORC_RT_SPS_INTERFACE void
+orc_rt_SimpleNativeMemoryMap_deallocateMultiple_sps_wrapper(
orc_rt_SessionRef Session, void *CallCtx,
orc_rt_WrapperFunctionReturn Return, orc_rt_WrapperFunctionBuffer ArgBytes);
diff --git a/orc-rt/lib/executor/SimpleNativeMemoryMap.cpp b/orc-rt/lib/executor/SimpleNativeMemoryMap.cpp
index 10cdcf5..987bd85 100644
--- a/orc-rt/lib/executor/SimpleNativeMemoryMap.cpp
+++ b/orc-rt/lib/executor/SimpleNativeMemoryMap.cpp
@@ -116,6 +116,11 @@
OnComplete(hostOSMemoryRelease(Addr, SI->Size));
}
+void SimpleNativeMemoryMap::releaseMultiple(OnReleaseCompleteFn &&OnComplete,
+ std::vector<void *> Addrs) {
+ releaseNext(std::move(OnComplete), std::move(Addrs), false, Error::success());
+}
+
void SimpleNativeMemoryMap::finalize(OnFinalizeCompleteFn &&OnComplete,
FinalizeRequest FR) {
@@ -207,6 +212,12 @@
OnComplete(Error::success());
}
+void SimpleNativeMemoryMap::deallocateMultiple(
+ OnDeallocateCompleteFn &&OnComplete, std::vector<void *> Bases) {
+ deallocateNext(std::move(OnComplete), std::move(Bases), false,
+ Error::success());
+}
+
void SimpleNativeMemoryMap::detach(ResourceManager::OnCompleteFn OnComplete) {
// Detach is a noop for now: we just retain all actions to run at shutdown
// time.
@@ -228,6 +239,64 @@
shutdownNext(std::move(OnComplete), std::move(Bases));
}
+void SimpleNativeMemoryMap::releaseNext(OnReleaseCompleteFn &&OnComplete,
+ std::vector<void *> Addrs,
+ bool AnyError, Error LastErr) {
+ // TODO: Log error?
+ if (LastErr) {
+ consumeError(std::move(LastErr));
+ AnyError |= true;
+ }
+
+ if (Addrs.empty()) {
+ if (!AnyError)
+ return OnComplete(Error::success());
+
+ return OnComplete(
+ make_error<StringError>("Failed to release some addresses"));
+ }
+
+ void *NextAddr = Addrs.back();
+ Addrs.pop_back();
+
+ release(
+ [this, OnComplete = std::move(OnComplete), AnyError = AnyError,
+ Addrs = std::move(Addrs)](Error Err) mutable {
+ releaseNext(std::move(OnComplete), std::move(Addrs), AnyError,
+ std::move(Err));
+ },
+ NextAddr);
+}
+
+void SimpleNativeMemoryMap::deallocateNext(OnDeallocateCompleteFn &&OnComplete,
+ std::vector<void *> Addrs,
+ bool AnyError, Error LastErr) {
+ // TODO: Log error?
+ if (LastErr) {
+ consumeError(std::move(LastErr));
+ AnyError |= true;
+ }
+
+ if (Addrs.empty()) {
+ if (!AnyError)
+ return OnComplete(Error::success());
+
+ return OnComplete(
+ make_error<StringError>("Failed to deallocate some addresses"));
+ }
+
+ void *NextAddr = Addrs.back();
+ Addrs.pop_back();
+
+ deallocate(
+ [this, OnComplete = std::move(OnComplete), AnyError = AnyError,
+ Addrs = std::move(Addrs)](Error Err) mutable {
+ deallocateNext(std::move(OnComplete), std::move(Addrs), AnyError,
+ std::move(Err));
+ },
+ NextAddr);
+}
+
void SimpleNativeMemoryMap::shutdownNext(
ResourceManager::OnCompleteFn OnComplete, std::vector<void *> Bases) {
if (Bases.empty())
@@ -303,14 +372,15 @@
WrapperFunction::handleWithAsyncMethod(&SimpleNativeMemoryMap::reserve));
}
-ORC_RT_SPS_INTERFACE void orc_rt_SimpleNativeMemoryMap_release_sps_wrapper(
+ORC_RT_SPS_INTERFACE void
+orc_rt_SimpleNativeMemoryMap_releaseMultiple_sps_wrapper(
orc_rt_SessionRef Session, void *CallCtx,
orc_rt_WrapperFunctionReturn Return,
orc_rt_WrapperFunctionBuffer ArgBytes) {
- using Sig = SPSError(SPSExecutorAddr, SPSExecutorAddr);
- SPSWrapperFunction<Sig>::handle(
- Session, CallCtx, Return, ArgBytes,
- WrapperFunction::handleWithAsyncMethod(&SimpleNativeMemoryMap::release));
+ using Sig = SPSError(SPSExecutorAddr, SPSSequence<SPSExecutorAddr>);
+ SPSWrapperFunction<Sig>::handle(Session, CallCtx, Return, ArgBytes,
+ WrapperFunction::handleWithAsyncMethod(
+ &SimpleNativeMemoryMap::releaseMultiple));
}
ORC_RT_SPS_INTERFACE void orc_rt_SimpleNativeMemoryMap_finalize_sps_wrapper(
@@ -324,14 +394,16 @@
WrapperFunction::handleWithAsyncMethod(&SimpleNativeMemoryMap::finalize));
}
-ORC_RT_SPS_INTERFACE void orc_rt_SimpleNativeMemoryMap_deallocate_sps_wrapper(
+ORC_RT_SPS_INTERFACE void
+orc_rt_SimpleNativeMemoryMap_deallocateMultiple_sps_wrapper(
orc_rt_SessionRef Session, void *CallCtx,
orc_rt_WrapperFunctionReturn Return,
orc_rt_WrapperFunctionBuffer ArgBytes) {
- using Sig = SPSError(SPSExecutorAddr, SPSExecutorAddr);
- SPSWrapperFunction<Sig>::handle(Session, CallCtx, Return, ArgBytes,
- WrapperFunction::handleWithAsyncMethod(
- &SimpleNativeMemoryMap::deallocate));
+ using Sig = SPSError(SPSExecutorAddr, SPSSequence<SPSExecutorAddr>);
+ SPSWrapperFunction<Sig>::handle(
+ Session, CallCtx, Return, ArgBytes,
+ WrapperFunction::handleWithAsyncMethod(
+ &SimpleNativeMemoryMap::deallocateMultiple));
}
} // namespace orc_rt
diff --git a/orc-rt/unittests/SimpleNativeMemoryMapTest.cpp b/orc-rt/unittests/SimpleNativeMemoryMapTest.cpp
index b7ef7f0..c54d791 100644
--- a/orc-rt/unittests/SimpleNativeMemoryMapTest.cpp
+++ b/orc-rt/unittests/SimpleNativeMemoryMapTest.cpp
@@ -107,6 +107,17 @@
}
template <typename OnCompleteFn>
+static void snmm_releaseMultiple(OnCompleteFn &&OnComplete,
+ SimpleNativeMemoryMap *Instance,
+ span<void *> Addr) {
+ using SPSSig = SPSError(SPSExecutorAddr, SPSSequence<SPSExecutorAddr>);
+ SPSWrapperFunction<SPSSig>::call(
+ DirectCaller(nullptr,
+ orc_rt_SimpleNativeMemoryMap_releaseMultiple_sps_wrapper),
+ std::forward<OnCompleteFn>(OnComplete), Instance, Addr);
+}
+
+template <typename OnCompleteFn>
static void snmm_finalize(OnCompleteFn &&OnComplete,
SimpleNativeMemoryMap *Instance,
TestSNMMFinalizeRequest FR) {
@@ -118,24 +129,16 @@
}
template <typename OnCompleteFn>
-static void snmm_deallocate(OnCompleteFn &&OnComplete,
- SimpleNativeMemoryMap *Instance, void *Base) {
- using SPSSig = SPSError(SPSExecutorAddr, SPSExecutorAddr);
+static void snmm_deallocateMultiple(OnCompleteFn &&OnComplete,
+ SimpleNativeMemoryMap *Instance,
+ span<void *> Base) {
+ using SPSSig = SPSError(SPSExecutorAddr, SPSSequence<SPSExecutorAddr>);
SPSWrapperFunction<SPSSig>::call(
DirectCaller(nullptr,
- orc_rt_SimpleNativeMemoryMap_deallocate_sps_wrapper),
+ orc_rt_SimpleNativeMemoryMap_deallocateMultiple_sps_wrapper),
std::forward<OnCompleteFn>(OnComplete), Instance, Base);
}
-template <typename OnCompleteFn>
-static void snmm_release(OnCompleteFn &&OnComplete,
- SimpleNativeMemoryMap *Instance, void *Addr) {
- using SPSSig = SPSError(SPSExecutorAddr, SPSExecutorAddr);
- SPSWrapperFunction<SPSSig>::call(
- DirectCaller(nullptr, orc_rt_SimpleNativeMemoryMap_release_sps_wrapper),
- std::forward<OnCompleteFn>(OnComplete), Instance, Addr);
-}
-
TEST(SimpleNativeMemoryMapTest, ReserveAndRelease) {
// Test that we can reserve and release a slab of address space as expected,
// without finalizing any memory within it.
@@ -145,7 +148,7 @@
auto Addr = cantFail(cantFail(ReserveAddr.get()));
std::future<Expected<Error>> ReleaseResult;
- snmm_release(waitFor(ReleaseResult), SNMM.get(), Addr);
+ snmm_releaseMultiple(waitFor(ReleaseResult), SNMM.get(), {&Addr, 1});
cantFail(cantFail(ReleaseResult.get()));
}
@@ -239,7 +242,8 @@
EXPECT_EQ(SentinelValue3, 0U);
std::future<Expected<Error>> DeallocResult;
- snmm_deallocate(waitFor(DeallocResult), SNMM.get(), FinalizeKeyAddr);
+ snmm_deallocateMultiple(waitFor(DeallocResult), SNMM.get(),
+ {&FinalizeKeyAddr, 1});
cantFail(cantFail(DeallocResult.get()));
EXPECT_EQ(SentinelValue1, 42U);
@@ -247,7 +251,7 @@
EXPECT_EQ(SentinelValue3, 0U);
std::future<Expected<Error>> ReleaseResult;
- snmm_release(waitFor(ReleaseResult), SNMM.get(), Addr);
+ snmm_releaseMultiple(waitFor(ReleaseResult), SNMM.get(), {&Addr, 1});
cantFail(cantFail(ReleaseResult.get()));
}