[llvm] 23d0e71 - [Orc] Use IntervalMap to store free memory regions in MapperJITLinkMemoryManager
Anubhab Ghosh via llvm-commits
llvm-commits at lists.llvm.org
Sun Aug 14 02:27:54 PDT 2022
Author: Anubhab Ghosh
Date: 2022-08-14T14:35:08+05:30
New Revision: 23d0e71fcbc467840efd6cbb83ffdb6c13fdc610
URL: https://github.com/llvm/llvm-project/commit/23d0e71fcbc467840efd6cbb83ffdb6c13fdc610
DIFF: https://github.com/llvm/llvm-project/commit/23d0e71fcbc467840efd6cbb83ffdb6c13fdc610.diff
LOG: [Orc] Use IntervalMap to store free memory regions in MapperJITLinkMemoryManager
MapperJITLinkMemoryManager uses a free list to keep track of available
memory regions. Using an IntervalMap instead of vector allow automatic
coalescing of memory regions as they are freed.
Differential Revision: https://reviews.llvm.org/D131831
Added:
Modified:
llvm/include/llvm/ExecutionEngine/Orc/MapperJITLinkMemoryManager.h
llvm/lib/ExecutionEngine/Orc/MapperJITLinkMemoryManager.cpp
llvm/unittests/ExecutionEngine/Orc/MapperJITLinkMemoryManagerTest.cpp
Removed:
################################################################################
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/MapperJITLinkMemoryManager.h b/llvm/include/llvm/ExecutionEngine/Orc/MapperJITLinkMemoryManager.h
index 4017b120790da..b1897d557b122 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/MapperJITLinkMemoryManager.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/MapperJITLinkMemoryManager.h
@@ -13,6 +13,7 @@
#ifndef LLVM_EXECUTIONENGINE_ORC_MAPPERJITLINKMEMORYMANAGER_H
#define LLVM_EXECUTIONENGINE_ORC_MAPPERJITLINKMEMORYMANAGER_H
+#include "llvm/ADT/IntervalMap.h"
#include "llvm/ExecutionEngine/JITLink/JITLinkMemoryManager.h"
#include "llvm/ExecutionEngine/Orc/MemoryMapper.h"
@@ -52,8 +53,12 @@ class MapperJITLinkMemoryManager : public jitlink::JITLinkMemoryManager {
// We reserve multiples of this from the executor address space
size_t ReservationUnits;
+
// Ranges that have been reserved in executor but not yet allocated
- std::vector<ExecutorAddrRange> AvailableMemory;
+ using AvailableMemoryMap = IntervalMap<ExecutorAddr, bool>;
+ AvailableMemoryMap::Allocator AMAllocator;
+ IntervalMap<ExecutorAddr, bool> AvailableMemory;
+
// Ranges that have been reserved in executor and already allocated
DenseMap<ExecutorAddr, ExecutorAddrDiff> UsedMemory;
diff --git a/llvm/lib/ExecutionEngine/Orc/MapperJITLinkMemoryManager.cpp b/llvm/lib/ExecutionEngine/Orc/MapperJITLinkMemoryManager.cpp
index bd773a10d9174..587adbf71d241 100644
--- a/llvm/lib/ExecutionEngine/Orc/MapperJITLinkMemoryManager.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/MapperJITLinkMemoryManager.cpp
@@ -57,7 +57,8 @@ class MapperJITLinkMemoryManager::InFlightAlloc
MapperJITLinkMemoryManager::MapperJITLinkMemoryManager(
size_t ReservationGranularity, std::unique_ptr<MemoryMapper> Mapper)
- : ReservationUnits(ReservationGranularity), Mapper(std::move(Mapper)) {}
+ : ReservationUnits(ReservationGranularity), AvailableMemory(AMAllocator),
+ Mapper(std::move(Mapper)) {}
void MapperJITLinkMemoryManager::allocate(const JITLinkDylib *JD, LinkGraph &G,
OnAllocatedFunction OnAllocated) {
@@ -72,20 +73,6 @@ void MapperJITLinkMemoryManager::allocate(const JITLinkDylib *JD, LinkGraph &G,
auto TotalSize = SegsSizes->total();
- Mutex.lock();
-
- // find an already reserved range that is large enough
- ExecutorAddrRange SelectedRange{};
- std::vector<ExecutorAddrRange>::iterator SelectedRangeIt;
- SelectedRangeIt =
- llvm::find_if(AvailableMemory, [TotalSize](ExecutorAddrRange Range) {
- return TotalSize < Range.size();
- });
- if (SelectedRangeIt != AvailableMemory.end()) {
- SelectedRange = *SelectedRangeIt;
- AvailableMemory.erase(SelectedRangeIt);
- }
-
auto CompleteAllocation = [this, &G, BL = std::move(BL),
OnAllocated = std::move(OnAllocated)](
Expected<ExecutorAddrRange> Result) mutable {
@@ -123,8 +110,7 @@ void MapperJITLinkMemoryManager::allocate(const JITLinkDylib *JD, LinkGraph &G,
if (NextSegAddr < Result->End) {
// Save the remaining memory for reuse in next allocation(s)
- auto RemainingRange = ExecutorAddrRange(NextSegAddr, Result->End);
- AvailableMemory.push_back(RemainingRange);
+ AvailableMemory.insert(NextSegAddr, Result->End - 1, true);
}
Mutex.unlock();
@@ -137,6 +123,20 @@ void MapperJITLinkMemoryManager::allocate(const JITLinkDylib *JD, LinkGraph &G,
std::move(SegInfos)));
};
+ Mutex.lock();
+
+ // find an already reserved range that is large enough
+ ExecutorAddrRange SelectedRange{};
+
+ for (AvailableMemoryMap::iterator It = AvailableMemory.begin();
+ It != AvailableMemory.end(); It++) {
+ if (It.stop() - It.start() + 1 >= TotalSize) {
+ SelectedRange = ExecutorAddrRange(It.start(), It.stop() + 1);
+ It.erase();
+ break;
+ }
+ }
+
if (SelectedRange.empty()) { // no already reserved range was found
auto TotalAllocation = alignTo(TotalSize, ReservationUnits);
Mapper->reserve(TotalAllocation, std::move(CompleteAllocation));
@@ -168,7 +168,7 @@ void MapperJITLinkMemoryManager::deallocate(
ExecutorAddrDiff Size = UsedMemory[Addr];
UsedMemory.erase(Addr);
- AvailableMemory.push_back({Addr, Addr + Size});
+ AvailableMemory.insert(Addr, Addr + Size - 1, true);
FA.release();
}
diff --git a/llvm/unittests/ExecutionEngine/Orc/MapperJITLinkMemoryManagerTest.cpp b/llvm/unittests/ExecutionEngine/Orc/MapperJITLinkMemoryManagerTest.cpp
index ca1b13c759f63..94a7b4e2526e1 100644
--- a/llvm/unittests/ExecutionEngine/Orc/MapperJITLinkMemoryManagerTest.cpp
+++ b/llvm/unittests/ExecutionEngine/Orc/MapperJITLinkMemoryManagerTest.cpp
@@ -1,4 +1,4 @@
-//===-------------- MapperJITLinkMemoryManagerTest.cpp ----------------===//
+//===---------------- 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.
@@ -131,4 +131,46 @@ TEST(MapperJITLinkMemoryManagerTest, InProcess) {
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, {{jitlink::MemProt::Read, {1024, Align(1)}}});
+ EXPECT_THAT_EXPECTED(SSA1, Succeeded());
+ auto SegInfo1 = SSA1->getSegInfo(jitlink::MemProt::Read);
+ ExecutorAddr TargetAddr1(SegInfo1.Addr);
+ auto FA1 = SSA1->finalize();
+ EXPECT_THAT_EXPECTED(FA1, Succeeded());
+
+ auto SSA2 = jitlink::SimpleSegmentAlloc::Create(
+ *MemMgr, nullptr, {{jitlink::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, {{jitlink::MemProt::Read, {2048, Align(1)}}});
+ EXPECT_THAT_EXPECTED(SSA3, Succeeded());
+
+ auto SegInfo3 = SSA3->getSegInfo(jitlink::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
More information about the llvm-commits
mailing list