Skip to content

Commit dcfa2ab

Browse files
committed
[BOLT][DWARF] Change to process and write out TUs first then CUs in batches
To reduce memory footprint changed so that we process and write out TUs first, reset DIEBuilder and process CUs. CUs are processed in buckets. First bucket contains all the CUs with cross CU references. Rest processd one at a time. clang-17 build in debug mode, by clang-17. before 8:25.81 real, 834.37 user, 86.03 sys, 0 amem, 79525064 mmem 8:02.20 real, 820.46 user, 81.81 sys, 0 amem, 79501616 mmem 7:52.69 real, 802.01 user, 83.99 sys, 0 amem, 79534392 mmem after 7:49.35 real, 822.04 user, 66.19 sys, 0 amem, 34934260 mmem 7:42.16 real, 825.46 user, 63.52 sys, 0 amem, 34951660 mmem 7:46.71 real, 821.11 user, 63.14 sys, 0 amem, 34981164 mmem Reviewed By: maksfb Differential Revision: https://reviews.llvm.org/D151909
1 parent 8362418 commit dcfa2ab

17 files changed

+1075
-454
lines changed

bolt/include/bolt/Core/DIEBuilder.h

Lines changed: 78 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ class DIEBuilder {
6060
std::unordered_map<uint64_t, uint32_t> DIEIDMap;
6161
};
6262

63+
enum class ProcessingType { DWARF4TUs, DWARF5TUs, CUs };
64+
6365
private:
6466
/// Contains information so that we we can update references in locexpr after
6567
/// we calculated all the final DIE offsets.
@@ -83,41 +85,54 @@ class DIEBuilder {
8385
DWARFAbbreviationDeclaration::AttributeSpec AttrSpec;
8486
};
8587

86-
/// A map of Units to Unit Index.
87-
std::unordered_map<uint64_t, uint32_t> UnitIDMap;
88-
/// A map of Type Units to Type DIEs.
89-
std::unordered_map<DWARFUnit *, DIE *> TypeDIEMap;
90-
std::vector<DWARFUnit *> DUList;
91-
std::vector<DWARFUnitInfo> CloneUnitCtxMap;
92-
std::vector<std::pair<DIEInfo *, AddrReferenceInfo>> AddrReferences;
88+
struct State {
89+
/// A map of Units to Unit Index.
90+
std::unordered_map<uint64_t, uint32_t> UnitIDMap;
91+
/// A map of Type Units to Type DIEs.
92+
std::unordered_map<DWARFUnit *, DIE *> TypeDIEMap;
93+
std::list<DWARFUnit *> DUList;
94+
std::vector<DWARFUnitInfo> CloneUnitCtxMap;
95+
std::vector<std::pair<DIEInfo *, AddrReferenceInfo>> AddrReferences;
96+
std::vector<DWARFUnit *> DWARF4TUVector;
97+
std::vector<DWARFUnit *> DWARF5TUVector;
98+
std::vector<DWARFUnit *> DWARFCUVector;
99+
std::vector<LocWithReference> LocWithReferencesToProcess;
100+
BumpPtrAllocator DIEAlloc;
101+
ProcessingType Type;
102+
};
103+
104+
std::unique_ptr<State> BuilderState;
93105
FoldingSet<DIEAbbrev> AbbreviationsSet;
94106
std::vector<std::unique_ptr<DIEAbbrev>> Abbreviations;
95-
std::vector<DWARFUnit *> DWARF4TUVector;
96-
std::vector<LocWithReference> LocWithReferencesToProcess;
97-
BumpPtrAllocator DIEAlloc;
107+
DWARFContext *DwarfContext{nullptr};
108+
bool IsDWO{false};
109+
uint64_t UnitSize{0};
110+
llvm::DenseSet<uint64_t> AllProcessed;
98111

112+
/// Returns current state of the DIEBuilder
113+
State &getState() { return *BuilderState.get(); }
99114
/// Resolve the reference in DIE, if target is not loaded into IR,
100115
/// pre-allocate it. \p RefCU will be updated to the Unit specific by \p
101116
/// RefValue.
102-
DWARFDie resolveDIEReference(const DWARFFormValue &RefValue,
103-
DWARFUnit *&RefCU,
104-
DWARFDebugInfoEntry &DwarfDebugInfoEntry,
105-
const std::vector<DWARFUnit *> &DUOffsetList);
117+
DWARFDie resolveDIEReference(
118+
const DWARFFormValue &RefValue,
119+
const DWARFAbbreviationDeclaration::AttributeSpec AttrSpec,
120+
DWARFUnit *&RefCU, DWARFDebugInfoEntry &DwarfDebugInfoEntry);
106121

107122
/// Resolve the reference in DIE, if target is not loaded into IR,
108123
/// pre-allocate it. \p RefCU will be updated to the Unit specific by \p
109124
/// RefValue.
110-
DWARFDie resolveDIEReference(const uint64_t ReffOffset, DWARFUnit *&RefCU,
111-
DWARFDebugInfoEntry &DwarfDebugInfoEntry,
112-
const std::vector<DWARFUnit *> &DUOffsetList);
125+
DWARFDie resolveDIEReference(
126+
const DWARFAbbreviationDeclaration::AttributeSpec AttrSpec,
127+
const uint64_t ReffOffset, DWARFUnit *&RefCU,
128+
DWARFDebugInfoEntry &DwarfDebugInfoEntry);
113129

114130
/// Clone one attribute according to the format. \return the size of this
115131
/// attribute.
116132
void
117133
cloneAttribute(DIE &Die, const DWARFDie &InputDIE, DWARFUnit &U,
118134
const DWARFFormValue &Val,
119-
const DWARFAbbreviationDeclaration::AttributeSpec AttrSpec,
120-
const std::vector<DWARFUnit *> &DUOffsetList);
135+
const DWARFAbbreviationDeclaration::AttributeSpec AttrSpec);
121136

122137
/// Clone an attribute in string format.
123138
void cloneStringAttribute(
@@ -129,7 +144,7 @@ class DIEBuilder {
129144
void cloneDieReferenceAttribute(
130145
DIE &Die, const DWARFUnit &U, const DWARFDie &InputDIE,
131146
const DWARFAbbreviationDeclaration::AttributeSpec AttrSpec,
132-
const DWARFFormValue &Val, const std::vector<DWARFUnit *> &DUOffsetList);
147+
const DWARFFormValue &Val);
133148

134149
/// Clone an attribute in block format.
135150
void cloneBlockAttribute(
@@ -175,23 +190,23 @@ class DIEBuilder {
175190
/// Update the Offset and Size of DIE.
176191
uint32_t computeDIEOffset(const DWARFUnit &CU, DIE &Die, uint32_t &CurOffset);
177192

178-
void registerUnit(DWARFUnit &DU);
193+
void registerUnit(DWARFUnit &DU, bool NeedSort);
179194

180195
/// \return the unique ID of \p U if it exists.
181196
std::optional<uint32_t> getUnitId(const DWARFUnit &DU);
182197

183198
DWARFUnitInfo &getUnitInfo(uint32_t UnitId) {
184-
return CloneUnitCtxMap[UnitId];
199+
return getState().CloneUnitCtxMap[UnitId];
185200
}
186201

187202
DIEInfo &getDIEInfo(uint32_t UnitId, uint32_t DIEId) {
188-
if (CloneUnitCtxMap[UnitId].DieInfoVector.size() > DIEId)
189-
return *CloneUnitCtxMap[UnitId].DieInfoVector[DIEId].get();
203+
if (getState().CloneUnitCtxMap[UnitId].DieInfoVector.size() > DIEId)
204+
return *getState().CloneUnitCtxMap[UnitId].DieInfoVector[DIEId].get();
190205

191206
errs() << "BOLT-WARNING: [internal-dwarf-error]: The DIE is not allocated "
192207
"before looking up, some"
193208
<< "unexpected corner cases happened.\n";
194-
return *CloneUnitCtxMap[UnitId].DieInfoVector.front().get();
209+
return *getState().CloneUnitCtxMap[UnitId].DieInfoVector.front().get();
195210
}
196211

197212
std::optional<uint32_t> getAllocDIEId(const DWARFUnit &DU,
@@ -223,16 +238,28 @@ class DIEBuilder {
223238

224239
/// Construct IR for \p DU. \p DUOffsetList specific the Unit in current
225240
/// Section.
226-
void constructFromUnit(DWARFUnit &DU, std::vector<DWARFUnit *> &DUOffsetList);
241+
void constructFromUnit(DWARFUnit &DU);
227242

228243
/// Construct a DIE for \p DDie in \p U. \p DUOffsetList specific the Unit in
229244
/// current Section.
230-
DIE *constructDIEFast(DWARFDie &DDie, DWARFUnit &U, uint32_t UnitId,
231-
std::vector<DWARFUnit *> &DUOffsetList);
245+
DIE *constructDIEFast(DWARFDie &DDie, DWARFUnit &U, uint32_t UnitId);
232246

233247
public:
234248
DIEBuilder(DWARFContext *DwarfContext, bool IsDWO = false);
235249

250+
/// Returns enum to what we are currently processing.
251+
ProcessingType getCurrentProcessingState() { return getState().Type; }
252+
253+
/// Constructs IR for Type Units.
254+
void buildTypeUnits(const bool Init = true);
255+
/// Constructs IR for all the CUs.
256+
void buildCompileUnits(const bool Init = true);
257+
/// Constructs IR for CUs in a vector.
258+
void buildCompileUnits(const std::vector<DWARFUnit *> &CUs);
259+
/// Preventing implicit conversions.
260+
template <class T> void buildCompileUnits(T) = delete;
261+
void buildBoth();
262+
236263
/// Returns DWARFUnitInfo for DWARFUnit
237264
DWARFUnitInfo &getUnitInfoByDwarfUnit(const DWARFUnit &DwarfUnit) {
238265
std::optional<uint32_t> UnitId = getUnitId(DwarfUnit);
@@ -247,16 +274,26 @@ class DIEBuilder {
247274
return Abbreviations;
248275
}
249276
DIE *getTypeDIE(DWARFUnit &DU) {
250-
if (TypeDIEMap.count(&DU))
251-
return TypeDIEMap[&DU];
277+
if (getState().TypeDIEMap.count(&DU))
278+
return getState().TypeDIEMap[&DU];
252279

253280
errs() << "BOLT-ERROR: unable to find TypeUnit for Type Unit at offset 0x"
254281
<< DU.getOffset() << "\n";
255282
return nullptr;
256283
}
257284

258-
std::vector<DWARFUnit *> getDWARF4TUVector() { return DWARF4TUVector; }
259-
bool isEmpty() { return CloneUnitCtxMap.empty(); }
285+
std::vector<DWARFUnit *> &getDWARF4TUVector() {
286+
return getState().DWARF4TUVector;
287+
}
288+
std::vector<DWARFUnit *> &getDWARF5TUVector() {
289+
return getState().DWARF5TUVector;
290+
}
291+
std::vector<DWARFUnit *> &getDWARFCUVector() {
292+
return getState().DWARFCUVector;
293+
}
294+
/// Returns list of CUs for which IR was build.
295+
std::list<DWARFUnit *> &getProcessedCUs() { return getState().DUList; }
296+
bool isEmpty() { return getState().CloneUnitCtxMap.empty(); }
260297

261298
DIE *getUnitDIEbyUnit(const DWARFUnit &DU) {
262299
const DWARFUnitInfo &U = getUnitInfoByDwarfUnit(DU);
@@ -272,37 +309,40 @@ class DIEBuilder {
272309
void finish();
273310

274311
// Interface to edit DIE
275-
template <class T> T *allocateDIEValue() { return new (DIEAlloc) T; }
312+
template <class T> T *allocateDIEValue() {
313+
return new (getState().DIEAlloc) T;
314+
}
276315

277316
DIEValueList::value_iterator addValue(DIEValueList *Die, const DIEValue &V) {
278-
return Die->addValue(DIEAlloc, V);
317+
return Die->addValue(getState().DIEAlloc, V);
279318
}
280319

281320
template <class T>
282321
DIEValueList::value_iterator addValue(DIEValueList *Die,
283322
dwarf::Attribute Attribute,
284323
dwarf::Form Form, T &&Value) {
285-
return Die->addValue(DIEAlloc, Attribute, Form, std::forward<T>(Value));
324+
return Die->addValue(getState().DIEAlloc, Attribute, Form,
325+
std::forward<T>(Value));
286326
}
287327

288328
template <class T>
289329
bool replaceValue(DIEValueList *Die, dwarf::Attribute Attribute,
290330
dwarf::Form Form, T &&NewValue) {
291-
return Die->replaceValue(DIEAlloc, Attribute, Form,
331+
return Die->replaceValue(getState().DIEAlloc, Attribute, Form,
292332
std::forward<T>(NewValue));
293333
}
294334

295335
template <class T>
296336
bool replaceValue(DIEValueList *Die, dwarf::Attribute Attribute,
297337
dwarf::Attribute NewAttribute, dwarf::Form Form,
298338
T &&NewValue) {
299-
return Die->replaceValue(DIEAlloc, Attribute, NewAttribute, Form,
339+
return Die->replaceValue(getState().DIEAlloc, Attribute, NewAttribute, Form,
300340
std::forward<T>(NewValue));
301341
}
302342

303343
bool replaceValue(DIEValueList *Die, dwarf::Attribute Attribute,
304344
dwarf::Form Form, DIEValue &NewValue) {
305-
return Die->replaceValue(DIEAlloc, Attribute, Form, NewValue);
345+
return Die->replaceValue(getState().DIEAlloc, Attribute, Form, NewValue);
306346
}
307347

308348
template <class T>

bolt/include/bolt/Core/DebugData.h

Lines changed: 14 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "llvm/Support/raw_ostream.h"
2323
#include <cstdint>
2424
#include <map>
25+
#include <memory>
2526
#include <mutex>
2627
#include <string>
2728
#include <unordered_map>
@@ -315,17 +316,12 @@ class DebugAddrWriter {
315316
/// Adds {\p Address, \p Index} to \p CU.
316317
void addIndexAddress(uint64_t Address, uint32_t Index, DWARFUnit &CU);
317318

318-
/// Creates consolidated .debug_addr section, and builds DWOID to offset map.
319-
virtual AddressSectionBuffer finalize();
319+
/// Write out entries in to .debug_addr section for CUs.
320+
virtual void update(DIEBuilder &DIEBlder, DWARFUnit &CUs);
320321

321-
/// Given DWARFUnit \p Unit returns offset of this CU in to .debug_addr
322-
/// section.
323-
virtual uint64_t getOffset(DWARFUnit &Unit);
324-
325-
/// Returns True if CU exists in the DebugAddrWriter.
326-
bool doesCUExist(DWARFUnit &Unit) {
327-
return DWOIdToOffsetMap.count(getCUID(Unit)) > 0;
328-
}
322+
/// Return buffer with all the entries in .debug_addr already writen out using
323+
/// update(...).
324+
virtual AddressSectionBuffer &finalize() { return *Buffer; }
329325

330326
/// Returns False if .debug_addr section was created..
331327
bool isInitialized() const { return !AddressMaps.empty(); }
@@ -387,22 +383,21 @@ class DebugAddrWriter {
387383
BinaryContext *BC;
388384
/// Maps DWOID to AddressForDWOCU.
389385
std::unordered_map<uint64_t, AddressForDWOCU> AddressMaps;
390-
/// Maps DWOID to offset within .debug_addr section.
391-
std::unordered_map<uint64_t, uint64_t> DWOIdToOffsetMap;
392386
/// Mutex used for parallel processing of debug info.
393387
std::mutex WriterMutex;
388+
std::unique_ptr<AddressSectionBuffer> Buffer;
389+
std::unique_ptr<raw_svector_ostream> AddressStream;
390+
/// Used to track sections that were not modified so that they can be re-used.
391+
DenseMap<uint64_t, uint64_t> UnmodifiedAddressOffsets;
394392
};
395393

396394
class DebugAddrWriterDwarf5 : public DebugAddrWriter {
397395
public:
398396
DebugAddrWriterDwarf5() = delete;
399397
DebugAddrWriterDwarf5(BinaryContext *BC) : DebugAddrWriter(BC) {}
400398

401-
/// Creates consolidated .debug_addr section, and builds DWOID to offset map.
402-
AddressSectionBuffer finalize() override;
403-
/// Given DWARFUnit \p Unit returns offset of this CU in to .debug_addr
404-
/// section.
405-
uint64_t getOffset(DWARFUnit &Unit) override;
399+
/// Write out entries in to .debug_addr section for CUs.
400+
virtual void update(DIEBuilder &DIEBlder, DWARFUnit &CUs) override;
406401

407402
protected:
408403
/// Given DWARFUnit \p Unit returns either DWO ID or it's offset within
@@ -433,7 +428,7 @@ class DebugStrOffsetsWriter {
433428
void updateAddressMap(uint32_t Index, uint32_t Address);
434429

435430
/// Writes out current sections entry into .debug_str_offsets.
436-
void finalizeSection(DWARFUnit &Unit);
431+
void finalizeSection(DWARFUnit &Unit, DIEBuilder &DIEBldr);
437432

438433
/// Returns False if no strings were added to .debug_str.
439434
bool isFinalized() const { return !StrOffsetsBuffer->empty(); }
@@ -447,7 +442,7 @@ class DebugStrOffsetsWriter {
447442
std::unique_ptr<DebugStrOffsetsBufferVector> StrOffsetsBuffer;
448443
std::unique_ptr<raw_svector_ostream> StrOffsetsStream;
449444
std::map<uint32_t, uint32_t> IndexToAddressMap;
450-
DenseSet<uint64_t> ProcessedBaseOffsets;
445+
std::unordered_map<uint64_t, uint64_t> ProcessedBaseOffsets;
451446
// Section size not including header.
452447
uint32_t CurrentSectionSize{0};
453448
bool StrOffsetSectionWasModified = false;

bolt/include/bolt/Rewrite/DWARFRewriter.h

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,9 @@ class DWARFRewriter {
105105
/// DWARFLegacy is all DWARF versions before DWARF 5.
106106
enum class DWARFVersion { DWARFLegacy, DWARF5 };
107107

108+
/// Used to track last CU offset for GDB Index.
109+
uint32_t CUOffset{0};
110+
108111
/// Update debug info for all DIEs in \p Unit.
109112
void updateUnitDebugInfo(DWARFUnit &Unit, DIEBuilder &DIEBldr,
110113
DebugLocWriter &DebugLocWriter,
@@ -128,8 +131,17 @@ class DWARFRewriter {
128131
std::unique_ptr<DebugBufferVector>
129132
makeFinalLocListsSection(DWARFVersion Version);
130133

134+
/// Finalize type sections in the main binary.
135+
CUOffsetMap finalizeTypeSections(DIEBuilder &DIEBlder, DIEStreamer &Streamer);
136+
137+
/// Process and write out CUs that are passsed in.
138+
void finalizeCompileUnits(DIEBuilder &DIEBlder, DIEStreamer &Streamer,
139+
CUOffsetMap &CUMap,
140+
const std::list<DWARFUnit *> &CUs);
141+
131142
/// Finalize debug sections in the main binary.
132-
CUOffsetMap finalizeDebugSections(DIEBuilder &DIEBlder);
143+
void finalizeDebugSections(DIEBuilder &DIEBlder, DIEStreamer &Streamer,
144+
raw_svector_ostream &ObjOS, CUOffsetMap &CUMap);
133145

134146
/// Patches the binary for DWARF address ranges (e.g. in functions and lexical
135147
/// blocks) to be updated.

0 commit comments

Comments
 (0)