diff --git a/src/AnalysisExporter/FileCompilations/FileCompilationsExporter.cpp b/src/AnalysisExporter/FileCompilations/FileCompilationsExporter.cpp index 30b8128..dd8ff38 100644 --- a/src/AnalysisExporter/FileCompilations/FileCompilationsExporter.cpp +++ b/src/AnalysisExporter/FileCompilations/FileCompilationsExporter.cpp @@ -2,6 +2,7 @@ #include #include +#include FileCompilationsExporter::FileCompilationsExporter(const TFileCompilationDataPerFile& data) : m_data(data) @@ -12,6 +13,7 @@ FileCompilationsExporter::~FileCompilationsExporter() { } +template bool FileCompilationsExporter::ExportTo(const std::string& path) const { std::ofstream out(path); @@ -37,23 +39,46 @@ bool FileCompilationsExporter::ExportTo(const std::string& path) const return lhsTotalDuration > rhsTotalDuration; }); + std::string timeType = "nanoseconds"; + + if (std::is_same::value) + { + timeType = "seconds"; + } + else if (std::is_same::value) + { + timeType = "miliseconds"; + } + // write data header to stream out << "File path" << ";" - << "Compilation time (nanoseconds)" << ";" - << "Front-end time (nanoseconds)" << ";" - << "Back-end time (nanoseconds)" << std::endl; + << "Compilation time (" << timeType << ")" << ";" + << "Front-end time (" << timeType << ")" << ";" + << "Back-end time (" << timeType << ")" << std::endl; // write data to stream for (auto&& data : dataPerFile) { - std::chrono::nanoseconds totalDuration = data->second.BackEnd.Stop - data->second.FrontEnd.Start; - + const FileCompilationData& perFile = data->second; + T compileTime = std::chrono::duration_cast(perFile.BackEnd.Stop - perFile.FrontEnd.Start); + T frontEndTime = std::chrono::duration_cast(perFile.FrontEnd.Stop - perFile.FrontEnd.Start); + T backEndTime = std::chrono::duration_cast(perFile.BackEnd.Stop - perFile.BackEnd.Start); + out << data->first << ";" - << (data->second.BackEnd.Stop - data->second.FrontEnd.Start).count() << ";" - << (data->second.FrontEnd.Stop - data->second.FrontEnd.Start).count() << ";" - << (data->second.BackEnd.Stop - data->second.BackEnd.Start).count() << std::endl; + << compileTime.count() << ";" + << frontEndTime.count() << ";" + << backEndTime.count() << std::endl; } out.close(); return true; -} \ No newline at end of file +} + +template +bool FileCompilationsExporter::ExportTo(const std::string& path) const; + +template +bool FileCompilationsExporter::ExportTo(const std::string& path) const; + +template +bool FileCompilationsExporter::ExportTo(const std::string& path) const; diff --git a/src/AnalysisExporter/FileCompilations/FileCompilationsExporter.h b/src/AnalysisExporter/FileCompilations/FileCompilationsExporter.h index 39c000a..56880dd 100644 --- a/src/AnalysisExporter/FileCompilations/FileCompilationsExporter.h +++ b/src/AnalysisExporter/FileCompilations/FileCompilationsExporter.h @@ -11,6 +11,7 @@ class FileCompilationsExporter ~FileCompilationsExporter(); // exports to CSV + template bool ExportTo(const std::string& path) const; private: diff --git a/src/AnalysisExporter/FileInclusions/FileInclusionTimesExporter.cpp b/src/AnalysisExporter/FileInclusions/FileInclusionTimesExporter.cpp index fd1cea6..c419398 100644 --- a/src/AnalysisExporter/FileInclusions/FileInclusionTimesExporter.cpp +++ b/src/AnalysisExporter/FileInclusions/FileInclusionTimesExporter.cpp @@ -25,6 +25,7 @@ FileInclusionTimesExporter::~FileInclusionTimesExporter() { } +template bool FileInclusionTimesExporter::ExportTo(const std::string& path) const { std::ofstream out(path); @@ -80,25 +81,47 @@ bool FileInclusionTimesExporter::ExportTo(const std::string& path) const return lhs.AverageInclusionTime > rhs.AverageInclusionTime; }); + + std::string timeType = "nanoseconds"; + + if (std::is_same::value) + { + timeType = "seconds"; + } + else if (std::is_same::value) + { + timeType = "miliseconds"; + } + // write data header to stream out << "File path" << ";" - << "Average elapsed time (nanoseconds)" << ";" - << "Minimum elapsed time (nanoseconds)" << ";" - << "Maximum elapsed time (nanoseconds)" << ";" - << "Standard deviation (nanoseconds)" << ";" + << "Average elapsed time (" << timeType << ")" << ";" + << "Minimum elapsed time (" << timeType << ")" << ";" + << "Maximum elapsed time (" << timeType << ")" << ";" + << "Standard deviation (" << timeType << ")" << ";" << "Occurrences" << std::endl; // write data to stream for (auto&& data : dataPerFile) { out << (*data.FilePath) << ";" - << data.AverageInclusionTime.count() << ";" - << data.MinimumInclusionTime.count() << ";" - << data.MaximumInclusionTime.count() << ";" - << data.StandardDeviation.count() << ";" + << std::chrono::duration_cast(data.AverageInclusionTime).count() << ";" + << std::chrono::duration_cast(data.MinimumInclusionTime).count() << ";" + << std::chrono::duration_cast(data.MaximumInclusionTime).count() << ";" + << std::chrono::duration_cast(data.StandardDeviation).count() << ";" << data.Occurrences << std::endl; } out.close(); return true; } + +template +bool FileInclusionTimesExporter::ExportTo(const std::string& path) const; + +template +bool FileInclusionTimesExporter::ExportTo(const std::string& path) const; + +template +bool FileInclusionTimesExporter::ExportTo(const std::string& path) const; + diff --git a/src/AnalysisExporter/FileInclusions/FileInclusionTimesExporter.h b/src/AnalysisExporter/FileInclusions/FileInclusionTimesExporter.h index 6210203..425ea60 100644 --- a/src/AnalysisExporter/FileInclusions/FileInclusionTimesExporter.h +++ b/src/AnalysisExporter/FileInclusions/FileInclusionTimesExporter.h @@ -12,6 +12,7 @@ class FileInclusionTimesExporter ~FileInclusionTimesExporter(); // exports to CSV format + template bool ExportTo(const std::string& path) const; private: diff --git a/src/AnalysisExporter/FunctionCompilations/FunctionCompilationsExporter.cpp b/src/AnalysisExporter/FunctionCompilations/FunctionCompilationsExporter.cpp index 5ce51c1..f4980fd 100644 --- a/src/AnalysisExporter/FunctionCompilations/FunctionCompilationsExporter.cpp +++ b/src/AnalysisExporter/FunctionCompilations/FunctionCompilationsExporter.cpp @@ -27,6 +27,7 @@ FunctionCompilationsExporter::~FunctionCompilationsExporter() { } +template bool FunctionCompilationsExporter::ExportTo(const std::string& path) const { std::ofstream out = std::ofstream(path); @@ -83,12 +84,24 @@ bool FunctionCompilationsExporter::ExportTo(const std::string& path) const return lhs.AverageCompilationTime > rhs.AverageCompilationTime; }); + + std::string timeType = "nanoseconds"; + + if (std::is_same::value) + { + timeType = "seconds"; + } + else if (std::is_same::value) + { + timeType = "miliseconds"; + } + // write data header to stream out << "Undecorated function name" << ";" - << "Average elapsed time (nanoseconds)" << ";" - << "Minimum elapsed time (nanoseconds)" << ";" - << "Maximum elapsed time (nanoseconds)" << ";" - << "Standard deviation (nanoseconds)" << ";" + << "Average elapsed time (" << timeType << ")" << ";" + << "Minimum elapsed time (" << timeType << ")" << ";" + << "Maximum elapsed time (" << timeType << ")" << ";" + << "Standard deviation (" << timeType << ")" << ";" << "Occurrences" << std::endl; // write data to file @@ -96,9 +109,9 @@ bool FunctionCompilationsExporter::ExportTo(const std::string& path) const { // dump to stream out << Utilities::CppBuildInsightsDataConversion::UndecorateFunction(*data.FunctionName) << ";" - << data.AverageCompilationTime.count() << ";" - << data.MinimumCompilationTime.count() << ";" - << data.MaximumCompilationTime.count() << ";" + << std::chrono::duration_cast(data.AverageCompilationTime).count() << ";" + << std::chrono::duration_cast(data.MinimumCompilationTime).count() << ";" + << std::chrono::duration_cast(data.MaximumCompilationTime).count() << ";" << data.StandardDeviation.count() << ";" << data.Occurrences << std::endl; } @@ -106,3 +119,13 @@ bool FunctionCompilationsExporter::ExportTo(const std::string& path) const out.close(); return true; } + +template +bool FunctionCompilationsExporter::ExportTo(const std::string& path) const; + +template +bool FunctionCompilationsExporter::ExportTo(const std::string& path) const; + +template +bool FunctionCompilationsExporter::ExportTo(const std::string& path) const; + diff --git a/src/AnalysisExporter/FunctionCompilations/FunctionCompilationsExporter.h b/src/AnalysisExporter/FunctionCompilations/FunctionCompilationsExporter.h index 7fa3610..55eb98b 100644 --- a/src/AnalysisExporter/FunctionCompilations/FunctionCompilationsExporter.h +++ b/src/AnalysisExporter/FunctionCompilations/FunctionCompilationsExporter.h @@ -12,6 +12,7 @@ class FunctionCompilationsExporter ~FunctionCompilationsExporter(); // exports to CSV format + template bool ExportTo(const std::string& path) const; private: diff --git a/src/AnalysisExporter/TemplateInstantiations/TemplateInstantiationsExporter.cpp b/src/AnalysisExporter/TemplateInstantiations/TemplateInstantiationsExporter.cpp index 021f100..42e152f 100644 --- a/src/AnalysisExporter/TemplateInstantiations/TemplateInstantiationsExporter.cpp +++ b/src/AnalysisExporter/TemplateInstantiations/TemplateInstantiationsExporter.cpp @@ -39,13 +39,16 @@ bool TemplateInstantiationsExporter::ExportTo(const std::string& path) const // aggregate data typedef std::unordered_map TAggregatedData; TAggregatedData aggregatedData; + + std::string symbolName = "Unknown"; + for (auto&& pair : m_templateInstantiations) { const std::chrono::nanoseconds& timeElapsed = pair.second.Duration; - + auto itSpecializationTemplateName = m_symbolNames.find(pair.second.Specialization); assert(itSpecializationTemplateName != m_symbolNames.end()); - + // from the docs: "Comparing types between different compiler front-end passes requires using symbol names" auto result = aggregatedData.try_emplace(itSpecializationTemplateName->second, DataPerTemplate()); auto& data = result.first->second; diff --git a/src/BuildAnalyzer/Analyzers/FileCompilations/FileCompilationsAnalyzer.cpp b/src/BuildAnalyzer/Analyzers/FileCompilations/FileCompilationsAnalyzer.cpp index dc65585..258272d 100644 --- a/src/BuildAnalyzer/Analyzers/FileCompilations/FileCompilationsAnalyzer.cpp +++ b/src/BuildAnalyzer/Analyzers/FileCompilations/FileCompilationsAnalyzer.cpp @@ -50,4 +50,5 @@ const wchar_t* FileCompilationsAnalyzer::GetFilePath(const CppBI::Activities::Co assert(compilerPass.OutputObjectPath() != nullptr); return compilerPass.OutputObjectPath(); + } diff --git a/src/BuildAnalyzer/BuildAnalyzer.cpp b/src/BuildAnalyzer/BuildAnalyzer.cpp index 49480bb..fb5e003 100644 --- a/src/BuildAnalyzer/BuildAnalyzer.cpp +++ b/src/BuildAnalyzer/BuildAnalyzer.cpp @@ -83,20 +83,40 @@ std::vector BuildAnalyzer::BuildAnalyzerList(const AnalysisOp return analyzers; } -bool BuildAnalyzer::ExportFunctionCompilationsData(const std::string& path) const +bool BuildAnalyzer::ExportFunctionCompilationsData(const std::string& path, TimeDisplayEnum timeDisplay) const { assert(m_analysisPerformed); FunctionCompilationsExporter exporter(m_functionCompilations.GetData()); - return exporter.ExportTo(path); + + if (timeDisplay == TimeDisplayEnum::Seconds) + { + return exporter.ExportTo(path); + } + else if (timeDisplay == TimeDisplayEnum::Milliseconds) + { + return exporter.ExportTo(path); + } + + return exporter.ExportTo(path); } -bool BuildAnalyzer::ExportFileInclusionTimesData(const std::string& path) const +bool BuildAnalyzer::ExportFileInclusionTimesData(const std::string& path, TimeDisplayEnum timeDisplay) const { assert(m_analysisPerformed); FileInclusionTimesExporter exporter(m_fileInclusions.GetTimeData()); - return exporter.ExportTo(path); + + if (timeDisplay == TimeDisplayEnum::Seconds) + { + return exporter.ExportTo(path); + } + else if (timeDisplay == TimeDisplayEnum::Milliseconds) + { + return exporter.ExportTo(path); + } + + return exporter.ExportTo(path); } bool BuildAnalyzer::ExportFileInclusionGraph(const std::string& path) const @@ -107,12 +127,21 @@ bool BuildAnalyzer::ExportFileInclusionGraph(const std::string& path) const return exporter.ExportTo(path); } -bool BuildAnalyzer::ExportFileCompilationsData(const std::string& path) const +bool BuildAnalyzer::ExportFileCompilationsData(const std::string& path, TimeDisplayEnum timeDisplay) const { assert(m_analysisPerformed); FileCompilationsExporter exporter(m_fileCompilations.GetData()); - return exporter.ExportTo(path); + if (timeDisplay == TimeDisplayEnum::Seconds) + { + return exporter.ExportTo(path); + } + else if (timeDisplay == TimeDisplayEnum::Milliseconds) + { + return exporter.ExportTo(path); + } + + return exporter.ExportTo(path); } bool BuildAnalyzer::ExportBuildTimeline(const std::string& path) const diff --git a/src/BuildAnalyzer/BuildAnalyzer.h b/src/BuildAnalyzer/BuildAnalyzer.h index 17b2646..5eba02d 100644 --- a/src/BuildAnalyzer/BuildAnalyzer.h +++ b/src/BuildAnalyzer/BuildAnalyzer.h @@ -17,6 +17,13 @@ namespace Microsoft { namespace Cpp { namespace BuildInsights { class BuildAnalyzer { public: + enum class TimeDisplayEnum + { + Nanoseconds, + Milliseconds, + Seconds, + }; + struct AnalysisOptions { std::chrono::milliseconds TimelineIgnoreFunctionsUnder = std::chrono::milliseconds(0); @@ -27,6 +34,7 @@ class BuildAnalyzer bool FileCompilations = true; bool BuildTimeline = true; bool TemplateInstantiations = true; + TimeDisplayEnum TimeDisplay = TimeDisplayEnum::Nanoseconds; }; public: @@ -36,10 +44,10 @@ class BuildAnalyzer inline bool IsAnalysisPerformed() const { return m_analysisPerformed; } bool Analyze(); - bool ExportFunctionCompilationsData(const std::string& path) const; - bool ExportFileInclusionTimesData(const std::string& path) const; + bool ExportFunctionCompilationsData(const std::string& path, TimeDisplayEnum timeDisplay) const; + bool ExportFileInclusionTimesData(const std::string& path, TimeDisplayEnum timeDisplay) const; bool ExportFileInclusionGraph(const std::string& path) const; - bool ExportFileCompilationsData(const std::string& path) const; + bool ExportFileCompilationsData(const std::string& path, TimeDisplayEnum timeDisplay) const; bool ExportBuildTimeline(const std::string& path) const; bool ExportTemplateInstantiationsData(const std::string& path) const; diff --git a/src/ConsoleMain/Main.cpp b/src/ConsoleMain/Main.cpp index 0ceea4a..b56a093 100644 --- a/src/ConsoleMain/Main.cpp +++ b/src/ConsoleMain/Main.cpp @@ -15,6 +15,7 @@ namespace const std::string s_defaultOutputPathFileCompilations = "FileCompilations.csv"; const std::string s_defaultOutputPathBuildTimeline = "BuildTimeline.json"; const std::string s_defaultOutputPathTemplateInstantiations = "TemplateInstantiations.csv"; + const std::string s_defaultTimingDisplay = "ns"; const unsigned int s_defaultTimelineIgnoreFunctionsUnderMs = 10; const unsigned int s_defaultTimelineIgnoreTemplatesUnderMs = 10; @@ -42,6 +43,7 @@ int main(int argc, char** argv) std::string outputPathFileCompilations = s_defaultOutputPathFileCompilations; std::string outputPathBuildTimeline = s_defaultOutputPathBuildTimeline; std::string outputPathTemplateInstantiations = s_defaultOutputPathTemplateInstantiations; + std::string timingDisplay = s_defaultTimingDisplay; unsigned int timelineIgnoreFunctionsUnderMs = s_defaultTimelineIgnoreFunctionsUnderMs; unsigned int timelineIgnoreTemplatesUnderMs = s_defaultTimelineIgnoreTemplatesUnderMs; @@ -68,7 +70,10 @@ int main(int argc, char** argv) ("out_file_inclusion_graph", "Path to output file inclusion graph", cxxopts::value(outputPathFileInclusionGraph)) ("out_file_compilations", "Path to output file compilations data", cxxopts::value(outputPathFileCompilations)) ("out_build_timeline", "Path to output build timeline", cxxopts::value(outputPathBuildTimeline)) - ("out_template_instantiations", "Path to output template instantiations data", cxxopts::value(outputPathTemplateInstantiations)); + ("out_template_instantiations", "Path to output template instantiations data", cxxopts::value(outputPathTemplateInstantiations)) + //timing display + ("timing", "Defaults to ns(nanoseconds), can use ms(milliseconds) or s(seconds)", cxxopts::value(timingDisplay)) + ; // parse command line try @@ -108,6 +113,7 @@ int main(int argc, char** argv) exit(-1); } + // what to build BuildAnalyzer::AnalysisOptions analysisOptions; analysisOptions.FunctionCompilations = analyzeAll || analyzeFunctionCompilations; @@ -119,6 +125,19 @@ int main(int argc, char** argv) analysisOptions.TimelineIgnoreFunctionsUnder = std::chrono::milliseconds(timelineIgnoreFunctionsUnderMs); analysisOptions.TimelineIgnoreTemplatesUnder = std::chrono::milliseconds(timelineIgnoreTemplatesUnderMs); + if (timingDisplay == "ms") + { + analysisOptions.TimeDisplay = BuildAnalyzer::TimeDisplayEnum::Milliseconds; + } + else if (timingDisplay == "s") + { + analysisOptions.TimeDisplay = BuildAnalyzer::TimeDisplayEnum::Seconds; + } + else + { + std::cout << "Unrecognized time display value '"<< timingDisplay <<"'. Defaulting to nanoseconds." << std::endl; + } + // analyze trace std::cout << "Analyzing..." << std::endl; BuildAnalyzer analyzer(inputPathTraceFile, analysisOptions); @@ -133,7 +152,7 @@ int main(int argc, char** argv) if (!outputPathFunctionCompilations.empty()) { - analyzer.ExportFunctionCompilationsData(outputPathFunctionCompilations); + analyzer.ExportFunctionCompilationsData(outputPathFunctionCompilations, analysisOptions.TimeDisplay); } else { @@ -147,7 +166,7 @@ int main(int argc, char** argv) if (!outputPathFileInclusionTimes.empty()) { - analyzer.ExportFileInclusionTimesData(outputPathFileInclusionTimes); + analyzer.ExportFileInclusionTimesData(outputPathFileInclusionTimes, analysisOptions.TimeDisplay); } else { @@ -175,7 +194,7 @@ int main(int argc, char** argv) if (!outputPathFileCompilations.empty()) { - analyzer.ExportFileCompilationsData(outputPathFileCompilations); + analyzer.ExportFileCompilationsData(outputPathFileCompilations, analysisOptions.TimeDisplay); } else {