From bfb0de66f9c61b6eb992c4a3284d9c0799718efd Mon Sep 17 00:00:00 2001 From: Alexandre Ganea Date: Mon, 1 Sep 2025 18:47:49 -0400 Subject: [PATCH 1/4] [LLD][COFF] Add more `--time-trace` tags for ThinLTO linking --- lld/COFF/SymbolTable.cpp | 8 +- llvm/lib/Bitcode/Reader/MetadataLoader.cpp | 2 + llvm/lib/IR/AutoUpgrade.cpp | 2 + llvm/lib/IR/DebugInfo.cpp | 2 + llvm/lib/IR/Module.cpp | 2 + llvm/lib/IR/Verifier.cpp | 12 +- llvm/lib/LTO/LTO.cpp | 45 ++-- llvm/lib/LTO/LTOBackend.cpp | 17 +- llvm/lib/Transforms/IPO/FunctionImport.cpp | 195 ++++++++++-------- .../lib/Transforms/IPO/WholeProgramDevirt.cpp | 2 + .../Transforms/Utils/FunctionImportUtils.cpp | 3 + 11 files changed, 172 insertions(+), 118 deletions(-) diff --git a/lld/COFF/SymbolTable.cpp b/lld/COFF/SymbolTable.cpp index 0a88807c00dd5..335f3d65a078f 100644 --- a/lld/COFF/SymbolTable.cpp +++ b/lld/COFF/SymbolTable.cpp @@ -1440,8 +1440,12 @@ void SymbolTable::compileBitcodeFiles() { llvm::TimeTraceScope timeScope("Compile bitcode"); ScopedTimer t(ctx.ltoTimer); lto.reset(new BitcodeCompiler(ctx)); - for (BitcodeFile *f : bitcodeFileInstances) - lto->add(*f); + { + llvm::TimeTraceScope addScope("Add bitcode file instances"); + for (BitcodeFile *f : bitcodeFileInstances) + lto->add(*f); + } + llvm::TimeTraceScope compileScope("LTO compile"); for (InputFile *newObj : lto->compile()) { ObjFile *obj = cast(newObj); obj->parse(); diff --git a/llvm/lib/Bitcode/Reader/MetadataLoader.cpp b/llvm/lib/Bitcode/Reader/MetadataLoader.cpp index 738e47b8b16c4..a5cedadd30981 100644 --- a/llvm/lib/Bitcode/Reader/MetadataLoader.cpp +++ b/llvm/lib/Bitcode/Reader/MetadataLoader.cpp @@ -43,6 +43,7 @@ #include "llvm/Support/CommandLine.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/TimeProfiler.h" #include #include @@ -1052,6 +1053,7 @@ void MetadataLoader::MetadataLoaderImpl::callMDTypeCallback(Metadata **Val, /// Parse a METADATA_BLOCK. If ModuleLevel is true then we are parsing /// module level metadata. Error MetadataLoader::MetadataLoaderImpl::parseMetadata(bool ModuleLevel) { + llvm::TimeTraceScope timeScope("Parse metadata"); if (!ModuleLevel && MetadataList.hasFwdRefs()) return error("Invalid metadata: fwd refs into function blocks"); diff --git a/llvm/lib/IR/AutoUpgrade.cpp b/llvm/lib/IR/AutoUpgrade.cpp index 7ea9c6dff13b8..8034b3ffe273e 100644 --- a/llvm/lib/IR/AutoUpgrade.cpp +++ b/llvm/lib/IR/AutoUpgrade.cpp @@ -48,6 +48,7 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/NVPTXAddrSpace.h" #include "llvm/Support/Regex.h" +#include "llvm/Support/TimeProfiler.h" #include "llvm/TargetParser/Triple.h" #include #include @@ -5256,6 +5257,7 @@ bool llvm::UpgradeDebugInfo(Module &M) { if (DisableAutoUpgradeDebugInfo) return false; + llvm::TimeTraceScope timeScope("Upgrade debug info"); // We need to get metadata before the module is verified (i.e., getModuleFlag // makes assumptions that we haven't verified yet). Carefully extract the flag // from the metadata. diff --git a/llvm/lib/IR/DebugInfo.cpp b/llvm/lib/IR/DebugInfo.cpp index b468d929b0280..166521a276643 100644 --- a/llvm/lib/IR/DebugInfo.cpp +++ b/llvm/lib/IR/DebugInfo.cpp @@ -36,6 +36,7 @@ #include "llvm/IR/Module.h" #include "llvm/IR/PassManager.h" #include "llvm/Support/Casting.h" +#include "llvm/Support/TimeProfiler.h" #include #include #include @@ -563,6 +564,7 @@ bool llvm::stripDebugInfo(Function &F) { } bool llvm::StripDebugInfo(Module &M) { + llvm::TimeTraceScope timeScope("Strip debug info"); bool Changed = false; for (NamedMDNode &NMD : llvm::make_early_inc_range(M.named_metadata())) { diff --git a/llvm/lib/IR/Module.cpp b/llvm/lib/IR/Module.cpp index 70d364176062f..30b5e48652b28 100644 --- a/llvm/lib/IR/Module.cpp +++ b/llvm/lib/IR/Module.cpp @@ -44,6 +44,7 @@ #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" #include "llvm/Support/RandomNumberGenerator.h" +#include "llvm/Support/TimeProfiler.h" #include "llvm/Support/VersionTuple.h" #include #include @@ -478,6 +479,7 @@ Error Module::materializeAll() { } Error Module::materializeMetadata() { + llvm::TimeTraceScope timeScope("Materialize metadata"); if (!Materializer) return Error::success(); return Materializer->materializeMetadata(); diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp index da05ff166122f..52f41747f8b9b 100644 --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -119,6 +119,7 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/ModRef.h" +#include "llvm/Support/TimeProfiler.h" #include "llvm/Support/raw_ostream.h" #include #include @@ -399,6 +400,7 @@ class Verifier : public InstVisitor, VerifierSupport { bool hasBrokenDebugInfo() const { return BrokenDebugInfo; } bool verify(const Function &F) { + llvm::TimeTraceScope timeScope("Verifier"); assert(F.getParent() == &M && "An instance of this class only works with a specific module!"); @@ -408,8 +410,10 @@ class Verifier : public InstVisitor, VerifierSupport { // out-of-date dominator tree and makes it significantly more complex to run // this code outside of a pass manager. // FIXME: It's really gross that we have to cast away constness here. - if (!F.empty()) + if (!F.empty()) { + llvm::TimeTraceScope domScope("Dominator Tree Builder"); DT.recalculate(const_cast(F)); + } for (const BasicBlock &BB : F) { if (!BB.empty() && BB.back().isTerminator()) @@ -431,7 +435,10 @@ class Verifier : public InstVisitor, VerifierSupport { Broken = false; // FIXME: We strip const here because the inst visitor strips const. - visit(const_cast(F)); + { + llvm::TimeTraceScope domScope("Verifier visit"); + visit(const_cast(F)); + } verifySiblingFuncletUnwinds(); if (ConvergenceVerifyHelper.sawTokens()) @@ -2832,6 +2839,7 @@ static Instruction *getSuccPad(Instruction *Terminator) { } void Verifier::verifySiblingFuncletUnwinds() { + llvm::TimeTraceScope domScope("Verifier verify sibling funclet unwinds"); SmallPtrSet Visited; SmallPtrSet Active; for (const auto &Pair : SiblingFuncletInfo) { diff --git a/llvm/lib/LTO/LTO.cpp b/llvm/lib/LTO/LTO.cpp index 35d24c17bbd93..424c6e251fb8c 100644 --- a/llvm/lib/LTO/LTO.cpp +++ b/llvm/lib/LTO/LTO.cpp @@ -631,6 +631,7 @@ LTO::~LTO() = default; void LTO::addModuleToGlobalRes(ArrayRef Syms, ArrayRef Res, unsigned Partition, bool InSummary) { + llvm::TimeTraceScope importScope("LTO add module to global resolution"); auto *ResI = Res.begin(); auto *ResE = Res.end(); (void)ResE; @@ -731,6 +732,7 @@ static void writeToResolutionFile(raw_ostream &OS, InputFile *Input, Error LTO::add(std::unique_ptr Input, ArrayRef Res) { + llvm::TimeTraceScope importScope("LTO add input", Input->getName()); assert(!CalledGetMaxTasks); if (Conf.ResolutionFile) @@ -756,6 +758,7 @@ Error LTO::add(std::unique_ptr Input, Expected> LTO::addModule(InputFile &Input, ArrayRef InputRes, unsigned ModI, ArrayRef Res) { + llvm::TimeTraceScope importScope("LTO add module", Input.getName()); Expected LTOInfo = Input.Mods[ModI].getLTOInfo(); if (!LTOInfo) return LTOInfo.takeError(); @@ -850,6 +853,7 @@ Expected< LTO::addRegularLTO(InputFile &Input, ArrayRef InputRes, BitcodeModule BM, ArrayRef Syms, ArrayRef Res) { + llvm::TimeTraceScope importScope("LTO add regular LTO"); RegularLTOState::AddedModule Mod; Expected> MOrErr = BM.getLazyModule(RegularLTO.Ctx, /*ShouldLazyLoadMetadata*/ true, @@ -1024,6 +1028,7 @@ LTO::addRegularLTO(InputFile &Input, ArrayRef InputRes, Error LTO::linkRegularLTO(RegularLTOState::AddedModule Mod, bool LivenessFromIndex) { + llvm::TimeTraceScope importScope("LTO link regular LTO"); std::vector Keep; for (GlobalValue *GV : Mod.Keep) { if (LivenessFromIndex && !ThinLTO.CombinedIndex.isGUIDLive(GV->getGUID())) { @@ -1063,6 +1068,7 @@ Error LTO::linkRegularLTO(RegularLTOState::AddedModule Mod, Expected> LTO::addThinLTO(BitcodeModule BM, ArrayRef Syms, ArrayRef Res) { + llvm::TimeTraceScope importScope("LTO add thin LTO"); ArrayRef ResTmp = Res; for (const InputFile::Symbol &Sym : Syms) { assert(!ResTmp.empty()); @@ -1252,6 +1258,7 @@ Error LTO::run(AddStreamFn AddStream, FileCache Cache) { void lto::updateMemProfAttributes(Module &Mod, const ModuleSummaryIndex &Index) { + llvm::TimeTraceScope importScope("LTO update memprof attributes"); if (Index.withSupportsHotColdNew()) return; @@ -1282,6 +1289,7 @@ void lto::updateMemProfAttributes(Module &Mod, } Error LTO::runRegularLTO(AddStreamFn AddStream) { + llvm::TimeTraceScope timeScope("Run regular LTO"); // Setup optimization remarks. auto DiagFileOrErr = lto::setupLLVMOptimizationRemarks( RegularLTO.CombinedModule->getContext(), Conf.RemarksFilename, @@ -1294,10 +1302,12 @@ Error LTO::runRegularLTO(AddStreamFn AddStream) { // Finalize linking of regular LTO modules containing summaries now that // we have computed liveness information. - for (auto &M : RegularLTO.ModsWithSummaries) - if (Error Err = linkRegularLTO(std::move(M), - /*LivenessFromIndex=*/true)) - return Err; + { + llvm::TimeTraceScope timeScope("Link regular LTO"); + for (auto &M : RegularLTO.ModsWithSummaries) + if (Error Err = linkRegularLTO(std::move(M), /*LivenessFromIndex=*/true)) + return Err; + } // Ensure we don't have inconsistently split LTO units with type tests. // FIXME: this checks both LTO and ThinLTO. It happens to work as we take @@ -1526,6 +1536,9 @@ class InProcessThinBackend : public CGThinBackend { const std::map &ResolvedODR, const GVSummaryMapTy &DefinedGlobals, MapVector &ModuleMap) { + auto ModuleID = BM.getModuleIdentifier(); + llvm::TimeTraceScope timeScope("Run ThinLTO backend thread (in-process)", + ModuleID); auto RunThinBackend = [&](AddStreamFn AddStream) { LTOLLVMContext BackendContext(Conf); Expected> MOrErr = BM.parseModule(BackendContext); @@ -1536,9 +1549,6 @@ class InProcessThinBackend : public CGThinBackend { ImportList, DefinedGlobals, &ModuleMap, Conf.CodeGenOnly); }; - - auto ModuleID = BM.getModuleIdentifier(); - if (ShouldEmitIndexFiles) { if (auto E = emitFiles(ImportList, ModuleID, ModuleID.str())) return E; @@ -1639,6 +1649,9 @@ class FirstRoundThinBackend : public InProcessThinBackend { const std::map &ResolvedODR, const GVSummaryMapTy &DefinedGlobals, MapVector &ModuleMap) override { + auto ModuleID = BM.getModuleIdentifier(); + llvm::TimeTraceScope timeScope("Run ThinLTO backend thread (first round)", + ModuleID); auto RunThinBackend = [&](AddStreamFn CGAddStream, AddStreamFn IRAddStream) { LTOLLVMContext BackendContext(Conf); @@ -1650,8 +1663,6 @@ class FirstRoundThinBackend : public InProcessThinBackend { ImportList, DefinedGlobals, &ModuleMap, Conf.CodeGenOnly, IRAddStream); }; - - auto ModuleID = BM.getModuleIdentifier(); // Like InProcessThinBackend, we produce index files as needed for // FirstRoundThinBackend. However, these files are not generated for // SecondRoundThinBackend. @@ -1735,6 +1746,9 @@ class SecondRoundThinBackend : public InProcessThinBackend { const std::map &ResolvedODR, const GVSummaryMapTy &DefinedGlobals, MapVector &ModuleMap) override { + auto ModuleID = BM.getModuleIdentifier(); + llvm::TimeTraceScope timeScope("Run ThinLTO backend thread (second round)", + ModuleID); auto RunThinBackend = [&](AddStreamFn AddStream) { LTOLLVMContext BackendContext(Conf); std::unique_ptr LoadedModule = @@ -1744,8 +1758,6 @@ class SecondRoundThinBackend : public InProcessThinBackend { ImportList, DefinedGlobals, &ModuleMap, /*CodeGenOnly=*/true); }; - - auto ModuleID = BM.getModuleIdentifier(); if (!Cache.isValid() || !CombinedIndex.modulePaths().count(ModuleID) || all_of(CombinedIndex.getModuleHash(ModuleID), [](uint32_t V) { return V == 0; })) @@ -1915,13 +1927,9 @@ ThinBackend lto::createWriteIndexesThinBackend( Error LTO::runThinLTO(AddStreamFn AddStream, FileCache Cache, const DenseSet &GUIDPreservedSymbols) { + llvm::TimeTraceScope timeScope("Run ThinLTO"); LLVM_DEBUG(dbgs() << "Running ThinLTO\n"); ThinLTO.CombinedIndex.releaseTemporaryMemory(); - timeTraceProfilerBegin("ThinLink", StringRef("")); - auto TimeTraceScopeExit = llvm::make_scope_exit([]() { - if (llvm::timeTraceProfilerEnabled()) - llvm::timeTraceProfilerEnd(); - }); if (ThinLTO.ModuleMap.empty()) return Error::success(); @@ -2069,11 +2077,6 @@ Error LTO::runThinLTO(AddStreamFn AddStream, FileCache Cache, generateParamAccessSummary(ThinLTO.CombinedIndex); - if (llvm::timeTraceProfilerEnabled()) - llvm::timeTraceProfilerEnd(); - - TimeTraceScopeExit.release(); - auto &ModuleMap = ThinLTO.ModulesToCompile ? *ThinLTO.ModulesToCompile : ThinLTO.ModuleMap; diff --git a/llvm/lib/LTO/LTOBackend.cpp b/llvm/lib/LTO/LTOBackend.cpp index 5e8cd12fe040b..402e4a5c6a8bd 100644 --- a/llvm/lib/LTO/LTOBackend.cpp +++ b/llvm/lib/LTO/LTOBackend.cpp @@ -366,6 +366,7 @@ bool lto::opt(const Config &Conf, TargetMachine *TM, unsigned Task, Module &Mod, bool IsThinLTO, ModuleSummaryIndex *ExportSummary, const ModuleSummaryIndex *ImportSummary, const std::vector &CmdArgs) { + llvm::TimeTraceScope timeScope("opt"); if (EmbedBitcode == LTOBitcodeEmbedding::EmbedPostMergePreOptimized) { // FIXME: the motivation for capturing post-merge bitcode and command line // is replicating the compilation environment from bitcode, without needing @@ -399,6 +400,7 @@ bool lto::opt(const Config &Conf, TargetMachine *TM, unsigned Task, Module &Mod, static void codegen(const Config &Conf, TargetMachine *TM, AddStreamFn AddStream, unsigned Task, Module &Mod, const ModuleSummaryIndex &CombinedIndex) { + llvm::TimeTraceScope timeScope("codegen"); if (Conf.PreCodeGenModuleHook && !Conf.PreCodeGenModuleHook(Task, Mod)) return; @@ -552,6 +554,7 @@ Error lto::finalizeOptimizationRemarks( Error lto::backend(const Config &C, AddStreamFn AddStream, unsigned ParallelCodeGenParallelismLevel, Module &Mod, ModuleSummaryIndex &CombinedIndex) { + llvm::TimeTraceScope timeScope("LTO backend"); Expected TOrErr = initAndLookupTarget(C, Mod); if (!TOrErr) return TOrErr.takeError(); @@ -577,6 +580,7 @@ Error lto::backend(const Config &C, AddStreamFn AddStream, static void dropDeadSymbols(Module &Mod, const GVSummaryMapTy &DefinedGlobals, const ModuleSummaryIndex &Index) { + llvm::TimeTraceScope timeScope("Drop dead symbols"); std::vector DeadGVs; for (auto &GV : Mod.global_values()) if (GlobalValueSummary *GVS = DefinedGlobals.lookup(GV.getGUID())) @@ -603,6 +607,7 @@ Error lto::thinBackend(const Config &Conf, unsigned Task, AddStreamFn AddStream, MapVector *ModuleMap, bool CodeGenOnly, AddStreamFn IRAddStream, const std::vector &CmdArgs) { + llvm::TimeTraceScope timeScope("Thin backend", Mod.getModuleIdentifier()); Expected TOrErr = initAndLookupTarget(Conf, Mod); if (!TOrErr) return TOrErr.takeError(); @@ -679,6 +684,7 @@ Error lto::thinBackend(const Config &Conf, unsigned Task, AddStreamFn AddStream, return finalizeOptimizationRemarks(std::move(DiagnosticOutputFile)); auto ModuleLoader = [&](StringRef Identifier) { + llvm::TimeTraceScope importScope("Module loader", Identifier); assert(Mod.getContext().isODRUniquingDebugTypes() && "ODR Type uniquing should be enabled on the context"); if (ModuleMap) { @@ -712,10 +718,13 @@ Error lto::thinBackend(const Config &Conf, unsigned Task, AddStreamFn AddStream, return MOrErr; }; - FunctionImporter Importer(CombinedIndex, ModuleLoader, - ClearDSOLocalOnDeclarations); - if (Error Err = Importer.importFunctions(Mod, ImportList).takeError()) - return Err; + { + llvm::TimeTraceScope importScope("Import functions"); + FunctionImporter Importer(CombinedIndex, ModuleLoader, + ClearDSOLocalOnDeclarations); + if (Error Err = Importer.importFunctions(Mod, ImportList).takeError()) + return Err; + } // Do this after any importing so that imported code is updated. updateMemProfAttributes(Mod, CombinedIndex); diff --git a/llvm/lib/Transforms/IPO/FunctionImport.cpp b/llvm/lib/Transforms/IPO/FunctionImport.cpp index 7bcb20de46ff6..96b274e2f45a9 100644 --- a/llvm/lib/Transforms/IPO/FunctionImport.cpp +++ b/llvm/lib/Transforms/IPO/FunctionImport.cpp @@ -40,6 +40,7 @@ #include "llvm/Support/JSON.h" #include "llvm/Support/Path.h" #include "llvm/Support/SourceMgr.h" +#include "llvm/Support/TimeProfiler.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Transforms/IPO/Internalize.h" #include "llvm/Transforms/Utils/Cloning.h" @@ -1550,6 +1551,7 @@ void llvm::computeDeadSymbolsWithConstProp( const DenseSet &GUIDPreservedSymbols, function_ref isPrevailing, bool ImportEnabled) { + llvm::TimeTraceScope timeScope("Dead symbols"); computeDeadSymbolsAndUpdateIndirectCalls(Index, GUIDPreservedSymbols, isPrevailing); if (ImportEnabled) @@ -1664,6 +1666,7 @@ bool llvm::convertToDeclaration(GlobalValue &GV) { void llvm::thinLTOFinalizeInModule(Module &TheModule, const GVSummaryMapTy &DefinedGlobals, bool PropagateAttrs) { + llvm::TimeTraceScope timeScope("ThinLTO finalize in module"); DenseSet NonPrevailingComdats; auto FinalizeInModule = [&](GlobalValue &GV, bool Propagate = false) { // See if the global summary analysis computed a new resolved linkage. @@ -1791,6 +1794,7 @@ void llvm::thinLTOFinalizeInModule(Module &TheModule, /// Run internalization on \p TheModule based on symmary analysis. void llvm::thinLTOInternalizeModule(Module &TheModule, const GVSummaryMapTy &DefinedGlobals) { + llvm::TimeTraceScope timeScope("ThinLTO internalize module"); // Declare a callback for the internalize pass that will ask for every // candidate GlobalValue if it can be internalized or not. auto MustPreserveGV = [&](const GlobalValue &GV) -> bool { @@ -1885,6 +1889,7 @@ Expected FunctionImporter::importFunctions( // Do the actual import of functions now, one Module at a time for (const auto &ModName : ImportList.getSourceModules()) { + llvm::TimeTraceScope timeScope("Import", ModName); // Get the module for the import Expected> SrcModuleOrErr = ModuleLoader(ModName); if (!SrcModuleOrErr) @@ -1900,102 +1905,114 @@ Expected FunctionImporter::importFunctions( // Find the globals to import SetVector GlobalsToImport; - for (Function &F : *SrcModule) { - if (!F.hasName()) - continue; - auto GUID = F.getGUID(); - auto MaybeImportType = ImportList.getImportType(ModName, GUID); - bool ImportDefinition = MaybeImportType == GlobalValueSummary::Definition; - - LLVM_DEBUG(dbgs() << (MaybeImportType ? "Is" : "Not") - << " importing function" - << (ImportDefinition - ? " definition " - : (MaybeImportType ? " declaration " : " ")) - << GUID << " " << F.getName() << " from " - << SrcModule->getSourceFileName() << "\n"); - if (ImportDefinition) { - if (Error Err = F.materialize()) - return std::move(Err); - // MemProf should match function's definition and summary, - // 'thinlto_src_module' is needed. - if (EnableImportMetadata || EnableMemProfContextDisambiguation) { - // Add 'thinlto_src_module' and 'thinlto_src_file' metadata for - // statistics and debugging. - F.setMetadata( - "thinlto_src_module", - MDNode::get(DestModule.getContext(), - {MDString::get(DestModule.getContext(), - SrcModule->getModuleIdentifier())})); - F.setMetadata( - "thinlto_src_file", - MDNode::get(DestModule.getContext(), - {MDString::get(DestModule.getContext(), - SrcModule->getSourceFileName())})); + { + llvm::TimeTraceScope findGlobalsScope("Find globals"); + for (Function &F : *SrcModule) { + if (!F.hasName()) + continue; + auto GUID = F.getGUID(); + auto MaybeImportType = ImportList.getImportType(ModName, GUID); + bool ImportDefinition = + MaybeImportType == GlobalValueSummary::Definition; + + LLVM_DEBUG(dbgs() << (MaybeImportType ? "Is" : "Not") + << " importing function" + << (ImportDefinition + ? " definition " + : (MaybeImportType ? " declaration " : " ")) + << GUID << " " << F.getName() << " from " + << SrcModule->getSourceFileName() << "\n"); + if (ImportDefinition) { + if (Error Err = F.materialize()) + return std::move(Err); + // MemProf should match function's definition and summary, + // 'thinlto_src_module' is needed. + if (EnableImportMetadata || EnableMemProfContextDisambiguation) { + // Add 'thinlto_src_module' and 'thinlto_src_file' metadata for + // statistics and debugging. + F.setMetadata( + "thinlto_src_module", + MDNode::get(DestModule.getContext(), + {MDString::get(DestModule.getContext(), + SrcModule->getModuleIdentifier())})); + F.setMetadata( + "thinlto_src_file", + MDNode::get(DestModule.getContext(), + {MDString::get(DestModule.getContext(), + SrcModule->getSourceFileName())})); + } + GlobalsToImport.insert(&F); } - GlobalsToImport.insert(&F); } } - for (GlobalVariable &GV : SrcModule->globals()) { - if (!GV.hasName()) - continue; - auto GUID = GV.getGUID(); - auto MaybeImportType = ImportList.getImportType(ModName, GUID); - bool ImportDefinition = MaybeImportType == GlobalValueSummary::Definition; - - LLVM_DEBUG(dbgs() << (MaybeImportType ? "Is" : "Not") - << " importing global" - << (ImportDefinition - ? " definition " - : (MaybeImportType ? " declaration " : " ")) - << GUID << " " << GV.getName() << " from " - << SrcModule->getSourceFileName() << "\n"); - if (ImportDefinition) { - if (Error Err = GV.materialize()) - return std::move(Err); - ImportedGVCount += GlobalsToImport.insert(&GV); + { + llvm::TimeTraceScope globalsScope("Globals"); + for (GlobalVariable &GV : SrcModule->globals()) { + if (!GV.hasName()) + continue; + auto GUID = GV.getGUID(); + auto MaybeImportType = ImportList.getImportType(ModName, GUID); + bool ImportDefinition = + MaybeImportType == GlobalValueSummary::Definition; + + LLVM_DEBUG(dbgs() << (MaybeImportType ? "Is" : "Not") + << " importing global" + << (ImportDefinition + ? " definition " + : (MaybeImportType ? " declaration " : " ")) + << GUID << " " << GV.getName() << " from " + << SrcModule->getSourceFileName() << "\n"); + if (ImportDefinition) { + if (Error Err = GV.materialize()) + return std::move(Err); + ImportedGVCount += GlobalsToImport.insert(&GV); + } } } - for (GlobalAlias &GA : SrcModule->aliases()) { - if (!GA.hasName() || isa(GA.getAliaseeObject())) - continue; - auto GUID = GA.getGUID(); - auto MaybeImportType = ImportList.getImportType(ModName, GUID); - bool ImportDefinition = MaybeImportType == GlobalValueSummary::Definition; - - LLVM_DEBUG(dbgs() << (MaybeImportType ? "Is" : "Not") - << " importing alias" - << (ImportDefinition - ? " definition " - : (MaybeImportType ? " declaration " : " ")) - << GUID << " " << GA.getName() << " from " - << SrcModule->getSourceFileName() << "\n"); - if (ImportDefinition) { - if (Error Err = GA.materialize()) - return std::move(Err); - // Import alias as a copy of its aliasee. - GlobalObject *GO = GA.getAliaseeObject(); - if (Error Err = GO->materialize()) - return std::move(Err); - auto *Fn = replaceAliasWithAliasee(SrcModule.get(), &GA); - LLVM_DEBUG(dbgs() << "Is importing aliasee fn " << GO->getGUID() << " " - << GO->getName() << " from " + { + llvm::TimeTraceScope aliasesScope("Aliases"); + for (GlobalAlias &GA : SrcModule->aliases()) { + if (!GA.hasName() || isa(GA.getAliaseeObject())) + continue; + auto GUID = GA.getGUID(); + auto MaybeImportType = ImportList.getImportType(ModName, GUID); + bool ImportDefinition = + MaybeImportType == GlobalValueSummary::Definition; + + LLVM_DEBUG(dbgs() << (MaybeImportType ? "Is" : "Not") + << " importing alias" + << (ImportDefinition + ? " definition " + : (MaybeImportType ? " declaration " : " ")) + << GUID << " " << GA.getName() << " from " << SrcModule->getSourceFileName() << "\n"); - if (EnableImportMetadata || EnableMemProfContextDisambiguation) { - // Add 'thinlto_src_module' and 'thinlto_src_file' metadata for - // statistics and debugging. - Fn->setMetadata( - "thinlto_src_module", - MDNode::get(DestModule.getContext(), - {MDString::get(DestModule.getContext(), - SrcModule->getModuleIdentifier())})); - Fn->setMetadata( - "thinlto_src_file", - MDNode::get(DestModule.getContext(), - {MDString::get(DestModule.getContext(), - SrcModule->getSourceFileName())})); + if (ImportDefinition) { + if (Error Err = GA.materialize()) + return std::move(Err); + // Import alias as a copy of its aliasee. + GlobalObject *GO = GA.getAliaseeObject(); + if (Error Err = GO->materialize()) + return std::move(Err); + auto *Fn = replaceAliasWithAliasee(SrcModule.get(), &GA); + LLVM_DEBUG(dbgs() << "Is importing aliasee fn " << GO->getGUID() + << " " << GO->getName() << " from " + << SrcModule->getSourceFileName() << "\n"); + if (EnableImportMetadata || EnableMemProfContextDisambiguation) { + // Add 'thinlto_src_module' and 'thinlto_src_file' metadata for + // statistics and debugging. + Fn->setMetadata( + "thinlto_src_module", + MDNode::get(DestModule.getContext(), + {MDString::get(DestModule.getContext(), + SrcModule->getModuleIdentifier())})); + Fn->setMetadata( + "thinlto_src_file", + MDNode::get(DestModule.getContext(), + {MDString::get(DestModule.getContext(), + SrcModule->getSourceFileName())})); + } + GlobalsToImport.insert(Fn); } - GlobalsToImport.insert(Fn); } } diff --git a/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp b/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp index cb98ed838f5d7..402eeea0402f8 100644 --- a/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp +++ b/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp @@ -90,6 +90,7 @@ #include "llvm/Support/Error.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/GlobPattern.h" +#include "llvm/Support/TimeProfiler.h" #include "llvm/TargetParser/Triple.h" #include "llvm/Transforms/IPO.h" #include "llvm/Transforms/IPO/FunctionAttrs.h" @@ -869,6 +870,7 @@ void llvm::updateVCallVisibilityInModule( void llvm::updatePublicTypeTestCalls(Module &M, bool WholeProgramVisibilityEnabledInLTO) { + llvm::TimeTraceScope importScope("Update public type test calls"); Function *PublicTypeTestFunc = Intrinsic::getDeclarationIfExists(&M, Intrinsic::public_type_test); if (!PublicTypeTestFunc) diff --git a/llvm/lib/Transforms/Utils/FunctionImportUtils.cpp b/llvm/lib/Transforms/Utils/FunctionImportUtils.cpp index 3bbe875bbe9e5..1a9e16be6989e 100644 --- a/llvm/lib/Transforms/Utils/FunctionImportUtils.cpp +++ b/llvm/lib/Transforms/Utils/FunctionImportUtils.cpp @@ -13,6 +13,8 @@ #include "llvm/Transforms/Utils/FunctionImportUtils.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/TimeProfiler.h" + using namespace llvm; /// Uses the "source_filename" instead of a Module hash ID for the suffix of @@ -370,6 +372,7 @@ void FunctionImportGlobalProcessing::run() { processGlobalsForThinLTO(); } void llvm::renameModuleForThinLTO(Module &M, const ModuleSummaryIndex &Index, bool ClearDSOLocalOnDeclarations, SetVector *GlobalsToImport) { + llvm::TimeTraceScope timeScope("Rename module for ThinLTO"); FunctionImportGlobalProcessing ThinLTOProcessing(M, Index, GlobalsToImport, ClearDSOLocalOnDeclarations); ThinLTOProcessing.run(); From 076d4756f9b9e7d76e88068f53dd683edebd41ea Mon Sep 17 00:00:00 2001 From: Alexandre Ganea Date: Wed, 3 Sep 2025 08:51:53 -0400 Subject: [PATCH 2/4] Remove some unneeded tags --- llvm/lib/IR/Verifier.cpp | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp index 52f41747f8b9b..4729b36b94ab8 100644 --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -410,10 +410,8 @@ class Verifier : public InstVisitor, VerifierSupport { // out-of-date dominator tree and makes it significantly more complex to run // this code outside of a pass manager. // FIXME: It's really gross that we have to cast away constness here. - if (!F.empty()) { - llvm::TimeTraceScope domScope("Dominator Tree Builder"); + if (!F.empty()) DT.recalculate(const_cast(F)); - } for (const BasicBlock &BB : F) { if (!BB.empty() && BB.back().isTerminator()) @@ -435,10 +433,7 @@ class Verifier : public InstVisitor, VerifierSupport { Broken = false; // FIXME: We strip const here because the inst visitor strips const. - { - llvm::TimeTraceScope domScope("Verifier visit"); - visit(const_cast(F)); - } + visit(const_cast(F)); verifySiblingFuncletUnwinds(); if (ConvergenceVerifyHelper.sawTokens()) @@ -2839,7 +2834,7 @@ static Instruction *getSuccPad(Instruction *Terminator) { } void Verifier::verifySiblingFuncletUnwinds() { - llvm::TimeTraceScope domScope("Verifier verify sibling funclet unwinds"); + llvm::TimeTraceScope timeTraceScope("Verifier verify sibling funclet unwinds"); SmallPtrSet Visited; SmallPtrSet Active; for (const auto &Pair : SiblingFuncletInfo) { From a4cf7ef61c110f14ad9d6564f82c9307b4d50e70 Mon Sep 17 00:00:00 2001 From: Alexandre Ganea Date: Wed, 3 Sep 2025 11:05:55 -0400 Subject: [PATCH 3/4] Fix tags + clang-format --- llvm/lib/IR/Verifier.cpp | 2 +- llvm/lib/LTO/LTO.cpp | 14 +++++++------- llvm/lib/LTO/LTOBackend.cpp | 2 +- llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp index 4729b36b94ab8..06ddb4574c860 100644 --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -2834,7 +2834,7 @@ static Instruction *getSuccPad(Instruction *Terminator) { } void Verifier::verifySiblingFuncletUnwinds() { - llvm::TimeTraceScope timeTraceScope("Verifier verify sibling funclet unwinds"); + llvm::TimeTraceScope timeScope("Verifier verify sibling funclet unwinds"); SmallPtrSet Visited; SmallPtrSet Active; for (const auto &Pair : SiblingFuncletInfo) { diff --git a/llvm/lib/LTO/LTO.cpp b/llvm/lib/LTO/LTO.cpp index 424c6e251fb8c..89192b39e811f 100644 --- a/llvm/lib/LTO/LTO.cpp +++ b/llvm/lib/LTO/LTO.cpp @@ -631,7 +631,7 @@ LTO::~LTO() = default; void LTO::addModuleToGlobalRes(ArrayRef Syms, ArrayRef Res, unsigned Partition, bool InSummary) { - llvm::TimeTraceScope importScope("LTO add module to global resolution"); + llvm::TimeTraceScope timeScope("LTO add module to global resolution"); auto *ResI = Res.begin(); auto *ResE = Res.end(); (void)ResE; @@ -732,7 +732,7 @@ static void writeToResolutionFile(raw_ostream &OS, InputFile *Input, Error LTO::add(std::unique_ptr Input, ArrayRef Res) { - llvm::TimeTraceScope importScope("LTO add input", Input->getName()); + llvm::TimeTraceScope timeScope("LTO add input", Input->getName()); assert(!CalledGetMaxTasks); if (Conf.ResolutionFile) @@ -758,7 +758,7 @@ Error LTO::add(std::unique_ptr Input, Expected> LTO::addModule(InputFile &Input, ArrayRef InputRes, unsigned ModI, ArrayRef Res) { - llvm::TimeTraceScope importScope("LTO add module", Input.getName()); + llvm::TimeTraceScope timeScope("LTO add module", Input.getName()); Expected LTOInfo = Input.Mods[ModI].getLTOInfo(); if (!LTOInfo) return LTOInfo.takeError(); @@ -853,7 +853,7 @@ Expected< LTO::addRegularLTO(InputFile &Input, ArrayRef InputRes, BitcodeModule BM, ArrayRef Syms, ArrayRef Res) { - llvm::TimeTraceScope importScope("LTO add regular LTO"); + llvm::TimeTraceScope timeScope("LTO add regular LTO"); RegularLTOState::AddedModule Mod; Expected> MOrErr = BM.getLazyModule(RegularLTO.Ctx, /*ShouldLazyLoadMetadata*/ true, @@ -1028,7 +1028,7 @@ LTO::addRegularLTO(InputFile &Input, ArrayRef InputRes, Error LTO::linkRegularLTO(RegularLTOState::AddedModule Mod, bool LivenessFromIndex) { - llvm::TimeTraceScope importScope("LTO link regular LTO"); + llvm::TimeTraceScope timeScope("LTO link regular LTO"); std::vector Keep; for (GlobalValue *GV : Mod.Keep) { if (LivenessFromIndex && !ThinLTO.CombinedIndex.isGUIDLive(GV->getGUID())) { @@ -1068,7 +1068,7 @@ Error LTO::linkRegularLTO(RegularLTOState::AddedModule Mod, Expected> LTO::addThinLTO(BitcodeModule BM, ArrayRef Syms, ArrayRef Res) { - llvm::TimeTraceScope importScope("LTO add thin LTO"); + llvm::TimeTraceScope timeScope("LTO add thin LTO"); ArrayRef ResTmp = Res; for (const InputFile::Symbol &Sym : Syms) { assert(!ResTmp.empty()); @@ -1258,7 +1258,7 @@ Error LTO::run(AddStreamFn AddStream, FileCache Cache) { void lto::updateMemProfAttributes(Module &Mod, const ModuleSummaryIndex &Index) { - llvm::TimeTraceScope importScope("LTO update memprof attributes"); + llvm::TimeTraceScope timeScope("LTO update memprof attributes"); if (Index.withSupportsHotColdNew()) return; diff --git a/llvm/lib/LTO/LTOBackend.cpp b/llvm/lib/LTO/LTOBackend.cpp index 402e4a5c6a8bd..ce42fc526beac 100644 --- a/llvm/lib/LTO/LTOBackend.cpp +++ b/llvm/lib/LTO/LTOBackend.cpp @@ -684,7 +684,7 @@ Error lto::thinBackend(const Config &Conf, unsigned Task, AddStreamFn AddStream, return finalizeOptimizationRemarks(std::move(DiagnosticOutputFile)); auto ModuleLoader = [&](StringRef Identifier) { - llvm::TimeTraceScope importScope("Module loader", Identifier); + llvm::TimeTraceScope moduleLoaderScope("Module loader", Identifier); assert(Mod.getContext().isODRUniquingDebugTypes() && "ODR Type uniquing should be enabled on the context"); if (ModuleMap) { diff --git a/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp b/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp index 402eeea0402f8..640e987d426d0 100644 --- a/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp +++ b/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp @@ -870,7 +870,7 @@ void llvm::updateVCallVisibilityInModule( void llvm::updatePublicTypeTestCalls(Module &M, bool WholeProgramVisibilityEnabledInLTO) { - llvm::TimeTraceScope importScope("Update public type test calls"); + llvm::TimeTraceScope timeScope("Update public type test calls"); Function *PublicTypeTestFunc = Intrinsic::getDeclarationIfExists(&M, Intrinsic::public_type_test); if (!PublicTypeTestFunc) From 13bf437e368b1f4eae576259dfd982d10d1efeac Mon Sep 17 00:00:00 2001 From: Alexandre Ganea Date: Wed, 3 Sep 2025 15:49:52 -0400 Subject: [PATCH 4/4] Adjust some tags following review --- lld/COFF/LTO.cpp | 2 ++ lld/COFF/SymbolTable.cpp | 2 -- llvm/lib/LTO/LTO.cpp | 10 ++++++++++ llvm/lib/Transforms/IPO/FunctionImport.cpp | 4 ++-- 4 files changed, 14 insertions(+), 4 deletions(-) diff --git a/lld/COFF/LTO.cpp b/lld/COFF/LTO.cpp index 1050874a1b10c..a988be610864a 100644 --- a/lld/COFF/LTO.cpp +++ b/lld/COFF/LTO.cpp @@ -26,6 +26,7 @@ #include "llvm/Support/Caching.h" #include "llvm/Support/CodeGen.h" #include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/TimeProfiler.h" #include "llvm/Support/raw_ostream.h" #include #include @@ -176,6 +177,7 @@ void BitcodeCompiler::add(BitcodeFile &f) { // Merge all the bitcode files we have seen, codegen the result // and return the resulting objects. std::vector BitcodeCompiler::compile() { + llvm::TimeTraceScope timeScope("Bitcode compile"); unsigned maxTasks = ltoObj->getMaxTasks(); buf.resize(maxTasks); files.resize(maxTasks); diff --git a/lld/COFF/SymbolTable.cpp b/lld/COFF/SymbolTable.cpp index 335f3d65a078f..26a2b4944dc6c 100644 --- a/lld/COFF/SymbolTable.cpp +++ b/lld/COFF/SymbolTable.cpp @@ -1437,7 +1437,6 @@ void SymbolTable::compileBitcodeFiles() { if (bitcodeFileInstances.empty()) return; - llvm::TimeTraceScope timeScope("Compile bitcode"); ScopedTimer t(ctx.ltoTimer); lto.reset(new BitcodeCompiler(ctx)); { @@ -1445,7 +1444,6 @@ void SymbolTable::compileBitcodeFiles() { for (BitcodeFile *f : bitcodeFileInstances) lto->add(*f); } - llvm::TimeTraceScope compileScope("LTO compile"); for (InputFile *newObj : lto->compile()) { ObjFile *obj = cast(newObj); obj->parse(); diff --git a/llvm/lib/LTO/LTO.cpp b/llvm/lib/LTO/LTO.cpp index 89192b39e811f..ce9ecc35e1922 100644 --- a/llvm/lib/LTO/LTO.cpp +++ b/llvm/lib/LTO/LTO.cpp @@ -1930,6 +1930,11 @@ Error LTO::runThinLTO(AddStreamFn AddStream, FileCache Cache, llvm::TimeTraceScope timeScope("Run ThinLTO"); LLVM_DEBUG(dbgs() << "Running ThinLTO\n"); ThinLTO.CombinedIndex.releaseTemporaryMemory(); + timeTraceProfilerBegin("ThinLink", StringRef("")); + auto TimeTraceScopeExit = llvm::make_scope_exit([]() { + if (llvm::timeTraceProfilerEnabled()) + llvm::timeTraceProfilerEnd(); + }); if (ThinLTO.ModuleMap.empty()) return Error::success(); @@ -2077,6 +2082,11 @@ Error LTO::runThinLTO(AddStreamFn AddStream, FileCache Cache, generateParamAccessSummary(ThinLTO.CombinedIndex); + if (llvm::timeTraceProfilerEnabled()) + llvm::timeTraceProfilerEnd(); + + TimeTraceScopeExit.release(); + auto &ModuleMap = ThinLTO.ModulesToCompile ? *ThinLTO.ModulesToCompile : ThinLTO.ModuleMap; diff --git a/llvm/lib/Transforms/IPO/FunctionImport.cpp b/llvm/lib/Transforms/IPO/FunctionImport.cpp index 96b274e2f45a9..83aa7de5400f5 100644 --- a/llvm/lib/Transforms/IPO/FunctionImport.cpp +++ b/llvm/lib/Transforms/IPO/FunctionImport.cpp @@ -1551,7 +1551,7 @@ void llvm::computeDeadSymbolsWithConstProp( const DenseSet &GUIDPreservedSymbols, function_ref isPrevailing, bool ImportEnabled) { - llvm::TimeTraceScope timeScope("Dead symbols"); + llvm::TimeTraceScope timeScope("Drop dead symbols and propagate attributes"); computeDeadSymbolsAndUpdateIndirectCalls(Index, GUIDPreservedSymbols, isPrevailing); if (ImportEnabled) @@ -1906,7 +1906,7 @@ Expected FunctionImporter::importFunctions( // Find the globals to import SetVector GlobalsToImport; { - llvm::TimeTraceScope findGlobalsScope("Find globals"); + llvm::TimeTraceScope functionsScope("Functions"); for (Function &F : *SrcModule) { if (!F.hasName()) continue;