Hi tareqsiraj, arielbernal,
Performance timers captured in each transform for all files they process
are now collected and arranged per source file in preparation for
writing to disk.
http://llvm-reviews.chandlerc.com/D912
Files:
cpp11-migrate/Core/CMakeLists.txt
cpp11-migrate/Core/PerfSupport.cpp
cpp11-migrate/Core/PerfSupport.h
cpp11-migrate/Core/Transform.cpp
cpp11-migrate/Core/Transform.h
cpp11-migrate/tool/Cpp11Migrate.cpp
unittests/cpp11-migrate/CMakeLists.txt
unittests/cpp11-migrate/PerfSupportTest.cpp
Index: cpp11-migrate/Core/CMakeLists.txt
===================================================================
--- cpp11-migrate/Core/CMakeLists.txt
+++ cpp11-migrate/Core/CMakeLists.txt
@@ -4,6 +4,7 @@
Transforms.cpp
Transform.cpp
IncludeExcludeInfo.cpp
+ PerfSupport.cpp
)
target_link_libraries(migrateCore
clangTooling
Index: cpp11-migrate/Core/PerfSupport.cpp
===================================================================
--- /dev/null
+++ cpp11-migrate/Core/PerfSupport.cpp
@@ -0,0 +1,97 @@
+//===-- cpp11-migrate/Cpp11Migrate.cpp - Main file C++11 migration tool ---===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief This file provides implementations for performance measuring helpers.
+///
+//===----------------------------------------------------------------------===//
+
+#include "PerfSupport.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/Process.h"
+#include "llvm/Support/Path.h"
+
+void collectSourcePerfData(const Transform &T, SourcePerfData &Data) {
+ for (Transform::TimingVec::const_iterator I = T.timing_begin(),
+ E = T.timing_end();
+ I != E; ++I) {
+ SourcePerfData::iterator DataI = Data.insert(
+ SourcePerfData::value_type(I->first, std::vector<PerfItem>())).first;
+ DataI->second
+ .push_back(PerfItem(T.getName(), I->second.getProcessTime() * 1000.0));
+ }
+}
+
+void writePerfDataJSON(
+ const llvm::StringRef DirectoryName,
+ const SourcePerfData &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<int>(T.getWallTime()) << "_" << Pid
+ << ".json";
+
+ std::string ErrorInfo;
+ llvm::raw_fd_ostream FileStream(SS.str().c_str(), ErrorInfo);
+ FileStream << "{\n";
+ FileStream << " \"Sources\" : [\n";
+ for (SourcePerfData::const_iterator I = TimingResults.begin(),
+ E = TimingResults.end();
+ I != E; ++I) {
+ // Terminate the last source with a comma before continuing to the next one.
+ if (I != TimingResults.begin())
+ FileStream << ",\n";
+
+ FileStream << " {\n";
+ FileStream << " \"Source \" : \"" << I->first << "\",\n";
+ FileStream << " \"Data\" : [\n";
+ for (std::vector<PerfItem>::const_iterator IE = I->second.begin(),
+ EE = I->second.end();
+ IE != EE; ++IE) {
+ // Terminate the last perf item with a comma before continuing to the next
+ // one.
+ if (IE != I->second.begin())
+ FileStream << ",\n";
+
+ FileStream << " {\n";
+ FileStream << " \"TimerId\" : \"" << IE->Label << "\",\n";
+ FileStream << " \"Time\" : " << llvm::format("%.2f", IE->Duration)
+ << "\n";
+
+ FileStream << " }";
+
+ }
+ FileStream << "\n ]\n";
+ FileStream << " }";
+ }
+ FileStream << "\n ]\n";
+ FileStream << "}";
+}
+
+void dumpPerfData(const SourcePerfData &Data) {
+ for (SourcePerfData::const_iterator I = Data.begin(), E = Data.end(); I != E;
+ ++I) {
+ llvm::errs() << I->first << ":\n";
+ for (std::vector<PerfItem>::const_iterator VecI = I->second.begin(),
+ VecE = I->second.end();
+ VecI != VecE; ++VecI) {
+ llvm::errs() << " " << VecI->Label << ": "
+ << llvm::format("%.1f", VecI->Duration) << "ms\n";
+ }
+ }
+}
Index: cpp11-migrate/Core/PerfSupport.h
===================================================================
--- /dev/null
+++ cpp11-migrate/Core/PerfSupport.h
@@ -0,0 +1,56 @@
+//===-- cpp11-migrate/PerfSupport.h - Perf measurement helpers --*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief This file provides helper functionality for measuring performance and
+/// recording data to file.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef CPP11_MIGRATE_PERFSUPPORT_H
+#define CPP11_MIGRATE_PERFSUPPORT_H
+
+#include <map>
+#include <vector>
+#include "Transform.h"
+#include "llvm/ADT/StringRef.h"
+
+/// \brief A single piece of performance data: a duration in milliseconds and a
+/// label for that duration.
+struct PerfItem {
+ PerfItem(const llvm::StringRef Label, double Duration)
+ : Label(Label), Duration(Duration) {}
+
+ /// Label for this performance measurement.
+ std::string Label;
+
+ /// Duration in milliseconds.
+ double Duration;
+};
+
+/// Maps source file names to a vector of durations/labels.
+typedef std::map<std::string, std::vector<PerfItem> > SourcePerfData;
+
+/// Extracts durations collected by a Transform for all sources and adds them
+/// to a SourcePerfData map where data is organized by source file.
+extern void collectSourcePerfData(const Transform &T, SourcePerfData &Data);
+
+/// Write timing results to a JSON formatted file.
+///
+/// File is placed in the directory given by \p DirectoryName. File is named in
+/// a unique way with time and process ID to avoid naming collisions with
+/// existing files or files being generated by other migrator processes.
+void writePerfDataJSON(
+ const llvm::StringRef DirectoryName,
+ const SourcePerfData &TimingResults);
+
+/// Dump a SourcePerfData map to llvm::errs().
+extern void dumpPerfData(const SourcePerfData &Data);
+
+#endif // CPP11_MIGRATE_PERFSUPPORT_H
Index: cpp11-migrate/Core/Transform.cpp
===================================================================
--- cpp11-migrate/Core/Transform.cpp
+++ cpp11-migrate/Core/Transform.cpp
@@ -51,3 +51,7 @@
Timings.back().second += llvm::TimeRecord::getCurrentTime(false);
}
+
+void Transform::addTiming(llvm::StringRef Label, llvm::TimeRecord Duration) {
+ Timings.push_back(std::make_pair(Label.str(), Duration));
+}
Index: cpp11-migrate/Core/Transform.h
===================================================================
--- cpp11-migrate/Core/Transform.h
+++ cpp11-migrate/Core/Transform.h
@@ -207,6 +207,13 @@
DeferredChanges = Changes;
}
+ /// \brief Allows subclasses to manually add performance timer data.
+ ///
+ /// \p Label should probably include the source file name somehow as the
+ /// duration info is simply added to the vector of timing data which holds
+ /// data for all sources processed by this transform.
+ void addTiming(llvm::StringRef Label, llvm::TimeRecord Duration);
+
private:
const std::string Name;
bool EnableTiming;
Index: cpp11-migrate/tool/Cpp11Migrate.cpp
===================================================================
--- cpp11-migrate/tool/Cpp11Migrate.cpp
+++ cpp11-migrate/tool/Cpp11Migrate.cpp
@@ -17,17 +17,15 @@
#include "Core/Transforms.h"
#include "Core/Transform.h"
+#include "Core/PerfSupport.h"
#include "LoopConvert/LoopConvert.h"
#include "UseNullptr/UseNullptr.h"
#include "UseAuto/UseAuto.h"
#include "AddOverride/AddOverride.h"
#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;
@@ -55,8 +53,8 @@
const char NoTiming[] = "no_timing";
static cl::opt<std::string> TimingDirectoryName(
- "report-times", cl::desc("Capture performance data and output to specified "
- "directory. Default ./migrate_perf"),
+ "perf", 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
@@ -87,60 +85,6 @@
}
};
-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<std::string, std::vector<ExecutionTime> > &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<int>(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<std::string, std::vector<ExecutionTime> >::const_iterator
- I = TimingResults.begin(),
- E = TimingResults.end();
- I != E; ++I) {
- FileStream << " {\n";
- FileStream << " \"Source \" : \"" << I->first << "\",\n";
- FileStream << " \"Data\" : [\n";
- for (std::vector<ExecutionTime>::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;
@@ -165,8 +109,6 @@
// 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<std::string, std::vector<ExecutionTime> > TimingResults;
-
TransformManager.createSelectedTransforms(EnableTiming);
if (TransformManager.begin() == TransformManager.end()) {
@@ -177,6 +119,8 @@
FileContentsByPath FileStates1, FileStates2,
*InputFileStates = &FileStates1, *OutputFileStates = &FileStates2;
+ SourcePerfData PerfData;
+
// Apply transforms.
for (Transforms::const_iterator I = TransformManager.begin(),
E = TransformManager.end();
@@ -188,6 +132,10 @@
// FIXME: Improve ClangTool to not abort if just one file fails.
return 1;
}
+
+ if (EnableTiming)
+ collectSourcePerfData(**I, PerfData);
+
if (SummaryMode) {
llvm::outs() << "Transform: " << (*I)->getName()
<< " - Accepted: "
@@ -236,12 +184,12 @@
}
// Report execution times.
- if (EnableTiming && TimingResults.size() > 0) {
+ if (EnableTiming && !PerfData.empty()) {
std::string DirectoryName = TimingDirectoryName;
// Use default directory name.
- if (DirectoryName == "")
+ if (DirectoryName.empty())
DirectoryName = "./migrate_perf";
- reportExecutionTimes(DirectoryName, TimingResults);
+ writePerfDataJSON(DirectoryName, PerfData);
}
return 0;
Index: unittests/cpp11-migrate/CMakeLists.txt
===================================================================
--- unittests/cpp11-migrate/CMakeLists.txt
+++ unittests/cpp11-migrate/CMakeLists.txt
@@ -8,7 +8,8 @@
add_extra_unittest(Cpp11MigrateTests
TransformTest.cpp
- IncludeExcludeTest.cpp)
+ IncludeExcludeTest.cpp
+ PerfSupportTest.cpp)
target_link_libraries(Cpp11MigrateTests
migrateCore
Index: unittests/cpp11-migrate/PerfSupportTest.cpp
===================================================================
--- /dev/null
+++ unittests/cpp11-migrate/PerfSupportTest.cpp
@@ -0,0 +1,89 @@
+#include "gtest/gtest.h"
+#include "Core/PerfSupport.h"
+
+using namespace llvm;
+using namespace clang;
+
+class TransformA : public Transform {
+public:
+ TransformA()
+ : Transform("TransformA", false) {}
+
+ virtual int apply(const FileContentsByPath &, RiskLevel,
+ const tooling::CompilationDatabase &,
+ const std::vector<std::string> &, FileContentsByPath &) {
+ return 0;
+ }
+
+ void addTiming(StringRef Label, TimeRecord Duration) {
+ Transform::addTiming(Label, Duration);
+ }
+};
+
+class TransformB : public Transform {
+public:
+ TransformB()
+ : Transform("TransformB", false) {}
+
+ virtual int apply(const FileContentsByPath &, RiskLevel,
+ const tooling::CompilationDatabase &,
+ const std::vector<std::string> &, FileContentsByPath &) {
+ return 0;
+ }
+
+ void addTiming(StringRef Label, TimeRecord Duration) {
+ Transform::addTiming(Label, Duration);
+ }
+};
+
+struct ExpectedResults {
+ const char *SourceName;
+ unsigned DataCount;
+ struct Datum {
+ const char *Label;
+ float Duration;
+ } Data[2];
+};
+
+TEST(PerfSupport, collectSourcePerfData) {
+ TransformA A;
+ TransformB B;
+
+ // The actual durations don't matter. Below only their relative ordering is
+ // tested to ensure times, labels, and sources all stay together properly.
+ A.addTiming("FileA.cpp", TimeRecord::getCurrentTime(/*Start=*/true));
+ A.addTiming("FileC.cpp", TimeRecord::getCurrentTime(/*Start=*/true));
+ B.addTiming("FileC.cpp", TimeRecord::getCurrentTime(/*Start=*/true));
+ B.addTiming("FileB.cpp", TimeRecord::getCurrentTime(/*Start=*/true));
+
+ SourcePerfData PerfData;
+ collectSourcePerfData(A, PerfData);
+
+ SourcePerfData::const_iterator FileAI = PerfData.find("FileA.cpp");
+ EXPECT_NE(FileAI, PerfData.end());
+ SourcePerfData::const_iterator FileCI = PerfData.find("FileC.cpp");
+ EXPECT_NE(FileCI, PerfData.end());
+ EXPECT_EQ(2u, PerfData.size());
+
+ EXPECT_EQ(1u, FileAI->second.size());
+ EXPECT_EQ("TransformA", FileAI->second[0].Label);
+ EXPECT_EQ(1u, FileCI->second.size());
+ EXPECT_EQ("TransformA", FileCI->second[0].Label);
+ EXPECT_LE(FileAI->second[0].Duration, FileCI->second[0].Duration);
+
+ collectSourcePerfData(B, PerfData);
+
+ SourcePerfData::const_iterator FileBI = PerfData.find("FileB.cpp");
+ EXPECT_NE(FileBI, PerfData.end());
+ EXPECT_EQ(3u, PerfData.size());
+
+ EXPECT_EQ(1u, FileAI->second.size());
+ EXPECT_EQ("TransformA", FileAI->second[0].Label);
+ EXPECT_EQ(2u, FileCI->second.size());
+ EXPECT_EQ("TransformA", FileCI->second[0].Label);
+ EXPECT_EQ("TransformB", FileCI->second[1].Label);
+ EXPECT_LE(FileCI->second[0].Duration, FileCI->second[1].Duration);
+ EXPECT_EQ(1u, FileBI->second.size());
+ EXPECT_EQ("TransformB", FileBI->second[0].Label);
+ EXPECT_LE(FileCI->second[1].Duration, FileBI->second[0].Duration);
+}
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits