[llvm] Reduce llvm-gsymutil memory usage (PR #91023)
Kevin Frei via llvm-commits
llvm-commits at lists.llvm.org
Fri Jun 7 14:13:04 PDT 2024
https://github.com/kevinfrei updated https://github.com/llvm/llvm-project/pull/91023
>From 95162dd73cf230886d0614008b6483d812474739 Mon Sep 17 00:00:00 2001
From: Kevin Frei <freik at meta.com>
Date: Tue, 30 Apr 2024 09:15:12 -0700
Subject: [PATCH 01/10] Release line tables when we're done with them
---
llvm/lib/DebugInfo/GSYM/DwarfTransformer.cpp | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/llvm/lib/DebugInfo/GSYM/DwarfTransformer.cpp b/llvm/lib/DebugInfo/GSYM/DwarfTransformer.cpp
index 601686fdd3dd5..9376515e3712f 100644
--- a/llvm/lib/DebugInfo/GSYM/DwarfTransformer.cpp
+++ b/llvm/lib/DebugInfo/GSYM/DwarfTransformer.cpp
@@ -587,6 +587,8 @@ Error DwarfTransformer::convert(uint32_t NumThreads, OutputAggregator &Out) {
DWARFDie Die = getDie(*CU);
CUInfo CUI(DICtx, dyn_cast<DWARFCompileUnit>(CU.get()));
handleDie(Out, CUI, Die);
+ // Release the line table, once we're done.
+ DICtx.clearLineTableForUnit(CU.get());
}
} else {
// LLVM Dwarf parser is not thread-safe and we need to parse all DWARF up
@@ -612,7 +614,7 @@ Error DwarfTransformer::convert(uint32_t NumThreads, OutputAggregator &Out) {
DWARFDie Die = getDie(*CU);
if (Die) {
CUInfo CUI(DICtx, dyn_cast<DWARFCompileUnit>(CU.get()));
- pool.async([this, CUI, &LogMutex, &Out, Die]() mutable {
+ pool.async([this, CUI, &CU, &LogMutex, &Out, Die]() mutable {
std::string storage;
raw_string_ostream StrStream(storage);
OutputAggregator ThreadOut(Out.GetOS() ? &StrStream : nullptr);
@@ -623,6 +625,9 @@ Error DwarfTransformer::convert(uint32_t NumThreads, OutputAggregator &Out) {
StrStream.flush();
Out << storage;
}
+ // Release the line table, once we're done.
+ DICtx.clearLineTableForUnit(CU.get());
+
Out.Merge(ThreadOut);
});
}
>From f206066ff61b1387703c4a0993ac5acee93dad6c Mon Sep 17 00:00:00 2001
From: Kevin Frei <freik at meta.com>
Date: Tue, 30 Apr 2024 14:54:53 -0700
Subject: [PATCH 02/10] Finished without crashing
---
llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h | 2 ++
llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp | 5 +++++
llvm/lib/DebugInfo/GSYM/DwarfTransformer.cpp | 5 ++++-
3 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h
index 80c27aea89312..52a8730a46c2c 100644
--- a/llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h
+++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h
@@ -566,6 +566,8 @@ class DWARFUnit {
Error tryExtractDIEsIfNeeded(bool CUDieOnly);
+ void freeDIEs();
+
private:
/// Size in bytes of the .debug_info data associated with this compile unit.
size_t getDebugInfoSize() const {
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp b/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp
index bdd04b00f557b..4786208c79fc2 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp
@@ -495,6 +495,11 @@ void DWARFUnit::extractDIEsIfNeeded(bool CUDieOnly) {
Context.getRecoverableErrorHandler()(std::move(e));
}
+void DWARFUnit::freeDIEs() {
+ if (DieArray.capacity())
+ std::vector<DWARFDebugInfoEntry>().swap(DieArray);
+}
+
Error DWARFUnit::tryExtractDIEsIfNeeded(bool CUDieOnly) {
if ((CUDieOnly && !DieArray.empty()) ||
DieArray.size() > 1)
diff --git a/llvm/lib/DebugInfo/GSYM/DwarfTransformer.cpp b/llvm/lib/DebugInfo/GSYM/DwarfTransformer.cpp
index 9376515e3712f..7204cefae1b84 100644
--- a/llvm/lib/DebugInfo/GSYM/DwarfTransformer.cpp
+++ b/llvm/lib/DebugInfo/GSYM/DwarfTransformer.cpp
@@ -625,8 +625,9 @@ Error DwarfTransformer::convert(uint32_t NumThreads, OutputAggregator &Out) {
StrStream.flush();
Out << storage;
}
- // Release the line table, once we're done.
+ // Release the line table and DIEs once we're done.
DICtx.clearLineTableForUnit(CU.get());
+ CU->freeDIEs();
Out.Merge(ThreadOut);
});
@@ -634,6 +635,8 @@ Error DwarfTransformer::convert(uint32_t NumThreads, OutputAggregator &Out) {
}
pool.wait();
}
+ for (const auto &CU : DICtx.compile_units())
+ CU->freeDIEs();
size_t FunctionsAddedCount = Gsym.getNumFunctionInfos() - NumBefore;
Out << "Loaded " << FunctionsAddedCount << " functions from DWARF.\n";
return Error::success();
>From af35ef0fa4d138ec007c402d89761d57edd1ee48 Mon Sep 17 00:00:00 2001
From: Kevin Frei <freik at meta.com>
Date: Wed, 1 May 2024 14:58:26 -0700
Subject: [PATCH 03/10] Added locking
---
llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h | 10 +++--
llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp | 41 ++++++++++++++-----
llvm/lib/DebugInfo/GSYM/DwarfTransformer.cpp | 13 +++---
3 files changed, 44 insertions(+), 20 deletions(-)
diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h
index 52a8730a46c2c..9614aab8bb9b5 100644
--- a/llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h
+++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h
@@ -22,6 +22,7 @@
#include "llvm/DebugInfo/DWARF/DWARFLocationExpression.h"
#include "llvm/DebugInfo/DWARF/DWARFUnitIndex.h"
#include "llvm/Support/DataExtractor.h"
+#include "llvm/Support/RWMutex.h"
#include <cassert>
#include <cstddef>
#include <cstdint>
@@ -257,6 +258,9 @@ class DWARFUnit {
std::shared_ptr<DWARFUnit> DWO;
+ mutable llvm::sys::RWMutex m_cu_die_array_mutex;
+ mutable llvm::sys::RWMutex m_all_die_array_mutex;
+
protected:
friend dwarf_linker::parallel::CompileUnit;
@@ -566,7 +570,8 @@ class DWARFUnit {
Error tryExtractDIEsIfNeeded(bool CUDieOnly);
- void freeDIEs();
+ /// clearDIEs - Clear parsed DIEs to keep memory usage low.
+ void clearDIEs(bool KeepCUDie);
private:
/// Size in bytes of the .debug_info data associated with this compile unit.
@@ -583,9 +588,6 @@ class DWARFUnit {
void extractDIEsToVector(bool AppendCUDie, bool AppendNonCUDIEs,
std::vector<DWARFDebugInfoEntry> &DIEs) const;
- /// clearDIEs - Clear parsed DIEs to keep memory usage low.
- void clearDIEs(bool KeepCUDie);
-
/// parseDWO - Parses .dwo file for current compile unit. Returns true if
/// it was actually constructed.
/// The \p AlternativeLocation specifies an alternative location to get
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp b/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp
index 4786208c79fc2..b3fdb4e017803 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp
@@ -495,26 +495,43 @@ void DWARFUnit::extractDIEsIfNeeded(bool CUDieOnly) {
Context.getRecoverableErrorHandler()(std::move(e));
}
-void DWARFUnit::freeDIEs() {
- if (DieArray.capacity())
- std::vector<DWARFDebugInfoEntry>().swap(DieArray);
-}
-
Error DWARFUnit::tryExtractDIEsIfNeeded(bool CUDieOnly) {
- if ((CUDieOnly && !DieArray.empty()) ||
- DieArray.size() > 1)
- return Error::success(); // Already parsed.
-
- bool HasCUDie = !DieArray.empty();
- extractDIEsToVector(!HasCUDie, !CUDieOnly, DieArray);
+ // read-lock:
+ {
+ llvm::sys::ScopedReader Lock(m_cu_die_array_mutex);
+ if ((CUDieOnly && !DieArray.empty()) ||
+ DieArray.size() > 1)
+ return Error::success(); // Already parsed.
+ }
+ bool HasCUDie = false;
+ // write-lock:
+ {
+ llvm::sys::ScopedWriter Lock(m_cu_die_array_mutex);
+ if ((CUDieOnly && !DieArray.empty()) ||
+ DieArray.size() > 1)
+ return Error::success(); // Already parsed.
+ HasCUDie = !DieArray.empty();
+ extractDIEsToVector(!HasCUDie, !CUDieOnly, DieArray);
+ }
+ // read-lock:
+{
+ llvm::sys::ScopedReader Lock(m_all_die_array_mutex);
if (DieArray.empty())
return Error::success();
// If CU DIE was just parsed, copy several attribute values from it.
if (HasCUDie)
return Error::success();
+}
+ // write-lock:
+llvm::sys::ScopedWriter Lock(m_all_die_array_mutex);
+ if (DieArray.empty())
+ return Error::success();
+ // If CU DIE was just parsed, copy several attribute values from it.
+ if (HasCUDie)
+ return Error::success();
DWARFDie UnitDie(this, &DieArray[0]);
if (std::optional<uint64_t> DWOId =
toUnsigned(UnitDie.find(DW_AT_GNU_dwo_id)))
@@ -663,6 +680,8 @@ void DWARFUnit::clearDIEs(bool KeepCUDie) {
// It depends on the implementation whether the request is fulfilled.
// Create a new vector with a small capacity and assign it to the DieArray to
// have previous contents freed.
+ llvm::sys::ScopedWriter CULock(m_cu_die_array_mutex);
+ llvm::sys::ScopedWriter AllLock(m_all_die_array_mutex);
DieArray = (KeepCUDie && !DieArray.empty())
? std::vector<DWARFDebugInfoEntry>({DieArray[0]})
: std::vector<DWARFDebugInfoEntry>();
diff --git a/llvm/lib/DebugInfo/GSYM/DwarfTransformer.cpp b/llvm/lib/DebugInfo/GSYM/DwarfTransformer.cpp
index 7204cefae1b84..bd4c24f3ee28e 100644
--- a/llvm/lib/DebugInfo/GSYM/DwarfTransformer.cpp
+++ b/llvm/lib/DebugInfo/GSYM/DwarfTransformer.cpp
@@ -619,24 +619,27 @@ Error DwarfTransformer::convert(uint32_t NumThreads, OutputAggregator &Out) {
raw_string_ostream StrStream(storage);
OutputAggregator ThreadOut(Out.GetOS() ? &StrStream : nullptr);
handleDie(ThreadOut, CUI, Die);
+ // Release the line table once we're done.
+ DICtx.clearLineTableForUnit(CU.get());
+ // Free any DIEs that were allocated by the DWARF parser.
+ // If/when they're needed by other CU's, they'll be recreated.
+ CU->clearDIEs(false);
// Print ThreadLogStorage lines into an actual stream under a lock
std::lock_guard<std::mutex> guard(LogMutex);
if (Out.GetOS()) {
StrStream.flush();
Out << storage;
}
- // Release the line table and DIEs once we're done.
- DICtx.clearLineTableForUnit(CU.get());
- CU->freeDIEs();
-
Out.Merge(ThreadOut);
+
});
}
}
pool.wait();
}
+ // Now get rid of all the DIEs that may have been recreated
for (const auto &CU : DICtx.compile_units())
- CU->freeDIEs();
+ CU->clearDIEs(false);
size_t FunctionsAddedCount = Gsym.getNumFunctionInfos() - NumBefore;
Out << "Loaded " << FunctionsAddedCount << " functions from DWARF.\n";
return Error::success();
>From 4adc2cc808bbda42cd8ad00d9cd95c13ec0b129b Mon Sep 17 00:00:00 2001
From: Kevin Frei <freik at meta.com>
Date: Fri, 3 May 2024 09:26:24 -0700
Subject: [PATCH 04/10] Code formatting
---
llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp | 28 ++++++++------------
llvm/lib/DebugInfo/GSYM/DwarfTransformer.cpp | 4 ++-
2 files changed, 14 insertions(+), 18 deletions(-)
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp b/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp
index b3fdb4e017803..cc79d9ec7130c 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp
@@ -496,42 +496,36 @@ void DWARFUnit::extractDIEsIfNeeded(bool CUDieOnly) {
}
Error DWARFUnit::tryExtractDIEsIfNeeded(bool CUDieOnly) {
- // read-lock:
{
llvm::sys::ScopedReader Lock(m_cu_die_array_mutex);
- if ((CUDieOnly && !DieArray.empty()) ||
- DieArray.size() > 1)
+ if ((CUDieOnly && !DieArray.empty()) || DieArray.size() > 1)
return Error::success(); // Already parsed.
}
bool HasCUDie = false;
- // write-lock:
{
llvm::sys::ScopedWriter Lock(m_cu_die_array_mutex);
- if ((CUDieOnly && !DieArray.empty()) ||
- DieArray.size() > 1)
+ if ((CUDieOnly && !DieArray.empty()) || DieArray.size() > 1)
return Error::success(); // Already parsed.
HasCUDie = !DieArray.empty();
extractDIEsToVector(!HasCUDie, !CUDieOnly, DieArray);
}
+ {
+ llvm::sys::ScopedReader Lock(m_all_die_array_mutex);
+ if (DieArray.empty())
+ return Error::success();
- // read-lock:
-{
- llvm::sys::ScopedReader Lock(m_all_die_array_mutex);
+ // If CU DIE was just parsed, copy several attribute values from it.
+ if (HasCUDie)
+ return Error::success();
+ }
+ llvm::sys::ScopedWriter Lock(m_all_die_array_mutex);
if (DieArray.empty())
return Error::success();
// If CU DIE was just parsed, copy several attribute values from it.
if (HasCUDie)
return Error::success();
-}
- // write-lock:
-llvm::sys::ScopedWriter Lock(m_all_die_array_mutex);
- if (DieArray.empty())
- return Error::success();
- // If CU DIE was just parsed, copy several attribute values from it.
- if (HasCUDie)
- return Error::success();
DWARFDie UnitDie(this, &DieArray[0]);
if (std::optional<uint64_t> DWOId =
toUnsigned(UnitDie.find(DW_AT_GNU_dwo_id)))
diff --git a/llvm/lib/DebugInfo/GSYM/DwarfTransformer.cpp b/llvm/lib/DebugInfo/GSYM/DwarfTransformer.cpp
index bd4c24f3ee28e..4a1ed91a7244f 100644
--- a/llvm/lib/DebugInfo/GSYM/DwarfTransformer.cpp
+++ b/llvm/lib/DebugInfo/GSYM/DwarfTransformer.cpp
@@ -589,6 +589,9 @@ Error DwarfTransformer::convert(uint32_t NumThreads, OutputAggregator &Out) {
handleDie(Out, CUI, Die);
// Release the line table, once we're done.
DICtx.clearLineTableForUnit(CU.get());
+ // Free any DIEs that were allocated by the DWARF parser.
+ // If/when they're needed by other CU's, they'll be recreated.
+ CU->clearDIEs(false);
}
} else {
// LLVM Dwarf parser is not thread-safe and we need to parse all DWARF up
@@ -631,7 +634,6 @@ Error DwarfTransformer::convert(uint32_t NumThreads, OutputAggregator &Out) {
Out << storage;
}
Out.Merge(ThreadOut);
-
});
}
}
>From bfbde2694d3a32025eaef60154406697d786e598 Mon Sep 17 00:00:00 2001
From: Kevin Frei <freik at meta.com>
Date: Mon, 13 May 2024 11:53:08 -0700
Subject: [PATCH 05/10] Updated from code review feedback
---
llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h | 4 ++--
llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp | 15 +++++++--------
llvm/lib/DebugInfo/GSYM/DwarfTransformer.cpp | 6 +++---
3 files changed, 12 insertions(+), 13 deletions(-)
diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h
index 9614aab8bb9b5..4e0601d1e042e 100644
--- a/llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h
+++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h
@@ -258,8 +258,8 @@ class DWARFUnit {
std::shared_ptr<DWARFUnit> DWO;
- mutable llvm::sys::RWMutex m_cu_die_array_mutex;
- mutable llvm::sys::RWMutex m_all_die_array_mutex;
+ mutable llvm::sys::RWMutex CUDieArrayMutex;
+ mutable llvm::sys::RWMutex AllDieArrayMutex;
protected:
friend dwarf_linker::parallel::CompileUnit;
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp b/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp
index cc79d9ec7130c..bd9c49bcd6b90 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp
@@ -497,35 +497,34 @@ void DWARFUnit::extractDIEsIfNeeded(bool CUDieOnly) {
Error DWARFUnit::tryExtractDIEsIfNeeded(bool CUDieOnly) {
{
- llvm::sys::ScopedReader Lock(m_cu_die_array_mutex);
+ llvm::sys::ScopedReader Lock(CUDieArrayMutex);
if ((CUDieOnly && !DieArray.empty()) || DieArray.size() > 1)
return Error::success(); // Already parsed.
}
bool HasCUDie = false;
{
- llvm::sys::ScopedWriter Lock(m_cu_die_array_mutex);
+ llvm::sys::ScopedWriter Lock(CUDieArrayMutex);
if ((CUDieOnly && !DieArray.empty()) || DieArray.size() > 1)
return Error::success(); // Already parsed.
HasCUDie = !DieArray.empty();
extractDIEsToVector(!HasCUDie, !CUDieOnly, DieArray);
}
{
- llvm::sys::ScopedReader Lock(m_all_die_array_mutex);
+ llvm::sys::ScopedReader Lock(AllDieArrayMutex);
if (DieArray.empty())
return Error::success();
- // If CU DIE was just parsed, copy several attribute values from it.
if (HasCUDie)
return Error::success();
}
- llvm::sys::ScopedWriter Lock(m_all_die_array_mutex);
+ llvm::sys::ScopedWriter Lock(AllDieArrayMutex);
if (DieArray.empty())
return Error::success();
- // If CU DIE was just parsed, copy several attribute values from it.
if (HasCUDie)
return Error::success();
+ // If CU DIE was just parsed, copy several attribute values from it.
DWARFDie UnitDie(this, &DieArray[0]);
if (std::optional<uint64_t> DWOId =
toUnsigned(UnitDie.find(DW_AT_GNU_dwo_id)))
@@ -674,8 +673,8 @@ void DWARFUnit::clearDIEs(bool KeepCUDie) {
// It depends on the implementation whether the request is fulfilled.
// Create a new vector with a small capacity and assign it to the DieArray to
// have previous contents freed.
- llvm::sys::ScopedWriter CULock(m_cu_die_array_mutex);
- llvm::sys::ScopedWriter AllLock(m_all_die_array_mutex);
+ llvm::sys::ScopedWriter CULock(CUDieArrayMutex);
+ llvm::sys::ScopedWriter AllLock(AllDieArrayMutex);
DieArray = (KeepCUDie && !DieArray.empty())
? std::vector<DWARFDebugInfoEntry>({DieArray[0]})
: std::vector<DWARFDebugInfoEntry>();
diff --git a/llvm/lib/DebugInfo/GSYM/DwarfTransformer.cpp b/llvm/lib/DebugInfo/GSYM/DwarfTransformer.cpp
index 4a1ed91a7244f..e1b30648b6a77 100644
--- a/llvm/lib/DebugInfo/GSYM/DwarfTransformer.cpp
+++ b/llvm/lib/DebugInfo/GSYM/DwarfTransformer.cpp
@@ -591,7 +591,7 @@ Error DwarfTransformer::convert(uint32_t NumThreads, OutputAggregator &Out) {
DICtx.clearLineTableForUnit(CU.get());
// Free any DIEs that were allocated by the DWARF parser.
// If/when they're needed by other CU's, they'll be recreated.
- CU->clearDIEs(false);
+ CU->clearDIEs(/*KeepCUDie=*/false);
}
} else {
// LLVM Dwarf parser is not thread-safe and we need to parse all DWARF up
@@ -626,7 +626,7 @@ Error DwarfTransformer::convert(uint32_t NumThreads, OutputAggregator &Out) {
DICtx.clearLineTableForUnit(CU.get());
// Free any DIEs that were allocated by the DWARF parser.
// If/when they're needed by other CU's, they'll be recreated.
- CU->clearDIEs(false);
+ CU->clearDIEs(/*KeepCUDie=*/false);
// Print ThreadLogStorage lines into an actual stream under a lock
std::lock_guard<std::mutex> guard(LogMutex);
if (Out.GetOS()) {
@@ -641,7 +641,7 @@ Error DwarfTransformer::convert(uint32_t NumThreads, OutputAggregator &Out) {
}
// Now get rid of all the DIEs that may have been recreated
for (const auto &CU : DICtx.compile_units())
- CU->clearDIEs(false);
+ CU->clearDIEs(/*KeepCUDie=*/false);
size_t FunctionsAddedCount = Gsym.getNumFunctionInfos() - NumBefore;
Out << "Loaded " << FunctionsAddedCount << " functions from DWARF.\n";
return Error::success();
>From 02301bc2b07421c67bb62a029a509957735d5979 Mon Sep 17 00:00:00 2001
From: Kevin Frei <freik at meta.com>
Date: Tue, 21 May 2024 08:40:17 -0700
Subject: [PATCH 06/10] Added the top level lock to prevent clearDies from
causing problems
---
llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h | 1 +
llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp | 2 ++
2 files changed, 3 insertions(+)
diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h
index 4e0601d1e042e..5315d10891ed1 100644
--- a/llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h
+++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h
@@ -258,6 +258,7 @@ class DWARFUnit {
std::shared_ptr<DWARFUnit> DWO;
+ mutable llvm::sys::RWMutex CUDieFreeMutex;
mutable llvm::sys::RWMutex CUDieArrayMutex;
mutable llvm::sys::RWMutex AllDieArrayMutex;
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp b/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp
index bd9c49bcd6b90..1c4866cbbb41d 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp
@@ -496,6 +496,7 @@ void DWARFUnit::extractDIEsIfNeeded(bool CUDieOnly) {
}
Error DWARFUnit::tryExtractDIEsIfNeeded(bool CUDieOnly) {
+ llvm::sys::ScopedReader FreeLock(CUDieFreeMutex);
{
llvm::sys::ScopedReader Lock(CUDieArrayMutex);
if ((CUDieOnly && !DieArray.empty()) || DieArray.size() > 1)
@@ -673,6 +674,7 @@ void DWARFUnit::clearDIEs(bool KeepCUDie) {
// It depends on the implementation whether the request is fulfilled.
// Create a new vector with a small capacity and assign it to the DieArray to
// have previous contents freed.
+ llvm::sys::ScopedWriter FreeLock(CUDieFreeMutex);
llvm::sys::ScopedWriter CULock(CUDieArrayMutex);
llvm::sys::ScopedWriter AllLock(AllDieArrayMutex);
DieArray = (KeepCUDie && !DieArray.empty())
>From f4a456d297a92b0c6bfefa5b8ffbf038f6003404 Mon Sep 17 00:00:00 2001
From: Kevin Frei <freik at meta.com>
Date: Tue, 21 May 2024 08:40:17 -0700
Subject: [PATCH 07/10] Using a helper to make the double checked locking more
legible
Summary:
Test Plan:
Reviewers:
Subscribers:
Tasks:
Tags:
Differential Revision: https://phabricator.intern.facebook.com/D57863981
---
llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h | 4 +
llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp | 78 +++++++++++++------
2 files changed, 58 insertions(+), 24 deletions(-)
diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h
index 5315d10891ed1..c83bcf96f295c 100644
--- a/llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h
+++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h
@@ -585,6 +585,10 @@ class DWARFUnit {
/// hasn't already been done
void extractDIEsIfNeeded(bool CUDieOnly);
+ /// extractAllDIEsHelper - helper to be invoked *only* from inside
+ /// tryExtractDIEsIfNeeded, which holds correct locks.
+ Error extractAllDIEsHelper();
+
/// extractDIEsToVector - Appends all parsed DIEs to a vector.
void extractDIEsToVector(bool AppendCUDie, bool AppendNonCUDIEs,
std::vector<DWARFDebugInfoEntry> &DIEs) const;
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp b/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp
index 1c4866cbbb41d..7fc1e3233df04 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp
@@ -495,36 +495,66 @@ void DWARFUnit::extractDIEsIfNeeded(bool CUDieOnly) {
Context.getRecoverableErrorHandler()(std::move(e));
}
-Error DWARFUnit::tryExtractDIEsIfNeeded(bool CUDieOnly) {
- llvm::sys::ScopedReader FreeLock(CUDieFreeMutex);
+static bool DoubleCheckedRWLocker(llvm::sys::RWMutex &Mutex,
+ const std::function<bool()> &reader,
+ const std::function<void()> &writer) {
{
- llvm::sys::ScopedReader Lock(CUDieArrayMutex);
- if ((CUDieOnly && !DieArray.empty()) || DieArray.size() > 1)
- return Error::success(); // Already parsed.
+ llvm::sys::ScopedReader Lock(Mutex);
+ if (reader())
+ return true;
}
+ llvm::sys::ScopedWriter Lock(Mutex);
+ if (reader())
+ return true;
+ // If we get here, then the reader function returned false. This means that
+ // no one else is currently writing to this data structure and it's safe for
+ // us to write to it now. We can use a scoped writer lock since there are no
+ // other readers or writers at this point.
+ writer();
+ return false;
+}
+
+Error DWARFUnit::tryExtractDIEsIfNeeded(bool CUDieOnly) {
+ llvm::sys::ScopedReader FreeLock(CUDieFreeMutex);
bool HasCUDie = false;
- {
- llvm::sys::ScopedWriter Lock(CUDieArrayMutex);
- if ((CUDieOnly && !DieArray.empty()) || DieArray.size() > 1)
- return Error::success(); // Already parsed.
- HasCUDie = !DieArray.empty();
- extractDIEsToVector(!HasCUDie, !CUDieOnly, DieArray);
- }
- {
- llvm::sys::ScopedReader Lock(AllDieArrayMutex);
- if (DieArray.empty())
- return Error::success();
+ Error Result = Error::success();
- if (HasCUDie)
- return Error::success();
- }
- llvm::sys::ScopedWriter Lock(AllDieArrayMutex);
- if (DieArray.empty())
- return Error::success();
+ // Lambda to check if the CU DIE has been extracted already.
+ auto CheckIfCUDieExtracted = [this, CUDieOnly]() {
+ // True means already parsed.
+ return ((CUDieOnly && !DieArray.empty()) || DieArray.size() > 1);
+ };
- if (HasCUDie)
- return Error::success();
+ // Lambda to extract the CU DIE.
+ auto ExtractCUDie = [this, CUDieOnly, &HasCUDie]() {
+ HasCUDie = !DieArray.empty();
+ extractDIEsToVector(!HasCUDie, !CUDieOnly, DieArray);
+ };
+
+ // Safely check if the CU DIE has been extract already. If not, then extract
+ // it.
+ if (DoubleCheckedRWLocker(CUDieArrayMutex, CheckIfCUDieExtracted,
+ ExtractCUDie))
+ return Result;
+
+ // Lambda to check if all DIEs have been extract already.
+ auto CheckIfAllDiesExtracted = [this, HasCUDie]() {
+ return (DieArray.empty() || HasCUDie);
+ };
+
+ // Lambda to extract all the DIEs using the helper function
+ auto ExtractAllDies = [this, &Result]() { Result = extractAllDIEsHelper(); };
+
+ // Safely check if *all* the DIEs have been parsed already. If not, then parse
+ // them.
+ DoubleCheckedRWLocker(AllDieArrayMutex, CheckIfAllDiesExtracted,
+ ExtractAllDies);
+ return Result;
+}
+// This should only be used from the tryExtractDIEsIfNeeded function:
+// it must already have all the proper locks acquired.
+Error DWARFUnit::extractAllDIEsHelper() {
// If CU DIE was just parsed, copy several attribute values from it.
DWARFDie UnitDie(this, &DieArray[0]);
if (std::optional<uint64_t> DWOId =
>From 371c7c815edb4792838f633252920bbb7272741c Mon Sep 17 00:00:00 2001
From: Kevin Frei <freik at meta.com>
Date: Thu, 6 Jun 2024 10:55:00 -0700
Subject: [PATCH 08/10] Fixed the error handling issues; fully tested
---
llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp b/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp
index 7fc1e3233df04..e71b794d92c27 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp
@@ -543,7 +543,13 @@ Error DWARFUnit::tryExtractDIEsIfNeeded(bool CUDieOnly) {
};
// Lambda to extract all the DIEs using the helper function
- auto ExtractAllDies = [this, &Result]() { Result = extractAllDIEsHelper(); };
+ auto ExtractAllDies = [this, &Result]() {
+ if (Error E = extractAllDIEsHelper()) {
+ // Consume the success placeholder and save the actual error
+ consumeError(std::move(Result));
+ Result = std::move(E);
+ }
+ };
// Safely check if *all* the DIEs have been parsed already. If not, then parse
// them.
>From 58c452020fa2c5e559280329e1f52ad1b47edeaa Mon Sep 17 00:00:00 2001
From: Kevin Frei <freik at meta.com>
Date: Thu, 6 Jun 2024 16:51:24 -0700
Subject: [PATCH 09/10] Refactored to make the overall code read more cleanly
---
llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h | 10 ++-
llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp | 73 ++++++++++---------
2 files changed, 46 insertions(+), 37 deletions(-)
diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h
index c83bcf96f295c..27bd2ea0f6827 100644
--- a/llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h
+++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFUnit.h
@@ -585,8 +585,16 @@ class DWARFUnit {
/// hasn't already been done
void extractDIEsIfNeeded(bool CUDieOnly);
+ /// extracCUDieIfNeeded - Parse CU DIE if it hasn't already been done.
+ /// Only to be used from extractDIEsIfNeeded, which holds the correct locks.
+ bool extractCUDieIfNeeded(bool CUDieOnly, bool &HasCUDie);
+
+ /// extractAllDIEsIfNeeded - Parses non-CU DIE's for a given CU if needed.
+ /// Only to be used from extractDIEsIfNeeded, which holds the correct locks.
+ Error extractAllDIEsIfNeeded(bool HasCUDie);
+
/// extractAllDIEsHelper - helper to be invoked *only* from inside
- /// tryExtractDIEsIfNeeded, which holds correct locks.
+ /// tryExtractDIEsIfNeeded, which holds the correct locks.
Error extractAllDIEsHelper();
/// extractDIEsToVector - Appends all parsed DIEs to a vector.
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp b/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp
index e71b794d92c27..a7ead8d072fe0 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp
@@ -514,50 +514,51 @@ static bool DoubleCheckedRWLocker(llvm::sys::RWMutex &Mutex,
return false;
}
-Error DWARFUnit::tryExtractDIEsIfNeeded(bool CUDieOnly) {
- llvm::sys::ScopedReader FreeLock(CUDieFreeMutex);
- bool HasCUDie = false;
- Error Result = Error::success();
-
- // Lambda to check if the CU DIE has been extracted already.
- auto CheckIfCUDieExtracted = [this, CUDieOnly]() {
- // True means already parsed.
- return ((CUDieOnly && !DieArray.empty()) || DieArray.size() > 1);
- };
-
- // Lambda to extract the CU DIE.
- auto ExtractCUDie = [this, CUDieOnly, &HasCUDie]() {
- HasCUDie = !DieArray.empty();
- extractDIEsToVector(!HasCUDie, !CUDieOnly, DieArray);
- };
-
+bool DWARFUnit::extractCUDieIfNeeded(bool CUDieOnly, bool &HasCUDie) {
// Safely check if the CU DIE has been extract already. If not, then extract
// it.
- if (DoubleCheckedRWLocker(CUDieArrayMutex, CheckIfCUDieExtracted,
- ExtractCUDie))
- return Result;
-
- // Lambda to check if all DIEs have been extract already.
- auto CheckIfAllDiesExtracted = [this, HasCUDie]() {
- return (DieArray.empty() || HasCUDie);
- };
-
- // Lambda to extract all the DIEs using the helper function
- auto ExtractAllDies = [this, &Result]() {
- if (Error E = extractAllDIEsHelper()) {
- // Consume the success placeholder and save the actual error
- consumeError(std::move(Result));
- Result = std::move(E);
- }
- };
+ return DoubleCheckedRWLocker(
+ CUDieArrayMutex,
+ // Calculate if the CU DIE has been extracted already.
+ [&]() {
+ return ((CUDieOnly && !DieArray.empty()) || DieArray.size() > 1);
+ },
+ // Lambda to extract the CU DIE.
+ [&]() {
+ HasCUDie = !DieArray.empty();
+ extractDIEsToVector(!HasCUDie, !CUDieOnly, DieArray);
+ });
+}
+Error DWARFUnit::extractAllDIEsIfNeeded(bool HasCUDie) {
// Safely check if *all* the DIEs have been parsed already. If not, then parse
// them.
- DoubleCheckedRWLocker(AllDieArrayMutex, CheckIfAllDiesExtracted,
- ExtractAllDies);
+ Error Result = Error::success();
+ DoubleCheckedRWLocker(
+ AllDieArrayMutex,
+ // Lambda to check if all DIEs have been extracted already.
+ [=]() { return (DieArray.empty() || HasCUDie); },
+ // Lambda to extract all the DIEs using the helper function
+ [&]() {
+ if (Error E = extractAllDIEsHelper()) {
+ // Consume the success placeholder and save the actual error
+ consumeError(std::move(Result));
+ Result = std::move(E);
+ }
+ });
return Result;
}
+Error DWARFUnit::tryExtractDIEsIfNeeded(bool CUDieOnly) {
+ // Take the CUDieFreeMutex lock to prevent the CU DIE from being freed
+ // after it was just parsed, but before the rest of the DIES are parsed.
+ llvm::sys::ScopedReader FreeLock(CUDieFreeMutex);
+ bool HasCUDie = false;
+ if (extractCUDieIfNeeded(CUDieOnly, HasCUDie))
+ return Error::success();
+ return extractAllDIEsIfNeeded(HasCUDie);
+}
+
// This should only be used from the tryExtractDIEsIfNeeded function:
// it must already have all the proper locks acquired.
Error DWARFUnit::extractAllDIEsHelper() {
>From a5b0eafd0eec1a4e32da481568a2323d994cb35b Mon Sep 17 00:00:00 2001
From: Kevin Frei <freik at meta.com>
Date: Fri, 7 Jun 2024 14:12:49 -0700
Subject: [PATCH 10/10] Removed the acquisition of extra, unecessary locks
---
llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp | 2 --
1 file changed, 2 deletions(-)
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp b/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp
index a7ead8d072fe0..be2bbf19de67a 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp
@@ -712,8 +712,6 @@ void DWARFUnit::clearDIEs(bool KeepCUDie) {
// Create a new vector with a small capacity and assign it to the DieArray to
// have previous contents freed.
llvm::sys::ScopedWriter FreeLock(CUDieFreeMutex);
- llvm::sys::ScopedWriter CULock(CUDieArrayMutex);
- llvm::sys::ScopedWriter AllLock(AllDieArrayMutex);
DieArray = (KeepCUDie && !DieArray.empty())
? std::vector<DWARFDebugInfoEntry>({DieArray[0]})
: std::vector<DWARFDebugInfoEntry>();
More information about the llvm-commits
mailing list