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 @@ ...@@ -19,6 +19,7 @@
#include "llvm/ExecutionEngine/RuntimeDyld.h" #include "llvm/ExecutionEngine/RuntimeDyld.h"
#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Memory.h" #include "llvm/Support/Memory.h"
#include "llvm/Support/Process.h"
#include "codegen/irgen/util.h" #include "codegen/irgen/util.h"
#include "codegen/unwinding.h" #include "codegen/unwinding.h"
...@@ -49,9 +50,14 @@ public: ...@@ -49,9 +50,14 @@ public:
private: private:
void invalidateInstructionCache(); void invalidateInstructionCache();
struct FreeMemBlock {
sys::MemoryBlock Free;
unsigned PendingPrefixIndex;
};
struct MemoryGroup { struct MemoryGroup {
SmallVector<sys::MemoryBlock, 16> PendingMem;
SmallVector<sys::MemoryBlock, 16> AllocatedMem; SmallVector<sys::MemoryBlock, 16> AllocatedMem;
SmallVector<sys::MemoryBlock, 16> FreeMem; SmallVector<FreeMemBlock, 16> FreeMem;
sys::MemoryBlock Near; sys::MemoryBlock Near;
}; };
...@@ -91,21 +97,33 @@ uint8_t* PystonMemoryManager::allocateSection(MemoryGroup& MemGroup, uintptr_t S ...@@ -91,21 +97,33 @@ uint8_t* PystonMemoryManager::allocateSection(MemoryGroup& MemGroup, uintptr_t S
uintptr_t RequiredSize = Alignment * ((Size + Alignment - 1) / Alignment + 1); uintptr_t RequiredSize = Alignment * ((Size + Alignment - 1) / Alignment + 1);
uintptr_t Addr = 0; uintptr_t Addr = 0;
// Look in the list of free memory regions and use a block there if one // Note that all sections get allocated as read-write. The permissions will
// is available. // be updated later based on memory group.
for (int i = 0, e = MemGroup.FreeMem.size(); i != e; ++i) { //
sys::MemoryBlock& MB = MemGroup.FreeMem[i]; for (FreeMemBlock& FreeMB : MemGroup.FreeMem) {
if (MB.size() >= RequiredSize) { if (FreeMB.Free.size() >= RequiredSize) {
Addr = (uintptr_t)MB.base(); Addr = (uintptr_t)FreeMB.Free.base();
uintptr_t EndOfBlock = Addr + MB.size(); uintptr_t EndOfBlock = Addr + FreeMB.Free.size();
// Align the address. // Align the address.
Addr = (Addr + Alignment - 1) & ~(uintptr_t)(Alignment - 1); 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; return (uint8_t*)Addr;
} }
} }
// No pre-allocated free block was large enough. Allocate a new memory region. // 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 // Note that all sections get allocated as read-write. The permissions will
// be updated later based on memory group. // be updated later based on memory group.
...@@ -120,7 +138,7 @@ uint8_t* PystonMemoryManager::allocateSection(MemoryGroup& MemGroup, uintptr_t S ...@@ -120,7 +138,7 @@ uint8_t* PystonMemoryManager::allocateSection(MemoryGroup& MemGroup, uintptr_t S
sys::Memory::MF_READ | sys::Memory::MF_WRITE, ec); sys::Memory::MF_READ | sys::Memory::MF_WRITE, ec);
if (ec) { if (ec) {
// FIXME: Add error propogation to the interface. // FIXME: Add error propogation to the interface.
return NULL; return nullptr;
} }
std::string stat_name = "mem_section_" + std::string(SectionName); std::string stat_name = "mem_section_" + std::string(SectionName);
...@@ -136,13 +154,17 @@ uint8_t* PystonMemoryManager::allocateSection(MemoryGroup& MemGroup, uintptr_t S ...@@ -136,13 +154,17 @@ uint8_t* PystonMemoryManager::allocateSection(MemoryGroup& MemGroup, uintptr_t S
// Align the address. // Align the address.
Addr = (Addr + Alignment - 1) & ~(uintptr_t)(Alignment - 1); 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 // The allocateMappedMemory may allocate much more memory than we need. In
// this case, we store the unused memory as a free memory block. // this case, we store the unused memory as a free memory block.
unsigned FreeSize = EndOfBlock - Addr - Size; unsigned FreeSize = EndOfBlock - Addr - Size;
if (FreeSize > 16) if (FreeSize > 16) {
MemGroup.FreeMem.push_back(sys::MemoryBlock((void*)(Addr + Size), FreeSize)); FreeMemBlock FreeMB;
FreeMB.Free = sys::MemoryBlock((void*)(Addr + Size), FreeSize);
// Return aligned address FreeMB.PendingPrefixIndex = (unsigned)-1;
MemGroup.FreeMem.push_back(FreeMB);
}
return (uint8_t*)Addr; return (uint8_t*)Addr;
} }
...@@ -185,15 +207,47 @@ bool PystonMemoryManager::finalizeMemory(std::string* ErrMsg) { ...@@ -185,15 +207,47 @@ bool PystonMemoryManager::finalizeMemory(std::string* ErrMsg) {
return false; 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) { 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; llvm_error_code ec;
ec = sys::Memory::protectMappedMemory(MemGroup.AllocatedMem[i], Permissions); ec = sys::Memory::protectMappedMemory(MB, Permissions);
if (ec) { if (ec) {
return 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 #if LLVMREV < 209952
return llvm_error_code::success(); return llvm_error_code::success();
...@@ -203,8 +257,8 @@ llvm_error_code PystonMemoryManager::applyMemoryGroupPermissions(MemoryGroup& Me ...@@ -203,8 +257,8 @@ llvm_error_code PystonMemoryManager::applyMemoryGroupPermissions(MemoryGroup& Me
} }
void PystonMemoryManager::invalidateInstructionCache() { void PystonMemoryManager::invalidateInstructionCache() {
for (int i = 0, e = CodeMem.AllocatedMem.size(); i != e; ++i) for (sys::MemoryBlock& Block : CodeMem.PendingMem)
sys::Memory::InvalidateInstructionCache(CodeMem.AllocatedMem[i].base(), CodeMem.AllocatedMem[i].size()); sys::Memory::InvalidateInstructionCache(Block.base(), Block.size());
} }
uint64_t PystonMemoryManager::getSymbolAddress(const std::string& name) { uint64_t PystonMemoryManager::getSymbolAddress(const std::string& name) {
...@@ -230,12 +284,10 @@ uint64_t PystonMemoryManager::getSymbolAddress(const std::string& name) { ...@@ -230,12 +284,10 @@ uint64_t PystonMemoryManager::getSymbolAddress(const std::string& name) {
} }
PystonMemoryManager::~PystonMemoryManager() { PystonMemoryManager::~PystonMemoryManager() {
for (unsigned i = 0, e = CodeMem.AllocatedMem.size(); i != e; ++i) for (MemoryGroup* Group : { &CodeMem, &RWDataMem, &RODataMem }) {
sys::Memory::releaseMappedMemory(CodeMem.AllocatedMem[i]); for (sys::MemoryBlock& Block : Group->AllocatedMem)
for (unsigned i = 0, e = RWDataMem.AllocatedMem.size(); i != e; ++i) sys::Memory::releaseMappedMemory(Block);
sys::Memory::releaseMappedMemory(RWDataMem.AllocatedMem[i]); }
for (unsigned i = 0, e = RODataMem.AllocatedMem.size(); i != e; ++i)
sys::Memory::releaseMappedMemory(RODataMem.AllocatedMem[i]);
} }
std::unique_ptr<llvm::RTDyldMemoryManager> createMemoryManager() { 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