[llvm] r371244 - [llvm-jitlink] Add optional slab allocator for testing locality optimizations.
Lang Hames via llvm-commits
llvm-commits at lists.llvm.org
Fri Sep 6 12:21:55 PDT 2019
Author: lhames
Date: Fri Sep 6 12:21:55 2019
New Revision: 371244
URL: http://llvm.org/viewvc/llvm-project?rev=371244&view=rev
Log:
[llvm-jitlink] Add optional slab allocator for testing locality optimizations.
The llvm-jitlink utility now accepts a '-slab-allocate <size>' option. If given,
llvm-jitlink will use a slab-based memory manager rather than the default
InProcessMemoryManager. Using a slab allocator will allow reliable testing of
future locality based optimizations (e.g. PLT and GOT elimination) in JITLink.
The <size> argument is a number, optionally followed by a units specifier (Kb,
Mb, or Gb). If the units are not given then the number is assumed to be in Kb.
Modified:
llvm/trunk/tools/llvm-jitlink/llvm-jitlink.cpp
llvm/trunk/tools/llvm-jitlink/llvm-jitlink.h
Modified: llvm/trunk/tools/llvm-jitlink/llvm-jitlink.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-jitlink/llvm-jitlink.cpp?rev=371244&r1=371243&r2=371244&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-jitlink/llvm-jitlink.cpp (original)
+++ llvm/trunk/tools/llvm-jitlink/llvm-jitlink.cpp Fri Sep 6 12:21:55 2019
@@ -31,6 +31,7 @@
#include "llvm/Support/DynamicLibrary.h"
#include "llvm/Support/InitLLVM.h"
#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Process.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/Timer.h"
@@ -99,6 +100,13 @@ static cl::opt<bool> ShowTimes("show-tim
cl::desc("Show times for llvm-jitlink phases"),
cl::init(false));
+static cl::opt<std::string> SlabAllocateSizeString(
+ "slab-allocate",
+ cl::desc("Allocate from a slab of the given size "
+ "(allowable suffixes: Kb, Mb, Gb. default = "
+ "Kb)"),
+ cl::init(""));
+
static cl::opt<bool> ShowRelocatedSectionContents(
"show-relocated-section-contents",
cl::desc("show section contents after fixups have been applied"),
@@ -221,7 +229,175 @@ static void dumpSectionContents(raw_ostr
}
}
-Session::Session(Triple TT) : ObjLayer(ES, MemMgr), TT(std::move(TT)) {
+class JITLinkSlabAllocator final : public JITLinkMemoryManager {
+public:
+ static Expected<std::unique_ptr<JITLinkSlabAllocator>>
+ Create(uint64_t SlabSize) {
+ Error Err = Error::success();
+ std::unique_ptr<JITLinkSlabAllocator> Allocator(
+ new JITLinkSlabAllocator(SlabSize, Err));
+ if (Err)
+ return std::move(Err);
+ return std::move(Allocator);
+ }
+
+ Expected<std::unique_ptr<JITLinkMemoryManager::Allocation>>
+ allocate(const SegmentsRequestMap &Request) override {
+
+ using AllocationMap = DenseMap<unsigned, sys::MemoryBlock>;
+
+ // Local class for allocation.
+ class IPMMAlloc : public Allocation {
+ public:
+ IPMMAlloc(AllocationMap SegBlocks) : SegBlocks(std::move(SegBlocks)) {}
+ MutableArrayRef<char> getWorkingMemory(ProtectionFlags Seg) override {
+ assert(SegBlocks.count(Seg) && "No allocation for segment");
+ return {static_cast<char *>(SegBlocks[Seg].base()),
+ SegBlocks[Seg].allocatedSize()};
+ }
+ JITTargetAddress getTargetMemory(ProtectionFlags Seg) override {
+ assert(SegBlocks.count(Seg) && "No allocation for segment");
+ return reinterpret_cast<JITTargetAddress>(SegBlocks[Seg].base());
+ }
+ void finalizeAsync(FinalizeContinuation OnFinalize) override {
+ OnFinalize(applyProtections());
+ }
+ Error deallocate() override {
+ for (auto &KV : SegBlocks)
+ if (auto EC = sys::Memory::releaseMappedMemory(KV.second))
+ return errorCodeToError(EC);
+ return Error::success();
+ }
+
+ private:
+ Error applyProtections() {
+ for (auto &KV : SegBlocks) {
+ auto &Prot = KV.first;
+ auto &Block = KV.second;
+ if (auto EC = sys::Memory::protectMappedMemory(Block, Prot))
+ return errorCodeToError(EC);
+ if (Prot & sys::Memory::MF_EXEC)
+ sys::Memory::InvalidateInstructionCache(Block.base(),
+ Block.allocatedSize());
+ }
+ return Error::success();
+ }
+
+ AllocationMap SegBlocks;
+ };
+
+ AllocationMap Blocks;
+
+ for (auto &KV : Request) {
+ auto &Seg = KV.second;
+
+ if (Seg.getContentAlignment() > PageSize)
+ return make_error<StringError>("Cannot request higher than page "
+ "alignment",
+ inconvertibleErrorCode());
+
+ if (PageSize % Seg.getContentAlignment() != 0)
+ return make_error<StringError>("Page size is not a multiple of "
+ "alignment",
+ inconvertibleErrorCode());
+
+ uint64_t ZeroFillStart =
+ alignTo(Seg.getContentSize(), Seg.getZeroFillAlignment());
+ uint64_t SegmentSize = ZeroFillStart + Seg.getZeroFillSize();
+
+ // Round segment size up to page boundary.
+ SegmentSize = (SegmentSize + PageSize - 1) & ~(PageSize - 1);
+
+ // Take segment bytes from the front of the slab.
+ void *SlabBase = SlabRemaining.base();
+ uint64_t SlabRemainingSize = SlabRemaining.allocatedSize();
+
+ if (SegmentSize > SlabRemainingSize)
+ return make_error<StringError>("Slab allocator out of memory",
+ inconvertibleErrorCode());
+
+ sys::MemoryBlock SegMem(SlabBase, SegmentSize);
+ SlabRemaining =
+ sys::MemoryBlock(reinterpret_cast<char *>(SlabBase) + SegmentSize,
+ SlabRemainingSize - SegmentSize);
+
+ // Zero out the zero-fill memory.
+ memset(static_cast<char *>(SegMem.base()) + ZeroFillStart, 0,
+ Seg.getZeroFillSize());
+
+ // Record the block for this segment.
+ Blocks[KV.first] = std::move(SegMem);
+ }
+ return std::unique_ptr<InProcessMemoryManager::Allocation>(
+ new IPMMAlloc(std::move(Blocks)));
+ }
+
+private:
+ JITLinkSlabAllocator(uint64_t SlabSize, Error &Err) {
+ ErrorAsOutParameter _(&Err);
+
+ PageSize = sys::Process::getPageSizeEstimate();
+
+ if (!isPowerOf2_64(PageSize)) {
+ Err = make_error<StringError>("Page size is not a power of 2",
+ inconvertibleErrorCode());
+ return;
+ }
+
+ // Round slab request up to page size.
+ SlabSize = (SlabSize + PageSize - 1) & ~(PageSize - 1);
+
+ const sys::Memory::ProtectionFlags ReadWrite =
+ static_cast<sys::Memory::ProtectionFlags>(sys::Memory::MF_READ |
+ sys::Memory::MF_WRITE);
+
+ std::error_code EC;
+ SlabRemaining =
+ sys::Memory::allocateMappedMemory(SlabSize, nullptr, ReadWrite, EC);
+
+ if (EC) {
+ Err = errorCodeToError(EC);
+ return;
+ }
+ }
+
+ sys::MemoryBlock SlabRemaining;
+ uint64_t PageSize = 0;
+};
+
+Expected<uint64_t> getSlabAllocSize(StringRef SizeString) {
+ SizeString = SizeString.trim();
+
+ uint64_t Units = 1024;
+
+ if (SizeString.endswith_lower("kb"))
+ SizeString = SizeString.drop_back(2).rtrim();
+ else if (SizeString.endswith_lower("mb")) {
+ Units = 1024 * 1024;
+ SizeString = SizeString.drop_back(2).rtrim();
+ } else if (SizeString.endswith_lower("gb")) {
+ Units = 1024 * 1024 * 1024;
+ SizeString = SizeString.drop_back(2).rtrim();
+ }
+
+ uint64_t SlabSize = 0;
+ if (SizeString.getAsInteger(10, SlabSize))
+ return make_error<StringError>("Invalid numeric format for slab size",
+ inconvertibleErrorCode());
+
+ return SlabSize * Units;
+}
+
+static std::unique_ptr<jitlink::JITLinkMemoryManager> createMemoryManager() {
+ if (!SlabAllocateSizeString.empty()) {
+ auto SlabSize = ExitOnErr(getSlabAllocSize(SlabAllocateSizeString));
+ return ExitOnErr(JITLinkSlabAllocator::Create(SlabSize));
+ }
+ return std::make_unique<jitlink::InProcessMemoryManager>();
+}
+
+Session::Session(Triple TT)
+ : MemMgr(createMemoryManager()), ObjLayer(ES, *MemMgr), TT(std::move(TT)) {
/// Local ObjectLinkingLayer::Plugin class to forward modifyPassConfig to the
/// Session.
Modified: llvm/trunk/tools/llvm-jitlink/llvm-jitlink.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-jitlink/llvm-jitlink.h?rev=371244&r1=371243&r2=371244&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-jitlink/llvm-jitlink.h (original)
+++ llvm/trunk/tools/llvm-jitlink/llvm-jitlink.h Fri Sep 6 12:21:55 2019
@@ -26,7 +26,7 @@ namespace llvm {
struct Session {
orc::ExecutionSession ES;
- jitlink::InProcessMemoryManager MemMgr;
+ std::unique_ptr<jitlink::JITLinkMemoryManager> MemMgr;
orc::ObjectLinkingLayer ObjLayer;
std::vector<orc::JITDylib *> JDSearchOrder;
Triple TT;
More information about the llvm-commits
mailing list