diff --git a/clang-tools-extra/cpp11-migrate/tool/Cpp11Migrate.cpp b/clang-tools-extra/cpp11-migrate/tool/Cpp11Migrate.cpp index 88c1bfcca702..8e24b29ac0eb 100644 --- a/clang-tools-extra/cpp11-migrate/tool/Cpp11Migrate.cpp +++ b/clang-tools-extra/cpp11-migrate/tool/Cpp11Migrate.cpp @@ -24,7 +24,10 @@ #include "clang/Frontend/FrontendActions.h" #include "clang/Tooling/CommonOptionsParser.h" #include "clang/Tooling/Tooling.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/Process.h" #include "llvm/Support/Signals.h" +#include "llvm/Support/Timer.h" namespace cl = llvm::cl; using namespace clang::tooling; @@ -50,6 +53,12 @@ static cl::opt SummaryMode("summary", cl::desc("Print transform summary"), cl::init(false)); +const char NoTiming[] = "no_timing"; +static cl::opt TimingDirectoryName( + "report-times", cl::desc("Capture performance data and output to specified " + "directory. Default ./migrate_perf"), + cl::init(NoTiming), cl::ValueOptional, cl::value_desc("directory name")); + // TODO: Remove cl::Hidden when functionality for acknowledging include/exclude // options are implemented in the tool. static cl::opt @@ -78,6 +87,60 @@ class EndSyntaxArgumentsAdjuster : public ArgumentsAdjuster { } }; +struct ExecutionTime { + std::string TimerId; + float Time; + ExecutionTime(const std::string &TimerId, float Time) + : TimerId(TimerId), Time(Time) {} +}; + +// Save execution times to a json formatted file. +void reportExecutionTimes( + const llvm::StringRef DirectoryName, + const std::map > &TimingResults) { + // Create directory path if it doesn't exist + llvm::sys::Path P(DirectoryName); + P.createDirectoryOnDisk(true); + + // Get PID and current time. + llvm::sys::self_process *SP = llvm::sys::process::get_self(); + unsigned Pid = SP->get_id(); + llvm::TimeRecord T = llvm::TimeRecord::getCurrentTime(); + + std::string FileName; + llvm::raw_string_ostream SS(FileName); + SS << P.str() << "/" << static_cast(T.getWallTime()) << Pid << ".json"; + + + std::string ErrorInfo; + llvm::raw_fd_ostream FileStream(SS.str().c_str(), ErrorInfo); + FileStream << "{\n"; + FileStream << " \"Sources\" : [\n"; + for (std::map >::const_iterator + I = TimingResults.begin(), + E = TimingResults.end(); + I != E; ++I) { + FileStream << " {\n"; + FileStream << " \"Source \" : \"" << I->first << "\",\n"; + FileStream << " \"Data\" : [\n"; + for (std::vector::const_iterator IE = I->second.begin(), + EE = I->second.end(); + IE != EE; ++IE) { + FileStream << " {\n"; + FileStream << " \"TimerId\" : \"" << (*IE).TimerId << "\",\n"; + FileStream << " \"Time\" : " << llvm::format("%6.2f", (*IE).Time) + << "\n"; + + FileStream << " },\n"; + + } + FileStream << " ]\n"; + FileStream << " },\n"; + } + FileStream << " ]\n"; + FileStream << "}"; +} + int main(int argc, const char **argv) { llvm::sys::PrintStackTraceOnErrorSignal(); Transforms TransformManager; @@ -99,7 +162,12 @@ int main(int argc, const char **argv) { // This causes options to be parsed. CommonOptionsParser OptionsParser(argc, argv); - TransformManager.createSelectedTransforms(/*EnableTiming=*/false); + // Since ExecutionTimeDirectoryName could be an empty string we compare + // against the default value when the command line option is not specified. + bool EnableTiming = (TimingDirectoryName != NoTiming); + std::map > TimingResults; + + TransformManager.createSelectedTransforms(EnableTiming); if (TransformManager.begin() == TransformManager.end()) { llvm::errs() << "No selected transforms\n"; @@ -167,5 +235,14 @@ int main(int argc, const char **argv) { FileStream << I->second; } + // Report execution times. + if (EnableTiming && TimingResults.size() > 0) { + std::string DirectoryName = TimingDirectoryName; + // Use default directory name. + if (DirectoryName == "") + DirectoryName = "./migrate_perf"; + reportExecutionTimes(DirectoryName, TimingResults); + } + return 0; }