diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -530,17 +530,14 @@ } if (config->timeTraceEnabled) { - // Write the result of the time trace profiler. - std::string path = args.getLastArgValue(OPT_time_trace_file_eq).str(); - if (path.empty()) - path = (config->outputFile + ".time-trace").str(); - std::error_code ec; - raw_fd_ostream os(path, ec, sys::fs::OF_Text); - if (ec) { - error("cannot open " + path + ": " + ec.message()); + if (auto E = timeTraceProfilerWrite(args.getLastArgValue(OPT_time_trace_file_eq).str(), + config->outputFile)) { + handleAllErrors(std::move(E), [&](const StringError &SE) { + error(SE.getMessage()); + }); return; } - timeTraceProfilerWrite(os); + timeTraceProfilerCleanup(); } } diff --git a/llvm/include/llvm/Support/TimeProfiler.h b/llvm/include/llvm/Support/TimeProfiler.h --- a/llvm/include/llvm/Support/TimeProfiler.h +++ b/llvm/include/llvm/Support/TimeProfiler.h @@ -9,6 +9,7 @@ #ifndef LLVM_SUPPORT_TIME_PROFILER_H #define LLVM_SUPPORT_TIME_PROFILER_H +#include "llvm/Support/Error.h" #include "llvm/Support/raw_ostream.h" namespace llvm { @@ -33,11 +34,19 @@ return getTimeTraceProfilerInstance() != nullptr; } -/// Write profiling data to output file. +/// Write profiling data to output stream. /// Data produced is JSON, in Chrome "Trace Event" format, see /// https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview void timeTraceProfilerWrite(raw_pwrite_stream &OS); +/// Write profiling data to a file. +/// The function will write to \p PreferredFileName if provided, if not +/// then will write to \p FallbackFileName appending .time-trace. +/// Returns a StringError indicating a failure if the function is +/// unable to open the file for writing. +Error timeTraceProfilerWrite(StringRef PreferredFileName, + StringRef FallbackFileName); + /// Manually begin a time section, with the given \p Name and \p Detail. /// Profiler copies the string data, so the pointers can be given into /// temporaries. Time sections can be hierarchical; every Begin must have a diff --git a/llvm/lib/Support/TimeProfiler.cpp b/llvm/lib/Support/TimeProfiler.cpp --- a/llvm/lib/Support/TimeProfiler.cpp +++ b/llvm/lib/Support/TimeProfiler.cpp @@ -279,6 +279,26 @@ TimeTraceProfilerInstance->Write(OS); } +Error timeTraceProfilerWrite(StringRef PreferredFileName, + StringRef FallbackFileName) { + assert(TimeTraceProfilerInstance != nullptr && + "Profiler object can't be null"); + + std::string Path = PreferredFileName.str(); + if (Path.empty()) { + Path = FallbackFileName == "-" ? "out" : FallbackFileName.str(); + Path += ".time-trace"; + } + + std::error_code EC; + raw_fd_ostream OS(Path, EC, sys::fs::OF_Text); + if (EC) + return createStringError(EC, "Could not open " + Path); + + timeTraceProfilerWrite(OS); + return Error::success(); +} + void timeTraceProfilerBegin(StringRef Name, StringRef Detail) { if (TimeTraceProfilerInstance != nullptr) TimeTraceProfilerInstance->begin(std::string(Name),