diff --git a/llvm/lib/LTO/LTO.cpp b/llvm/lib/LTO/LTO.cpp index 36360081fa4a..e451b6d8c263 100644 --- a/llvm/lib/LTO/LTO.cpp +++ b/llvm/lib/LTO/LTO.cpp @@ -43,6 +43,7 @@ #include "llvm/Support/Error.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/JSON.h" +#include "llvm/Support/ManagedStatic.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" #include "llvm/Support/Process.h" @@ -2321,6 +2322,45 @@ std::vector lto::generateModulesOrdering(ArrayRef R) { } namespace { +// There can be many temporary files to remove. Performing deletion in +// the background can save a few seconds on Windows hosts. Experimentation +// showed that serial deletion is most efficient, hence a single thread. +struct BackgroundDeletion : llvm::DefaultThreadPool { + BackgroundDeletion() + : llvm::DefaultThreadPool(llvm::heavyweight_hardware_concurrency(1)) {} + + ~BackgroundDeletion() { + wait(); + for (const std::string &Warning : Warnings) + errs() << "warning: could not remove the file " << Warning << "\n"; + } + + void remove(SmallVector &&Files, const Config &Conf) { + async([this, Files = std::move(Files), TTE = Conf.TimeTraceEnabled, + TTG = Conf.TimeTraceGranularity] { + if (LLVM_ENABLE_THREADS && TTE) + timeTraceProfilerInitialize(TTG, "Remove DTLTO temporary files"); + { + llvm::TimeTraceScope TimeScope("Remove DTLTO temporary files"); + for (const auto &F : Files) { + std::error_code EC = sys::fs::remove(F, true); + if (EC && + EC != std::make_error_code(std::errc::no_such_file_or_directory)) + Warnings.emplace_back("'" + F + "': " + EC.message()); + } + } + if (LLVM_ENABLE_THREADS && TTE) + timeTraceProfilerFinishThread(); + }); + } + + SmallVector Warnings; +}; + +// Use a ManagedStatic to allow the thread to run until llvm_shutdown() is +// called for the current process. +static llvm::ManagedStatic BackgroundDeleter; + /// This out-of-process backend does not perform code generation when invoked /// for each task. Instead, it generates the necessary information (e.g., the /// summary index shard, import list, etc.) to enable code generation to be @@ -2653,13 +2693,15 @@ public: return std::move(*Err); llvm::scope_exit CleanPerJobFiles([&] { - llvm::TimeTraceScope TimeScope("Remove DTLTO temporary files"); - if (!SaveTemps) - for (auto &Job : Jobs) { - removeFile(Job.NativeObjectPath); - if (!ShouldEmitIndexFiles) - removeFile(Job.SummaryIndexPath); - } + if (SaveTemps) + return; + SmallVector Files; + for (auto &Job : Jobs) { + Files.push_back(std::string(Job.NativeObjectPath)); + if (!ShouldEmitIndexFiles) + Files.push_back(std::string(Job.SummaryIndexPath)); + } + BackgroundDeleter->remove(std::move(Files), Conf); }); const StringRef BCError = "DTLTO backend compilation: "; diff --git a/llvm/tools/llvm-lto2/llvm-lto2.cpp b/llvm/tools/llvm-lto2/llvm-lto2.cpp index 95e8053dab32..69020b71f429 100644 --- a/llvm/tools/llvm-lto2/llvm-lto2.cpp +++ b/llvm/tools/llvm-lto2/llvm-lto2.cpp @@ -26,6 +26,7 @@ #include "llvm/Support/CommandLine.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/InitLLVM.h" +#include "llvm/Support/ManagedStatic.h" #include "llvm/Support/PluginLoader.h" #include "llvm/Support/TargetSelect.h" #include "llvm/Support/Threading.h" @@ -284,7 +285,11 @@ static int run(int argc, char **argv) { if (TimeTrace) timeTraceProfilerInitialize(TimeTraceGranularity, argv[0]); - llvm::scope_exit TimeTraceScopeExit([]() { + llvm::scope_exit ShutdownScopeExit([]() { + // llvm_shutdown must be called before finalizing the time trace to + // ensure that time trace scopes from ManagedStatic destructors are + // flushed and recorded. + llvm::llvm_shutdown(); if (TimeTrace) { check(timeTraceProfilerWrite(TimeTraceFile, OutputFilename), "timeTraceProfilerWrite failed");