Commit f60f6788 authored by Dong-hee Na's avatar Dong-hee Na

Change section memory manager to fix performance problem in long-running SectionMemoryManagers

parent 75562e57
......@@ -19,6 +19,7 @@
#include "llvm/ExecutionEngine/RuntimeDyld.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Memory.h"
#include "llvm/Support/Process.h"
#include "codegen/irgen/util.h"
#include "codegen/unwinding.h"
......@@ -49,9 +50,14 @@ public:
private:
void invalidateInstructionCache();
struct FreeMemBlock {
sys::MemoryBlock Free;
unsigned PendingPrefixIndex;
};
struct MemoryGroup {
SmallVector<sys::MemoryBlock, 16> PendingMem;
SmallVector<sys::MemoryBlock, 16> AllocatedMem;
SmallVector<sys::MemoryBlock, 16> FreeMem;
SmallVector<FreeMemBlock, 16> FreeMem;
sys::MemoryBlock Near;
};
......@@ -91,21 +97,33 @@ uint8_t* PystonMemoryManager::allocateSection(MemoryGroup& MemGroup, uintptr_t S
uintptr_t RequiredSize = Alignment * ((Size + Alignment - 1) / Alignment + 1);
uintptr_t Addr = 0;
// Look in the list of free memory regions and use a block there if one
// is available.
for (int i = 0, e = MemGroup.FreeMem.size(); i != e; ++i) {
sys::MemoryBlock& MB = MemGroup.FreeMem[i];
if (MB.size() >= RequiredSize) {
Addr = (uintptr_t)MB.base();
uintptr_t EndOfBlock = Addr + MB.size();
// Note that all sections get allocated as read-write. The permissions will
// be updated later based on memory group.
//
for (FreeMemBlock& FreeMB : MemGroup.FreeMem) {
if (FreeMB.Free.size() >= RequiredSize) {
Addr = (uintptr_t)FreeMB.Free.base();
uintptr_t EndOfBlock = Addr + FreeMB.Free.size();
// Align the address.
Addr = (Addr + Alignment - 1) & ~(uintptr_t)(Alignment - 1);
// Store cutted free memory block.
MemGroup.FreeMem[i] = sys::MemoryBlock((void*)(Addr + Size), EndOfBlock - Addr - Size);
if (FreeMB.PendingPrefixIndex == (unsigned)-1) {
// The part of the block we're giving out to the user is now pending
MemGroup.PendingMem.push_back(sys::MemoryBlock((void*)Addr, Size));
// Remember this pending block, such that future allocations can just
// modify it rather than creating a new one
FreeMB.PendingPrefixIndex = MemGroup.PendingMem.size() - 1;
} else {
sys::MemoryBlock& PendingMB = MemGroup.PendingMem[FreeMB.PendingPrefixIndex];
PendingMB = sys::MemoryBlock(PendingMB.base(), Addr + Size - (uintptr_t)PendingMB.base());
}
// Remember how much free space is now left in this block
FreeMB.Free = sys::MemoryBlock((void*)(Addr + Size), EndOfBlock - Addr - Size);
return (uint8_t*)Addr;
}
}
// No pre-allocated free block was large enough. Allocate a new memory region.
// Note that all sections get allocated as read-write. The permissions will
// be updated later based on memory group.
......@@ -120,7 +138,7 @@ uint8_t* PystonMemoryManager::allocateSection(MemoryGroup& MemGroup, uintptr_t S
sys::Memory::MF_READ | sys::Memory::MF_WRITE, ec);
if (ec) {
// FIXME: Add error propogation to the interface.
return NULL;
return nullptr;
}
std::string stat_name = "mem_section_" + std::string(SectionName);
......@@ -136,13 +154,17 @@ uint8_t* PystonMemoryManager::allocateSection(MemoryGroup& MemGroup, uintptr_t S
// Align the address.
Addr = (Addr + Alignment - 1) & ~(uintptr_t)(Alignment - 1);
MemGroup.PendingMem.push_back(sys::MemoryBlock((void*)Addr, Size));
// The allocateMappedMemory may allocate much more memory than we need. In
// this case, we store the unused memory as a free memory block.
unsigned FreeSize = EndOfBlock - Addr - Size;
if (FreeSize > 16)
MemGroup.FreeMem.push_back(sys::MemoryBlock((void*)(Addr + Size), FreeSize));
// Return aligned address
if (FreeSize > 16) {
FreeMemBlock FreeMB;
FreeMB.Free = sys::MemoryBlock((void*)(Addr + Size), FreeSize);
FreeMB.PendingPrefixIndex = (unsigned)-1;
MemGroup.FreeMem.push_back(FreeMB);
}
return (uint8_t*)Addr;
}
......@@ -185,15 +207,47 @@ bool PystonMemoryManager::finalizeMemory(std::string* ErrMsg) {
return false;
}
static sys::MemoryBlock trimBlockToPageSize(sys::MemoryBlock M) {
static const size_t PageSize = sys::Process::getPageSize();
size_t StartOverlap = (PageSize - ((uintptr_t)M.base() % PageSize)) % PageSize;
size_t TrimmedSize = M.size();
TrimmedSize -= StartOverlap;
TrimmedSize -= TrimmedSize % PageSize;
sys::MemoryBlock Trimmed((void*)((uintptr_t)M.base() + StartOverlap), TrimmedSize);
assert(((uintptr_t)Trimmed.base() % PageSize) == 0);
assert((Trimmed.size() % PageSize) == 0);
assert(M.base() <= Trimmed.base() && Trimmed.size() <= M.size());
return Trimmed;
}
llvm_error_code PystonMemoryManager::applyMemoryGroupPermissions(MemoryGroup& MemGroup, unsigned Permissions) {
for (int i = 0, e = MemGroup.AllocatedMem.size(); i != e; ++i) {
for (sys::MemoryBlock& MB : MemGroup.PendingMem) {
llvm_error_code ec;
ec = sys::Memory::protectMappedMemory(MemGroup.AllocatedMem[i], Permissions);
ec = sys::Memory::protectMappedMemory(MB, Permissions);
if (ec) {
return ec;
}
}
MemGroup.PendingMem.clear();
// Now go through free blocks and trim any of them that don't span the entire
// page because one of the pending blocks may have overlapped it.
for (FreeMemBlock& FreeMB : MemGroup.FreeMem) {
FreeMB.Free = trimBlockToPageSize(FreeMB.Free);
// We cleared the PendingMem list, so all these pointers are now invalid
FreeMB.PendingPrefixIndex = (unsigned)-1;
}
// Remove all blocks which are now empty
MemGroup.FreeMem.erase(std::remove_if(MemGroup.FreeMem.begin(), MemGroup.FreeMem.end(), [](FreeMemBlock& FreeMB) {
return FreeMB.Free.size() == 0;
}), MemGroup.FreeMem.end());
#if LLVMREV < 209952
return llvm_error_code::success();
......@@ -203,8 +257,8 @@ llvm_error_code PystonMemoryManager::applyMemoryGroupPermissions(MemoryGroup& Me
}
void PystonMemoryManager::invalidateInstructionCache() {
for (int i = 0, e = CodeMem.AllocatedMem.size(); i != e; ++i)
sys::Memory::InvalidateInstructionCache(CodeMem.AllocatedMem[i].base(), CodeMem.AllocatedMem[i].size());
for (sys::MemoryBlock& Block : CodeMem.PendingMem)
sys::Memory::InvalidateInstructionCache(Block.base(), Block.size());
}
uint64_t PystonMemoryManager::getSymbolAddress(const std::string& name) {
......@@ -230,12 +284,10 @@ uint64_t PystonMemoryManager::getSymbolAddress(const std::string& name) {
}
PystonMemoryManager::~PystonMemoryManager() {
for (unsigned i = 0, e = CodeMem.AllocatedMem.size(); i != e; ++i)
sys::Memory::releaseMappedMemory(CodeMem.AllocatedMem[i]);
for (unsigned i = 0, e = RWDataMem.AllocatedMem.size(); i != e; ++i)
sys::Memory::releaseMappedMemory(RWDataMem.AllocatedMem[i]);
for (unsigned i = 0, e = RODataMem.AllocatedMem.size(); i != e; ++i)
sys::Memory::releaseMappedMemory(RODataMem.AllocatedMem[i]);
for (MemoryGroup* Group : { &CodeMem, &RWDataMem, &RODataMem }) {
for (sys::MemoryBlock& Block : Group->AllocatedMem)
sys::Memory::releaseMappedMemory(Block);
}
}
std::unique_ptr<llvm::RTDyldMemoryManager> createMemoryManager() {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment