diff options
Diffstat (limited to 'lld/ELF/Driver.cpp')
-rw-r--r-- | lld/ELF/Driver.cpp | 55 |
1 files changed, 44 insertions, 11 deletions
diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp index c721e872e12..cc4cefc6ed9 100644 --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -56,6 +56,7 @@ #include "llvm/Support/Path.h" #include "llvm/Support/TarWriter.h" #include "llvm/Support/TargetSelect.h" +#include "llvm/Support/TimeProfiler.h" #include "llvm/Support/raw_ostream.h" #include <cstdlib> #include <utility> @@ -490,6 +491,10 @@ void LinkerDriver::main(ArrayRef<const char *> argsArr) { if (args.hasArg(OPT_version)) return; + // Initialize time trace. + if (config->timeTraceEnabled) + timeTraceProfilerInitialize(config->timeTraceGranularity, config->progName); + initLLVM(); createFiles(args); if (errorCount()) @@ -509,19 +514,34 @@ void LinkerDriver::main(ArrayRef<const char *> argsArr) { switch (config->ekind) { case ELF32LEKind: link<ELF32LE>(args); - return; + break; case ELF32BEKind: link<ELF32BE>(args); - return; + break; case ELF64LEKind: link<ELF64LE>(args); - return; + break; case ELF64BEKind: link<ELF64BE>(args); - return; + break; default: llvm_unreachable("unknown Config->EKind"); } + + if (config->timeTraceEnabled) { + std::string path = args.getLastArgValue(OPT_time_trace_file_eq); + if (path.empty()) + path = (config->outputFile + ".time-trace").str(); + + std::error_code ec; + raw_fd_ostream os(path, errorCode, sys::fs::F_Text); + if (ec) { + error("cannot open " + path + ": " + ec.message()); + return; + } + timeTraceProfilerWrite(os); + timeTraceProfilerCleanup(); + } } static std::string getRpath(opt::InputArgList &args) { @@ -953,6 +973,9 @@ static void readConfigs(opt::InputArgList &args) { getOldNewOptions(args, OPT_thinlto_object_suffix_replace_eq); config->thinLTOPrefixReplace = getOldNewOptions(args, OPT_thinlto_prefix_replace_eq); + config->timeTraceEnabled = args.hasArg(OPT_time_trace); + config->timeTraceGranularity = + args::getInteger(args, OPT_time_trace_granularity, 500); config->trace = args.hasArg(OPT_trace); config->undefined = args::getStrings(args, OPT_undefined); config->undefinedVersion = @@ -1597,6 +1620,7 @@ static Symbol *addUndefined(StringRef name) { // Because all bitcode files that the program consists of are passed to // the compiler at once, it can do a whole-program optimization. template <class ELFT> void LinkerDriver::compileBitcodeFiles() { + llvm::TimeTraceScope timeScope("LTO"); // Compile bitcode files and replace bitcode symbols. lto.reset(new BitcodeCompiler); for (BitcodeFile *file : bitcodeFiles) @@ -1723,6 +1747,8 @@ template <class ELFT> static uint32_t getAndFeatures() { // Do actual linking. Note that when this function is called, // all linker scripts have already been parsed. template <class ELFT> void LinkerDriver::link(opt::InputArgList &args) { + llvm::TimeTraceScope timeScope("ExecuteLinker"); + // If a -hash-style option was not given, set to a default value, // which varies depending on the target. if (!args.hasArg(OPT_hash_style)) { @@ -1762,8 +1788,11 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &args) { // symbols that we need to the symbol table. This process might // add files to the link, via autolinking, these files are always // appended to the Files vector. - for (size_t i = 0; i < files.size(); ++i) - parseFile(files[i]); + { + llvm::TimeTraceScope timeScope("Parse input files"); + for (size_t i = 0; i < files.size(); ++i) + parseFile(files[i]); + } // Now that we have every file, we can decide if we will need a // dynamic symbol table. @@ -1981,11 +2010,15 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &args) { // merging MergeInputSections into a single MergeSyntheticSection. From this // point onwards InputSectionDescription::sections should be used instead of // sectionBases. - for (BaseCommand *base : script->sectionCommands) - if (auto *sec = dyn_cast<OutputSection>(base)) - sec->finalizeInputSections(); - llvm::erase_if(inputSections, - [](InputSectionBase *s) { return isa<MergeInputSection>(s); }); + { + llvm::TimeTraceScope timeScope("Merge input sections"); + for (BaseCommand *base : script->sectionCommands) + if (auto *sec = dyn_cast<OutputSection>(base)) + sec->finalizeInputSections(); + llvm::erase_if(inputSections, [](InputSectionBase *s) { + return isa<MergeInputSection>(s); + }); + } // Two input sections with different output sections should not be folded. // ICF runs after processSectionCommands() so that we know the output sections. |