https://github.com/ilovepi created https://github.com/llvm/llvm-project/pull/141139
This patch re-enables -ftime-trace support in clang-doc. Initial support in #97644 was reverted, and never relanded. This patch adds back the command line option, and leverages the RAII tracing infrastructure more thoroughly. >From 7ac1e0572340ed698f142544057b19be07f192a8 Mon Sep 17 00:00:00 2001 From: Paul Kirth <paulki...@google.com> Date: Wed, 21 May 2025 09:50:32 -0700 Subject: [PATCH] [clang-doc] Reenable time trace support This patch re-enables -ftime-trace support in clang-doc. Initial support in #97644 was reverted, and never relanded. This patch adds back the command line option, and leverages the RAII tracing infrastructure more thoroughly. --- clang-tools-extra/clang-doc/BitcodeReader.cpp | 8 + .../clang-doc/HTMLMustacheGenerator.cpp | 33 +- clang-tools-extra/clang-doc/Mapper.cpp | 84 +++-- .../clang-doc/Representation.cpp | 6 +- clang-tools-extra/clang-doc/Representation.h | 5 +- .../clang-doc/tool/ClangDocMain.cpp | 295 +++++++++++------- 6 files changed, 268 insertions(+), 163 deletions(-) diff --git a/clang-tools-extra/clang-doc/BitcodeReader.cpp b/clang-tools-extra/clang-doc/BitcodeReader.cpp index f8e338eb7c6ed..546dd0254ec01 100644 --- a/clang-tools-extra/clang-doc/BitcodeReader.cpp +++ b/clang-tools-extra/clang-doc/BitcodeReader.cpp @@ -9,6 +9,7 @@ #include "BitcodeReader.h" #include "llvm/ADT/IndexedMap.h" #include "llvm/Support/Error.h" +#include "llvm/Support/TimeProfiler.h" #include "llvm/Support/raw_ostream.h" #include <optional> @@ -672,6 +673,7 @@ llvm::Error ClangDocBitcodeReader::readRecord(unsigned ID, T I) { template <> llvm::Error ClangDocBitcodeReader::readRecord(unsigned ID, Reference *I) { + llvm::TimeTraceScope("Reducing infos", "readRecord"); Record R; llvm::StringRef Blob; llvm::Expected<unsigned> MaybeRecID = Stream.readRecord(ID, R, &Blob); @@ -683,6 +685,7 @@ llvm::Error ClangDocBitcodeReader::readRecord(unsigned ID, Reference *I) { // Read a block of records into a single info. template <typename T> llvm::Error ClangDocBitcodeReader::readBlock(unsigned ID, T I) { + llvm::TimeTraceScope("Reducing infos", "readBlock"); if (llvm::Error Err = Stream.EnterSubBlock(ID)) return Err; @@ -713,6 +716,7 @@ llvm::Error ClangDocBitcodeReader::readBlock(unsigned ID, T I) { template <typename T> llvm::Error ClangDocBitcodeReader::readSubBlock(unsigned ID, T I) { + llvm::TimeTraceScope("Reducing infos", "readSubBlock"); switch (ID) { // Blocks can only have certain types of sub blocks. case BI_COMMENT_BLOCK_ID: { @@ -819,6 +823,7 @@ llvm::Error ClangDocBitcodeReader::readSubBlock(unsigned ID, T I) { ClangDocBitcodeReader::Cursor ClangDocBitcodeReader::skipUntilRecordOrBlock(unsigned &BlockOrRecordID) { + llvm::TimeTraceScope("Reducing infos", "skipUntilRecordOrBlock"); BlockOrRecordID = 0; while (!Stream.AtEndOfStream()) { @@ -880,6 +885,7 @@ llvm::Error ClangDocBitcodeReader::validateStream() { } llvm::Error ClangDocBitcodeReader::readBlockInfoBlock() { + llvm::TimeTraceScope("Reducing infos", "readBlockInfoBlock"); Expected<std::optional<llvm::BitstreamBlockInfo>> MaybeBlockInfo = Stream.ReadBlockInfoBlock(); if (!MaybeBlockInfo) @@ -895,6 +901,7 @@ llvm::Error ClangDocBitcodeReader::readBlockInfoBlock() { template <typename T> llvm::Expected<std::unique_ptr<Info>> ClangDocBitcodeReader::createInfo(unsigned ID) { + llvm::TimeTraceScope("Reducing infos", "createInfo"); std::unique_ptr<Info> I = std::make_unique<T>(); if (auto Err = readBlock(ID, static_cast<T *>(I.get()))) return std::move(Err); @@ -903,6 +910,7 @@ ClangDocBitcodeReader::createInfo(unsigned ID) { llvm::Expected<std::unique_ptr<Info>> ClangDocBitcodeReader::readBlockToInfo(unsigned ID) { + llvm::TimeTraceScope("Reducing infos", "readBlockToInfo"); switch (ID) { case BI_NAMESPACE_BLOCK_ID: return createInfo<NamespaceInfo>(ID); diff --git a/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp b/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp index 366deb55b77b9..e34e1d052f197 100644 --- a/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp +++ b/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp @@ -18,6 +18,8 @@ #include "llvm/Support/Error.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Mustache.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/TimeProfiler.h" using namespace llvm; using namespace llvm::json; @@ -81,13 +83,18 @@ static Error setupTemplateFiles(const clang::doc::ClangDocContext &CDCtx) { Error MustacheHTMLGenerator::generateDocs( StringRef RootDir, StringMap<std::unique_ptr<doc::Info>> Infos, const clang::doc::ClangDocContext &CDCtx) { - if (auto Err = setupTemplateFiles(CDCtx)) - return Err; + { + llvm::TimeTraceScope TS("Setup Templates"); + if (auto Err = setupTemplateFiles(CDCtx)) + return Err; + } + // Track which directories we already tried to create. StringSet<> CreatedDirs; // Collect all output by file name and create the necessary directories. StringMap<std::vector<doc::Info *>> FileToInfos; for (const auto &Group : Infos) { + llvm::TimeTraceScope TS("setup directories"); doc::Info *Info = Group.getValue().get(); SmallString<128> Path; @@ -104,15 +111,19 @@ Error MustacheHTMLGenerator::generateDocs( FileToInfos[Path].push_back(Info); } - for (const auto &Group : FileToInfos) { - std::error_code FileErr; - raw_fd_ostream InfoOS(Group.getKey(), FileErr, sys::fs::OF_None); - if (FileErr) - return createFileOpenError(Group.getKey(), FileErr); - - for (const auto &Info : Group.getValue()) - if (Error Err = generateDocForInfo(Info, InfoOS, CDCtx)) - return Err; + { + llvm::TimeTraceScope TS("Generate Docs"); + for (const auto &Group : FileToInfos) { + llvm::TimeTraceScope TS("Info to Doc"); + std::error_code FileErr; + raw_fd_ostream InfoOS(Group.getKey(), FileErr, sys::fs::OF_None); + if (FileErr) + return createFileOpenError(Group.getKey(), FileErr); + + for (const auto &Info : Group.getValue()) + if (Error Err = generateDocForInfo(Info, InfoOS, CDCtx)) + return Err; + } } return Error::success(); } diff --git a/clang-tools-extra/clang-doc/Mapper.cpp b/clang-tools-extra/clang-doc/Mapper.cpp index a17645c3f3a31..bbc8dc54ed4a3 100644 --- a/clang-tools-extra/clang-doc/Mapper.cpp +++ b/clang-tools-extra/clang-doc/Mapper.cpp @@ -13,7 +13,9 @@ #include "clang/Index/USRGeneration.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringSet.h" +#include "llvm/Support/Error.h" #include "llvm/Support/Mutex.h" +#include "llvm/Support/TimeProfiler.h" namespace clang { namespace doc { @@ -40,48 +42,66 @@ Location MapASTVisitor::getDeclLocation(const NamedDecl *D) const { } void MapASTVisitor::HandleTranslationUnit(ASTContext &Context) { + if (CDCtx.FTimeTrace) + llvm::timeTraceProfilerInitialize(200, "clang-doc"); TraverseDecl(Context.getTranslationUnitDecl()); + if (CDCtx.FTimeTrace) + llvm::timeTraceProfilerFinishThread(); } template <typename T> bool MapASTVisitor::mapDecl(const T *D, bool IsDefinition) { - // If we're looking a decl not in user files, skip this decl. - if (D->getASTContext().getSourceManager().isInSystemHeader(D->getLocation())) - return true; + llvm::TimeTraceScope TS("Mapping declaration"); + { + llvm::TimeTraceScope TS("Preamble"); + // If we're looking a decl not in user files, skip this decl. + if (D->getASTContext().getSourceManager().isInSystemHeader( + D->getLocation())) + return true; - // Skip function-internal decls. - if (D->getParentFunctionOrMethod()) - return true; + // Skip function-internal decls. + if (D->getParentFunctionOrMethod()) + return true; + } + + std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>> CP; - llvm::SmallString<128> USR; - // If there is an error generating a USR for the decl, skip this decl. - if (index::generateUSRForDecl(D, USR)) - return true; - // Prevent Visiting USR twice { - llvm::sys::SmartScopedLock<true> Guard(USRVisitedGuard); - StringRef Visited = USR.str(); - if (USRVisited.count(Visited) && !isTypedefAnonRecord<T>(D)) + llvm::TimeTraceScope TS("emit info from astnode"); + llvm::SmallString<128> USR; + // If there is an error generating a USR for the decl, skip this decl. + if (index::generateUSRForDecl(D, USR)) return true; - // We considered a USR to be visited only when its defined - if (IsDefinition) - USRVisited.insert(Visited); + // Prevent Visiting USR twice + { + llvm::sys::SmartScopedLock<true> Guard(USRVisitedGuard); + StringRef Visited = USR.str(); + if (USRVisited.count(Visited) && !isTypedefAnonRecord<T>(D)) + return true; + // We considered a USR to be visited only when its defined + if (IsDefinition) + USRVisited.insert(Visited); + } + bool IsFileInRootDir; + llvm::SmallString<128> File = + getFile(D, D->getASTContext(), CDCtx.SourceRoot, IsFileInRootDir); + CP = serialize::emitInfo(D, getComment(D, D->getASTContext()), + getDeclLocation(D), CDCtx.PublicOnly); + } + + auto &[Child, Parent] = CP; + + { + llvm::TimeTraceScope TS("serialized info into bitcode"); + // A null in place of a valid Info indicates that the serializer is skipping + // this decl for some reason (e.g. we're only reporting public decls). + if (Child) + CDCtx.ECtx->reportResult(llvm::toHex(llvm::toStringRef(Child->USR)), + serialize::serialize(Child)); + if (Parent) + CDCtx.ECtx->reportResult(llvm::toHex(llvm::toStringRef(Parent->USR)), + serialize::serialize(Parent)); } - bool IsFileInRootDir; - llvm::SmallString<128> File = - getFile(D, D->getASTContext(), CDCtx.SourceRoot, IsFileInRootDir); - auto [Child, Parent] = - serialize::emitInfo(D, getComment(D, D->getASTContext()), - getDeclLocation(D), CDCtx.PublicOnly); - - // A null in place of a valid Info indicates that the serializer is skipping - // this decl for some reason (e.g. we're only reporting public decls). - if (Child) - CDCtx.ECtx->reportResult(llvm::toHex(llvm::toStringRef(Child->USR)), - serialize::serialize(Child)); - if (Parent) - CDCtx.ECtx->reportResult(llvm::toHex(llvm::toStringRef(Parent->USR)), - serialize::serialize(Parent)); return true; } diff --git a/clang-tools-extra/clang-doc/Representation.cpp b/clang-tools-extra/clang-doc/Representation.cpp index 9ab2f342d969a..ad93ed66b86a1 100644 --- a/clang-tools-extra/clang-doc/Representation.cpp +++ b/clang-tools-extra/clang-doc/Representation.cpp @@ -369,9 +369,11 @@ ClangDocContext::ClangDocContext(tooling::ExecutionContext *ECtx, StringRef OutDirectory, StringRef SourceRoot, StringRef RepositoryUrl, StringRef RepositoryLinePrefix, StringRef Base, - std::vector<std::string> UserStylesheets) + std::vector<std::string> UserStylesheets, + bool FTimeTrace) : ECtx(ECtx), ProjectName(ProjectName), PublicOnly(PublicOnly), - OutDirectory(OutDirectory), UserStylesheets(UserStylesheets), Base(Base) { + FTimeTrace(FTimeTrace), OutDirectory(OutDirectory), + UserStylesheets(UserStylesheets), Base(Base) { llvm::SmallString<128> SourceRootDir(SourceRoot); if (SourceRoot.empty()) // If no SourceRoot was provided the current path is used as the default diff --git a/clang-tools-extra/clang-doc/Representation.h b/clang-tools-extra/clang-doc/Representation.h index a2e01719eb59e..e7c67574da1e4 100644 --- a/clang-tools-extra/clang-doc/Representation.h +++ b/clang-tools-extra/clang-doc/Representation.h @@ -518,10 +518,13 @@ struct ClangDocContext { ClangDocContext(tooling::ExecutionContext *ECtx, StringRef ProjectName, bool PublicOnly, StringRef OutDirectory, StringRef SourceRoot, StringRef RepositoryUrl, StringRef RepositoryCodeLinePrefix, - StringRef Base, std::vector<std::string> UserStylesheets); + StringRef Base, std::vector<std::string> UserStylesheets, + bool FTimeTrace = false); tooling::ExecutionContext *ECtx; std::string ProjectName; // Name of project clang-doc is documenting. bool PublicOnly; // Indicates if only public declarations are documented. + bool FTimeTrace; // Indicates if ftime trace is turned on + int Granularity; // Granularity of ftime trace std::string OutDirectory; // Directory for outputting generated files. std::string SourceRoot; // Directory where processed files are stored. Links // to definition locations will only be generated if diff --git a/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp b/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp index 8e8f7053a8f87..a205c8f031cfe 100644 --- a/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp +++ b/clang-tools-extra/clang-doc/tool/ClangDocMain.cpp @@ -41,6 +41,7 @@ #include "llvm/Support/Process.h" #include "llvm/Support/Signals.h" #include "llvm/Support/ThreadPool.h" +#include "llvm/Support/TimeProfiler.h" #include "llvm/Support/raw_ostream.h" #include <atomic> #include <mutex> @@ -110,6 +111,11 @@ static llvm::cl::opt<std::string> RepositoryCodeLinePrefix( llvm::cl::desc("Prefix of line code for repository."), llvm::cl::cat(ClangDocCategory)); +static llvm::cl::opt<bool> FTimeTrace("ftime-trace", llvm::cl::desc(R"( +Turn on time profiler. Generates clang-doc-tracing.json)"), + llvm::cl::init(false), + llvm::cl::cat(ClangDocCategory)); + enum OutputFormatTy { md, yaml, @@ -256,140 +262,195 @@ Example usage for a project using a compile commands database: return 1; } - // Fail early if an invalid format was provided. - std::string Format = getFormatString(); - llvm::outs() << "Emiting docs in " << Format << " format.\n"; - auto G = doc::findGeneratorByName(Format); - if (!G) { - llvm::errs() << toString(G.takeError()) << "\n"; - return 1; - } - - ArgumentsAdjuster ArgAdjuster; - if (!DoxygenOnly) - ArgAdjuster = combineAdjusters( - getInsertArgumentAdjuster("-fparse-all-comments", - tooling::ArgumentInsertPosition::END), - ArgAdjuster); - - clang::doc::ClangDocContext CDCtx = { - Executor->get()->getExecutionContext(), - ProjectName, - PublicOnly, - OutDirectory, - SourceRoot, - RepositoryUrl, - RepositoryCodeLinePrefix, - BaseDirectory, - {UserStylesheets.begin(), UserStylesheets.end()}}; - - if (Format == "html") { - if (auto Err = getHtmlAssetFiles(argv[0], CDCtx)) { - llvm::errs() << toString(std::move(Err)) << "\n"; + // turns on ftime trace profiling + if (FTimeTrace) + llvm::timeTraceProfilerInitialize(200, "clang-doc"); + { + llvm::TimeTraceScope("main"); + + // Fail early if an invalid format was provided. + std::string Format = getFormatString(); + llvm::outs() << "Emiting docs in " << Format << " format.\n"; + auto G = doc::findGeneratorByName(Format); + if (!G) { + llvm::errs() << toString(G.takeError()) << "\n"; return 1; } - } - // Mapping phase - llvm::outs() << "Mapping decls...\n"; - auto Err = - Executor->get()->execute(doc::newMapperActionFactory(CDCtx), ArgAdjuster); - if (Err) { - if (IgnoreMappingFailures) - llvm::errs() << "Error mapping decls in files. Clang-doc will ignore " - "these files and continue:\n" - << toString(std::move(Err)) << "\n"; - else { - llvm::errs() << toString(std::move(Err)) << "\n"; - return 1; + ArgumentsAdjuster ArgAdjuster; + if (!DoxygenOnly) + ArgAdjuster = combineAdjusters( + getInsertArgumentAdjuster("-fparse-all-comments", + tooling::ArgumentInsertPosition::END), + ArgAdjuster); + + clang::doc::ClangDocContext CDCtx = { + Executor->get()->getExecutionContext(), + ProjectName, + PublicOnly, + OutDirectory, + SourceRoot, + RepositoryUrl, + RepositoryCodeLinePrefix, + BaseDirectory, + {UserStylesheets.begin(), UserStylesheets.end()}, + FTimeTrace}; + + if (Format == "html") { + if (auto Err = getHtmlAssetFiles(argv[0], CDCtx)) { + llvm::errs() << toString(std::move(Err)) << "\n"; + return 1; + } } - } - // Collect values into output by key. - // In ToolResults, the Key is the hashed USR and the value is the - // bitcode-encoded representation of the Info object. - llvm::outs() << "Collecting infos...\n"; - llvm::StringMap<std::vector<StringRef>> USRToBitcode; - Executor->get()->getToolResults()->forEachResult( - [&](StringRef Key, StringRef Value) { - USRToBitcode[Key].emplace_back(Value); - }); - - // Collects all Infos according to their unique USR value. This map is added - // to from the thread pool below and is protected by the USRToInfoMutex. - llvm::sys::Mutex USRToInfoMutex; - llvm::StringMap<std::unique_ptr<doc::Info>> USRToInfo; - - // First reducing phase (reduce all decls into one info per decl). - llvm::outs() << "Reducing " << USRToBitcode.size() << " infos...\n"; - std::atomic<bool> Error; - Error = false; - llvm::sys::Mutex IndexMutex; - // ExecutorConcurrency is a flag exposed by AllTUsExecution.h - llvm::DefaultThreadPool Pool(llvm::hardware_concurrency(ExecutorConcurrency)); - for (auto &Group : USRToBitcode) { - Pool.async([&]() { - std::vector<std::unique_ptr<doc::Info>> Infos; - for (auto &Bitcode : Group.getValue()) { - llvm::BitstreamCursor Stream(Bitcode); - doc::ClangDocBitcodeReader Reader(Stream); - auto ReadInfos = Reader.readBitcode(); - if (!ReadInfos) { - llvm::errs() << toString(ReadInfos.takeError()) << "\n"; - Error = true; - return; - } - std::move(ReadInfos->begin(), ReadInfos->end(), - std::back_inserter(Infos)); + if (Format == "mustache") { + if (auto Err = getMustacheHtmlFiles(argv[0], CDCtx)) { + llvm::errs() << toString(std::move(Err)) << "\n"; + return 1; } + } - auto Reduced = doc::mergeInfos(Infos); - if (!Reduced) { - llvm::errs() << llvm::toString(Reduced.takeError()); - return; + llvm::timeTraceProfilerBegin("Executor Launch", "total runtime"); + // Mapping phase + llvm::outs() << "Mapping decls...\n"; + auto Err = Executor->get()->execute(doc::newMapperActionFactory(CDCtx), + ArgAdjuster); + llvm::timeTraceProfilerEnd(); + if (Err) { + if (IgnoreMappingFailures) + llvm::errs() << "Error mapping decls in files. Clang-doc will ignore " + "these files and continue:\n" + << toString(std::move(Err)) << "\n"; + else { + llvm::errs() << toString(std::move(Err)) << "\n"; + return 1; } + } - // Add a reference to this Info in the Index - { - std::lock_guard<llvm::sys::Mutex> Guard(IndexMutex); - clang::doc::Generator::addInfoToIndex(CDCtx.Idx, Reduced.get().get()); + // Collect values into output by key. + // In ToolResults, the Key is the hashed USR and the value is the + // bitcode-encoded representation of the Info object. + llvm::timeTraceProfilerBegin("Collect Info", "total runtime"); + llvm::outs() << "Collecting infos...\n"; + llvm::StringMap<std::vector<StringRef>> USRToBitcode; + Executor->get()->getToolResults()->forEachResult( + [&](StringRef Key, StringRef Value) { + USRToBitcode[Key].emplace_back(Value); + }); + llvm::timeTraceProfilerEnd(); + + // Collects all Infos according to their unique USR value. This map is added + // to from the thread pool below and is protected by the USRToInfoMutex. + llvm::sys::Mutex USRToInfoMutex; + llvm::StringMap<std::unique_ptr<doc::Info>> USRToInfo; + + // First reducing phase (reduce all decls into one info per decl). + llvm::outs() << "Reducing " << USRToBitcode.size() << " infos...\n"; + std::atomic<bool> Error; + Error = false; + llvm::sys::Mutex IndexMutex; + // ExecutorConcurrency is a flag exposed by AllTUsExecution.h + llvm::DefaultThreadPool Pool( + llvm::hardware_concurrency(ExecutorConcurrency)); + { + llvm::TimeTraceScope TS("Reduce"); + for (auto &Group : USRToBitcode) { + Pool.async([&]() { + if (FTimeTrace) + llvm::timeTraceProfilerInitialize(200, "clang-doc"); + + std::vector<std::unique_ptr<doc::Info>> Infos; + { + llvm::TimeTraceScope Red("decoding bitcode"); + for (auto &Bitcode : Group.getValue()) { + llvm::BitstreamCursor Stream(Bitcode); + doc::ClangDocBitcodeReader Reader(Stream); + auto ReadInfos = Reader.readBitcode(); + if (!ReadInfos) { + llvm::errs() << toString(ReadInfos.takeError()) << "\n"; + Error = true; + return; + } + std::move(ReadInfos->begin(), ReadInfos->end(), + std::back_inserter(Infos)); + } + } + + std::unique_ptr<doc::Info> Reduced; + + { + llvm::TimeTraceScope Merge("merging bitcode"); + auto ExpReduced = doc::mergeInfos(Infos); + + if (!ExpReduced) { + llvm::errs() << llvm::toString(ExpReduced.takeError()); + return; + } + Reduced = std::move(*ExpReduced); + } + + // Add a reference to this Info in the Index + { + llvm::TimeTraceScope Merge("addInfoToIndex"); + std::lock_guard<llvm::sys::Mutex> Guard(IndexMutex); + clang::doc::Generator::addInfoToIndex(CDCtx.Idx, Reduced.get()); + } + // Save in the result map (needs a lock due to threaded access). + + { + llvm::TimeTraceScope Merge("USRToInfo"); + std::lock_guard<llvm::sys::Mutex> Guard(USRToInfoMutex); + USRToInfo[Group.getKey()] = std::move(Reduced); + } + + if (CDCtx.FTimeTrace) + llvm::timeTraceProfilerFinishThread(); + }); } - // Save in the result map (needs a lock due to threaded access). - { - std::lock_guard<llvm::sys::Mutex> Guard(USRToInfoMutex); - USRToInfo[Group.getKey()] = std::move(Reduced.get()); - } - }); - } + Pool.wait(); + } - Pool.wait(); + if (Error) + return 1; - if (Error) - return 1; + { + llvm::TimeTraceScope Sort("Sort USRToInfo"); + sortUsrToInfo(USRToInfo); + } - sortUsrToInfo(USRToInfo); + llvm::timeTraceProfilerBegin("Writing output", "total runtime"); + // Ensure the root output directory exists. + if (std::error_code Err = llvm::sys::fs::create_directories(OutDirectory); + Err != std::error_code()) { + llvm::errs() << "Failed to create directory '" << OutDirectory << "'\n"; + return 1; + } - // Ensure the root output directory exists. - if (std::error_code Err = llvm::sys::fs::create_directories(OutDirectory); - Err != std::error_code()) { - llvm::errs() << "Failed to create directory '" << OutDirectory << "'\n"; - return 1; - } + // Run the generator. + llvm::outs() << "Generating docs...\n"; + if (auto Err = + G->get()->generateDocs(OutDirectory, std::move(USRToInfo), CDCtx)) { + llvm::errs() << toString(std::move(Err)) << "\n"; + return 1; + } - // Run the generator. - llvm::outs() << "Generating docs...\n"; - if (auto Err = - G->get()->generateDocs(OutDirectory, std::move(USRToInfo), CDCtx)) { - llvm::errs() << toString(std::move(Err)) << "\n"; - return 1; + llvm::outs() << "Generating assets for docs...\n"; + Err = G->get()->createResources(CDCtx); + if (Err) { + llvm::outs() << "warning: " << toString(std::move(Err)) << "\n"; + } + llvm::timeTraceProfilerEnd(); } - - llvm::outs() << "Generating assets for docs...\n"; - Err = G->get()->createResources(CDCtx); - if (Err) { - llvm::outs() << "warning: " << toString(std::move(Err)) << "\n"; + if (FTimeTrace) { + std::error_code EC; + llvm::raw_fd_ostream OS("clang-doc-tracing.json", EC, + llvm::sys::fs::OF_Text); + if (!EC) { + llvm::timeTraceProfilerWrite(OS); + llvm::timeTraceProfilerCleanup(); + } else + return 1; } - return 0; } _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits