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.
232 lines
8.2 KiB
C++
232 lines
8.2 KiB
C++
//===-- SimpleNativeMemoryMapTest.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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// Test SimpleNativeMemoryMap APIs.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "orc-rt/SimpleNativeMemoryMap.h"
|
|
#include "orc-rt/SPSAllocAction.h"
|
|
|
|
#include "AllocActionTestUtils.h"
|
|
#include "CommonTestUtils.h"
|
|
#include "gtest/gtest.h"
|
|
|
|
#include <cstring>
|
|
|
|
using 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();
|
|
}
|
|
|
|
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
|
|
// are applied as expected.
|
|
// 3. deinitialize the initialized range, with deallocation actions applied as
|
|
// expected.
|
|
// 4. release the address range.
|
|
|
|
SimpleNativeMemoryMap SNMM;
|
|
|
|
std::future<Expected<void *>> ReserveResult;
|
|
SNMM.reserve(waitFor(ReserveResult), 1024 * 1024 * 1024);
|
|
void *Addr = cantFail(ReserveResult.get());
|
|
|
|
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
|
|
uint64_t SentinelValue2 =
|
|
0; // Written in initialize, read back during dealloc.
|
|
uint64_t SentinelValue3 = 42; // Read from zero-filled region.
|
|
|
|
// Build initial content vector.
|
|
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));
|
|
|
|
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({
|
|
*MakeAllocAction<SPSExecutorAddr, SPSExecutorAddr>::from(
|
|
read_value_sps_allocaction, ExecutorAddr::fromPtr(&SentinelValue1),
|
|
ExecutorAddr::fromPtr(InitializeBase)),
|
|
{} // No dealloc action.
|
|
});
|
|
|
|
// Write value in finalize action, then read back into Sentinel 2.
|
|
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))});
|
|
|
|
// Read first 64 bits of the zero-fill region.
|
|
IR.AAPs.push_back({
|
|
*MakeAllocAction<SPSExecutorAddr, SPSExecutorAddr>::from(
|
|
read_value_sps_allocaction, ExecutorAddr::fromPtr(&SentinelValue3),
|
|
ExecutorAddr::fromPtr(InitializeBase) + sizeof(uint64_t) * 2),
|
|
{} // No dealloc action.
|
|
});
|
|
|
|
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<Error> DeallocResult;
|
|
SNMM.deinitializeMultiple(waitFor(DeallocResult), {InitializeKeyAddr});
|
|
cantFail(DeallocResult.get());
|
|
|
|
EXPECT_EQ(SentinelValue1, 42U);
|
|
EXPECT_EQ(SentinelValue2, 42U);
|
|
EXPECT_EQ(SentinelValue3, 0U);
|
|
|
|
std::future<Error> ReleaseResult;
|
|
SNMM.releaseMultiple(waitFor(ReleaseResult), {Addr});
|
|
cantFail(ReleaseResult.get());
|
|
}
|
|
|
|
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.
|
|
|
|
SimpleNativeMemoryMap SNMM;
|
|
|
|
std::future<Expected<void *>> ReserveResult;
|
|
SNMM.reserve(waitFor(ReserveResult), 1024 * 1024 * 1024);
|
|
void *Addr = cantFail(ReserveResult.get());
|
|
|
|
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, {}});
|
|
|
|
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))});
|
|
|
|
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));
|
|
ShutdownResult.get();
|
|
|
|
EXPECT_EQ(SentinelValue, 42);
|
|
}
|
|
|
|
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.
|
|
|
|
SimpleNativeMemoryMap SNMM;
|
|
|
|
std::future<Expected<void *>> ReserveResult;
|
|
SNMM.reserve(waitFor(ReserveResult), 1024 * 1024 * 1024);
|
|
void *Addr = cantFail(ReserveResult.get());
|
|
|
|
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, {}});
|
|
|
|
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))});
|
|
|
|
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));
|
|
DetachResult.get();
|
|
|
|
EXPECT_EQ(SentinelValue, 0);
|
|
|
|
std::future<void> ShutdownResult;
|
|
SNMM.onShutdown(waitFor(ShutdownResult));
|
|
ShutdownResult.get();
|
|
|
|
EXPECT_EQ(SentinelValue, 42);
|
|
}
|