177 lines
5.6 KiB
C++
177 lines
5.6 KiB
C++
//===---------------- MapperJITLinkMemoryManagerTest.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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "OrcTestCommon.h"
|
|
|
|
#include "llvm/ExecutionEngine/Orc/MapperJITLinkMemoryManager.h"
|
|
|
|
#include "llvm/ExecutionEngine/Orc/MemoryMapper.h"
|
|
#include "llvm/Testing/Support/Error.h"
|
|
|
|
#include <vector>
|
|
|
|
using namespace llvm;
|
|
using namespace llvm::jitlink;
|
|
using namespace llvm::orc;
|
|
using namespace llvm::orc::shared;
|
|
|
|
namespace {
|
|
|
|
class CounterMapper final : public MemoryMapper {
|
|
public:
|
|
CounterMapper(std::unique_ptr<MemoryMapper> Mapper)
|
|
: Mapper(std::move(Mapper)) {}
|
|
|
|
unsigned int getPageSize() override { return Mapper->getPageSize(); }
|
|
|
|
void reserve(size_t NumBytes, OnReservedFunction OnReserved) override {
|
|
++ReserveCount;
|
|
return Mapper->reserve(NumBytes, std::move(OnReserved));
|
|
}
|
|
|
|
void initialize(AllocInfo &AI, OnInitializedFunction OnInitialized) override {
|
|
++InitCount;
|
|
return Mapper->initialize(AI, std::move(OnInitialized));
|
|
}
|
|
|
|
char *prepare(ExecutorAddr Addr, size_t ContentSize) override {
|
|
return Mapper->prepare(Addr, ContentSize);
|
|
}
|
|
|
|
void deinitialize(ArrayRef<ExecutorAddr> Allocations,
|
|
OnDeinitializedFunction OnDeInitialized) override {
|
|
++DeinitCount;
|
|
return Mapper->deinitialize(Allocations, std::move(OnDeInitialized));
|
|
}
|
|
|
|
void release(ArrayRef<ExecutorAddr> Reservations,
|
|
OnReleasedFunction OnRelease) override {
|
|
++ReleaseCount;
|
|
|
|
return Mapper->release(Reservations, std::move(OnRelease));
|
|
}
|
|
|
|
int ReserveCount = 0, InitCount = 0, DeinitCount = 0, ReleaseCount = 0;
|
|
|
|
private:
|
|
std::unique_ptr<MemoryMapper> Mapper;
|
|
};
|
|
|
|
TEST(MapperJITLinkMemoryManagerTest, InProcess) {
|
|
auto Mapper = std::make_unique<CounterMapper>(
|
|
cantFail(InProcessMemoryMapper::Create()));
|
|
|
|
auto *Counter = static_cast<CounterMapper *>(Mapper.get());
|
|
|
|
auto MemMgr = std::make_unique<MapperJITLinkMemoryManager>(16 * 1024 * 1024,
|
|
std::move(Mapper));
|
|
|
|
EXPECT_EQ(Counter->ReserveCount, 0);
|
|
EXPECT_EQ(Counter->InitCount, 0);
|
|
|
|
StringRef Hello = "hello";
|
|
auto SSA1 = jitlink::SimpleSegmentAlloc::Create(
|
|
*MemMgr, nullptr, {{MemProt::Read, {Hello.size(), Align(1)}}});
|
|
EXPECT_THAT_EXPECTED(SSA1, Succeeded());
|
|
|
|
EXPECT_EQ(Counter->ReserveCount, 1);
|
|
EXPECT_EQ(Counter->InitCount, 0);
|
|
|
|
auto SegInfo1 = SSA1->getSegInfo(MemProt::Read);
|
|
memcpy(SegInfo1.WorkingMem.data(), Hello.data(), Hello.size());
|
|
|
|
auto FA1 = SSA1->finalize();
|
|
EXPECT_THAT_EXPECTED(FA1, Succeeded());
|
|
|
|
EXPECT_EQ(Counter->ReserveCount, 1);
|
|
EXPECT_EQ(Counter->InitCount, 1);
|
|
|
|
auto SSA2 = jitlink::SimpleSegmentAlloc::Create(
|
|
*MemMgr, nullptr, {{MemProt::Read, {Hello.size(), Align(1)}}});
|
|
EXPECT_THAT_EXPECTED(SSA2, Succeeded());
|
|
|
|
// last reservation should be reused
|
|
EXPECT_EQ(Counter->ReserveCount, 1);
|
|
EXPECT_EQ(Counter->InitCount, 1);
|
|
|
|
auto SegInfo2 = SSA2->getSegInfo(MemProt::Read);
|
|
memcpy(SegInfo2.WorkingMem.data(), Hello.data(), Hello.size());
|
|
auto FA2 = SSA2->finalize();
|
|
EXPECT_THAT_EXPECTED(FA2, Succeeded());
|
|
|
|
EXPECT_EQ(Counter->ReserveCount, 1);
|
|
EXPECT_EQ(Counter->InitCount, 2);
|
|
|
|
ExecutorAddr TargetAddr1(SegInfo1.Addr);
|
|
ExecutorAddr TargetAddr2(SegInfo2.Addr);
|
|
|
|
const char *TargetMem1 = TargetAddr1.toPtr<const char *>();
|
|
StringRef TargetHello1(TargetMem1, Hello.size());
|
|
EXPECT_EQ(Hello, TargetHello1);
|
|
|
|
const char *TargetMem2 = TargetAddr2.toPtr<const char *>();
|
|
StringRef TargetHello2(TargetMem2, Hello.size());
|
|
EXPECT_EQ(Hello, TargetHello2);
|
|
|
|
EXPECT_EQ(Counter->DeinitCount, 0);
|
|
|
|
auto Err2 = MemMgr->deallocate(std::move(*FA1));
|
|
EXPECT_THAT_ERROR(std::move(Err2), Succeeded());
|
|
|
|
EXPECT_EQ(Counter->DeinitCount, 1);
|
|
|
|
auto Err3 = MemMgr->deallocate(std::move(*FA2));
|
|
EXPECT_THAT_ERROR(std::move(Err3), Succeeded());
|
|
|
|
EXPECT_EQ(Counter->DeinitCount, 2);
|
|
}
|
|
|
|
TEST(MapperJITLinkMemoryManagerTest, Coalescing) {
|
|
auto Mapper = cantFail(InProcessMemoryMapper::Create());
|
|
auto MemMgr = std::make_unique<MapperJITLinkMemoryManager>(16 * 1024 * 1024,
|
|
std::move(Mapper));
|
|
|
|
auto SSA1 = jitlink::SimpleSegmentAlloc::Create(
|
|
*MemMgr, nullptr, {{MemProt::Read, {1024, Align(1)}}});
|
|
EXPECT_THAT_EXPECTED(SSA1, Succeeded());
|
|
auto SegInfo1 = SSA1->getSegInfo(MemProt::Read);
|
|
ExecutorAddr TargetAddr1(SegInfo1.Addr);
|
|
auto FA1 = SSA1->finalize();
|
|
EXPECT_THAT_EXPECTED(FA1, Succeeded());
|
|
|
|
auto SSA2 = jitlink::SimpleSegmentAlloc::Create(
|
|
*MemMgr, nullptr, {{MemProt::Read, {1024, Align(1)}}});
|
|
EXPECT_THAT_EXPECTED(SSA2, Succeeded());
|
|
auto FA2 = SSA2->finalize();
|
|
EXPECT_THAT_EXPECTED(FA2, Succeeded());
|
|
|
|
auto Err2 = MemMgr->deallocate(std::move(*FA1));
|
|
EXPECT_THAT_ERROR(std::move(Err2), Succeeded());
|
|
|
|
auto Err3 = MemMgr->deallocate(std::move(*FA2));
|
|
EXPECT_THAT_ERROR(std::move(Err3), Succeeded());
|
|
|
|
auto SSA3 = jitlink::SimpleSegmentAlloc::Create(
|
|
*MemMgr, nullptr, {{MemProt::Read, {2048, Align(1)}}});
|
|
EXPECT_THAT_EXPECTED(SSA3, Succeeded());
|
|
|
|
auto SegInfo3 = SSA3->getSegInfo(MemProt::Read);
|
|
ExecutorAddr TargetAddr3(SegInfo3.Addr);
|
|
|
|
auto FA3 = SSA3->finalize();
|
|
EXPECT_THAT_EXPECTED(FA3, Succeeded());
|
|
|
|
// previous two freed 1024 blocks should be fused to form a 2048 block
|
|
EXPECT_EQ(TargetAddr1, TargetAddr3);
|
|
|
|
auto Err4 = MemMgr->deallocate(std::move(*FA3));
|
|
EXPECT_THAT_ERROR(std::move(Err4), Succeeded());
|
|
}
|
|
|
|
} // namespace
|