[lld-macho] Add more TimeTraceScopes

I added just enough to allow us to see a top-level breakdown of time taken. This
is the result of loading the time-trace output into `chrome:://tracing`:

ef5e8234f3/tracing.png

Reviewed By: oontvoo

Differential Revision: https://reviews.llvm.org/D99311
This commit is contained in:
Jez Ng 2021-03-25 14:39:44 -04:00
parent 53fd1ada76
commit 4bcaafeb0e
4 changed files with 79 additions and 52 deletions

View File

@ -85,7 +85,7 @@ struct Configuration {
uint32_t headerPad;
uint32_t dylibCompatibilityVersion = 0;
uint32_t dylibCurrentVersion = 0;
uint32_t timeTraceGranularity;
uint32_t timeTraceGranularity = 0;
std::string progName;
llvm::StringRef installName;
llvm::StringRef mapFile;

View File

@ -496,6 +496,7 @@ static void initLLVM() {
}
static void compileBitcodeFiles() {
TimeTraceScope timeScope("LTO");
auto *lto = make<BitcodeCompiler>();
for (InputFile *file : inputFiles)
if (auto *bitcodeFile = dyn_cast<BitcodeFile>(file))
@ -510,6 +511,7 @@ static void compileBitcodeFiles() {
// all InputFiles have been loaded.) As a result, later operations won't see
// any CommonSymbols.
static void replaceCommonSymbols() {
TimeTraceScope timeScope("Replace common symbols");
for (macho::Symbol *sym : symtab->getSymbols()) {
auto *common = dyn_cast<CommonSymbol>(sym);
if (common == nullptr)
@ -772,6 +774,44 @@ static void handleSymbolPatterns(InputArgList &args,
}
}
void createFiles(const InputArgList &args) {
TimeTraceScope timeScope("Load input files");
// This loop should be reserved for options whose exact ordering matters.
// Other options should be handled via filtered() and/or getLastArg().
for (const Arg *arg : args) {
const Option &opt = arg->getOption();
warnIfDeprecatedOption(opt);
warnIfUnimplementedOption(opt);
switch (opt.getID()) {
case OPT_INPUT:
addFile(arg->getValue(), false);
break;
case OPT_weak_library:
if (auto *dylibFile =
dyn_cast_or_null<DylibFile>(addFile(arg->getValue(), false)))
dylibFile->forceWeakImport = true;
break;
case OPT_filelist:
addFileList(arg->getValue());
break;
case OPT_force_load:
addFile(arg->getValue(), true);
break;
case OPT_l:
case OPT_weak_l:
addLibrary(arg->getValue(), opt.getID() == OPT_weak_l);
break;
case OPT_framework:
case OPT_weak_framework:
addFramework(arg->getValue(), opt.getID() == OPT_weak_framework);
break;
default:
break;
}
}
}
bool macho::link(ArrayRef<const char *> argsArr, bool canExitEarly,
raw_ostream &stdoutOS, raw_ostream &stderrOS) {
lld::stdoutOS = &stdoutOS;
@ -952,44 +992,10 @@ bool macho::link(ArrayRef<const char *> argsArr, bool canExitEarly,
timeTraceProfilerInitialize(config->timeTraceGranularity, config->progName);
{
llvm::TimeTraceScope timeScope("Link", StringRef("ExecuteLinker"));
TimeTraceScope timeScope("Link", StringRef("ExecuteLinker"));
initLLVM(); // must be run before any call to addFile()
// This loop should be reserved for options whose exact ordering matters.
// Other options should be handled via filtered() and/or getLastArg().
for (const Arg *arg : args) {
const Option &opt = arg->getOption();
warnIfDeprecatedOption(opt);
warnIfUnimplementedOption(opt);
switch (opt.getID()) {
case OPT_INPUT:
addFile(arg->getValue(), false);
break;
case OPT_weak_library:
if (auto *dylibFile =
dyn_cast_or_null<DylibFile>(addFile(arg->getValue(), false)))
dylibFile->forceWeakImport = true;
break;
case OPT_filelist:
addFileList(arg->getValue());
break;
case OPT_force_load:
addFile(arg->getValue(), true);
break;
case OPT_l:
case OPT_weak_l:
addLibrary(arg->getValue(), opt.getID() == OPT_weak_l);
break;
case OPT_framework:
case OPT_weak_framework:
addFramework(arg->getValue(), opt.getID() == OPT_weak_framework);
break;
default:
break;
}
}
createFiles(args);
config->isPic = config->outputType == MH_DYLIB ||
config->outputType == MH_BUNDLE || isPie(args);
@ -1060,12 +1066,15 @@ bool macho::link(ArrayRef<const char *> argsArr, bool canExitEarly,
inputFiles.insert(make<OpaqueFile>(*buffer, segName, sectName));
}
// Initialize InputSections.
for (const InputFile *file : inputFiles) {
for (const SubsectionMap &map : file->subsections) {
for (const auto &p : map) {
InputSection *isec = p.second;
inputSections.push_back(isec);
{
TimeTraceScope timeScope("Gathering input sections");
// Gather all InputSections into one vector.
for (const InputFile *file : inputFiles) {
for (const SubsectionMap &map : file->subsections) {
for (const auto &p : map) {
InputSection *isec = p.second;
inputSections.push_back(isec);
}
}
}
}

View File

@ -33,6 +33,7 @@
#include "Symbols.h"
#include "Target.h"
#include "llvm/Support/Parallel.h"
#include "llvm/Support/TimeProfiler.h"
using namespace llvm;
using namespace llvm::sys;
@ -93,6 +94,8 @@ void macho::writeMapFile() {
if (config->mapFile.empty())
return;
TimeTraceScope timeScope("Write map file");
// Open a map file for writing.
std::error_code ec;
raw_fd_ostream os(config->mapFile, ec, sys::fs::OF_None);

View File

@ -27,6 +27,7 @@
#include "llvm/Support/LEB128.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/TimeProfiler.h"
#include "llvm/Support/xxhash.h"
#include <algorithm>
@ -56,6 +57,7 @@ public:
void writeSections();
void writeUuid();
void writeCodeSignature();
void writeOutputFile();
void run();
@ -502,6 +504,7 @@ static void prepareSymbolRelocation(lld::macho::Symbol *sym,
}
void Writer::scanRelocations() {
TimeTraceScope timeScope("Scan relocations");
for (InputSection *isec : inputSections) {
if (isec->segname == segment_names::ld) {
prepareCompactUnwind(isec);
@ -534,6 +537,7 @@ void Writer::scanRelocations() {
}
void Writer::scanSymbols() {
TimeTraceScope timeScope("Scan symbols");
for (const macho::Symbol *sym : symtab->getSymbols()) {
if (const auto *defined = dyn_cast<Defined>(sym)) {
if (defined->overridesWeakDef)
@ -737,6 +741,8 @@ static std::function<bool(T, T)> compareByOrder(F ord) {
// segments, output sections within each segment, and input sections within each
// output segment.
static void sortSegmentsAndSections() {
TimeTraceScope timeScope("Sort segments and sections");
llvm::stable_sort(outputSegments,
compareByOrder<OutputSegment *>(segmentOrder));
@ -777,6 +783,7 @@ static NamePair maybeRenameSection(NamePair key) {
}
void Writer::createOutputSections() {
TimeTraceScope timeScope("Create output sections");
// First, create hidden sections
stringTableSection = make<StringTableSection>();
unwindInfoSection = make<UnwindInfoSection>(); // TODO(gkm): only when no -r
@ -834,6 +841,7 @@ void Writer::createOutputSections() {
}
void Writer::finalizeAddressses() {
TimeTraceScope timeScope("Finalize addresses");
// Ensure that segments (and the sections they contain) are allocated
// addresses in ascending order, which dyld requires.
//
@ -848,6 +856,7 @@ void Writer::finalizeAddressses() {
}
void Writer::finalizeLinkEditSegment() {
TimeTraceScope timeScope("Finalize __LINKEDIT segment");
// Fill __LINKEDIT contents.
in.rebase->finalizeContents();
in.binding->finalizeContents();
@ -904,6 +913,7 @@ void Writer::writeSections() {
}
void Writer::writeUuid() {
TimeTraceScope timeScope("Computing UUID");
uint64_t digest =
xxHash64({buffer->getBufferStart(), buffer->getBufferEnd()});
uuidCommand->writeUuid(digest);
@ -914,6 +924,19 @@ void Writer::writeCodeSignature() {
codeSignatureSection->writeHashes(buffer->getBufferStart());
}
void Writer::writeOutputFile() {
TimeTraceScope timeScope("Write output file");
openFile();
if (errorCount())
return;
writeSections();
writeUuid();
writeCodeSignature();
if (auto e = buffer->commit())
error("failed to write to the output file: " + toString(std::move(e)));
}
void Writer::run() {
prepareBranchTarget(config->entry);
scanRelocations();
@ -927,15 +950,7 @@ void Writer::run() {
finalizeAddressses();
finalizeLinkEditSegment();
writeMapFile();
openFile();
if (errorCount())
return;
writeSections();
writeUuid();
writeCodeSignature();
if (auto e = buffer->commit())
error("failed to write to the output file: " + toString(std::move(e)));
writeOutputFile();
}
void macho::writeResult() { Writer().run(); }