[llvm] [llvm-rtdyld] Precalculate required memory upfront (PR #72254)
Sjoerd Meijer via llvm-commits
llvm-commits at lists.llvm.org
Tue Nov 14 05:46:25 PST 2023
https://github.com/sjoerdmeijer created https://github.com/llvm/llvm-project/pull/72254
This changes the behaviour of llvm-rtdyld to calculate and allocate all required memory for objects and its data/code section upfront as opposed to doing this on-demand.
Allocation of the memory upfront avoids fragmentation of the memory, which is a workaround for relocations getting out of range as explained and discussed here:
https://discourse.llvm.org/t/problems-with-code-model-large-and-relocations/70511
>From 8442c0fd63c42558534f9b33f4f6efdc8305aca7 Mon Sep 17 00:00:00 2001
From: Sjoerd Meijer <smeijer at nvidia.com>
Date: Wed, 8 Nov 2023 18:57:30 +0530
Subject: [PATCH] [llvm-rtdyld] Precalculate required memory upfront
This changes the behaviour of llvm-rtdyld to calculate and allocate all
required memory for objects and its data/code section upfront as opposed
to doing this on-demand.
Allocation of the memory upfront avoids fragmentation of the memory,
which is a workaround for relocations getting out of range as explained
and discussed here:
https://discourse.llvm.org/t/problems-with-code-model-large-and-relocations/70511
---
.../llvm/ExecutionEngine/RuntimeDyld.h | 5 ++
.../RuntimeDyld/RuntimeDyld.cpp | 24 ++++++++++
.../RuntimeDyld/RuntimeDyldImpl.h | 18 +++++---
llvm/tools/llvm-rtdyld/llvm-rtdyld.cpp | 46 ++++++++++++++++---
4 files changed, 80 insertions(+), 13 deletions(-)
diff --git a/llvm/include/llvm/ExecutionEngine/RuntimeDyld.h b/llvm/include/llvm/ExecutionEngine/RuntimeDyld.h
index 468296ac1523344..423715453b7c9d1 100644
--- a/llvm/include/llvm/ExecutionEngine/RuntimeDyld.h
+++ b/llvm/include/llvm/ExecutionEngine/RuntimeDyld.h
@@ -194,6 +194,11 @@ class RuntimeDyld {
RuntimeDyld &operator=(const RuntimeDyld &) = delete;
~RuntimeDyld();
+ /// TODO
+ Error precalculateMemorySize(const object::ObjectFile &Obj,
+ uint64_t &CodeSize, Align &CodeAlign, uint64_t &RODataSize, Align
+ &RODataAlign, uint64_t &RWDataSize, Align &RWDataAlign);
+
/// Add the referenced object file to the list of objects to be loaded and
/// relocated.
std::unique_ptr<LoadedObjectInfo> loadObject(const object::ObjectFile &O);
diff --git a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp
index a9aaff42433f655..83cafa2d4e7a768 100644
--- a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp
+++ b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp
@@ -541,6 +541,8 @@ Error RuntimeDyldImpl::computeTotalAllocSize(
std::vector<uint64_t> ROSectionSizes;
std::vector<uint64_t> RWSectionSizes;
+ Arch = (Triple::ArchType)Obj.getArch();
+
// Collect sizes of all sections to be loaded;
// also determine the max alignment of all sections
for (section_iterator SI = Obj.section_begin(), SE = Obj.section_end();
@@ -1343,6 +1345,28 @@ createRuntimeDyldMachO(
return Dyld;
}
+Error RuntimeDyld::precalculateMemorySize(
+ const ObjectFile &Obj, uint64_t &CodeSize, Align &CodeAlign,
+ uint64_t &RODataSize, Align &RODataAlign, uint64_t &RWDataSize,
+ Align &RWDataAlign) {
+ if (!Dyld) {
+ if (!Obj.isELF())
+ report_fatal_error("Incompatible object format!");
+
+ Dyld =
+ createRuntimeDyldELF(static_cast<Triple::ArchType>(Obj.getArch()),
+ MemMgr, Resolver, ProcessAllSections,
+ std::move(NotifyStubEmitted));
+ }
+ if (!Dyld->isCompatibleFile(Obj))
+ report_fatal_error("Incompatible object format!");
+
+ auto Err = Dyld->computeTotalAllocSize(Obj, CodeSize, CodeAlign, RODataSize,
+ RODataAlign, RWDataSize, RWDataAlign);
+ return Err;
+}
+
+
std::unique_ptr<RuntimeDyld::LoadedObjectInfo>
RuntimeDyld::loadObject(const ObjectFile &Obj) {
if (!Dyld) {
diff --git a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h
index 73e2b365f109a99..75caf019551019a 100644
--- a/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h
+++ b/llvm/lib/ExecutionEngine/RuntimeDyld/RuntimeDyldImpl.h
@@ -421,13 +421,6 @@ class RuntimeDyldImpl {
/// Resolve relocations to external symbols.
Error resolveExternalSymbols();
- // Compute an upper bound of the memory that is required to load all
- // sections
- Error computeTotalAllocSize(const ObjectFile &Obj, uint64_t &CodeSize,
- Align &CodeAlign, uint64_t &RODataSize,
- Align &RODataAlign, uint64_t &RWDataSize,
- Align &RWDataAlign);
-
// Compute GOT size
unsigned computeGOTSize(const ObjectFile &Obj);
@@ -435,6 +428,9 @@ class RuntimeDyldImpl {
unsigned computeSectionStubBufSize(const ObjectFile &Obj,
const SectionRef &Section);
+
+
+
// Implementation of the generic part of the loadObject algorithm.
Expected<ObjSectionToIDMap> loadObjectImpl(const object::ObjectFile &Obj);
@@ -464,6 +460,14 @@ class RuntimeDyldImpl {
virtual ~RuntimeDyldImpl();
+// Compute an upper bound of the memory that is required to load all
+ // sections
+ Error computeTotalAllocSize(const ObjectFile &Obj, uint64_t &CodeSize,
+ Align &CodeAlign, uint64_t &RODataSize,
+ Align &RODataAlign, uint64_t &RWDataSize,
+ Align &RWDataAlign);
+
+
void setProcessAllSections(bool ProcessAllSections) {
this->ProcessAllSections = ProcessAllSections;
}
diff --git a/llvm/tools/llvm-rtdyld/llvm-rtdyld.cpp b/llvm/tools/llvm-rtdyld/llvm-rtdyld.cpp
index 107b555a99faa40..a89c9ce4863cf33 100644
--- a/llvm/tools/llvm-rtdyld/llvm-rtdyld.cpp
+++ b/llvm/tools/llvm-rtdyld/llvm-rtdyld.cpp
@@ -14,6 +14,7 @@
#include "llvm/DebugInfo/DIContext.h"
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
#include "llvm/ExecutionEngine/RTDyldMemoryManager.h"
+
#include "llvm/ExecutionEngine/RuntimeDyld.h"
#include "llvm/ExecutionEngine/RuntimeDyldChecker.h"
#include "llvm/MC/MCAsmInfo.h"
@@ -549,20 +550,30 @@ static int executeInput() {
// Instantiate a dynamic linker.
TrivialMemoryManager MemMgr;
- doPreallocation(MemMgr);
RuntimeDyld Dyld(MemMgr, MemMgr);
+ uint64_t TotalCodeSize = 0;
+ uint64_t TotalRODataSize = 0;
+ uint64_t TotalRWDataSize = 0;
+
+
// If we don't have any input files, read from stdin.
- if (!InputFileList.size())
+ if (!InputFileList.size()) {
InputFileList.push_back("-");
+ }
+
{
TimeRegion TR(Timers ? &Timers->LoadObjectsTimer : nullptr);
+ // First, iterate over the list of objects to calculate the object sizes
+ // before we actually allocate the memory.
for (auto &File : InputFileList) {
// Load the input memory buffer.
ErrorOr<std::unique_ptr<MemoryBuffer>> InputBuffer =
MemoryBuffer::getFileOrSTDIN(File);
+
if (std::error_code EC = InputBuffer.getError())
ErrorAndExit("unable to read input: '" + EC.message() + "'");
+
Expected<std::unique_ptr<ObjectFile>> MaybeObj(
ObjectFile::createObjectFile((*InputBuffer)->getMemBufferRef()));
@@ -576,11 +587,34 @@ static int executeInput() {
ObjectFile &Obj = **MaybeObj;
- // Load the object file
- Dyld.loadObject(Obj);
- if (Dyld.hasError()) {
+ uint64_t CodeSize, RODataSize, RWDataSize;
+ Align CodeAlign, RODataAlign, RWDataAlign;
+
+ Error Err = Dyld.precalculateMemorySize(Obj, CodeSize, CodeAlign,
+ RODataSize, RODataAlign, RWDataSize, RWDataAlign);
+ if (Err)
+ ErrorAndExit("Can't compute total size");
+
+ TotalCodeSize += CodeSize;
+ TotalRODataSize += RODataSize;
+ TotalRWDataSize += RWDataSize;
+ }
+
+ if (!PreallocMemory)
+ PreallocMemory = TotalCodeSize + TotalRODataSize + TotalRWDataSize;
+ doPreallocation(MemMgr);
+
+ // Now, iterate over the list again to actually load the objects.
+ for (auto &File : InputFileList) {
+ ErrorOr<std::unique_ptr<MemoryBuffer>> InputBuffer =
+ MemoryBuffer::getFileOrSTDIN(File);
+ Expected<std::unique_ptr<ObjectFile>> MaybeObj(
+ ObjectFile::createObjectFile((*InputBuffer)->getMemBufferRef()));
+ assert(MaybeObj);
+
+ Dyld.loadObject(**MaybeObj);
+ if (Dyld.hasError())
ErrorAndExit(Dyld.getErrorString());
- }
}
}
More information about the llvm-commits
mailing list