Skip to content

Commit 31142fa

Browse files
committed
compress DebugObject to save memory
Account for debug info memory as well, since this info is usually about 10x the size of the data that was being tracked, although this compression appears to reduce that by at least half.
1 parent 2c4776d commit 31142fa

File tree

5 files changed

+59
-22
lines changed

5 files changed

+59
-22
lines changed

src/debug-registry.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,8 @@ class JITDebugInfoRegistry
100100
private:
101101

102102
struct LazyObjectInfo {
103-
std::unique_ptr<MemoryBuffer> data;
103+
SmallVector<uint8_t, 0> data;
104+
size_t uncompressedsize;
104105
std::unique_ptr<const llvm::object::ObjectFile> object;
105106
std::unique_ptr<llvm::DIContext> context;
106107
LazyObjectInfo() = delete;

src/debuginfo.cpp

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <llvm/DebugInfo/DWARF/DWARFContext.h>
88
#include <llvm/Object/SymbolSize.h>
99
#include <llvm/Support/MemoryBuffer.h>
10+
#include <llvm/Support/MemoryBufferRef.h>
1011
#include <llvm/IR/Function.h>
1112
#include <llvm/ADT/StringRef.h>
1213
#include <llvm/ADT/StringMap.h>
@@ -335,8 +336,12 @@ void JITDebugInfoRegistry::registerJITObject(const object::ObjectFile &Object,
335336
#endif // defined(_OS_X86_64_)
336337
#endif // defined(_OS_WINDOWS_)
337338

338-
auto ObjectCopy = new LazyObjectInfo{MemoryBuffer::getMemBufferCopy(Object.getData())}; // intentionally leaked so that we don't need to ref-count it
339+
SmallVector<uint8_t, 0> packed;
340+
compression::zlib::compress(ArrayRef<uint8_t>((uint8_t*)Object.getData().data(), Object.getData().size()), packed, compression::zlib::DefaultCompression);
341+
jl_jit_add_bytes(packed.size());
342+
auto ObjectCopy = new LazyObjectInfo{packed, Object.getData().size()}; // intentionally leaked so that we don't need to ref-count it, intentionally copied so that we exact-size the allocation (since no shrink_to_fit function)
339343
auto symbols = object::computeSymbolSizes(Object);
344+
bool hassection = false;
340345
for (const auto &sym_size : symbols) {
341346
const object::SymbolRef &sym_iter = sym_size.first;
342347
object::SymbolRef::Type SymbolType = cantFail(sym_iter.getType());
@@ -385,6 +390,7 @@ void JITDebugInfoRegistry::registerJITObject(const object::ObjectFile &Object,
385390
jl_profile_atomic([&]() JL_NOTSAFEPOINT {
386391
if (mi)
387392
linfomap[Addr] = std::make_pair(Size, mi);
393+
hassection = true;
388394
objectmap.insert(std::pair{SectionLoadAddr, SectionInfo{
389395
ObjectCopy,
390396
(size_t)SectionSize,
@@ -393,6 +399,8 @@ void JITDebugInfoRegistry::registerJITObject(const object::ObjectFile &Object,
393399
}});
394400
});
395401
}
402+
if (!hassection) // clang-sa demands that we do this to fool cplusplus.NewDeleteLeaks
403+
delete ObjectCopy;
396404
}
397405

398406
void jl_register_jit_object(const object::ObjectFile &Object,
@@ -1211,13 +1219,32 @@ int jl_DI_for_fptr(uint64_t fptr, uint64_t *symsize, int64_t *slide,
12111219
if (fit != objmap.end() && fptr < fit->first + fit->second.SectionSize) {
12121220
*slide = fit->second.slide;
12131221
auto lazyobject = fit->second.object;
1214-
if (!lazyobject->object)
1215-
lazyobject->object = cantFail(object::ObjectFile::createObjectFile(lazyobject->data->getMemBufferRef()));
1216-
*Section = *std::next(lazyobject->object->section_begin(), fit->second.SectionIndex);
1217-
if (context) {
1218-
if (lazyobject->context == nullptr)
1219-
lazyobject->context = DWARFContext::create(*lazyobject->object);
1220-
*context = lazyobject->context.get();
1222+
if (!lazyobject->object && !lazyobject->data.empty()) {
1223+
if (lazyobject->uncompressedsize) {
1224+
SmallVector<uint8_t, 0> unpacked;
1225+
Error E = compression::zlib::decompress(lazyobject->data, unpacked, lazyobject->uncompressedsize);
1226+
if (E)
1227+
lazyobject->data.clear();
1228+
else
1229+
lazyobject->data = std::move(unpacked);
1230+
jl_jit_add_bytes(lazyobject->data.size() - lazyobject->uncompressedsize);
1231+
lazyobject->uncompressedsize = 0;
1232+
}
1233+
if (!lazyobject->data.empty()) {
1234+
auto obj = object::ObjectFile::createObjectFile(MemoryBufferRef(StringRef((const char*)lazyobject->data.data(), lazyobject->data.size()), "jit.o"));
1235+
if (obj)
1236+
lazyobject->object = std::move(*obj);
1237+
else
1238+
lazyobject->data.clear();
1239+
}
1240+
}
1241+
if (lazyobject->object) {
1242+
*Section = *std::next(lazyobject->object->section_begin(), fit->second.SectionIndex);
1243+
if (context) {
1244+
if (lazyobject->context == nullptr)
1245+
lazyobject->context = DWARFContext::create(*lazyobject->object);
1246+
*context = lazyobject->context.get();
1247+
}
12211248
}
12221249
found = 1;
12231250
}

src/debuginfo.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// This file is a part of Julia. License is MIT: https://julialang.org/license
22

33
// Declarations for debuginfo.cpp
4+
void jl_jit_add_bytes(size_t bytes) JL_NOTSAFEPOINT;
45

56
int jl_DI_for_fptr(uint64_t fptr, uint64_t *symsize, int64_t *slide,
67
llvm::object::SectionRef *Section, llvm::DIContext **context) JL_NOTSAFEPOINT;

src/jitlayers.cpp

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -798,12 +798,12 @@ class JLDebuginfoPlugin : public ObjectLinkingLayer::Plugin {
798798

799799
class JLMemoryUsagePlugin : public ObjectLinkingLayer::Plugin {
800800
private:
801-
std::atomic<size_t> &total_size;
801+
std::atomic<size_t> &jit_bytes_size;
802802

803803
public:
804804

805-
JLMemoryUsagePlugin(std::atomic<size_t> &total_size)
806-
: total_size(total_size) {}
805+
JLMemoryUsagePlugin(std::atomic<size_t> &jit_bytes_size)
806+
: jit_bytes_size(jit_bytes_size) {}
807807

808808
Error notifyFailed(orc::MaterializationResponsibility &MR) override {
809809
return Error::success();
@@ -852,7 +852,7 @@ class JLMemoryUsagePlugin : public ObjectLinkingLayer::Plugin {
852852
}
853853
(void) code_size;
854854
(void) data_size;
855-
this->total_size.fetch_add(graph_size, std::memory_order_relaxed);
855+
this->jit_bytes_size.fetch_add(graph_size, std::memory_order_relaxed);
856856
jl_timing_counter_inc(JL_TIMING_COUNTER_JITSize, graph_size);
857857
jl_timing_counter_inc(JL_TIMING_COUNTER_JITCodeSize, code_size);
858858
jl_timing_counter_inc(JL_TIMING_COUNTER_JITDataSize, data_size);
@@ -1598,7 +1598,7 @@ JuliaOJIT::JuliaOJIT()
15981598
ES, std::move(ehRegistrar)));
15991599

16001600
ObjectLayer.addPlugin(std::make_unique<JLDebuginfoPlugin>());
1601-
ObjectLayer.addPlugin(std::make_unique<JLMemoryUsagePlugin>(total_size));
1601+
ObjectLayer.addPlugin(std::make_unique<JLMemoryUsagePlugin>(jit_bytes_size));
16021602
#else
16031603
ObjectLayer.setNotifyLoaded(
16041604
[this](orc::MaterializationResponsibility &MR,
@@ -2010,19 +2010,20 @@ std::string JuliaOJIT::getMangledName(const GlobalValue *GV)
20102010
return getMangledName(GV->getName());
20112011
}
20122012

2013-
#ifdef JL_USE_JITLINK
20142013
size_t JuliaOJIT::getTotalBytes() const
20152014
{
2016-
return total_size.load(std::memory_order_relaxed);
2015+
auto bytes = jit_bytes_size.load(std::memory_order_relaxed);
2016+
#ifndef JL_USE_JITLINK
2017+
size_t getRTDyldMemoryManagerTotalBytes(RTDyldMemoryManager *mm) JL_NOTSAFEPOINT;
2018+
bytes += getRTDyldMemoryManagerTotalBytes(MemMgr.get());
2019+
#endif
2020+
return bytes;
20172021
}
2018-
#else
2019-
size_t getRTDyldMemoryManagerTotalBytes(RTDyldMemoryManager *mm) JL_NOTSAFEPOINT;
20202022

2021-
size_t JuliaOJIT::getTotalBytes() const
2023+
void JuliaOJIT::addBytes(size_t bytes)
20222024
{
2023-
return getRTDyldMemoryManagerTotalBytes(MemMgr.get());
2025+
jit_bytes_size.fetch_add(bytes, std::memory_order_relaxed);
20242026
}
2025-
#endif
20262027

20272028
void JuliaOJIT::printTimers()
20282029
{
@@ -2307,3 +2308,9 @@ size_t jl_jit_total_bytes_impl(void)
23072308
{
23082309
return jl_ExecutionEngine->getTotalBytes();
23092310
}
2311+
2312+
// API for adding bytes to record being owned by the JIT
2313+
void jl_jit_add_bytes(size_t bytes)
2314+
{
2315+
jl_ExecutionEngine->addBytes(bytes);
2316+
}

src/jitlayers.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -559,6 +559,7 @@ class JuliaOJIT {
559559
TargetIRAnalysis getTargetIRAnalysis() const JL_NOTSAFEPOINT;
560560

561561
size_t getTotalBytes() const JL_NOTSAFEPOINT;
562+
void addBytes(size_t bytes) JL_NOTSAFEPOINT;
562563
void printTimers() JL_NOTSAFEPOINT;
563564

564565
jl_locked_stream &get_dump_emitted_mi_name_stream() JL_NOTSAFEPOINT {
@@ -605,10 +606,10 @@ class JuliaOJIT {
605606

606607
ResourcePool<orc::ThreadSafeContext, 0, std::queue<orc::ThreadSafeContext>> ContextPool;
607608

609+
std::atomic<size_t> jit_bytes_size{0};
608610
#ifndef JL_USE_JITLINK
609611
const std::shared_ptr<RTDyldMemoryManager> MemMgr;
610612
#else
611-
std::atomic<size_t> total_size{0};
612613
const std::unique_ptr<jitlink::JITLinkMemoryManager> MemMgr;
613614
#endif
614615
ObjLayerT ObjectLayer;

0 commit comments

Comments
 (0)