Skip to content

Commit bdc128b

Browse files
committed
Resolve performance issue by templating MarkLive on --why-live
1 parent 0f1b043 commit bdc128b

File tree

1 file changed

+43
-34
lines changed

1 file changed

+43
-34
lines changed

lld/ELF/MarkLive.cpp

Lines changed: 43 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -48,18 +48,18 @@ namespace {
4848
// Something that can be the most proximate reason that something else is alive.
4949
typedef std::variant<InputSectionBase *, Symbol *> LiveReason;
5050

51-
template <class ELFT> class MarkLive {
51+
template <class ELFT, bool TrackWhyLive> class MarkLive {
5252
public:
5353
MarkLive(Ctx &ctx, unsigned partition) : ctx(ctx), partition(partition) {}
5454

5555
void run();
5656
void moveToMain();
57+
void printWhyLive(Symbol *s) const;
5758

5859
private:
5960
void enqueue(InputSectionBase *sec, uint64_t offset = 0,
6061
Symbol *sym = nullptr,
6162
std::optional<LiveReason> reason = std::nullopt);
62-
void printWhyLive(Symbol *s) const;
6363
void markSymbol(Symbol *sym);
6464
void mark();
6565

@@ -108,16 +108,16 @@ static uint64_t getAddend(Ctx &, InputSectionBase &sec,
108108
return rel.r_addend;
109109
}
110110

111-
template <class ELFT>
111+
template <class ELFT, bool TrackWhyLive>
112112
template <class RelTy>
113-
void MarkLive<ELFT>::resolveReloc(InputSectionBase &sec, RelTy &rel,
114-
bool fromFDE) {
113+
void MarkLive<ELFT, TrackWhyLive>::resolveReloc(InputSectionBase &sec,
114+
RelTy &rel, bool fromFDE) {
115115
// If a symbol is referenced in a live section, it is used.
116116
Symbol &sym = sec.file->getRelocTargetSym(rel);
117117
sym.used = true;
118118

119-
LiveReason reason;
120-
if (!ctx.arg.whyLive.empty()) {
119+
std::optional<LiveReason> reason;
120+
if (TrackWhyLive) {
121121
Defined *reasonSym = sec.getEnclosingSymbol(rel.r_offset);
122122
reason = reasonSym ? LiveReason(reasonSym) : LiveReason(&sec);
123123
}
@@ -142,7 +142,7 @@ void MarkLive<ELFT>::resolveReloc(InputSectionBase &sec, RelTy &rel,
142142
if (!(fromFDE && ((relSec->flags & (SHF_EXECINSTR | SHF_LINK_ORDER)) ||
143143
relSec->nextInSectionGroup))) {
144144
Symbol *canonicalSym = d;
145-
if (!ctx.arg.whyLive.empty() && d->isSection()) {
145+
if (TrackWhyLive && d->isSection()) {
146146
if (Symbol *s = relSec->getEnclosingSymbol(offset))
147147
canonicalSym = s;
148148
else
@@ -156,8 +156,8 @@ void MarkLive<ELFT>::resolveReloc(InputSectionBase &sec, RelTy &rel,
156156
if (auto *ss = dyn_cast<SharedSymbol>(&sym)) {
157157
if (!ss->isWeak()) {
158158
cast<SharedFile>(ss->file)->isNeeded = true;
159-
if (!ctx.arg.whyLive.empty())
160-
whyLive.try_emplace(&sym, reason);
159+
if (TrackWhyLive)
160+
whyLive.try_emplace(&sym, *reason);
161161
}
162162
}
163163

@@ -179,10 +179,10 @@ void MarkLive<ELFT>::resolveReloc(InputSectionBase &sec, RelTy &rel,
179179
// A possible improvement would be to fully process .eh_frame in the middle of
180180
// the gc pass. With that we would be able to also gc some sections holding
181181
// LSDAs and personality functions if we found that they were unused.
182-
template <class ELFT>
182+
template <class ELFT, bool TrackWhyLive>
183183
template <class RelTy>
184-
void MarkLive<ELFT>::scanEhFrameSection(EhInputSection &eh,
185-
ArrayRef<RelTy> rels) {
184+
void MarkLive<ELFT, TrackWhyLive>::scanEhFrameSection(EhInputSection &eh,
185+
ArrayRef<RelTy> rels) {
186186
for (const EhSectionPiece &cie : eh.cies)
187187
if (cie.firstRelocation != unsigned(-1))
188188
resolveReloc(eh, rels[cie.firstRelocation], false);
@@ -219,9 +219,10 @@ static bool isReserved(InputSectionBase *sec) {
219219
}
220220
}
221221

222-
template <class ELFT>
223-
void MarkLive<ELFT>::enqueue(InputSectionBase *sec, uint64_t offset,
224-
Symbol *sym, std::optional<LiveReason> reason) {
222+
template <class ELFT, bool TrackWhyLive>
223+
void MarkLive<ELFT, TrackWhyLive>::enqueue(InputSectionBase *sec,
224+
uint64_t offset, Symbol *sym,
225+
std::optional<LiveReason> reason) {
225226
// Usually, a whole section is marked as live or dead, but in mergeable
226227
// (splittable) sections, each piece of data has independent liveness bit.
227228
// So we explicitly tell it which offset is in use.
@@ -235,7 +236,7 @@ void MarkLive<ELFT>::enqueue(InputSectionBase *sec, uint64_t offset,
235236
return;
236237
sec->partition = sec->partition ? 1 : partition;
237238

238-
if (!ctx.arg.whyLive.empty() && reason) {
239+
if (TrackWhyLive && reason) {
239240
if (sym) {
240241
// If a specific symbol is referenced, that makes it alive. It may in turn
241242
// make its section alive.
@@ -253,7 +254,8 @@ void MarkLive<ELFT>::enqueue(InputSectionBase *sec, uint64_t offset,
253254
}
254255

255256
// Print the stack of reasons that the given symbol is live.
256-
template <class ELFT> void MarkLive<ELFT>::printWhyLive(Symbol *s) const {
257+
template <class ELFT, bool TrackWhyLive>
258+
void MarkLive<ELFT, TrackWhyLive>::printWhyLive(Symbol *s) const {
257259
// Skip dead symbols. A symbol is dead if it belongs to a dead section.
258260
if (auto *d = dyn_cast<Defined>(s)) {
259261
auto *reason = dyn_cast_or_null<InputSectionBase>(d->section);
@@ -296,7 +298,8 @@ template <class ELFT> void MarkLive<ELFT>::printWhyLive(Symbol *s) const {
296298
}
297299
}
298300

299-
template <class ELFT> void MarkLive<ELFT>::markSymbol(Symbol *sym) {
301+
template <class ELFT, bool TrackWhyLive>
302+
void MarkLive<ELFT, TrackWhyLive>::markSymbol(Symbol *sym) {
300303
if (auto *d = dyn_cast_or_null<Defined>(sym))
301304
if (auto *isec = dyn_cast_or_null<InputSectionBase>(d->section))
302305
enqueue(isec, d->value, sym);
@@ -305,7 +308,8 @@ template <class ELFT> void MarkLive<ELFT>::markSymbol(Symbol *sym) {
305308
// This is the main function of the garbage collector.
306309
// Starting from GC-root sections, this function visits all reachable
307310
// sections to set their "Live" bits.
308-
template <class ELFT> void MarkLive<ELFT>::run() {
311+
template <class ELFT, bool TrackWhyLive>
312+
void MarkLive<ELFT, TrackWhyLive>::run() {
309313
// Add GC root symbols.
310314

311315
// Preserve externally-visible symbols if the symbols defined by this
@@ -346,7 +350,7 @@ template <class ELFT> void MarkLive<ELFT>::run() {
346350
}
347351
for (InputSectionBase *sec : ctx.inputSections) {
348352
if (sec->flags & SHF_GNU_RETAIN) {
349-
enqueue(sec, 0, nullptr, std::nullopt);
353+
enqueue(sec);
350354
continue;
351355
}
352356
if (sec->flags & SHF_LINK_ORDER)
@@ -397,9 +401,19 @@ template <class ELFT> void MarkLive<ELFT>::run() {
397401
}
398402

399403
mark();
404+
405+
if (TrackWhyLive) {
406+
for (Symbol *sym : ctx.symtab->getSymbols()) {
407+
if (llvm::any_of(ctx.arg.whyLive, [sym](const llvm::GlobPattern &pat) {
408+
return pat.match(sym->getName());
409+
}))
410+
printWhyLive(sym);
411+
}
412+
}
400413
}
401414

402-
template <class ELFT> void MarkLive<ELFT>::mark() {
415+
template <class ELFT, bool TrackWhyLive>
416+
void MarkLive<ELFT, TrackWhyLive>::mark() {
403417
// Mark all reachable sections.
404418
while (!queue.empty()) {
405419
InputSectionBase &sec = *queue.pop_back_val();
@@ -419,15 +433,6 @@ template <class ELFT> void MarkLive<ELFT>::mark() {
419433
if (sec.nextInSectionGroup)
420434
enqueue(sec.nextInSectionGroup, 0, nullptr, &sec);
421435
}
422-
423-
if (!ctx.arg.whyLive.empty()) {
424-
for (Symbol *sym : ctx.symtab->getSymbols()) {
425-
if (llvm::any_of(ctx.arg.whyLive, [sym](const llvm::GlobPattern &pat) {
426-
return pat.match(sym->getName());
427-
}))
428-
printWhyLive(sym);
429-
}
430-
}
431436
}
432437

433438
// Move the sections for some symbols to the main partition, specifically ifuncs
@@ -439,7 +444,8 @@ template <class ELFT> void MarkLive<ELFT>::mark() {
439444
// We also need to move sections whose names are C identifiers that are referred
440445
// to from __start_/__stop_ symbols because there will only be one set of
441446
// symbols for the whole program.
442-
template <class ELFT> void MarkLive<ELFT>::moveToMain() {
447+
template <class ELFT, bool TrackWhyLive>
448+
void MarkLive<ELFT, TrackWhyLive>::moveToMain() {
443449
for (ELFFileBase *file : ctx.objectFiles)
444450
for (Symbol *s : file->getSymbols())
445451
if (auto *d = dyn_cast<Defined>(s))
@@ -478,13 +484,16 @@ template <class ELFT> void elf::markLive(Ctx &ctx) {
478484

479485
// Follow the graph to mark all live sections.
480486
for (unsigned i = 1, e = ctx.partitions.size(); i <= e; ++i)
481-
MarkLive<ELFT>(ctx, i).run();
487+
if (ctx.arg.whyLive.empty())
488+
MarkLive<ELFT, false>(ctx, i).run();
489+
else
490+
MarkLive<ELFT, true>(ctx, i).run();
482491

483492
// If we have multiple partitions, some sections need to live in the main
484493
// partition even if they were allocated to a loadable partition. Move them
485494
// there now.
486495
if (ctx.partitions.size() != 1)
487-
MarkLive<ELFT>(ctx, 1).moveToMain();
496+
MarkLive<ELFT, false>(ctx, 1).moveToMain();
488497

489498
// Report garbage-collected sections.
490499
if (ctx.arg.printGcSections)

0 commit comments

Comments
 (0)