Index: include/llvm/ADT/Statistic.h =================================================================== --- include/llvm/ADT/Statistic.h +++ include/llvm/ADT/Statistic.h @@ -25,6 +25,7 @@ #ifndef LLVM_ADT_STATISTIC_H #define LLVM_ADT_STATISTIC_H +#include "llvm/ADT/FunctionExtras.h" #include "llvm/Config/llvm-config.h" #include "llvm/Support/Compiler.h" #include @@ -174,10 +175,14 @@ /// Check if statistics are enabled. bool AreStatisticsEnabled(); -/// Return a file stream to print our output on. -std::unique_ptr CreateInfoOutputFile(); +/// Return a stream to print our output into. +std::unique_ptr getInfoOutputStream(); -/// Print statistics to the file returned by CreateInfoOutputFile(). +/// Set a callback that provides a stream for info-output +void setInfoOutputStreamProvider( + llvm::unique_function()> OStreamProvider); + +/// Print statistics to the stream returned by getInfoOutputStream(). void PrintStatistics(); /// Print statistics to the given output stream. Index: lib/IR/PassTimingInfo.cpp =================================================================== --- lib/IR/PassTimingInfo.cpp +++ lib/IR/PassTimingInfo.cpp @@ -111,7 +111,7 @@ } /// Prints out timing information and then resets the timers. -void PassTimingInfo::print() { TG.print(*CreateInfoOutputFile()); } +void PassTimingInfo::print() { TG.print(*getInfoOutputStream()); } Timer *PassTimingInfo::newPassTimer(StringRef PassID, StringRef PassDesc) { unsigned &num = PassIDCountMap[PassID]; @@ -181,7 +181,7 @@ TimePassesHandler::TimePassesHandler(bool Enabled) : TG("pass", "... Pass execution timing report ..."), Enabled(Enabled) {} -void TimePassesHandler::print() { TG.print(*CreateInfoOutputFile()); } +void TimePassesHandler::print() { TG.print(*getInfoOutputStream()); } LLVM_DUMP_METHOD void TimePassesHandler::dump() const { dbgs() << "Dumping timers for " << getTypeName() Index: lib/Support/Statistic.cpp =================================================================== --- lib/Support/Statistic.cpp +++ lib/Support/Statistic.cpp @@ -35,6 +35,20 @@ #include using namespace llvm; +// This ugly hack is brought to you courtesy of constructor/destructor ordering +// being unspecified by C++. Basically the problem is that a Statistic object +// gets destroyed, which ends up calling 'GetLibSupportInfoOutputFile()' +// (below), which calls this function. LibSupportInfoOutputFilename used to be +// a global variable, but sometimes it would get destroyed before the Statistic, +// causing havoc to ensue. We "fix" this by creating the string the first time +// it is needed and never destroying it. +static ManagedStatic LibSupportInfoOutputFilename; + +static cl::opt + InfoOutputFilename("info-output-file", cl::value_desc("filename"), + cl::desc("File to append -stats and -timer output to"), + cl::Hidden, cl::location(*LibSupportInfoOutputFilename)); + /// -stats - Command line option to cause transformations to emit stats about /// what they did. /// @@ -234,7 +248,7 @@ if (Stats.Stats.empty()) return; // Get the stream to write to. - std::unique_ptr OutStream = CreateInfoOutputFile(); + std::unique_ptr OutStream = getInfoOutputStream(); if (StatsAsJSON) PrintStatisticsJSON(*OutStream); else @@ -246,7 +260,7 @@ // do nothing, so stats are never Registered. if (Stats) { // Get the stream to write to. - std::unique_ptr OutStream = CreateInfoOutputFile(); + std::unique_ptr OutStream = getInfoOutputStream(); (*OutStream) << "Statistics are disabled. " << "Build with asserts or with -DLLVM_ENABLE_STATS\n"; } @@ -265,3 +279,49 @@ void llvm::ResetStatistics() { StatInfo->reset(); } + +namespace { + +std::unique_ptr createInfoOutputFile() { + std::string OutputFilename = *LibSupportInfoOutputFilename; + if (OutputFilename.empty()) + return llvm::make_unique(2, false); // stderr. + if (OutputFilename == "-") + return llvm::make_unique(1, false); // stdout. + + // Append mode is used because the info output file is opened and closed + // each time -stats or -time-passes wants to print output to it. To + // compensate for this, the test-suite Makefiles have code to delete the + // info output file before running commands which write to it. + std::error_code EC; + auto Result = llvm::make_unique( + OutputFilename, EC, sys::fs::F_Append | sys::fs::F_Text); + if (!EC) + return Result; + + errs() << "Error opening info-output-file '" << OutputFilename + << " for appending!\n"; + return llvm::make_unique(2, false); // stderr. +} + +static llvm::unique_function()> + InfoOStreamProvider; + +} // namespace + +void llvm::setInfoOutputStreamProvider( + llvm::unique_function()> + OStreamProvider) { + static sys::SmartMutex InfoOutputProviderMutex; + sys::SmartScopedLock Lock(InfoOutputProviderMutex); + InfoOStreamProvider = std::move(OStreamProvider); +} + +std::unique_ptr llvm::getInfoOutputStream() { + if (InfoOStreamProvider) { + std::unique_ptr CustomStream = InfoOStreamProvider(); + if (CustomStream) + return std::move(CustomStream); + } + return std::unique_ptr{createInfoOutputFile()}; +} Index: lib/Support/Timer.cpp =================================================================== --- lib/Support/Timer.cpp +++ lib/Support/Timer.cpp @@ -26,18 +26,6 @@ using namespace llvm; -// This ugly hack is brought to you courtesy of constructor/destructor ordering -// being unspecified by C++. Basically the problem is that a Statistic object -// gets destroyed, which ends up calling 'GetLibSupportInfoOutputFile()' -// (below), which calls this function. LibSupportInfoOutputFilename used to be -// a global variable, but sometimes it would get destroyed before the Statistic, -// causing havoc to ensue. We "fix" this by creating the string the first time -// it is needed and never destroying it. -static ManagedStatic LibSupportInfoOutputFilename; -static std::string &getLibSupportInfoOutputFilename() { - return *LibSupportInfoOutputFilename; -} - static ManagedStatic > TimerLock; /// Allows llvm::Timer to emit signposts when supported. @@ -49,32 +37,6 @@ "tracking (this may be slow)"), cl::Hidden); - static cl::opt - InfoOutputFilename("info-output-file", cl::value_desc("filename"), - cl::desc("File to append -stats and -timer output to"), - cl::Hidden, cl::location(getLibSupportInfoOutputFilename())); -} - -std::unique_ptr llvm::CreateInfoOutputFile() { - const std::string &OutputFilename = getLibSupportInfoOutputFilename(); - if (OutputFilename.empty()) - return llvm::make_unique(2, false); // stderr. - if (OutputFilename == "-") - return llvm::make_unique(1, false); // stdout. - - // Append mode is used because the info output file is opened and closed - // each time -stats or -time-passes wants to print output to it. To - // compensate for this, the test-suite Makefiles have code to delete the - // info output file before running commands which write to it. - std::error_code EC; - auto Result = llvm::make_unique( - OutputFilename, EC, sys::fs::F_Append | sys::fs::F_Text); - if (!EC) - return Result; - - errs() << "Error opening info-output-file '" - << OutputFilename << " for appending!\n"; - return llvm::make_unique(2, false); // stderr. } namespace { @@ -283,7 +245,7 @@ if (FirstTimer || TimersToPrint.empty()) return; - std::unique_ptr OutStream = CreateInfoOutputFile(); + std::unique_ptr OutStream = getInfoOutputStream(); PrintQueuedTimers(*OutStream); }