[clang-tools-extra] r183274 - cpp11-migrate: collect performance timers per source file

Edwin Vane edwin.vane at intel.com
Tue Jun 4 15:37:02 PDT 2013


Author: revane
Date: Tue Jun  4 17:37:02 2013
New Revision: 183274

URL: http://llvm.org/viewvc/llvm-project?rev=183274&view=rev
Log:
cpp11-migrate: collect performance timers per source file

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.

This revision is the last piece of the initial implementation of performance timer capturing.

Added:
    clang-tools-extra/trunk/cpp11-migrate/Core/PerfSupport.cpp
    clang-tools-extra/trunk/cpp11-migrate/Core/PerfSupport.h
    clang-tools-extra/trunk/unittests/cpp11-migrate/PerfSupportTest.cpp
Modified:
    clang-tools-extra/trunk/cpp11-migrate/Core/CMakeLists.txt
    clang-tools-extra/trunk/cpp11-migrate/Core/Transform.cpp
    clang-tools-extra/trunk/cpp11-migrate/Core/Transform.h
    clang-tools-extra/trunk/cpp11-migrate/tool/Cpp11Migrate.cpp
    clang-tools-extra/trunk/unittests/cpp11-migrate/CMakeLists.txt

Modified: clang-tools-extra/trunk/cpp11-migrate/Core/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/cpp11-migrate/Core/CMakeLists.txt?rev=183274&r1=183273&r2=183274&view=diff
==============================================================================
--- clang-tools-extra/trunk/cpp11-migrate/Core/CMakeLists.txt (original)
+++ clang-tools-extra/trunk/cpp11-migrate/Core/CMakeLists.txt Tue Jun  4 17:37:02 2013
@@ -1,12 +1,13 @@
-set(LLVM_LINK_COMPONENTS support)
-
-add_clang_library(migrateCore
-  Transforms.cpp
-  Transform.cpp
-  IncludeExcludeInfo.cpp
-  )
-target_link_libraries(migrateCore
-  clangTooling
-  clangBasic
-  clangASTMatchers
-  )
+set(LLVM_LINK_COMPONENTS support)
+
+add_clang_library(migrateCore
+  Transforms.cpp
+  Transform.cpp
+  IncludeExcludeInfo.cpp
+  PerfSupport.cpp
+  )
+target_link_libraries(migrateCore
+  clangTooling
+  clangBasic
+  clangASTMatchers
+  )

Added: clang-tools-extra/trunk/cpp11-migrate/Core/PerfSupport.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/cpp11-migrate/Core/PerfSupport.cpp?rev=183274&view=auto
==============================================================================
--- clang-tools-extra/trunk/cpp11-migrate/Core/PerfSupport.cpp (added)
+++ clang-tools-extra/trunk/cpp11-migrate/Core/PerfSupport.cpp Tue Jun  4 17:37:02 2013
@@ -0,0 +1,101 @@
+//===-- 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.
+  // FIXME: id_type on Windows is NOT a process id despite the function name.
+  // Need to call GetProcessId() providing it what get_id() returns. For now
+  // disabling PID-based file names until this is fixed properly.
+  //llvm::sys::self_process *SP = llvm::sys::process::get_self();
+  //id_type Pid = SP->get_id();
+  unsigned Pid = 0;
+  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";
+    }
+  }
+}

Added: clang-tools-extra/trunk/cpp11-migrate/Core/PerfSupport.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/cpp11-migrate/Core/PerfSupport.h?rev=183274&view=auto
==============================================================================
--- clang-tools-extra/trunk/cpp11-migrate/Core/PerfSupport.h (added)
+++ clang-tools-extra/trunk/cpp11-migrate/Core/PerfSupport.h Tue Jun  4 17:37:02 2013
@@ -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, float Duration)
+      : Label(Label), Duration(Duration) {}
+
+  /// Label for this performance measurement.
+  std::string Label;
+
+  /// Duration in milliseconds.
+  float 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

Modified: clang-tools-extra/trunk/cpp11-migrate/Core/Transform.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/cpp11-migrate/Core/Transform.cpp?rev=183274&r1=183273&r2=183274&view=diff
==============================================================================
--- clang-tools-extra/trunk/cpp11-migrate/Core/Transform.cpp (original)
+++ clang-tools-extra/trunk/cpp11-migrate/Core/Transform.cpp Tue Jun  4 17:37:02 2013
@@ -1,53 +1,57 @@
-#include "Core/Transform.h"
-#include "clang/Basic/FileManager.h"
-#include "clang/Basic/SourceManager.h"
-#include "clang/Rewrite/Core/Rewriter.h"
-#include "llvm/Support/raw_ostream.h"
-
-using namespace clang;
-
-void collectResults(clang::Rewriter &Rewrite,
-                    const FileContentsByPath &InputStates,
-                    FileContentsByPath &Results) {
-  // Copy the contents of InputStates to be modified.
-  Results = InputStates;
-
-  for (Rewriter::buffer_iterator I = Rewrite.buffer_begin(),
-                                 E = Rewrite.buffer_end();
-       I != E; ++I) {
-    const FileEntry *Entry = Rewrite.getSourceMgr().getFileEntryForID(I->first);
-    assert(Entry != 0 && "Expected a FileEntry");
-    assert(Entry->getName() != 0 &&
-           "Unexpected NULL return from FileEntry::getName()");
-
-    std::string ResultBuf;
-
-    // Get a copy of the rewritten buffer from the Rewriter.
-    llvm::raw_string_ostream StringStream(ResultBuf);
-    I->second.write(StringStream);
-
-    // Cause results to be written to ResultBuf.
-    StringStream.str();
-
-    // FIXME: Use move semantics to avoid copies of the buffer contents if
-    // benchmarking shows the copies are expensive, especially for large source
-    // files.
-    Results[Entry->getName()] = ResultBuf;
-  }
-}
-
-bool Transform::handleBeginSource(CompilerInstance &CI, StringRef Filename) {
-  if (!EnableTiming)
-    return true;
-
-  Timings.push_back(std::make_pair(Filename.str(), llvm::TimeRecord()));
-  Timings.back().second -= llvm::TimeRecord::getCurrentTime(true);
-  return true;
-}
-
-void Transform::handleEndSource() {
-  if (!EnableTiming)
-    return;
-
-  Timings.back().second += llvm::TimeRecord::getCurrentTime(false);
-}
+#include "Core/Transform.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Rewrite/Core/Rewriter.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace clang;
+
+void collectResults(clang::Rewriter &Rewrite,
+                    const FileContentsByPath &InputStates,
+                    FileContentsByPath &Results) {
+  // Copy the contents of InputStates to be modified.
+  Results = InputStates;
+
+  for (Rewriter::buffer_iterator I = Rewrite.buffer_begin(),
+                                 E = Rewrite.buffer_end();
+       I != E; ++I) {
+    const FileEntry *Entry = Rewrite.getSourceMgr().getFileEntryForID(I->first);
+    assert(Entry != 0 && "Expected a FileEntry");
+    assert(Entry->getName() != 0 &&
+           "Unexpected NULL return from FileEntry::getName()");
+
+    std::string ResultBuf;
+
+    // Get a copy of the rewritten buffer from the Rewriter.
+    llvm::raw_string_ostream StringStream(ResultBuf);
+    I->second.write(StringStream);
+
+    // Cause results to be written to ResultBuf.
+    StringStream.str();
+
+    // FIXME: Use move semantics to avoid copies of the buffer contents if
+    // benchmarking shows the copies are expensive, especially for large source
+    // files.
+    Results[Entry->getName()] = ResultBuf;
+  }
+}
+
+bool Transform::handleBeginSource(CompilerInstance &CI, StringRef Filename) {
+  if (!EnableTiming)
+    return true;
+
+  Timings.push_back(std::make_pair(Filename.str(), llvm::TimeRecord()));
+  Timings.back().second -= llvm::TimeRecord::getCurrentTime(true);
+  return true;
+}
+
+void Transform::handleEndSource() {
+  if (!EnableTiming)
+    return;
+
+  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));
+}

Modified: clang-tools-extra/trunk/cpp11-migrate/Core/Transform.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/cpp11-migrate/Core/Transform.h?rev=183274&r1=183273&r2=183274&view=diff
==============================================================================
--- clang-tools-extra/trunk/cpp11-migrate/Core/Transform.h (original)
+++ clang-tools-extra/trunk/cpp11-migrate/Core/Transform.h Tue Jun  4 17:37:02 2013
@@ -1,219 +1,226 @@
-//===-- cpp11-migrate/Transform.h - Transform Base Class Def'n --*- 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 the definition for the base Transform class from
-/// which all transforms must subclass.
-///
-//===----------------------------------------------------------------------===//
-#ifndef LLVM_TOOLS_CLANG_TOOLS_EXTRA_CPP11_MIGRATE_TRANSFORM_H
-#define LLVM_TOOLS_CLANG_TOOLS_EXTRA_CPP11_MIGRATE_TRANSFORM_H
-
-#include <string>
-#include <vector>
-#include "clang/Tooling/Tooling.h"
-#include "llvm/Support/Timer.h"
-
-// For RewriterContainer
-#include "clang/Rewrite/Core/Rewriter.h"
-#include "clang/Basic/LangOptions.h"
-#include "clang/Basic/DiagnosticOptions.h"
-#include "clang/Frontend/TextDiagnosticPrinter.h"
-#include "clang/Basic/SourceManager.h"
-#include "llvm/Support/raw_ostream.h"
-////
-
-
-/// \brief Description of the riskiness of actions that can be taken by
-/// transforms.
-enum RiskLevel {
-  /// Transformations that will not change semantics.
-  RL_Safe,
-
-  /// Transformations that might change semantics.
-  RL_Reasonable,
-
-  /// Transformations that are likely to change semantics.
-  RL_Risky
-};
-
-// Forward declarations
-namespace clang {
-namespace tooling {
-class CompilationDatabase;
-} // namespace tooling
-} // namespace clang
-
-/// \brief The key is the path of a file, which is mapped to a
-/// buffer with the possibly modified contents of that file.
-typedef std::map<std::string, std::string> FileContentsByPath;
-
-/// \brief In \p Results place copies of the buffers resulting from applying
-/// all rewrites represented by \p Rewrite.
-///
-/// \p Results is made up of pairs {filename, buffer contents}. Pairs are
-/// simply appended to \p Results.
-void collectResults(clang::Rewriter &Rewrite,
-                    const FileContentsByPath &InputStates,
-                    FileContentsByPath &Results);
-
-/// \brief Class for containing a Rewriter instance and all of
-/// its lifetime dependencies.
-///
-/// Subclasses of Transform using RefactoringTools will need to create
-/// Rewriters in order to apply Replacements and get the resulting buffer.
-/// Rewriter requires some objects to exist at least as long as it does so this
-/// class contains instances of those objects.
-///
-/// FIXME: These objects should really come from somewhere more global instead
-/// of being recreated for every Transform subclass, especially diagnostics.
-class RewriterContainer {
-public:
-  RewriterContainer(clang::FileManager &Files,
-                    const FileContentsByPath &InputStates)
-    : DiagOpts(new clang::DiagnosticOptions()),
-      DiagnosticPrinter(llvm::errs(), DiagOpts.getPtr()),
-      Diagnostics(llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs>(
-                    new clang::DiagnosticIDs()),
-                  DiagOpts.getPtr(), &DiagnosticPrinter, false),
-      Sources(Diagnostics, Files),
-      Rewrite(Sources, DefaultLangOptions) {
-
-    // Overwrite source manager's file contents with data from InputStates
-    for (FileContentsByPath::const_iterator I = InputStates.begin(),
-                                            E = InputStates.end();
-         I != E; ++I) {
-      Sources.overrideFileContents(Files.getFile(I->first),
-                                   llvm::MemoryBuffer::getMemBuffer(I->second));
-    }
-  }
-
-  clang::Rewriter &getRewriter() { return Rewrite; }
-
-private:
-  clang::LangOptions DefaultLangOptions;
-  llvm::IntrusiveRefCntPtr<clang::DiagnosticOptions> DiagOpts;
-  clang::TextDiagnosticPrinter DiagnosticPrinter;
-  clang::DiagnosticsEngine Diagnostics;
-  clang::SourceManager Sources;
-  clang::Rewriter Rewrite;
-};
-
-/// \brief Abstract base class for all C++11 migration transforms.
-///
-/// Per-source performance timing is handled by the callbacks
-/// handleBeginSource() and handleEndSource() if timing is enabled. See
-/// clang::tooling::newFrontendActionFactory() for how to register
-/// a Transform object for callbacks.
-class Transform : public clang::tooling::SourceFileCallbacks {
-public:
-  /// \brief Constructor
-  /// \param Name Name of the transform for human-readable purposes (e.g. -help
-  /// text)
-  /// \param EnableTiming Enable the timing of the duration between calls to
-  /// handleBeginSource() and handleEndSource(). When a Transform object is
-  /// registered for FrontendAction source file callbacks, this behaviour can
-  /// be used to time the application of a MatchFinder by subclasses. Durations
-  /// are automatically stored in a TimingVec.
-  Transform(llvm::StringRef Name, bool EnableTiming)
-      : Name(Name), EnableTiming(EnableTiming) {
-    Reset();
-  }
-
-  virtual ~Transform() {}
-
-  /// \brief Apply a transform to all files listed in \p SourcePaths.
-  ///
-  /// \p Database must contain information for how to compile all files in \p
-  /// SourcePaths. \p InputStates contains the file contents of files in \p
-  /// SourcePaths and should take precedence over content of files on disk.
-  /// Upon return, \p ResultStates shall contain the result of performing this
-  /// transform on the files listed in \p SourcePaths.
-  virtual int apply(const FileContentsByPath &InputStates,
-                    RiskLevel MaxRiskLevel,
-                    const clang::tooling::CompilationDatabase &Database,
-                    const std::vector<std::string> &SourcePaths,
-                    FileContentsByPath &ResultStates) = 0;
-
-  /// \brief Query if changes were made during the last call to apply().
-  bool getChangesMade() const { return AcceptedChanges > 0; }
-
-  /// \brief Query if changes were not made due to conflicts with other changes
-  /// made during the last call to apply() or if changes were too risky for the
-  /// requested risk level.
-  bool getChangesNotMade() const {
-    return RejectedChanges > 0 || DeferredChanges > 0;
-  }
-
-  /// \brief Query the number of accepted changes.
-  unsigned getAcceptedChanges() const { return AcceptedChanges; }
-  /// \brief Query the number of changes considered too risky.
-  unsigned getRejectedChanges() const { return RejectedChanges; }
-  /// \brief Query the number of changes not made because they conflicted with
-  /// early changes.
-  unsigned getDeferredChanges() const { return DeferredChanges; }
-
-  /// \brief Query transform name.
-  llvm::StringRef getName() const { return Name; }
-
-  /// \brief Reset internal state of the transform.
-  ///
-  /// Useful if calling apply() several times with one instantiation of a
-  /// transform.
-  void Reset() {
-    AcceptedChanges = 0;
-    RejectedChanges = 0;
-    DeferredChanges = 0;
-  }
-
-  /// \brief Callback for notification of the start of processing of a source
-  /// file by a FrontendAction. Starts a performance timer if timing was
-  /// enabled.
-  virtual bool handleBeginSource(clang::CompilerInstance &CI,
-                                 llvm::StringRef Filename) LLVM_OVERRIDE;
-
-  /// \brief Callback for notification of the end of processing of a source
-  /// file by a FrontendAction. Stops a performance timer if timing was enabled
-  /// and records the elapsed time. For a given source, handleBeginSource() and
-  /// handleEndSource() are expected to be called in pairs.
-  virtual void handleEndSource() LLVM_OVERRIDE;
-
-  /// \brief Performance timing data is stored as a vector of pairs. Pairs are
-  /// formed of:
-  /// \li Name of source file.
-  /// \li Elapsed time.
-  typedef std::vector<std::pair<std::string, llvm::TimeRecord> > TimingVec;
-
-  /// \brief Return an iterator to the start of collected timing data.
-  TimingVec::const_iterator timing_begin() const { return Timings.begin(); }
-  /// \brief Return an iterator to the start of collected timing data.
-  TimingVec::const_iterator timing_end() const { return Timings.end(); }
-
-protected:
-
-  void setAcceptedChanges(unsigned Changes) {
-    AcceptedChanges = Changes;
-  }
-  void setRejectedChanges(unsigned Changes) {
-    RejectedChanges = Changes;
-  }
-  void setDeferredChanges(unsigned Changes) {
-    DeferredChanges = Changes;
-  }
-
-private:
-  const std::string Name;
-  bool EnableTiming;
-  TimingVec Timings;
-  unsigned AcceptedChanges;
-  unsigned RejectedChanges;
-  unsigned DeferredChanges;
-};
-
-#endif // LLVM_TOOLS_CLANG_TOOLS_EXTRA_CPP11_MIGRATE_TRANSFORM_H
+//===-- cpp11-migrate/Transform.h - Transform Base Class Def'n --*- 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 the definition for the base Transform class from
+/// which all transforms must subclass.
+///
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_TOOLS_CLANG_TOOLS_EXTRA_CPP11_MIGRATE_TRANSFORM_H
+#define LLVM_TOOLS_CLANG_TOOLS_EXTRA_CPP11_MIGRATE_TRANSFORM_H
+
+#include <string>
+#include <vector>
+#include "clang/Tooling/Tooling.h"
+#include "llvm/Support/Timer.h"
+
+// For RewriterContainer
+#include "clang/Rewrite/Core/Rewriter.h"
+#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/DiagnosticOptions.h"
+#include "clang/Frontend/TextDiagnosticPrinter.h"
+#include "clang/Basic/SourceManager.h"
+#include "llvm/Support/raw_ostream.h"
+////
+
+
+/// \brief Description of the riskiness of actions that can be taken by
+/// transforms.
+enum RiskLevel {
+  /// Transformations that will not change semantics.
+  RL_Safe,
+
+  /// Transformations that might change semantics.
+  RL_Reasonable,
+
+  /// Transformations that are likely to change semantics.
+  RL_Risky
+};
+
+// Forward declarations
+namespace clang {
+namespace tooling {
+class CompilationDatabase;
+} // namespace tooling
+} // namespace clang
+
+/// \brief The key is the path of a file, which is mapped to a
+/// buffer with the possibly modified contents of that file.
+typedef std::map<std::string, std::string> FileContentsByPath;
+
+/// \brief In \p Results place copies of the buffers resulting from applying
+/// all rewrites represented by \p Rewrite.
+///
+/// \p Results is made up of pairs {filename, buffer contents}. Pairs are
+/// simply appended to \p Results.
+void collectResults(clang::Rewriter &Rewrite,
+                    const FileContentsByPath &InputStates,
+                    FileContentsByPath &Results);
+
+/// \brief Class for containing a Rewriter instance and all of
+/// its lifetime dependencies.
+///
+/// Subclasses of Transform using RefactoringTools will need to create
+/// Rewriters in order to apply Replacements and get the resulting buffer.
+/// Rewriter requires some objects to exist at least as long as it does so this
+/// class contains instances of those objects.
+///
+/// FIXME: These objects should really come from somewhere more global instead
+/// of being recreated for every Transform subclass, especially diagnostics.
+class RewriterContainer {
+public:
+  RewriterContainer(clang::FileManager &Files,
+                    const FileContentsByPath &InputStates)
+    : DiagOpts(new clang::DiagnosticOptions()),
+      DiagnosticPrinter(llvm::errs(), DiagOpts.getPtr()),
+      Diagnostics(llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs>(
+                    new clang::DiagnosticIDs()),
+                  DiagOpts.getPtr(), &DiagnosticPrinter, false),
+      Sources(Diagnostics, Files),
+      Rewrite(Sources, DefaultLangOptions) {
+
+    // Overwrite source manager's file contents with data from InputStates
+    for (FileContentsByPath::const_iterator I = InputStates.begin(),
+                                            E = InputStates.end();
+         I != E; ++I) {
+      Sources.overrideFileContents(Files.getFile(I->first),
+                                   llvm::MemoryBuffer::getMemBuffer(I->second));
+    }
+  }
+
+  clang::Rewriter &getRewriter() { return Rewrite; }
+
+private:
+  clang::LangOptions DefaultLangOptions;
+  llvm::IntrusiveRefCntPtr<clang::DiagnosticOptions> DiagOpts;
+  clang::TextDiagnosticPrinter DiagnosticPrinter;
+  clang::DiagnosticsEngine Diagnostics;
+  clang::SourceManager Sources;
+  clang::Rewriter Rewrite;
+};
+
+/// \brief Abstract base class for all C++11 migration transforms.
+///
+/// Per-source performance timing is handled by the callbacks
+/// handleBeginSource() and handleEndSource() if timing is enabled. See
+/// clang::tooling::newFrontendActionFactory() for how to register
+/// a Transform object for callbacks.
+class Transform : public clang::tooling::SourceFileCallbacks {
+public:
+  /// \brief Constructor
+  /// \param Name Name of the transform for human-readable purposes (e.g. -help
+  /// text)
+  /// \param EnableTiming Enable the timing of the duration between calls to
+  /// handleBeginSource() and handleEndSource(). When a Transform object is
+  /// registered for FrontendAction source file callbacks, this behaviour can
+  /// be used to time the application of a MatchFinder by subclasses. Durations
+  /// are automatically stored in a TimingVec.
+  Transform(llvm::StringRef Name, bool EnableTiming)
+      : Name(Name), EnableTiming(EnableTiming) {
+    Reset();
+  }
+
+  virtual ~Transform() {}
+
+  /// \brief Apply a transform to all files listed in \p SourcePaths.
+  ///
+  /// \p Database must contain information for how to compile all files in \p
+  /// SourcePaths. \p InputStates contains the file contents of files in \p
+  /// SourcePaths and should take precedence over content of files on disk.
+  /// Upon return, \p ResultStates shall contain the result of performing this
+  /// transform on the files listed in \p SourcePaths.
+  virtual int apply(const FileContentsByPath &InputStates,
+                    RiskLevel MaxRiskLevel,
+                    const clang::tooling::CompilationDatabase &Database,
+                    const std::vector<std::string> &SourcePaths,
+                    FileContentsByPath &ResultStates) = 0;
+
+  /// \brief Query if changes were made during the last call to apply().
+  bool getChangesMade() const { return AcceptedChanges > 0; }
+
+  /// \brief Query if changes were not made due to conflicts with other changes
+  /// made during the last call to apply() or if changes were too risky for the
+  /// requested risk level.
+  bool getChangesNotMade() const {
+    return RejectedChanges > 0 || DeferredChanges > 0;
+  }
+
+  /// \brief Query the number of accepted changes.
+  unsigned getAcceptedChanges() const { return AcceptedChanges; }
+  /// \brief Query the number of changes considered too risky.
+  unsigned getRejectedChanges() const { return RejectedChanges; }
+  /// \brief Query the number of changes not made because they conflicted with
+  /// early changes.
+  unsigned getDeferredChanges() const { return DeferredChanges; }
+
+  /// \brief Query transform name.
+  llvm::StringRef getName() const { return Name; }
+
+  /// \brief Reset internal state of the transform.
+  ///
+  /// Useful if calling apply() several times with one instantiation of a
+  /// transform.
+  void Reset() {
+    AcceptedChanges = 0;
+    RejectedChanges = 0;
+    DeferredChanges = 0;
+  }
+
+  /// \brief Callback for notification of the start of processing of a source
+  /// file by a FrontendAction. Starts a performance timer if timing was
+  /// enabled.
+  virtual bool handleBeginSource(clang::CompilerInstance &CI,
+                                 llvm::StringRef Filename) LLVM_OVERRIDE;
+
+  /// \brief Callback for notification of the end of processing of a source
+  /// file by a FrontendAction. Stops a performance timer if timing was enabled
+  /// and records the elapsed time. For a given source, handleBeginSource() and
+  /// handleEndSource() are expected to be called in pairs.
+  virtual void handleEndSource() LLVM_OVERRIDE;
+
+  /// \brief Performance timing data is stored as a vector of pairs. Pairs are
+  /// formed of:
+  /// \li Name of source file.
+  /// \li Elapsed time.
+  typedef std::vector<std::pair<std::string, llvm::TimeRecord> > TimingVec;
+
+  /// \brief Return an iterator to the start of collected timing data.
+  TimingVec::const_iterator timing_begin() const { return Timings.begin(); }
+  /// \brief Return an iterator to the start of collected timing data.
+  TimingVec::const_iterator timing_end() const { return Timings.end(); }
+
+protected:
+
+  void setAcceptedChanges(unsigned Changes) {
+    AcceptedChanges = Changes;
+  }
+  void setRejectedChanges(unsigned Changes) {
+    RejectedChanges = Changes;
+  }
+  void setDeferredChanges(unsigned Changes) {
+    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;
+  TimingVec Timings;
+  unsigned AcceptedChanges;
+  unsigned RejectedChanges;
+  unsigned DeferredChanges;
+};
+
+#endif // LLVM_TOOLS_CLANG_TOOLS_EXTRA_CPP11_MIGRATE_TRANSFORM_H

Modified: clang-tools-extra/trunk/cpp11-migrate/tool/Cpp11Migrate.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/cpp11-migrate/tool/Cpp11Migrate.cpp?rev=183274&r1=183273&r2=183274&view=diff
==============================================================================
--- clang-tools-extra/trunk/cpp11-migrate/tool/Cpp11Migrate.cpp (original)
+++ clang-tools-extra/trunk/cpp11-migrate/tool/Cpp11Migrate.cpp Tue Jun  4 17:37:02 2013
@@ -1,252 +1,196 @@
-//===-- 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 implements the C++11 feature migration tool main function
-/// and transformation framework.
-///
-/// See user documentation for usage instructions.
-///
-//===----------------------------------------------------------------------===//
-
-#include "Core/Transforms.h"
-#include "Core/Transform.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;
-
-static cl::opt<RiskLevel> MaxRiskLevel(
-    "risk", cl::desc("Select a maximum risk level:"),
-    cl::values(clEnumValN(RL_Safe, "safe", "Only safe transformations"),
-               clEnumValN(RL_Reasonable, "reasonable",
-                          "Enable transformations that might change "
-                          "semantics (default)"),
-               clEnumValN(RL_Risky, "risky",
-                          "Enable transformations that are likely to "
-                          "change semantics"),
-               clEnumValEnd),
-    cl::init(RL_Reasonable));
-
-static cl::opt<bool> FinalSyntaxCheck(
-    "final-syntax-check",
-    cl::desc("Check for correct syntax after applying transformations"),
-    cl::init(false));
-
-static cl::opt<bool>
-SummaryMode("summary", cl::desc("Print transform summary"),
-            cl::init(false));
-
-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"),
-    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<std::string>
-IncludePaths("include", cl::Hidden,
-             cl::desc("Comma seperated list of paths to consider to be "
-                      "transformed"));
-static cl::opt<std::string>
-ExcludePaths("exclude", cl::Hidden,
-             cl::desc("Comma seperated list of paths that can not "
-                      "be transformed"));
-static cl::opt<std::string>
-IncludeFromFile("include-from", cl::Hidden, cl::value_desc("filename"),
-                cl::desc("File containing a list of paths to consider to "
-                         "be transformed"));
-static cl::opt<std::string>
-ExcludeFromFile("exclude-from", cl::Hidden, cl::value_desc("filename"),
-                cl::desc("File containing a list of paths that can not be "
-                         "transforms"));
-
-class EndSyntaxArgumentsAdjuster : public ArgumentsAdjuster {
-  CommandLineArguments Adjust(const CommandLineArguments &Args) {
-    CommandLineArguments AdjustedArgs = Args;
-    AdjustedArgs.push_back("-fsyntax-only");
-    AdjustedArgs.push_back("-std=c++11");
-    return AdjustedArgs;
-  }
-};
-
-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.
-  // FIXME: id_type on Windows is NOT a process id despite the function name.
-  // Need to call GetProcessId() providing it what get_id() returns. For now
-  // disabling PID-based file names until this is fixed properly.
-  //llvm::sys::self_process *SP = llvm::sys::process::get_self();
-  //id_type Pid = SP->get_id();
-  unsigned Pid = 0;
-  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;
-
-  TransformManager.registerTransform(
-      "loop-convert", "Make use of range-based for loops where possible",
-      &ConstructTransform<LoopConvertTransform>);
-  TransformManager.registerTransform(
-      "use-nullptr", "Make use of nullptr keyword where possible",
-      &ConstructTransform<UseNullptrTransform>);
-  TransformManager.registerTransform(
-      "use-auto", "Use of 'auto' type specifier",
-      &ConstructTransform<UseAutoTransform>);
-  TransformManager.registerTransform(
-      "add-override", "Make use of override specifier where possible",
-      &ConstructTransform<AddOverrideTransform>);
-  // Add more transform options here.
-
-  // This causes options to be parsed.
-  CommonOptionsParser OptionsParser(argc, argv);
-
-  // 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()) {
-    llvm::errs() << "No selected transforms\n";
-    return 1;
-  }
-
-  FileContentsByPath FileStates1, FileStates2,
-      *InputFileStates = &FileStates1, *OutputFileStates = &FileStates2;
-
-  // Apply transforms.
-  for (Transforms::const_iterator I = TransformManager.begin(),
-                                  E = TransformManager.end();
-       I != E; ++I) {
-    if ((*I)->apply(*InputFileStates, MaxRiskLevel,
-                    OptionsParser.getCompilations(),
-                    OptionsParser.getSourcePathList(), *OutputFileStates) !=
-        0) {
-      // FIXME: Improve ClangTool to not abort if just one file fails.
-      return 1;
-    }
-    if (SummaryMode) {
-      llvm::outs() << "Transform: " << (*I)->getName()
-                   << " - Accepted: "
-                   << (*I)->getAcceptedChanges();
-      if ((*I)->getChangesNotMade()) {
-         llvm::outs() << " - Rejected: "
-                      << (*I)->getRejectedChanges()
-                      << " - Deferred: "
-                      << (*I)->getDeferredChanges();
-      }
-      llvm::outs() << "\n";
-    }
-    std::swap(InputFileStates, OutputFileStates);
-    OutputFileStates->clear();
-  }
-
-  // Final state of files is pointed at by InputFileStates.
-
-  if (FinalSyntaxCheck) {
-    ClangTool EndSyntaxTool(OptionsParser.getCompilations(),
-                            OptionsParser.getSourcePathList());
-
-    // Add c++11 support to clang.
-    EndSyntaxTool.setArgumentsAdjuster(new EndSyntaxArgumentsAdjuster);
-
-    for (FileContentsByPath::const_iterator I = InputFileStates->begin(),
-                                            E = InputFileStates->end();
-         I != E; ++I) {
-      EndSyntaxTool.mapVirtualFile(I->first, I->second);
-    }
-
-    if (EndSyntaxTool.run(newFrontendActionFactory<clang::SyntaxOnlyAction>())
-        != 0) {
-      return 1;
-    }
-  }
-
-  // Write results to file.
-  for (FileContentsByPath::const_iterator I = InputFileStates->begin(),
-                                          E = InputFileStates->end();
-       I != E; ++I) {
-    std::string ErrorInfo;
-    llvm::raw_fd_ostream FileStream(I->first.c_str(), ErrorInfo,
-                                    llvm::raw_fd_ostream::F_Binary);
-    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;
-}
+//===-- 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 implements the C++11 feature migration tool main function
+/// and transformation framework.
+///
+/// See user documentation for usage instructions.
+///
+//===----------------------------------------------------------------------===//
+
+#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/Signals.h"
+
+namespace cl = llvm::cl;
+using namespace clang::tooling;
+
+static cl::opt<RiskLevel> MaxRiskLevel(
+    "risk", cl::desc("Select a maximum risk level:"),
+    cl::values(clEnumValN(RL_Safe, "safe", "Only safe transformations"),
+               clEnumValN(RL_Reasonable, "reasonable",
+                          "Enable transformations that might change "
+                          "semantics (default)"),
+               clEnumValN(RL_Risky, "risky",
+                          "Enable transformations that are likely to "
+                          "change semantics"),
+               clEnumValEnd),
+    cl::init(RL_Reasonable));
+
+static cl::opt<bool> FinalSyntaxCheck(
+    "final-syntax-check",
+    cl::desc("Check for correct syntax after applying transformations"),
+    cl::init(false));
+
+static cl::opt<bool>
+SummaryMode("summary", cl::desc("Print transform summary"),
+            cl::init(false));
+
+const char NoTiming[] = "no_timing";
+static cl::opt<std::string> TimingDirectoryName(
+    "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
+// options are implemented in the tool.
+static cl::opt<std::string>
+IncludePaths("include", cl::Hidden,
+             cl::desc("Comma seperated list of paths to consider to be "
+                      "transformed"));
+static cl::opt<std::string>
+ExcludePaths("exclude", cl::Hidden,
+             cl::desc("Comma seperated list of paths that can not "
+                      "be transformed"));
+static cl::opt<std::string>
+IncludeFromFile("include-from", cl::Hidden, cl::value_desc("filename"),
+                cl::desc("File containing a list of paths to consider to "
+                         "be transformed"));
+static cl::opt<std::string>
+ExcludeFromFile("exclude-from", cl::Hidden, cl::value_desc("filename"),
+                cl::desc("File containing a list of paths that can not be "
+                         "transforms"));
+
+class EndSyntaxArgumentsAdjuster : public ArgumentsAdjuster {
+  CommandLineArguments Adjust(const CommandLineArguments &Args) {
+    CommandLineArguments AdjustedArgs = Args;
+    AdjustedArgs.push_back("-fsyntax-only");
+    AdjustedArgs.push_back("-std=c++11");
+    return AdjustedArgs;
+  }
+};
+
+int main(int argc, const char **argv) {
+  llvm::sys::PrintStackTraceOnErrorSignal();
+  Transforms TransformManager;
+
+  TransformManager.registerTransform(
+      "loop-convert", "Make use of range-based for loops where possible",
+      &ConstructTransform<LoopConvertTransform>);
+  TransformManager.registerTransform(
+      "use-nullptr", "Make use of nullptr keyword where possible",
+      &ConstructTransform<UseNullptrTransform>);
+  TransformManager.registerTransform(
+      "use-auto", "Use of 'auto' type specifier",
+      &ConstructTransform<UseAutoTransform>);
+  TransformManager.registerTransform(
+      "add-override", "Make use of override specifier where possible",
+      &ConstructTransform<AddOverrideTransform>);
+  // Add more transform options here.
+
+  // This causes options to be parsed.
+  CommonOptionsParser OptionsParser(argc, argv);
+
+  // 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);
+  TransformManager.createSelectedTransforms(EnableTiming);
+
+  if (TransformManager.begin() == TransformManager.end()) {
+    llvm::errs() << "No selected transforms\n";
+    return 1;
+  }
+
+  FileContentsByPath FileStates1, FileStates2,
+      *InputFileStates = &FileStates1, *OutputFileStates = &FileStates2;
+
+  SourcePerfData PerfData;
+
+  // Apply transforms.
+  for (Transforms::const_iterator I = TransformManager.begin(),
+                                  E = TransformManager.end();
+       I != E; ++I) {
+    if ((*I)->apply(*InputFileStates, MaxRiskLevel,
+                    OptionsParser.getCompilations(),
+                    OptionsParser.getSourcePathList(), *OutputFileStates) !=
+        0) {
+      // 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: "
+                   << (*I)->getAcceptedChanges();
+      if ((*I)->getChangesNotMade()) {
+         llvm::outs() << " - Rejected: "
+                      << (*I)->getRejectedChanges()
+                      << " - Deferred: "
+                      << (*I)->getDeferredChanges();
+      }
+      llvm::outs() << "\n";
+    }
+    std::swap(InputFileStates, OutputFileStates);
+    OutputFileStates->clear();
+  }
+
+  // Final state of files is pointed at by InputFileStates.
+
+  if (FinalSyntaxCheck) {
+    ClangTool EndSyntaxTool(OptionsParser.getCompilations(),
+                            OptionsParser.getSourcePathList());
+
+    // Add c++11 support to clang.
+    EndSyntaxTool.setArgumentsAdjuster(new EndSyntaxArgumentsAdjuster);
+
+    for (FileContentsByPath::const_iterator I = InputFileStates->begin(),
+                                            E = InputFileStates->end();
+         I != E; ++I) {
+      EndSyntaxTool.mapVirtualFile(I->first, I->second);
+    }
+
+    if (EndSyntaxTool.run(newFrontendActionFactory<clang::SyntaxOnlyAction>())
+        != 0) {
+      return 1;
+    }
+  }
+
+  // Write results to file.
+  for (FileContentsByPath::const_iterator I = InputFileStates->begin(),
+                                          E = InputFileStates->end();
+       I != E; ++I) {
+    std::string ErrorInfo;
+    llvm::raw_fd_ostream FileStream(I->first.c_str(), ErrorInfo,
+                                    llvm::raw_fd_ostream::F_Binary);
+    FileStream << I->second;
+  }
+
+  // Report execution times.
+  if (EnableTiming && !PerfData.empty()) {
+    std::string DirectoryName = TimingDirectoryName;
+    // Use default directory name.
+    if (DirectoryName.empty())
+      DirectoryName = "./migrate_perf";
+    writePerfDataJSON(DirectoryName, PerfData);
+  }
+
+  return 0;
+}

Modified: clang-tools-extra/trunk/unittests/cpp11-migrate/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/cpp11-migrate/CMakeLists.txt?rev=183274&r1=183273&r2=183274&view=diff
==============================================================================
--- clang-tools-extra/trunk/unittests/cpp11-migrate/CMakeLists.txt (original)
+++ clang-tools-extra/trunk/unittests/cpp11-migrate/CMakeLists.txt Tue Jun  4 17:37:02 2013
@@ -1,18 +1,19 @@
-set(LLVM_LINK_COMPONENTS
-  support
-  )
-
-get_filename_component(CPP11_MIGRATE_SOURCE_DIR
-  ${CMAKE_CURRENT_SOURCE_DIR}/../../cpp11-migrate REALPATH)
-include_directories(${CPP11_MIGRATE_SOURCE_DIR})
-
-add_extra_unittest(Cpp11MigrateTests
-  TransformTest.cpp
-  IncludeExcludeTest.cpp)
-
-target_link_libraries(Cpp11MigrateTests
-  migrateCore
-  clangTooling
-  clangBasic
-  clangASTMatchers
-  )
+set(LLVM_LINK_COMPONENTS
+  support
+  )
+
+get_filename_component(CPP11_MIGRATE_SOURCE_DIR
+  ${CMAKE_CURRENT_SOURCE_DIR}/../../cpp11-migrate REALPATH)
+include_directories(${CPP11_MIGRATE_SOURCE_DIR})
+
+add_extra_unittest(Cpp11MigrateTests
+  TransformTest.cpp
+  IncludeExcludeTest.cpp
+  PerfSupportTest.cpp)
+
+target_link_libraries(Cpp11MigrateTests
+  migrateCore
+  clangTooling
+  clangBasic
+  clangASTMatchers
+  )

Added: clang-tools-extra/trunk/unittests/cpp11-migrate/PerfSupportTest.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/cpp11-migrate/PerfSupportTest.cpp?rev=183274&view=auto
==============================================================================
--- clang-tools-extra/trunk/unittests/cpp11-migrate/PerfSupportTest.cpp (added)
+++ clang-tools-extra/trunk/unittests/cpp11-migrate/PerfSupportTest.cpp Tue Jun  4 17:37:02 2013
@@ -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);
+}





More information about the cfe-commits mailing list