[orc-rt] Move SPS controller interface funcs into their own headers. (#186991)

This provides clean separation between the ORC runtime code that
implements runtime functionality and the wrapper functions that permit
this code to be called from the controller via the
ExecutorProcessControl API.

Separating the controller interface from the implementation functions
should allow clients to introduce alternative serialization schemes if
they want (e.g. JSON).

In particular, this commit adds a new orc-rt/include/orc-rt/sps-ci
directory and moves SimpleNativeMemoryMap SPS controller interface into
a new header in that directory. This commit also splits the
implementation and testing of the SPS controller interface for
SimpleNativeMemoryMap into separate files.
This commit is contained in:
Lang Hames 2026-03-17 21:39:09 +11:00 committed by GitHub
parent e904d559c5
commit 612d80348f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 598 additions and 286 deletions

View File

@ -23,6 +23,8 @@ set(ORC_RT_HEADERS
orc-rt/SimpleNativeMemoryMap.h
orc-rt/SimplePackedSerialization.h
orc-rt/SPSAllocAction.h
orc-rt/sps-ci/AllSPSCI.h
orc-rt/sps-ci/SimpleNativeMemoryMapSPSCI.h
orc-rt/SPSMemoryFlags.h
orc-rt/SPSWrapperFunction.h
orc-rt/SPSWrapperFunctionBuffer.h

View File

@ -19,6 +19,8 @@
#include <unordered_map>
#include <vector>
#define ORC_RT_SYMTAB_PAIR(sym) {{#sym}, reinterpret_cast<const void *>(&sym)}
namespace orc_rt {
/// A symbol table defining the interface exposed by the ORC runtime to the

View File

@ -18,7 +18,12 @@
#include "orc-rt/SimplePackedSerialization.h"
#include "orc-rt/WrapperFunction.h"
#define ORC_RT_SPS_INTERFACE ORC_RT_INTERFACE
#define ORC_RT_SPS_WRAPPER(Name, SPSSig, Handle) \
static void Name(orc_rt_SessionRef S, uint64_t CallId, \
orc_rt_WrapperFunctionReturn Return, \
orc_rt_WrapperFunctionBuffer ArgBytes) { \
SPSWrapperFunction<SPSSig>::handle(S, CallId, Return, ArgBytes, Handle); \
}
namespace orc_rt {
namespace detail {

View File

@ -16,7 +16,6 @@
#include "orc-rt/AllocAction.h"
#include "orc-rt/Error.h"
#include "orc-rt/MemoryFlags.h"
#include "orc-rt/SPSWrapperFunction.h"
#include "orc-rt/Service.h"
#include "orc-rt/move_only_function.h"
@ -113,22 +112,4 @@ private:
} // namespace orc_rt
ORC_RT_SPS_INTERFACE void orc_rt_SimpleNativeMemoryMap_reserve_sps_wrapper(
orc_rt_SessionRef S, uint64_t CallId, orc_rt_WrapperFunctionReturn Return,
orc_rt_WrapperFunctionBuffer ArgBytes);
ORC_RT_SPS_INTERFACE void
orc_rt_SimpleNativeMemoryMap_releaseMultiple_sps_wrapper(
orc_rt_SessionRef S, uint64_t CallId, orc_rt_WrapperFunctionReturn Return,
orc_rt_WrapperFunctionBuffer ArgBytes);
ORC_RT_SPS_INTERFACE void orc_rt_SimpleNativeMemoryMap_initialize_sps_wrapper(
orc_rt_SessionRef S, uint64_t CallId, orc_rt_WrapperFunctionReturn Return,
orc_rt_WrapperFunctionBuffer ArgBytes);
ORC_RT_SPS_INTERFACE void
orc_rt_SimpleNativeMemoryMap_deinitializeMultiple_sps_wrapper(
orc_rt_SessionRef S, uint64_t CallId, orc_rt_WrapperFunctionReturn Return,
orc_rt_WrapperFunctionBuffer ArgBytes);
#endif // ORC_RT_SIMPLENATIVEMEMORYMAP_H

View File

@ -0,0 +1,26 @@
//===- AllSPSCI.h -- All SPS Controller Interface registrations -*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// Convenience header that includes all SPS Controller Interface headers and
// declares addAll.
//
//===----------------------------------------------------------------------===//
#ifndef ORC_RT_SPS_CI_ALLSPSCI_H
#define ORC_RT_SPS_CI_ALLSPSCI_H
#include "orc-rt/sps-ci/SimpleNativeMemoryMapSPSCI.h"
namespace orc_rt::sps_ci {
/// Add all SPS interfaces to the controller interface.
Error addAll(ControllerInterface &CI);
} // namespace orc_rt::sps_ci
#endif // ORC_RT_SPS_CI_ALLSPSCI_H

View File

@ -0,0 +1,25 @@
//===------- SimpleNativeMemoryMapSPSCI.h -- SNMM SPS CI --------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// SPS Controller Interface registration for SimpleNativeMemoryMap.
//
//===----------------------------------------------------------------------===//
#ifndef ORC_RT_SPS_CI_SIMPLENATIVEMEMORYMAPSPSCI_H
#define ORC_RT_SPS_CI_SIMPLENATIVEMEMORYMAPSPSCI_H
#include "orc-rt/ControllerInterface.h"
namespace orc_rt::sps_ci {
/// Add the SimpleNativeMemoryMap SPS interface to the controller interface.
Error addSimpleNativeMemoryMap(ControllerInterface &CI);
} // namespace orc_rt::sps_ci
#endif // ORC_RT_SPS_CI_SIMPLENATIVEMEMORYMAPSPSCI_H

View File

@ -9,6 +9,8 @@ set(files
SimpleNativeMemoryMap.cpp
TaskDispatcher.cpp
ThreadPoolTaskDispatcher.cpp
sps-ci/AllSPSCI.cpp
sps-ci/SimpleNativeMemoryMapSPSCI.cpp
)
add_library(orc-rt-executor STATIC ${files})

View File

@ -14,8 +14,6 @@
//===----------------------------------------------------------------------===//
#include "orc-rt/SimpleNativeMemoryMap.h"
#include "orc-rt/SPSAllocAction.h"
#include "orc-rt/SPSMemoryFlags.h"
#include <sstream>
#if defined(__APPLE__) || defined(__linux__)
@ -26,47 +24,6 @@
namespace orc_rt {
struct SPSSimpleNativeMemoryMapSegment;
template <>
class SPSSerializationTraits<
SPSSimpleNativeMemoryMapSegment,
SimpleNativeMemoryMap::InitializeRequest::Segment> {
using SPSType =
SPSTuple<SPSAllocGroup, SPSExecutorAddr, uint64_t, SPSSequence<char>>;
public:
static bool
deserialize(SPSInputBuffer &IB,
SimpleNativeMemoryMap::InitializeRequest::Segment &S) {
AllocGroup AG;
ExecutorAddr Address;
uint64_t Size;
span<const char> Content;
if (!SPSType::AsArgList::deserialize(IB, AG, Address, Size, Content))
return false;
if (Size > std::numeric_limits<size_t>::max())
return false;
S = {AG, Address.toPtr<char *>(), static_cast<size_t>(Size), Content};
return true;
}
};
struct SPSSimpleNativeMemoryMapInitializeRequest;
template <>
class SPSSerializationTraits<SPSSimpleNativeMemoryMapInitializeRequest,
SimpleNativeMemoryMap::InitializeRequest> {
using SPSType = SPSTuple<SPSSequence<SPSSimpleNativeMemoryMapSegment>,
SPSSequence<SPSAllocActionPair>>;
public:
static bool deserialize(SPSInputBuffer &IB,
SimpleNativeMemoryMap::InitializeRequest &FR) {
return SPSType::AsArgList::deserialize(IB, FR.Segments, FR.AAPs);
}
};
void SimpleNativeMemoryMap::reserve(OnReserveCompleteFn &&OnComplete,
size_t Size) {
// FIXME: Get page size from session object.
@ -366,44 +323,4 @@ Error SimpleNativeMemoryMap::recordDeallocActions(
return Error::success();
}
ORC_RT_SPS_INTERFACE void orc_rt_SimpleNativeMemoryMap_reserve_sps_wrapper(
orc_rt_SessionRef S, uint64_t CallId, orc_rt_WrapperFunctionReturn Return,
orc_rt_WrapperFunctionBuffer ArgBytes) {
using Sig = SPSExpected<SPSExecutorAddr>(SPSExecutorAddr, SPSSize);
SPSWrapperFunction<Sig>::handle(
S, CallId, Return, ArgBytes,
WrapperFunction::handleWithAsyncMethod(&SimpleNativeMemoryMap::reserve));
}
ORC_RT_SPS_INTERFACE void
orc_rt_SimpleNativeMemoryMap_releaseMultiple_sps_wrapper(
orc_rt_SessionRef S, uint64_t CallId, orc_rt_WrapperFunctionReturn Return,
orc_rt_WrapperFunctionBuffer ArgBytes) {
using Sig = SPSError(SPSExecutorAddr, SPSSequence<SPSExecutorAddr>);
SPSWrapperFunction<Sig>::handle(S, CallId, Return, ArgBytes,
WrapperFunction::handleWithAsyncMethod(
&SimpleNativeMemoryMap::releaseMultiple));
}
ORC_RT_SPS_INTERFACE void orc_rt_SimpleNativeMemoryMap_initialize_sps_wrapper(
orc_rt_SessionRef S, uint64_t CallId, orc_rt_WrapperFunctionReturn Return,
orc_rt_WrapperFunctionBuffer ArgBytes) {
using Sig = SPSExpected<SPSExecutorAddr>(
SPSExecutorAddr, SPSSimpleNativeMemoryMapInitializeRequest);
SPSWrapperFunction<Sig>::handle(S, CallId, Return, ArgBytes,
WrapperFunction::handleWithAsyncMethod(
&SimpleNativeMemoryMap::initialize));
}
ORC_RT_SPS_INTERFACE void
orc_rt_SimpleNativeMemoryMap_deinitializeMultiple_sps_wrapper(
orc_rt_SessionRef S, uint64_t CallId, orc_rt_WrapperFunctionReturn Return,
orc_rt_WrapperFunctionBuffer ArgBytes) {
using Sig = SPSError(SPSExecutorAddr, SPSSequence<SPSExecutorAddr>);
SPSWrapperFunction<Sig>::handle(
S, CallId, Return, ArgBytes,
WrapperFunction::handleWithAsyncMethod(
&SimpleNativeMemoryMap::deinitializeMultiple));
}
} // namespace orc_rt

View File

@ -0,0 +1,28 @@
//===- AllSPSCI.cpp -------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// Implementation of sps_ci::addAll.
//
//===----------------------------------------------------------------------===//
#include "orc-rt/sps-ci/AllSPSCI.h"
namespace orc_rt::sps_ci {
Error addAll(ControllerInterface &CI) {
using AdderFn = Error (*)(ControllerInterface &);
AdderFn Adders[] = {addSimpleNativeMemoryMap};
for (auto *Adder : Adders)
if (auto Err = Adder(CI))
return Err;
return Error::success();
}
} // namespace orc_rt::sps_ci

View File

@ -0,0 +1,101 @@
//===- SimpleNativeMemoryMapSPSCI.cpp -------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// SPS Controller Interface implementation for SimpleNativeMemoryMap.
//
//===----------------------------------------------------------------------===//
#include "orc-rt/sps-ci/SimpleNativeMemoryMapSPSCI.h"
#include "orc-rt/SPSAllocAction.h"
#include "orc-rt/SPSMemoryFlags.h"
#include "orc-rt/SPSWrapperFunction.h"
#include "orc-rt/SimpleNativeMemoryMap.h"
namespace orc_rt {
struct SPSSimpleNativeMemoryMapSegment;
template <>
class SPSSerializationTraits<
SPSSimpleNativeMemoryMapSegment,
SimpleNativeMemoryMap::InitializeRequest::Segment> {
using SPSType =
SPSTuple<SPSAllocGroup, SPSExecutorAddr, uint64_t, SPSSequence<char>>;
public:
static bool
deserialize(SPSInputBuffer &IB,
SimpleNativeMemoryMap::InitializeRequest::Segment &S) {
AllocGroup AG;
ExecutorAddr Address;
uint64_t Size;
span<const char> Content;
if (!SPSType::AsArgList::deserialize(IB, AG, Address, Size, Content))
return false;
if (Size > std::numeric_limits<size_t>::max())
return false;
S = {AG, Address.toPtr<char *>(), static_cast<size_t>(Size), Content};
return true;
}
};
struct SPSSimpleNativeMemoryMapInitializeRequest;
template <>
class SPSSerializationTraits<SPSSimpleNativeMemoryMapInitializeRequest,
SimpleNativeMemoryMap::InitializeRequest> {
using SPSType = SPSTuple<SPSSequence<SPSSimpleNativeMemoryMapSegment>,
SPSSequence<SPSAllocActionPair>>;
public:
static bool deserialize(SPSInputBuffer &IB,
SimpleNativeMemoryMap::InitializeRequest &FR) {
return SPSType::AsArgList::deserialize(IB, FR.Segments, FR.AAPs);
}
};
namespace sps_ci {
ORC_RT_SPS_WRAPPER(
orc_rt_SimpleNativeMemoryMap_reserve_sps_wrapper,
SPSExpected<SPSExecutorAddr>(SPSExecutorAddr, SPSSize),
WrapperFunction::handleWithAsyncMethod(&SimpleNativeMemoryMap::reserve))
ORC_RT_SPS_WRAPPER(orc_rt_SimpleNativeMemoryMap_releaseMultiple_sps_wrapper,
SPSError(SPSExecutorAddr, SPSSequence<SPSExecutorAddr>),
WrapperFunction::handleWithAsyncMethod(
&SimpleNativeMemoryMap::releaseMultiple))
ORC_RT_SPS_WRAPPER(
orc_rt_SimpleNativeMemoryMap_initialize_sps_wrapper,
SPSExpected<SPSExecutorAddr>(SPSExecutorAddr,
SPSSimpleNativeMemoryMapInitializeRequest),
WrapperFunction::handleWithAsyncMethod(&SimpleNativeMemoryMap::initialize))
ORC_RT_SPS_WRAPPER(
orc_rt_SimpleNativeMemoryMap_deinitializeMultiple_sps_wrapper,
SPSError(SPSExecutorAddr, SPSSequence<SPSExecutorAddr>),
WrapperFunction::handleWithAsyncMethod(
&SimpleNativeMemoryMap::deinitializeMultiple))
static std::pair<const char *, const void *>
orc_rt_SimpleNativeMemoryMap_sps_interface[] = {
ORC_RT_SYMTAB_PAIR(orc_rt_SimpleNativeMemoryMap_reserve_sps_wrapper),
ORC_RT_SYMTAB_PAIR(
orc_rt_SimpleNativeMemoryMap_releaseMultiple_sps_wrapper),
ORC_RT_SYMTAB_PAIR(orc_rt_SimpleNativeMemoryMap_initialize_sps_wrapper),
ORC_RT_SYMTAB_PAIR(
orc_rt_SimpleNativeMemoryMap_deinitializeMultiple_sps_wrapper)};
Error addSimpleNativeMemoryMap(ControllerInterface &CI) {
return CI.addSymbolsUnique(orc_rt_SimpleNativeMemoryMap_sps_interface);
}
} // namespace sps_ci
} // namespace orc_rt

View File

@ -31,6 +31,7 @@ add_orc_rt_unittest(CoreTests
ScopeExitTest.cpp
SessionTest.cpp
SimpleNativeMemoryMapTest.cpp
SimpleNativeMemoryMapSPSCITest.cpp
SimplePackedSerializationTest.cpp
SPSAllocActionTest.cpp
SPSMemoryFlagsTest.cpp
@ -43,6 +44,7 @@ add_orc_rt_unittest(CoreTests
iterator_range-test.cpp
move_only_function-test.cpp
span-test.cpp
DISABLE_LLVM_LINK_LLVM_DYLIB
)
target_compile_options(CoreTests PRIVATE ${ORC_RT_COMPILE_FLAGS})

View File

@ -9,7 +9,10 @@
#ifndef ORC_RT_UNITTEST_COMMONTESTUTILS_H
#define ORC_RT_UNITTEST_COMMONTESTUTILS_H
#include "orc-rt/move_only_function.h"
#include <cstddef>
#include <future>
template <size_t Idx = 0> class OpCounter {
public:
@ -64,4 +67,17 @@ template <size_t Idx> size_t OpCounter<Idx>::MoveConstructions = 0;
template <size_t Idx> size_t OpCounter<Idx>::MoveAssignments = 0;
template <size_t Idx> size_t OpCounter<Idx>::Destructions = 0;
template <typename T>
orc_rt::move_only_function<void(T)> waitFor(std::future<T> &F) {
std::promise<T> P;
F = P.get_future();
return [P = std::move(P)](T Val) mutable { P.set_value(std::move(Val)); };
}
inline orc_rt::move_only_function<void()> waitFor(std::future<void> &F) {
std::promise<void> P;
F = P.get_future();
return [P = std::move(P)]() mutable { P.set_value(); };
}
#endif // ORC_RT_UNITTEST_COMMONTESTUTILS_H

View File

@ -0,0 +1,319 @@
//===- SimpleNativeMemoryMapSPSControllerInterfaceTest.cpp ----------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// Tests for SimpleNativeMemoryMap's SPS Controller Interface.
//
//===----------------------------------------------------------------------===//
#include "orc-rt/sps-ci/SimpleNativeMemoryMapSPSCI.h"
#include "orc-rt/SPSAllocAction.h"
#include "orc-rt/SPSMemoryFlags.h"
#include "orc-rt/SPSWrapperFunction.h"
#include "orc-rt/SimpleNativeMemoryMap.h"
#include "AllocActionTestUtils.h"
#include "CommonTestUtils.h"
#include "DirectCaller.h"
#include "gtest/gtest.h"
using namespace orc_rt;
namespace orc_rt {
struct SPSSimpleNativeMemoryMapSegment;
struct SPSSimpleNativeMemoryMapInitializeRequest;
/// A SimpleNativeMemoryMap::InitializeRequest::Segment plus segment content (if
/// segment content type is regular).
struct TestSNMMSegment
: public SimpleNativeMemoryMap::InitializeRequest::Segment {
TestSNMMSegment(AllocGroup AG, char *Address, size_t Size,
std::vector<char> C = {})
: SimpleNativeMemoryMap::InitializeRequest::Segment(
{AG, Address, Size, {}}),
OwnedContent(std::move(C)) {
this->Content = {OwnedContent.data(), OwnedContent.size()};
}
std::vector<char> OwnedContent;
};
template <>
class SPSSerializationTraits<SPSSimpleNativeMemoryMapSegment, TestSNMMSegment> {
using SPSType =
SPSTuple<SPSAllocGroup, SPSExecutorAddr, uint64_t, SPSSequence<char>>;
public:
static size_t size(const TestSNMMSegment &S) {
return SPSType::AsArgList::size(S.AG, ExecutorAddr::fromPtr(S.Address),
static_cast<uint64_t>(S.Size), S.Content);
}
static bool serialize(SPSOutputBuffer &OB, const TestSNMMSegment &S) {
return SPSType::AsArgList::serialize(
OB, S.AG, ExecutorAddr::fromPtr(S.Address),
static_cast<uint64_t>(S.Size), S.Content);
}
};
struct TestSNMMInitializeRequest {
std::vector<TestSNMMSegment> Segments;
std::vector<AllocActionPair> AAPs;
};
template <>
class SPSSerializationTraits<SPSSimpleNativeMemoryMapInitializeRequest,
TestSNMMInitializeRequest> {
using SPSType = SPSTuple<SPSSequence<SPSSimpleNativeMemoryMapSegment>,
SPSSequence<SPSAllocActionPair>>;
public:
static size_t size(const TestSNMMInitializeRequest &IR) {
return SPSType::AsArgList::size(IR.Segments, IR.AAPs);
}
static bool serialize(SPSOutputBuffer &OB,
const TestSNMMInitializeRequest &IR) {
return SPSType::AsArgList::serialize(OB, IR.Segments, IR.AAPs);
}
};
} // namespace orc_rt
// Write the given value to the address pointed to by P.
static orc_rt_WrapperFunctionBuffer
write_value_sps_allocaction(const char *ArgData, size_t ArgSize) {
return SPSAllocActionFunction<SPSExecutorAddr, uint64_t>::handle(
ArgData, ArgSize,
[](ExecutorAddr P, uint64_t Val) {
*P.toPtr<uint64_t *>() = Val;
return WrapperFunctionBuffer();
})
.release();
}
// Read the uint64_t value at Src and write it to Dst.
static orc_rt_WrapperFunctionBuffer
read_value_sps_allocaction(const char *ArgData, size_t ArgSize) {
return SPSAllocActionFunction<SPSExecutorAddr, SPSExecutorAddr>::handle(
ArgData, ArgSize,
[](ExecutorAddr Dst, ExecutorAddr Src) {
*Dst.toPtr<uint64_t *>() = *Src.toPtr<uint64_t *>();
return WrapperFunctionBuffer();
})
.release();
}
class SimpleNativeMemoryMapSPSCITest : public ::testing::Test {
protected:
void SetUp() override {
cantFail(sps_ci::addSimpleNativeMemoryMap(CI));
SNMM = std::make_unique<SimpleNativeMemoryMap>();
}
void TearDown() override {
if (SNMM) {
std::future<void> F;
SNMM->onShutdown(waitFor(F));
F.get();
}
}
DirectCaller caller(const char *Name) {
return DirectCaller(nullptr, reinterpret_cast<orc_rt_WrapperFunction>(
const_cast<void *>(CI.at(Name))));
}
template <typename OnCompleteFn>
void spsReserve(OnCompleteFn &&OnComplete, size_t Size) {
using SPSSig = SPSExpected<SPSExecutorAddr>(SPSExecutorAddr, SPSSize);
SPSWrapperFunction<SPSSig>::call(
caller("orc_rt_SimpleNativeMemoryMap_reserve_sps_wrapper"),
std::forward<OnCompleteFn>(OnComplete), SNMM.get(), Size);
}
template <typename OnCompleteFn>
void spsReleaseMultiple(OnCompleteFn &&OnComplete, span<void *> Addrs) {
using SPSSig = SPSError(SPSExecutorAddr, SPSSequence<SPSExecutorAddr>);
SPSWrapperFunction<SPSSig>::call(
caller("orc_rt_SimpleNativeMemoryMap_releaseMultiple_sps_wrapper"),
std::forward<OnCompleteFn>(OnComplete), SNMM.get(), Addrs);
}
template <typename OnCompleteFn>
void spsInitialize(OnCompleteFn &&OnComplete, TestSNMMInitializeRequest IR) {
using SPSSig = SPSExpected<SPSExecutorAddr>(
SPSExecutorAddr, SPSSimpleNativeMemoryMapInitializeRequest);
SPSWrapperFunction<SPSSig>::call(
caller("orc_rt_SimpleNativeMemoryMap_initialize_sps_wrapper"),
std::forward<OnCompleteFn>(OnComplete), SNMM.get(), std::move(IR));
}
template <typename OnCompleteFn>
void spsDeinitializeMultiple(OnCompleteFn &&OnComplete, span<void *> Bases) {
using SPSSig = SPSError(SPSExecutorAddr, SPSSequence<SPSExecutorAddr>);
SPSWrapperFunction<SPSSig>::call(
caller("orc_rt_SimpleNativeMemoryMap_deinitializeMultiple_sps_wrapper"),
std::forward<OnCompleteFn>(OnComplete), SNMM.get(), Bases);
}
ControllerInterface CI;
std::unique_ptr<SimpleNativeMemoryMap> SNMM;
};
TEST_F(SimpleNativeMemoryMapSPSCITest, Registration) {
EXPECT_TRUE(CI.count("orc_rt_SimpleNativeMemoryMap_reserve_sps_wrapper"));
EXPECT_TRUE(
CI.count("orc_rt_SimpleNativeMemoryMap_releaseMultiple_sps_wrapper"));
EXPECT_TRUE(CI.count("orc_rt_SimpleNativeMemoryMap_initialize_sps_wrapper"));
EXPECT_TRUE(CI.count(
"orc_rt_SimpleNativeMemoryMap_deinitializeMultiple_sps_wrapper"));
}
TEST_F(SimpleNativeMemoryMapSPSCITest, ReserveAndRelease) {
std::future<Expected<Expected<void *>>> ReserveAddr;
spsReserve(waitFor(ReserveAddr), 1024 * 1024 * 1024);
auto *Addr = cantFail(cantFail(ReserveAddr.get()));
std::future<Expected<Error>> ReleaseResult;
spsReleaseMultiple(waitFor(ReleaseResult), {&Addr, 1});
cantFail(cantFail(ReleaseResult.get()));
}
TEST_F(SimpleNativeMemoryMapSPSCITest, FullPipelineForOneRWSegment) {
std::future<Expected<Expected<void *>>> ReserveAddr;
spsReserve(waitFor(ReserveAddr), 1024 * 1024 * 1024);
void *Addr = cantFail(cantFail(ReserveAddr.get()));
std::future<Expected<Expected<void *>>> InitializeKey;
TestSNMMInitializeRequest IR;
char *InitializeBase = reinterpret_cast<char *>(Addr) + 64 * 1024;
uint64_t SentinelValue1 = 0;
uint64_t SentinelValue2 = 0;
uint64_t SentinelValue3 = 42;
std::vector<char> Content;
Content.resize(sizeof(uint64_t) * 2);
memcpy(Content.data(), &SentinelValue3, sizeof(uint64_t));
memcpy(Content.data() + sizeof(uint64_t), &SentinelValue1, sizeof(uint64_t));
IR.Segments.push_back({MemProt::Read | MemProt::Write, InitializeBase,
64 * 1024, std::move(Content)});
IR.AAPs.push_back(
{*MakeAllocAction<SPSExecutorAddr, SPSExecutorAddr>::from(
read_value_sps_allocaction, ExecutorAddr::fromPtr(&SentinelValue1),
ExecutorAddr::fromPtr(InitializeBase)),
{}});
IR.AAPs.push_back(
{*MakeAllocAction<SPSExecutorAddr, uint64_t>::from(
write_value_sps_allocaction,
ExecutorAddr::fromPtr(InitializeBase) + sizeof(uint64_t),
uint64_t(42)),
*MakeAllocAction<SPSExecutorAddr, SPSExecutorAddr>::from(
read_value_sps_allocaction, ExecutorAddr::fromPtr(&SentinelValue2),
ExecutorAddr::fromPtr(InitializeBase) + sizeof(uint64_t))});
IR.AAPs.push_back(
{*MakeAllocAction<SPSExecutorAddr, SPSExecutorAddr>::from(
read_value_sps_allocaction, ExecutorAddr::fromPtr(&SentinelValue3),
ExecutorAddr::fromPtr(InitializeBase) + sizeof(uint64_t) * 2),
{}});
spsInitialize(waitFor(InitializeKey), std::move(IR));
void *InitializeKeyAddr = cantFail(cantFail(InitializeKey.get()));
EXPECT_EQ(SentinelValue1, 42U);
EXPECT_EQ(SentinelValue2, 0U);
EXPECT_EQ(SentinelValue3, 0U);
std::future<Expected<Error>> DeallocResult;
spsDeinitializeMultiple(waitFor(DeallocResult), {&InitializeKeyAddr, 1});
cantFail(cantFail(DeallocResult.get()));
EXPECT_EQ(SentinelValue1, 42U);
EXPECT_EQ(SentinelValue2, 42U);
EXPECT_EQ(SentinelValue3, 0U);
std::future<Expected<Error>> ReleaseResult;
spsReleaseMultiple(waitFor(ReleaseResult), {&Addr, 1});
cantFail(cantFail(ReleaseResult.get()));
}
TEST_F(SimpleNativeMemoryMapSPSCITest, ReserveInitializeShutdown) {
std::future<Expected<Expected<void *>>> ReserveAddr;
spsReserve(waitFor(ReserveAddr), 1024 * 1024 * 1024);
void *Addr = cantFail(cantFail(ReserveAddr.get()));
std::future<Expected<Expected<void *>>> InitializeKey;
TestSNMMInitializeRequest IR;
char *InitializeBase = reinterpret_cast<char *>(Addr) + 64 * 1024;
uint64_t SentinelValue = 0;
IR.Segments.push_back(
{MemProt::Read | MemProt::Write, InitializeBase, 64 * 1024});
IR.AAPs.push_back(
{*MakeAllocAction<SPSExecutorAddr, uint64_t>::from(
write_value_sps_allocaction, ExecutorAddr::fromPtr(InitializeBase),
uint64_t(42)),
*MakeAllocAction<SPSExecutorAddr, SPSExecutorAddr>::from(
read_value_sps_allocaction, ExecutorAddr::fromPtr(&SentinelValue),
ExecutorAddr::fromPtr(InitializeBase))});
spsInitialize(waitFor(InitializeKey), std::move(IR));
cantFail(cantFail(InitializeKey.get()));
EXPECT_EQ(SentinelValue, 0U);
std::future<void> ShutdownResult;
SNMM->onShutdown(waitFor(ShutdownResult));
ShutdownResult.get();
SNMM.reset();
EXPECT_EQ(SentinelValue, 42);
}
TEST_F(SimpleNativeMemoryMapSPSCITest, ReserveInitializeDetachShutdown) {
std::future<Expected<Expected<void *>>> ReserveAddr;
spsReserve(waitFor(ReserveAddr), 1024 * 1024 * 1024);
void *Addr = cantFail(cantFail(ReserveAddr.get()));
std::future<Expected<Expected<void *>>> InitializeKey;
TestSNMMInitializeRequest IR;
char *InitializeBase = reinterpret_cast<char *>(Addr) + 64 * 1024;
uint64_t SentinelValue = 0;
IR.Segments.push_back(
{MemProt::Read | MemProt::Write, InitializeBase, 64 * 1024});
IR.AAPs.push_back(
{*MakeAllocAction<SPSExecutorAddr, uint64_t>::from(
write_value_sps_allocaction, ExecutorAddr::fromPtr(InitializeBase),
uint64_t(42)),
*MakeAllocAction<SPSExecutorAddr, SPSExecutorAddr>::from(
read_value_sps_allocaction, ExecutorAddr::fromPtr(&SentinelValue),
ExecutorAddr::fromPtr(InitializeBase))});
spsInitialize(waitFor(InitializeKey), std::move(IR));
cantFail(cantFail(InitializeKey.get()));
EXPECT_EQ(SentinelValue, 0U);
std::future<void> DetachResult;
SNMM->onDetach(waitFor(DetachResult));
DetachResult.get();
EXPECT_EQ(SentinelValue, 0);
std::future<void> ShutdownResult;
SNMM->onShutdown(waitFor(ShutdownResult));
ShutdownResult.get();
SNMM.reset();
EXPECT_EQ(SentinelValue, 42);
}

View File

@ -12,154 +12,15 @@
#include "orc-rt/SimpleNativeMemoryMap.h"
#include "orc-rt/SPSAllocAction.h"
#include "orc-rt/SPSMemoryFlags.h"
#include "AllocActionTestUtils.h"
#include "DirectCaller.h"
#include "CommonTestUtils.h"
#include "gtest/gtest.h"
#include <future>
#include <cstring>
using namespace orc_rt;
namespace orc_rt {
struct SPSSimpleNativeMemoryMapSegment;
/// A SimpleNativeMemoryMap::InitializeRequest::Segment plus segment content (if
/// segment content type is regular).
struct TestSNMMSegment
: public SimpleNativeMemoryMap::InitializeRequest::Segment {
TestSNMMSegment(AllocGroup AG, char *Address, size_t Size,
std::vector<char> C = {})
: SimpleNativeMemoryMap::InitializeRequest::Segment(
{AG, Address, Size, {}}),
OwnedContent(std::move(C)) {
this->Content = {OwnedContent.data(), OwnedContent.size()};
}
std::vector<char> OwnedContent;
};
template <>
class SPSSerializationTraits<SPSSimpleNativeMemoryMapSegment, TestSNMMSegment> {
using SPSType =
SPSTuple<SPSAllocGroup, SPSExecutorAddr, uint64_t, SPSSequence<char>>;
public:
static size_t size(const TestSNMMSegment &S) {
return SPSType::AsArgList::size(S.AG, ExecutorAddr::fromPtr(S.Address),
static_cast<uint64_t>(S.Size), S.Content);
}
static bool serialize(SPSOutputBuffer &OB, const TestSNMMSegment &S) {
return SPSType::AsArgList::serialize(
OB, S.AG, ExecutorAddr::fromPtr(S.Address),
static_cast<uint64_t>(S.Size), S.Content);
}
};
struct SPSSimpleNativeMemoryMapInitializeRequest;
struct TestSNMMInitializeRequest {
std::vector<TestSNMMSegment> Segments;
std::vector<AllocActionPair> AAPs;
};
template <>
class SPSSerializationTraits<SPSSimpleNativeMemoryMapInitializeRequest,
TestSNMMInitializeRequest> {
using SPSType = SPSTuple<SPSSequence<SPSSimpleNativeMemoryMapSegment>,
SPSSequence<SPSAllocActionPair>>;
public:
static size_t size(const TestSNMMInitializeRequest &IR) {
return SPSType::AsArgList::size(IR.Segments, IR.AAPs);
}
static bool serialize(SPSOutputBuffer &OB,
const TestSNMMInitializeRequest &IR) {
return SPSType::AsArgList::serialize(OB, IR.Segments, IR.AAPs);
}
};
} // namespace orc_rt
template <typename T> move_only_function<void(T)> waitFor(std::future<T> &F) {
std::promise<T> P;
F = P.get_future();
return [P = std::move(P)](T Val) mutable { P.set_value(std::move(Val)); };
}
move_only_function<void()> waitFor(std::future<void> &F) {
std::promise<void> P;
F = P.get_future();
return [P = std::move(P)]() mutable { P.set_value(); };
}
TEST(SimpleNativeMemoryMapTest, CreateAndDestroy) {
// Test that we can create and destroy a SimpleNativeMemoryMap instance as
// expected.
auto SNMM = std::make_unique<SimpleNativeMemoryMap>();
}
template <typename OnCompleteFn>
static void snmm_reserve(OnCompleteFn &&OnComplete,
SimpleNativeMemoryMap *Instance, size_t Size) {
using SPSSig = SPSExpected<SPSExecutorAddr>(SPSExecutorAddr, SPSSize);
SPSWrapperFunction<SPSSig>::call(
DirectCaller(nullptr, orc_rt_SimpleNativeMemoryMap_reserve_sps_wrapper),
std::forward<OnCompleteFn>(OnComplete), Instance, Size);
}
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_initialize(OnCompleteFn &&OnComplete,
SimpleNativeMemoryMap *Instance,
TestSNMMInitializeRequest IR) {
using SPSSig = SPSExpected<SPSExecutorAddr>(
SPSExecutorAddr, SPSSimpleNativeMemoryMapInitializeRequest);
SPSWrapperFunction<SPSSig>::call(
DirectCaller(nullptr,
orc_rt_SimpleNativeMemoryMap_initialize_sps_wrapper),
std::forward<OnCompleteFn>(OnComplete), Instance, std::move(IR));
}
template <typename OnCompleteFn>
static void snmm_deinitializeMultiple(OnCompleteFn &&OnComplete,
SimpleNativeMemoryMap *Instance,
span<void *> Base) {
using SPSSig = SPSError(SPSExecutorAddr, SPSSequence<SPSExecutorAddr>);
SPSWrapperFunction<SPSSig>::call(
DirectCaller(
nullptr,
orc_rt_SimpleNativeMemoryMap_deinitializeMultiple_sps_wrapper),
std::forward<OnCompleteFn>(OnComplete), Instance, Base);
}
TEST(SimpleNativeMemoryMapTest, ReserveAndRelease) {
// Test that we can reserve and release a slab of address space as expected,
// without finalizing any memory within it.
auto SNMM = std::make_unique<SimpleNativeMemoryMap>();
std::future<Expected<Expected<void *>>> ReserveAddr;
snmm_reserve(waitFor(ReserveAddr), SNMM.get(), 1024 * 1024 * 1024);
auto Addr = cantFail(cantFail(ReserveAddr.get()));
std::future<Expected<Error>> ReleaseResult;
snmm_releaseMultiple(waitFor(ReleaseResult), SNMM.get(), {&Addr, 1});
cantFail(cantFail(ReleaseResult.get()));
}
// Write the given value to the address pointed to by P.
static orc_rt_WrapperFunctionBuffer
write_value_sps_allocaction(const char *ArgData, size_t ArgSize) {
@ -173,7 +34,6 @@ write_value_sps_allocaction(const char *ArgData, size_t ArgSize) {
}
// Read the uint64_t value at Src and write it to Dst.
// Increments int via pointer.
static orc_rt_WrapperFunctionBuffer
read_value_sps_allocaction(const char *ArgData, size_t ArgSize) {
return SPSAllocActionFunction<SPSExecutorAddr, SPSExecutorAddr>::handle(
@ -185,7 +45,27 @@ read_value_sps_allocaction(const char *ArgData, size_t ArgSize) {
.release();
}
TEST(SimpleNativeMemoryMap, FullPipelineForOneRWSegment) {
TEST(SimpleNativeMemoryMapTest, CreateAndDestroy) {
// Test that we can create and destroy a SimpleNativeMemoryMap instance as
// expected.
auto SNMM = std::make_unique<SimpleNativeMemoryMap>();
}
TEST(SimpleNativeMemoryMapTest, ReserveAndRelease) {
// Test that we can reserve and release a slab of address space as expected,
// without finalizing any memory within it.
SimpleNativeMemoryMap SNMM;
std::future<Expected<void *>> ReserveResult;
SNMM.reserve(waitFor(ReserveResult), 1024 * 1024 * 1024);
void *Addr = cantFail(ReserveResult.get());
std::future<Error> ReleaseResult;
SNMM.releaseMultiple(waitFor(ReleaseResult), {Addr});
cantFail(ReleaseResult.get());
}
TEST(SimpleNativeMemoryMapTest, FullPipelineForOneRWSegment) {
// Test that we can:
// 1. reserve some address space.
// 2. initialize a range within it as read/write, and that finalize actions
@ -194,13 +74,12 @@ TEST(SimpleNativeMemoryMap, FullPipelineForOneRWSegment) {
// expected.
// 4. release the address range.
auto SNMM = std::make_unique<SimpleNativeMemoryMap>();
std::future<Expected<Expected<void *>>> ReserveAddr;
snmm_reserve(waitFor(ReserveAddr), SNMM.get(), 1024 * 1024 * 1024);
void *Addr = cantFail(cantFail(ReserveAddr.get()));
SimpleNativeMemoryMap SNMM;
std::future<Expected<void *>> ReserveResult;
SNMM.reserve(waitFor(ReserveResult), 1024 * 1024 * 1024);
void *Addr = cantFail(ReserveResult.get());
std::future<Expected<Expected<void *>>> InitializeKey;
TestSNMMInitializeRequest IR;
char *InitializeBase = // Initialize addr at non-zero (64kb) offset from base.
reinterpret_cast<char *>(Addr) + 64 * 1024;
uint64_t SentinelValue1 = 0; // Read from pre-filled content
@ -214,8 +93,11 @@ TEST(SimpleNativeMemoryMap, FullPipelineForOneRWSegment) {
memcpy(Content.data(), &SentinelValue3, sizeof(uint64_t));
memcpy(Content.data() + sizeof(uint64_t), &SentinelValue1, sizeof(uint64_t));
IR.Segments.push_back({MemProt::Read | MemProt::Write, InitializeBase,
64 * 1024, std::move(Content)});
SimpleNativeMemoryMap::InitializeRequest IR;
IR.Segments.push_back({MemProt::Read | MemProt::Write,
InitializeBase,
64 * 1024,
{Content.data(), Content.size()}});
// Read initial content into Sentinel 1.
IR.AAPs.push_back({
@ -243,44 +125,44 @@ TEST(SimpleNativeMemoryMap, FullPipelineForOneRWSegment) {
{} // No dealloc action.
});
snmm_initialize(waitFor(InitializeKey), SNMM.get(), std::move(IR));
void *InitializeKeyAddr = cantFail(cantFail(InitializeKey.get()));
std::future<Expected<void *>> InitializeResult;
SNMM.initialize(waitFor(InitializeResult), std::move(IR));
void *InitializeKeyAddr = cantFail(InitializeResult.get());
EXPECT_EQ(SentinelValue1, 42U);
EXPECT_EQ(SentinelValue2, 0U);
EXPECT_EQ(SentinelValue3, 0U);
std::future<Expected<Error>> DeallocResult;
snmm_deinitializeMultiple(waitFor(DeallocResult), SNMM.get(),
{&InitializeKeyAddr, 1});
cantFail(cantFail(DeallocResult.get()));
std::future<Error> DeallocResult;
SNMM.deinitializeMultiple(waitFor(DeallocResult), {InitializeKeyAddr});
cantFail(DeallocResult.get());
EXPECT_EQ(SentinelValue1, 42U);
EXPECT_EQ(SentinelValue2, 42U);
EXPECT_EQ(SentinelValue3, 0U);
std::future<Expected<Error>> ReleaseResult;
snmm_releaseMultiple(waitFor(ReleaseResult), SNMM.get(), {&Addr, 1});
cantFail(cantFail(ReleaseResult.get()));
std::future<Error> ReleaseResult;
SNMM.releaseMultiple(waitFor(ReleaseResult), {Addr});
cantFail(ReleaseResult.get());
}
TEST(SimpleNativeMemoryMap, ReserveInitializeShutdown) {
TEST(SimpleNativeMemoryMapTest, ReserveInitializeShutdown) {
// Test that memory is deinitialized in the case where we reserve and
// initialize some memory, then just shut down the memory manager.
auto SNMM = std::make_unique<SimpleNativeMemoryMap>();
std::future<Expected<Expected<void *>>> ReserveAddr;
snmm_reserve(waitFor(ReserveAddr), SNMM.get(), 1024 * 1024 * 1024);
void *Addr = cantFail(cantFail(ReserveAddr.get()));
SimpleNativeMemoryMap SNMM;
std::future<Expected<void *>> ReserveResult;
SNMM.reserve(waitFor(ReserveResult), 1024 * 1024 * 1024);
void *Addr = cantFail(ReserveResult.get());
std::future<Expected<Expected<void *>>> InitializeKey;
TestSNMMInitializeRequest IR;
char *InitializeBase = // Initialize addr at non-zero (64kb) offset from base.
reinterpret_cast<char *>(Addr) + 64 * 1024;
uint64_t SentinelValue = 0;
SimpleNativeMemoryMap::InitializeRequest IR;
IR.Segments.push_back(
{MemProt::Read | MemProt::Write, InitializeBase, 64 * 1024});
{MemProt::Read | MemProt::Write, InitializeBase, 64 * 1024, {}});
IR.AAPs.push_back(
{*MakeAllocAction<SPSExecutorAddr, uint64_t>::from(
@ -289,35 +171,37 @@ TEST(SimpleNativeMemoryMap, ReserveInitializeShutdown) {
*MakeAllocAction<SPSExecutorAddr, SPSExecutorAddr>::from(
read_value_sps_allocaction, ExecutorAddr::fromPtr(&SentinelValue),
ExecutorAddr::fromPtr(InitializeBase))});
snmm_initialize(waitFor(InitializeKey), SNMM.get(), std::move(IR));
cantFail(cantFail(InitializeKey.get()));
std::future<Expected<void *>> InitializeResult;
SNMM.initialize(waitFor(InitializeResult), std::move(IR));
cantFail(InitializeResult.get());
EXPECT_EQ(SentinelValue, 0U);
std::future<void> ShutdownResult;
SNMM->onShutdown(waitFor(ShutdownResult));
SNMM.onShutdown(waitFor(ShutdownResult));
ShutdownResult.get();
EXPECT_EQ(SentinelValue, 42);
}
TEST(SimpleNativeMemoryMap, ReserveInitializeDetachShutdown) {
TEST(SimpleNativeMemoryMapTest, ReserveInitializeDetachShutdown) {
// Test that memory is deinitialized in the case where we reserve and
// initialize some memory, then just shut down the memory manager.
auto SNMM = std::make_unique<SimpleNativeMemoryMap>();
std::future<Expected<Expected<void *>>> ReserveAddr;
snmm_reserve(waitFor(ReserveAddr), SNMM.get(), 1024 * 1024 * 1024);
void *Addr = cantFail(cantFail(ReserveAddr.get()));
SimpleNativeMemoryMap SNMM;
std::future<Expected<void *>> ReserveResult;
SNMM.reserve(waitFor(ReserveResult), 1024 * 1024 * 1024);
void *Addr = cantFail(ReserveResult.get());
std::future<Expected<Expected<void *>>> InitializeKey;
TestSNMMInitializeRequest IR;
char *InitializeBase = // Initialize addr at non-zero (64kb) offset from base.
reinterpret_cast<char *>(Addr) + 64 * 1024;
uint64_t SentinelValue = 0;
SimpleNativeMemoryMap::InitializeRequest IR;
IR.Segments.push_back(
{MemProt::Read | MemProt::Write, InitializeBase, 64 * 1024});
{MemProt::Read | MemProt::Write, InitializeBase, 64 * 1024, {}});
IR.AAPs.push_back(
{*MakeAllocAction<SPSExecutorAddr, uint64_t>::from(
@ -326,19 +210,21 @@ TEST(SimpleNativeMemoryMap, ReserveInitializeDetachShutdown) {
*MakeAllocAction<SPSExecutorAddr, SPSExecutorAddr>::from(
read_value_sps_allocaction, ExecutorAddr::fromPtr(&SentinelValue),
ExecutorAddr::fromPtr(InitializeBase))});
snmm_initialize(waitFor(InitializeKey), SNMM.get(), std::move(IR));
cantFail(cantFail(InitializeKey.get()));
std::future<Expected<void *>> InitializeResult;
SNMM.initialize(waitFor(InitializeResult), std::move(IR));
cantFail(InitializeResult.get());
EXPECT_EQ(SentinelValue, 0U);
std::future<void> DetachResult;
SNMM->onDetach(waitFor(DetachResult));
SNMM.onDetach(waitFor(DetachResult));
DetachResult.get();
EXPECT_EQ(SentinelValue, 0);
std::future<void> ShutdownResult;
SNMM->onShutdown(waitFor(ShutdownResult));
SNMM.onShutdown(waitFor(ShutdownResult));
ShutdownResult.get();
EXPECT_EQ(SentinelValue, 42);