diff --git a/orc-rt/include/CMakeLists.txt b/orc-rt/include/CMakeLists.txt index df381d5223a4..e16941b9d24f 100644 --- a/orc-rt/include/CMakeLists.txt +++ b/orc-rt/include/CMakeLists.txt @@ -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 diff --git a/orc-rt/include/orc-rt/ControllerInterface.h b/orc-rt/include/orc-rt/ControllerInterface.h index 0955c6d57c90..54b310bf9e6e 100644 --- a/orc-rt/include/orc-rt/ControllerInterface.h +++ b/orc-rt/include/orc-rt/ControllerInterface.h @@ -19,6 +19,8 @@ #include #include +#define ORC_RT_SYMTAB_PAIR(sym) {{#sym}, reinterpret_cast(&sym)} + namespace orc_rt { /// A symbol table defining the interface exposed by the ORC runtime to the diff --git a/orc-rt/include/orc-rt/SPSWrapperFunction.h b/orc-rt/include/orc-rt/SPSWrapperFunction.h index d61792db9435..4f32179545e5 100644 --- a/orc-rt/include/orc-rt/SPSWrapperFunction.h +++ b/orc-rt/include/orc-rt/SPSWrapperFunction.h @@ -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::handle(S, CallId, Return, ArgBytes, Handle); \ + } namespace orc_rt { namespace detail { diff --git a/orc-rt/include/orc-rt/SimpleNativeMemoryMap.h b/orc-rt/include/orc-rt/SimpleNativeMemoryMap.h index 067702654cb5..d98e094c6fb9 100644 --- a/orc-rt/include/orc-rt/SimpleNativeMemoryMap.h +++ b/orc-rt/include/orc-rt/SimpleNativeMemoryMap.h @@ -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 diff --git a/orc-rt/include/orc-rt/sps-ci/AllSPSCI.h b/orc-rt/include/orc-rt/sps-ci/AllSPSCI.h new file mode 100644 index 000000000000..e92ba6ad3914 --- /dev/null +++ b/orc-rt/include/orc-rt/sps-ci/AllSPSCI.h @@ -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 diff --git a/orc-rt/include/orc-rt/sps-ci/SimpleNativeMemoryMapSPSCI.h b/orc-rt/include/orc-rt/sps-ci/SimpleNativeMemoryMapSPSCI.h new file mode 100644 index 000000000000..7d8e705e1b3a --- /dev/null +++ b/orc-rt/include/orc-rt/sps-ci/SimpleNativeMemoryMapSPSCI.h @@ -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 diff --git a/orc-rt/lib/executor/CMakeLists.txt b/orc-rt/lib/executor/CMakeLists.txt index 752006430273..6d05386a097f 100644 --- a/orc-rt/lib/executor/CMakeLists.txt +++ b/orc-rt/lib/executor/CMakeLists.txt @@ -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}) diff --git a/orc-rt/lib/executor/SimpleNativeMemoryMap.cpp b/orc-rt/lib/executor/SimpleNativeMemoryMap.cpp index 378e0a3907fc..49ccf9382a00 100644 --- a/orc-rt/lib/executor/SimpleNativeMemoryMap.cpp +++ b/orc-rt/lib/executor/SimpleNativeMemoryMap.cpp @@ -14,8 +14,6 @@ //===----------------------------------------------------------------------===// #include "orc-rt/SimpleNativeMemoryMap.h" -#include "orc-rt/SPSAllocAction.h" -#include "orc-rt/SPSMemoryFlags.h" #include #if defined(__APPLE__) || defined(__linux__) @@ -26,47 +24,6 @@ namespace orc_rt { -struct SPSSimpleNativeMemoryMapSegment; - -template <> -class SPSSerializationTraits< - SPSSimpleNativeMemoryMapSegment, - SimpleNativeMemoryMap::InitializeRequest::Segment> { - using SPSType = - SPSTuple>; - -public: - static bool - deserialize(SPSInputBuffer &IB, - SimpleNativeMemoryMap::InitializeRequest::Segment &S) { - AllocGroup AG; - ExecutorAddr Address; - uint64_t Size; - span Content; - if (!SPSType::AsArgList::deserialize(IB, AG, Address, Size, Content)) - return false; - if (Size > std::numeric_limits::max()) - return false; - S = {AG, Address.toPtr(), static_cast(Size), Content}; - return true; - } -}; - -struct SPSSimpleNativeMemoryMapInitializeRequest; - -template <> -class SPSSerializationTraits { - using SPSType = SPSTuple, - SPSSequence>; - -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, SPSSize); - SPSWrapperFunction::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); - SPSWrapperFunction::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, SPSSimpleNativeMemoryMapInitializeRequest); - SPSWrapperFunction::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); - SPSWrapperFunction::handle( - S, CallId, Return, ArgBytes, - WrapperFunction::handleWithAsyncMethod( - &SimpleNativeMemoryMap::deinitializeMultiple)); -} - } // namespace orc_rt diff --git a/orc-rt/lib/executor/sps-ci/AllSPSCI.cpp b/orc-rt/lib/executor/sps-ci/AllSPSCI.cpp new file mode 100644 index 000000000000..e1f002781132 --- /dev/null +++ b/orc-rt/lib/executor/sps-ci/AllSPSCI.cpp @@ -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 diff --git a/orc-rt/lib/executor/sps-ci/SimpleNativeMemoryMapSPSCI.cpp b/orc-rt/lib/executor/sps-ci/SimpleNativeMemoryMapSPSCI.cpp new file mode 100644 index 000000000000..466cf725750f --- /dev/null +++ b/orc-rt/lib/executor/sps-ci/SimpleNativeMemoryMapSPSCI.cpp @@ -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>; + +public: + static bool + deserialize(SPSInputBuffer &IB, + SimpleNativeMemoryMap::InitializeRequest::Segment &S) { + AllocGroup AG; + ExecutorAddr Address; + uint64_t Size; + span Content; + if (!SPSType::AsArgList::deserialize(IB, AG, Address, Size, Content)) + return false; + if (Size > std::numeric_limits::max()) + return false; + S = {AG, Address.toPtr(), static_cast(Size), Content}; + return true; + } +}; + +struct SPSSimpleNativeMemoryMapInitializeRequest; + +template <> +class SPSSerializationTraits { + using SPSType = SPSTuple, + SPSSequence>; + +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, SPSSize), + WrapperFunction::handleWithAsyncMethod(&SimpleNativeMemoryMap::reserve)) + +ORC_RT_SPS_WRAPPER(orc_rt_SimpleNativeMemoryMap_releaseMultiple_sps_wrapper, + SPSError(SPSExecutorAddr, SPSSequence), + WrapperFunction::handleWithAsyncMethod( + &SimpleNativeMemoryMap::releaseMultiple)) + +ORC_RT_SPS_WRAPPER( + orc_rt_SimpleNativeMemoryMap_initialize_sps_wrapper, + SPSExpected(SPSExecutorAddr, + SPSSimpleNativeMemoryMapInitializeRequest), + WrapperFunction::handleWithAsyncMethod(&SimpleNativeMemoryMap::initialize)) + +ORC_RT_SPS_WRAPPER( + orc_rt_SimpleNativeMemoryMap_deinitializeMultiple_sps_wrapper, + SPSError(SPSExecutorAddr, SPSSequence), + WrapperFunction::handleWithAsyncMethod( + &SimpleNativeMemoryMap::deinitializeMultiple)) + +static std::pair + 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 diff --git a/orc-rt/unittests/CMakeLists.txt b/orc-rt/unittests/CMakeLists.txt index 593066a39fe1..a7cfa616c5ab 100644 --- a/orc-rt/unittests/CMakeLists.txt +++ b/orc-rt/unittests/CMakeLists.txt @@ -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}) diff --git a/orc-rt/unittests/CommonTestUtils.h b/orc-rt/unittests/CommonTestUtils.h index 1c66bddaf75b..d5a6c644537e 100644 --- a/orc-rt/unittests/CommonTestUtils.h +++ b/orc-rt/unittests/CommonTestUtils.h @@ -9,7 +9,10 @@ #ifndef ORC_RT_UNITTEST_COMMONTESTUTILS_H #define ORC_RT_UNITTEST_COMMONTESTUTILS_H +#include "orc-rt/move_only_function.h" + #include +#include template class OpCounter { public: @@ -64,4 +67,17 @@ template size_t OpCounter::MoveConstructions = 0; template size_t OpCounter::MoveAssignments = 0; template size_t OpCounter::Destructions = 0; +template +orc_rt::move_only_function waitFor(std::future &F) { + std::promise 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 waitFor(std::future &F) { + std::promise P; + F = P.get_future(); + return [P = std::move(P)]() mutable { P.set_value(); }; +} + #endif // ORC_RT_UNITTEST_COMMONTESTUTILS_H diff --git a/orc-rt/unittests/SimpleNativeMemoryMapSPSCITest.cpp b/orc-rt/unittests/SimpleNativeMemoryMapSPSCITest.cpp new file mode 100644 index 000000000000..37c1b2577f90 --- /dev/null +++ b/orc-rt/unittests/SimpleNativeMemoryMapSPSCITest.cpp @@ -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 C = {}) + : SimpleNativeMemoryMap::InitializeRequest::Segment( + {AG, Address, Size, {}}), + OwnedContent(std::move(C)) { + this->Content = {OwnedContent.data(), OwnedContent.size()}; + } + + std::vector OwnedContent; +}; + +template <> +class SPSSerializationTraits { + using SPSType = + SPSTuple>; + +public: + static size_t size(const TestSNMMSegment &S) { + return SPSType::AsArgList::size(S.AG, ExecutorAddr::fromPtr(S.Address), + static_cast(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(S.Size), S.Content); + } +}; + +struct TestSNMMInitializeRequest { + std::vector Segments; + std::vector AAPs; +}; + +template <> +class SPSSerializationTraits { + using SPSType = SPSTuple, + SPSSequence>; + +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::handle( + ArgData, ArgSize, + [](ExecutorAddr P, uint64_t Val) { + *P.toPtr() = 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::handle( + ArgData, ArgSize, + [](ExecutorAddr Dst, ExecutorAddr Src) { + *Dst.toPtr() = *Src.toPtr(); + return WrapperFunctionBuffer(); + }) + .release(); +} + +class SimpleNativeMemoryMapSPSCITest : public ::testing::Test { +protected: + void SetUp() override { + cantFail(sps_ci::addSimpleNativeMemoryMap(CI)); + SNMM = std::make_unique(); + } + + void TearDown() override { + if (SNMM) { + std::future F; + SNMM->onShutdown(waitFor(F)); + F.get(); + } + } + + DirectCaller caller(const char *Name) { + return DirectCaller(nullptr, reinterpret_cast( + const_cast(CI.at(Name)))); + } + + template + void spsReserve(OnCompleteFn &&OnComplete, size_t Size) { + using SPSSig = SPSExpected(SPSExecutorAddr, SPSSize); + SPSWrapperFunction::call( + caller("orc_rt_SimpleNativeMemoryMap_reserve_sps_wrapper"), + std::forward(OnComplete), SNMM.get(), Size); + } + + template + void spsReleaseMultiple(OnCompleteFn &&OnComplete, span Addrs) { + using SPSSig = SPSError(SPSExecutorAddr, SPSSequence); + SPSWrapperFunction::call( + caller("orc_rt_SimpleNativeMemoryMap_releaseMultiple_sps_wrapper"), + std::forward(OnComplete), SNMM.get(), Addrs); + } + + template + void spsInitialize(OnCompleteFn &&OnComplete, TestSNMMInitializeRequest IR) { + using SPSSig = SPSExpected( + SPSExecutorAddr, SPSSimpleNativeMemoryMapInitializeRequest); + SPSWrapperFunction::call( + caller("orc_rt_SimpleNativeMemoryMap_initialize_sps_wrapper"), + std::forward(OnComplete), SNMM.get(), std::move(IR)); + } + + template + void spsDeinitializeMultiple(OnCompleteFn &&OnComplete, span Bases) { + using SPSSig = SPSError(SPSExecutorAddr, SPSSequence); + SPSWrapperFunction::call( + caller("orc_rt_SimpleNativeMemoryMap_deinitializeMultiple_sps_wrapper"), + std::forward(OnComplete), SNMM.get(), Bases); + } + + ControllerInterface CI; + std::unique_ptr 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>> ReserveAddr; + spsReserve(waitFor(ReserveAddr), 1024 * 1024 * 1024); + auto *Addr = cantFail(cantFail(ReserveAddr.get())); + + std::future> ReleaseResult; + spsReleaseMultiple(waitFor(ReleaseResult), {&Addr, 1}); + cantFail(cantFail(ReleaseResult.get())); +} + +TEST_F(SimpleNativeMemoryMapSPSCITest, FullPipelineForOneRWSegment) { + std::future>> ReserveAddr; + spsReserve(waitFor(ReserveAddr), 1024 * 1024 * 1024); + void *Addr = cantFail(cantFail(ReserveAddr.get())); + + std::future>> InitializeKey; + TestSNMMInitializeRequest IR; + char *InitializeBase = reinterpret_cast(Addr) + 64 * 1024; + uint64_t SentinelValue1 = 0; + uint64_t SentinelValue2 = 0; + uint64_t SentinelValue3 = 42; + + std::vector 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::from( + read_value_sps_allocaction, ExecutorAddr::fromPtr(&SentinelValue1), + ExecutorAddr::fromPtr(InitializeBase)), + {}}); + + IR.AAPs.push_back( + {*MakeAllocAction::from( + write_value_sps_allocaction, + ExecutorAddr::fromPtr(InitializeBase) + sizeof(uint64_t), + uint64_t(42)), + *MakeAllocAction::from( + read_value_sps_allocaction, ExecutorAddr::fromPtr(&SentinelValue2), + ExecutorAddr::fromPtr(InitializeBase) + sizeof(uint64_t))}); + + IR.AAPs.push_back( + {*MakeAllocAction::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> DeallocResult; + spsDeinitializeMultiple(waitFor(DeallocResult), {&InitializeKeyAddr, 1}); + cantFail(cantFail(DeallocResult.get())); + + EXPECT_EQ(SentinelValue1, 42U); + EXPECT_EQ(SentinelValue2, 42U); + EXPECT_EQ(SentinelValue3, 0U); + + std::future> ReleaseResult; + spsReleaseMultiple(waitFor(ReleaseResult), {&Addr, 1}); + cantFail(cantFail(ReleaseResult.get())); +} + +TEST_F(SimpleNativeMemoryMapSPSCITest, ReserveInitializeShutdown) { + std::future>> ReserveAddr; + spsReserve(waitFor(ReserveAddr), 1024 * 1024 * 1024); + void *Addr = cantFail(cantFail(ReserveAddr.get())); + + std::future>> InitializeKey; + TestSNMMInitializeRequest IR; + char *InitializeBase = reinterpret_cast(Addr) + 64 * 1024; + uint64_t SentinelValue = 0; + + IR.Segments.push_back( + {MemProt::Read | MemProt::Write, InitializeBase, 64 * 1024}); + + IR.AAPs.push_back( + {*MakeAllocAction::from( + write_value_sps_allocaction, ExecutorAddr::fromPtr(InitializeBase), + uint64_t(42)), + *MakeAllocAction::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 ShutdownResult; + SNMM->onShutdown(waitFor(ShutdownResult)); + ShutdownResult.get(); + SNMM.reset(); + + EXPECT_EQ(SentinelValue, 42); +} + +TEST_F(SimpleNativeMemoryMapSPSCITest, ReserveInitializeDetachShutdown) { + std::future>> ReserveAddr; + spsReserve(waitFor(ReserveAddr), 1024 * 1024 * 1024); + void *Addr = cantFail(cantFail(ReserveAddr.get())); + + std::future>> InitializeKey; + TestSNMMInitializeRequest IR; + char *InitializeBase = reinterpret_cast(Addr) + 64 * 1024; + uint64_t SentinelValue = 0; + + IR.Segments.push_back( + {MemProt::Read | MemProt::Write, InitializeBase, 64 * 1024}); + + IR.AAPs.push_back( + {*MakeAllocAction::from( + write_value_sps_allocaction, ExecutorAddr::fromPtr(InitializeBase), + uint64_t(42)), + *MakeAllocAction::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 DetachResult; + SNMM->onDetach(waitFor(DetachResult)); + DetachResult.get(); + + EXPECT_EQ(SentinelValue, 0); + + std::future ShutdownResult; + SNMM->onShutdown(waitFor(ShutdownResult)); + ShutdownResult.get(); + SNMM.reset(); + + EXPECT_EQ(SentinelValue, 42); +} diff --git a/orc-rt/unittests/SimpleNativeMemoryMapTest.cpp b/orc-rt/unittests/SimpleNativeMemoryMapTest.cpp index 30b1f5a8bf18..adb590ad69bf 100644 --- a/orc-rt/unittests/SimpleNativeMemoryMapTest.cpp +++ b/orc-rt/unittests/SimpleNativeMemoryMapTest.cpp @@ -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 +#include 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 C = {}) - : SimpleNativeMemoryMap::InitializeRequest::Segment( - {AG, Address, Size, {}}), - OwnedContent(std::move(C)) { - this->Content = {OwnedContent.data(), OwnedContent.size()}; - } - - std::vector OwnedContent; -}; - -template <> -class SPSSerializationTraits { - using SPSType = - SPSTuple>; - -public: - static size_t size(const TestSNMMSegment &S) { - return SPSType::AsArgList::size(S.AG, ExecutorAddr::fromPtr(S.Address), - static_cast(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(S.Size), S.Content); - } -}; - -struct SPSSimpleNativeMemoryMapInitializeRequest; - -struct TestSNMMInitializeRequest { - std::vector Segments; - std::vector AAPs; -}; - -template <> -class SPSSerializationTraits { - using SPSType = SPSTuple, - SPSSequence>; - -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 move_only_function waitFor(std::future &F) { - std::promise P; - F = P.get_future(); - return [P = std::move(P)](T Val) mutable { P.set_value(std::move(Val)); }; -} - -move_only_function waitFor(std::future &F) { - std::promise 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(); -} - -template -static void snmm_reserve(OnCompleteFn &&OnComplete, - SimpleNativeMemoryMap *Instance, size_t Size) { - using SPSSig = SPSExpected(SPSExecutorAddr, SPSSize); - SPSWrapperFunction::call( - DirectCaller(nullptr, orc_rt_SimpleNativeMemoryMap_reserve_sps_wrapper), - std::forward(OnComplete), Instance, Size); -} - -template -static void snmm_releaseMultiple(OnCompleteFn &&OnComplete, - SimpleNativeMemoryMap *Instance, - span Addr) { - using SPSSig = SPSError(SPSExecutorAddr, SPSSequence); - SPSWrapperFunction::call( - DirectCaller(nullptr, - orc_rt_SimpleNativeMemoryMap_releaseMultiple_sps_wrapper), - std::forward(OnComplete), Instance, Addr); -} - -template -static void snmm_initialize(OnCompleteFn &&OnComplete, - SimpleNativeMemoryMap *Instance, - TestSNMMInitializeRequest IR) { - using SPSSig = SPSExpected( - SPSExecutorAddr, SPSSimpleNativeMemoryMapInitializeRequest); - SPSWrapperFunction::call( - DirectCaller(nullptr, - orc_rt_SimpleNativeMemoryMap_initialize_sps_wrapper), - std::forward(OnComplete), Instance, std::move(IR)); -} - -template -static void snmm_deinitializeMultiple(OnCompleteFn &&OnComplete, - SimpleNativeMemoryMap *Instance, - span Base) { - using SPSSig = SPSError(SPSExecutorAddr, SPSSequence); - SPSWrapperFunction::call( - DirectCaller( - nullptr, - orc_rt_SimpleNativeMemoryMap_deinitializeMultiple_sps_wrapper), - std::forward(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(); - std::future>> ReserveAddr; - snmm_reserve(waitFor(ReserveAddr), SNMM.get(), 1024 * 1024 * 1024); - auto Addr = cantFail(cantFail(ReserveAddr.get())); - - std::future> 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::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(); +} + +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> ReserveResult; + SNMM.reserve(waitFor(ReserveResult), 1024 * 1024 * 1024); + void *Addr = cantFail(ReserveResult.get()); + + std::future 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(); - std::future>> ReserveAddr; - snmm_reserve(waitFor(ReserveAddr), SNMM.get(), 1024 * 1024 * 1024); - void *Addr = cantFail(cantFail(ReserveAddr.get())); + SimpleNativeMemoryMap SNMM; + + std::future> ReserveResult; + SNMM.reserve(waitFor(ReserveResult), 1024 * 1024 * 1024); + void *Addr = cantFail(ReserveResult.get()); - std::future>> InitializeKey; - TestSNMMInitializeRequest IR; char *InitializeBase = // Initialize addr at non-zero (64kb) offset from base. reinterpret_cast(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> 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> DeallocResult; - snmm_deinitializeMultiple(waitFor(DeallocResult), SNMM.get(), - {&InitializeKeyAddr, 1}); - cantFail(cantFail(DeallocResult.get())); + std::future DeallocResult; + SNMM.deinitializeMultiple(waitFor(DeallocResult), {InitializeKeyAddr}); + cantFail(DeallocResult.get()); EXPECT_EQ(SentinelValue1, 42U); EXPECT_EQ(SentinelValue2, 42U); EXPECT_EQ(SentinelValue3, 0U); - std::future> ReleaseResult; - snmm_releaseMultiple(waitFor(ReleaseResult), SNMM.get(), {&Addr, 1}); - cantFail(cantFail(ReleaseResult.get())); + std::future 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(); - std::future>> ReserveAddr; - snmm_reserve(waitFor(ReserveAddr), SNMM.get(), 1024 * 1024 * 1024); - void *Addr = cantFail(cantFail(ReserveAddr.get())); + SimpleNativeMemoryMap SNMM; + + std::future> ReserveResult; + SNMM.reserve(waitFor(ReserveResult), 1024 * 1024 * 1024); + void *Addr = cantFail(ReserveResult.get()); - std::future>> InitializeKey; - TestSNMMInitializeRequest IR; char *InitializeBase = // Initialize addr at non-zero (64kb) offset from base. reinterpret_cast(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::from( @@ -289,35 +171,37 @@ TEST(SimpleNativeMemoryMap, ReserveInitializeShutdown) { *MakeAllocAction::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> InitializeResult; + SNMM.initialize(waitFor(InitializeResult), std::move(IR)); + cantFail(InitializeResult.get()); EXPECT_EQ(SentinelValue, 0U); std::future 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(); - std::future>> ReserveAddr; - snmm_reserve(waitFor(ReserveAddr), SNMM.get(), 1024 * 1024 * 1024); - void *Addr = cantFail(cantFail(ReserveAddr.get())); + SimpleNativeMemoryMap SNMM; + + std::future> ReserveResult; + SNMM.reserve(waitFor(ReserveResult), 1024 * 1024 * 1024); + void *Addr = cantFail(ReserveResult.get()); - std::future>> InitializeKey; - TestSNMMInitializeRequest IR; char *InitializeBase = // Initialize addr at non-zero (64kb) offset from base. reinterpret_cast(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::from( @@ -326,19 +210,21 @@ TEST(SimpleNativeMemoryMap, ReserveInitializeDetachShutdown) { *MakeAllocAction::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> InitializeResult; + SNMM.initialize(waitFor(InitializeResult), std::move(IR)); + cantFail(InitializeResult.get()); EXPECT_EQ(SentinelValue, 0U); std::future DetachResult; - SNMM->onDetach(waitFor(DetachResult)); + SNMM.onDetach(waitFor(DetachResult)); DetachResult.get(); EXPECT_EQ(SentinelValue, 0); std::future ShutdownResult; - SNMM->onShutdown(waitFor(ShutdownResult)); + SNMM.onShutdown(waitFor(ShutdownResult)); ShutdownResult.get(); EXPECT_EQ(SentinelValue, 42);