diff options
author | Edwin Vane <edwin.vane@intel.com> | 2013-05-30 17:48:11 +0000 |
---|---|---|
committer | Edwin Vane <edwin.vane@intel.com> | 2013-05-30 17:48:11 +0000 |
commit | b76a13eb4ee46fabb7eb55fb13d5687d25db800f (patch) | |
tree | e2c98f8b18a66acacdcd7c9127874891eb99290b /clang-tools-extra | |
parent | 8fe6d11b84ddbde08aeeae528e208e82a3ecc3c5 (diff) | |
download | bcm5719-llvm-b76a13eb4ee46fabb7eb55fb13d5687d25db800f.tar.gz bcm5719-llvm-b76a13eb4ee46fabb7eb55fb13d5687d25db800f.zip |
cpp11-migrate: Transforms collect timing data.
Using updated form of newFrontendActionFactory(), Transforms now automatically
measure, if requested, how long it takes to apply a MatchFinder to a source
file. Other per-transform overhead, e.g. applying replacements, is not
currently measured. This behaviour is disabled for now and soon will be
connected to a new command line arg.
llvm-svn: 182942
Diffstat (limited to 'clang-tools-extra')
14 files changed, 172 insertions, 20 deletions
diff --git a/clang-tools-extra/cpp11-migrate/AddOverride/AddOverride.cpp b/clang-tools-extra/cpp11-migrate/AddOverride/AddOverride.cpp index d75c658ec69..f431c34c88f 100644 --- a/clang-tools-extra/cpp11-migrate/AddOverride/AddOverride.cpp +++ b/clang-tools-extra/cpp11-migrate/AddOverride/AddOverride.cpp @@ -45,7 +45,8 @@ int AddOverrideTransform::apply(const FileContentsByPath &InputStates, Finder.addMatcher(makeCandidateForOverrideAttrMatcher(), &Fixer); - if (int result = AddOverrideTool.run(newFrontendActionFactory(&Finder))) { + if (int result = AddOverrideTool.run( + newFrontendActionFactory(&Finder, /*Callbacks=*/ this))) { llvm::errs() << "Error encountered during translation.\n"; return result; } diff --git a/clang-tools-extra/cpp11-migrate/AddOverride/AddOverride.h b/clang-tools-extra/cpp11-migrate/AddOverride/AddOverride.h index 9b1aa1535ba..1e9de5d5c71 100644 --- a/clang-tools-extra/cpp11-migrate/AddOverride/AddOverride.h +++ b/clang-tools-extra/cpp11-migrate/AddOverride/AddOverride.h @@ -24,7 +24,8 @@ /// member functions overriding base class virtual functions. class AddOverrideTransform : public Transform { public: - AddOverrideTransform() : Transform("AddOverride") {} + AddOverrideTransform(bool EnableTiming) + : Transform("AddOverride", EnableTiming) {} /// \see Transform::run(). virtual int apply(const FileContentsByPath &InputStates, diff --git a/clang-tools-extra/cpp11-migrate/Core/Transform.cpp b/clang-tools-extra/cpp11-migrate/Core/Transform.cpp index d235356075f..c6bb835321d 100644 --- a/clang-tools-extra/cpp11-migrate/Core/Transform.cpp +++ b/clang-tools-extra/cpp11-migrate/Core/Transform.cpp @@ -35,3 +35,19 @@ void collectResults(clang::Rewriter &Rewrite, 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); +} diff --git a/clang-tools-extra/cpp11-migrate/Core/Transform.h b/clang-tools-extra/cpp11-migrate/Core/Transform.h index adc02989536..73a2a00a816 100644 --- a/clang-tools-extra/cpp11-migrate/Core/Transform.h +++ b/clang-tools-extra/cpp11-migrate/Core/Transform.h @@ -17,6 +17,8 @@ #include <string> #include <vector> +#include "clang/Tooling/Tooling.h" +#include "llvm/Support/Timer.h" // For RewriterContainer #include "clang/Rewrite/Core/Rewriter.h" @@ -104,9 +106,23 @@ private: }; /// \brief Abstract base class for all C++11 migration transforms. -class Transform { +/// +/// 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: - Transform(llvm::StringRef Name) : Name(Name) { + /// \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(); } @@ -156,7 +172,31 @@ public: 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; } @@ -169,6 +209,8 @@ protected: private: const std::string Name; + bool EnableTiming; + TimingVec Timings; unsigned AcceptedChanges; unsigned RejectedChanges; unsigned DeferredChanges; diff --git a/clang-tools-extra/cpp11-migrate/Core/Transforms.cpp b/clang-tools-extra/cpp11-migrate/Core/Transforms.cpp index d7eae694870..85c0e2103a7 100644 --- a/clang-tools-extra/cpp11-migrate/Core/Transforms.cpp +++ b/clang-tools-extra/cpp11-migrate/Core/Transforms.cpp @@ -35,11 +35,11 @@ void Transforms::registerTransform(llvm::StringRef OptName, new cl::opt<bool>(OptName.data(), cl::desc(Description.data())), Creator)); } -void Transforms::createSelectedTransforms() { +void Transforms::createSelectedTransforms(bool EnableTiming) { for (OptionVec::iterator I = Options.begin(), E = Options.end(); I != E; ++I) { if (*I->first) { - ChosenTransforms.push_back(I->second()); + ChosenTransforms.push_back(I->second(EnableTiming)); } } } diff --git a/clang-tools-extra/cpp11-migrate/Core/Transforms.h b/clang-tools-extra/cpp11-migrate/Core/Transforms.h index 67e38b025c8..b19b0316d90 100644 --- a/clang-tools-extra/cpp11-migrate/Core/Transforms.h +++ b/clang-tools-extra/cpp11-migrate/Core/Transforms.h @@ -28,10 +28,10 @@ class Option; } // namespace llvm class Transform; -typedef Transform *(*TransformCreator)(); +typedef Transform *(*TransformCreator)(bool); template <typename T> -Transform *ConstructTransform() { - return new T(); +Transform *ConstructTransform(bool EnableTiming) { + return new T(EnableTiming); } /// \brief Class encapsulating the creation of command line bool options @@ -55,7 +55,7 @@ public: /// \brief Instantiate all transforms that were selected on the command line. /// /// Call *after* parsing options. - void createSelectedTransforms(); + void createSelectedTransforms(bool EnableTiming); /// \brief Return an iterator to the start of a container of instantiated /// transforms. diff --git a/clang-tools-extra/cpp11-migrate/LoopConvert/LoopConvert.cpp b/clang-tools-extra/cpp11-migrate/LoopConvert/LoopConvert.cpp index 7e95d7555cd..9afd4990e45 100644 --- a/clang-tools-extra/cpp11-migrate/LoopConvert/LoopConvert.cpp +++ b/clang-tools-extra/cpp11-migrate/LoopConvert/LoopConvert.cpp @@ -64,7 +64,8 @@ int LoopConvertTransform::apply(const FileContentsByPath &InputStates, MaxRisk, LFK_PseudoArray); Finder.addMatcher(makePseudoArrayLoopMatcher(), &PseudoarrrayLoopFixer); - if (int result = LoopTool.run(newFrontendActionFactory(&Finder))) { + if (int result = LoopTool.run( + newFrontendActionFactory(&Finder, /*Callbacks=*/ this))) { llvm::errs() << "Error encountered during translation.\n"; return result; } diff --git a/clang-tools-extra/cpp11-migrate/LoopConvert/LoopConvert.h b/clang-tools-extra/cpp11-migrate/LoopConvert/LoopConvert.h index 361855d3f1c..25c6460af04 100644 --- a/clang-tools-extra/cpp11-migrate/LoopConvert/LoopConvert.h +++ b/clang-tools-extra/cpp11-migrate/LoopConvert/LoopConvert.h @@ -23,7 +23,8 @@ /// for-loops where possible. class LoopConvertTransform : public Transform { public: - LoopConvertTransform() : Transform("LoopConvert") {} + LoopConvertTransform(bool EnableTiming) + : Transform("LoopConvert", EnableTiming) {} /// \see Transform::run(). virtual int apply(const FileContentsByPath &InputStates, diff --git a/clang-tools-extra/cpp11-migrate/UseAuto/UseAuto.cpp b/clang-tools-extra/cpp11-migrate/UseAuto/UseAuto.cpp index 7a56e1c1250..a8e839d1c81 100644 --- a/clang-tools-extra/cpp11-migrate/UseAuto/UseAuto.cpp +++ b/clang-tools-extra/cpp11-migrate/UseAuto/UseAuto.cpp @@ -43,7 +43,8 @@ int UseAutoTransform::apply(const FileContentsByPath &InputStates, Finder.addMatcher(makeIteratorDeclMatcher(), &ReplaceIterators); Finder.addMatcher(makeDeclWithNewMatcher(), &ReplaceNew); - if (int Result = UseAutoTool.run(newFrontendActionFactory(&Finder))) { + if (int Result = UseAutoTool.run( + newFrontendActionFactory(&Finder, /*Callbacks=*/ this))) { llvm::errs() << "Error encountered during translation.\n"; return Result; } diff --git a/clang-tools-extra/cpp11-migrate/UseAuto/UseAuto.h b/clang-tools-extra/cpp11-migrate/UseAuto/UseAuto.h index 684da880e89..5e83d867a8e 100644 --- a/clang-tools-extra/cpp11-migrate/UseAuto/UseAuto.h +++ b/clang-tools-extra/cpp11-migrate/UseAuto/UseAuto.h @@ -29,7 +29,7 @@ /// p2 are not handled by this transform. class UseAutoTransform : public Transform { public: - UseAutoTransform() : Transform("UseAuto") {} + UseAutoTransform(bool EnableTiming) : Transform("UseAuto", EnableTiming) {} /// \see Transform::run(). virtual int apply(const FileContentsByPath &InputStates, diff --git a/clang-tools-extra/cpp11-migrate/UseNullptr/UseNullptr.cpp b/clang-tools-extra/cpp11-migrate/UseNullptr/UseNullptr.cpp index 573604a9c53..0f8b1a84f4b 100644 --- a/clang-tools-extra/cpp11-migrate/UseNullptr/UseNullptr.cpp +++ b/clang-tools-extra/cpp11-migrate/UseNullptr/UseNullptr.cpp @@ -47,7 +47,8 @@ int UseNullptrTransform::apply(const FileContentsByPath &InputStates, Finder.addMatcher(makeCastSequenceMatcher(), &Fixer); - if (int result = UseNullptrTool.run(newFrontendActionFactory(&Finder))) { + if (int result = UseNullptrTool.run( + newFrontendActionFactory(&Finder, /*Callbacks=*/ this))) { llvm::errs() << "Error encountered during translation.\n"; return result; } diff --git a/clang-tools-extra/cpp11-migrate/UseNullptr/UseNullptr.h b/clang-tools-extra/cpp11-migrate/UseNullptr/UseNullptr.h index 02691f6e08b..49cdc45baa5 100644 --- a/clang-tools-extra/cpp11-migrate/UseNullptr/UseNullptr.h +++ b/clang-tools-extra/cpp11-migrate/UseNullptr/UseNullptr.h @@ -23,7 +23,8 @@ /// C++11's nullptr keyword where possible. class UseNullptrTransform : public Transform { public: - UseNullptrTransform() : Transform("UseNullptr") {} + UseNullptrTransform(bool EnableTiming) + : Transform("UseNullptr", EnableTiming) {} /// \see Transform::run(). virtual int apply(const FileContentsByPath &InputStates, diff --git a/clang-tools-extra/cpp11-migrate/tool/Cpp11Migrate.cpp b/clang-tools-extra/cpp11-migrate/tool/Cpp11Migrate.cpp index d71626ce828..88c1bfcca70 100644 --- a/clang-tools-extra/cpp11-migrate/tool/Cpp11Migrate.cpp +++ b/clang-tools-extra/cpp11-migrate/tool/Cpp11Migrate.cpp @@ -99,7 +99,7 @@ int main(int argc, const char **argv) { // This causes options to be parsed. CommonOptionsParser OptionsParser(argc, argv); - TransformManager.createSelectedTransforms(); + TransformManager.createSelectedTransforms(/*EnableTiming=*/false); if (TransformManager.begin() == TransformManager.end()) { llvm::errs() << "No selected transforms\n"; diff --git a/clang-tools-extra/unittests/cpp11-migrate/TransformTest.cpp b/clang-tools-extra/unittests/cpp11-migrate/TransformTest.cpp index 9d64930e327..76e5e3a1f94 100644 --- a/clang-tools-extra/unittests/cpp11-migrate/TransformTest.cpp +++ b/clang-tools-extra/unittests/cpp11-migrate/TransformTest.cpp @@ -1,13 +1,20 @@ #include "gtest/gtest.h" #include "Core/Transform.h" +#include "clang/AST/ASTConsumer.h" +#include "clang/AST/DeclGroup.h" +#include "llvm/Support/Process.h" +#include "llvm/Support/Path.h" + +using namespace clang; class DummyTransform : public Transform { public: - DummyTransform(llvm::StringRef Name) : Transform(Name) {} + DummyTransform(llvm::StringRef Name, bool EnableTiming) + : Transform(Name, EnableTiming) {} virtual int apply(const FileContentsByPath &, RiskLevel , - const clang::tooling::CompilationDatabase &, + const tooling::CompilationDatabase &, const std::vector<std::string> &, FileContentsByPath &) { return 0; } @@ -23,7 +30,7 @@ public: }; TEST(Transform, Interface) { - DummyTransform T("my_transform"); + DummyTransform T("my_transform", /*EnableTiming=*/false); ASSERT_EQ("my_transform", T.getName()); ASSERT_EQ(0u, T.getAcceptedChanges()); ASSERT_EQ(0u, T.getRejectedChanges()); @@ -48,3 +55,83 @@ TEST(Transform, Interface) { T.setRejectedChanges(1); ASSERT_TRUE(T.getChangesNotMade()); } + +class FindTopLevelDeclConsumer : public ASTConsumer { +public: + FindTopLevelDeclConsumer(bool *Called) : Called(Called) {} + + virtual bool HandleTopLevelDecl(DeclGroupRef DeclGroup) { + llvm::sys::TimeValue UserStart; + llvm::sys::TimeValue SystemStart; + llvm::sys::TimeValue UserNow; + llvm::sys::TimeValue SystemNow; + llvm::sys::TimeValue Wall; + + // Busy-wait until the user/system time combined is more than 1ms + llvm::sys::TimeValue OneMS(0, 1000000); + llvm::sys::Process::GetTimeUsage(Wall, UserStart, SystemStart); + do { + llvm::sys::Process::GetTimeUsage(Wall, UserNow, SystemNow); + } while (UserNow - UserStart + SystemNow - SystemStart < OneMS); + *Called = true; + return true; + } + bool *Called; +}; + +struct ConsumerFactory { + ASTConsumer *newASTConsumer() { + return new FindTopLevelDeclConsumer(&Called); + } + bool Called; +}; + +TEST(Transform, Timings) { + DummyTransform T("timing_transform", /*EnableTiming=*/true); + + // All the path stuff is to make the test work independently of OS. + + // The directory used is not important since the path gets mapped to a virtual + // file anyway. What is important is that we have an absolute path with which + // to use with mapVirtualFile(). + llvm::sys::Path FileA = llvm::sys::Path::GetCurrentDirectory(); + std::string CurrentDir = FileA.str(); + FileA.appendComponent("a.cc"); + std::string FileAName = FileA.str(); + llvm::sys::Path FileB = llvm::sys::Path::GetCurrentDirectory(); + FileB.appendComponent("b.cc"); + std::string FileBName = FileB.str(); + + tooling::FixedCompilationDatabase Compilations(CurrentDir, std::vector<std::string>()); + std::vector<std::string> Sources; + Sources.push_back(FileAName); + Sources.push_back(FileBName); + tooling::ClangTool Tool(Compilations, Sources); + + Tool.mapVirtualFile(FileAName, "void a() {}"); + Tool.mapVirtualFile(FileBName, "void b() {}"); + + ConsumerFactory Factory; + Tool.run(newFrontendActionFactory(&Factory, &T)); + + EXPECT_TRUE(Factory.Called); + Transform::TimingVec::const_iterator I = T.timing_begin(); + EXPECT_GT(I->second.getProcessTime(), 0.0); + + // The success of the test shouldn't depend on the order of iteration through + // timers. + llvm::sys::Path FirstFile(I->first); + if (FileA == FirstFile) { + ++I; + EXPECT_EQ(FileB, llvm::sys::Path(I->first)); + EXPECT_GT(I->second.getProcessTime(), 0.0); + } else if (FileB == FirstFile) { + ++I; + EXPECT_EQ(FileA, llvm::sys::Path(I->first)); + EXPECT_GT(I->second.getProcessTime(), 0.0); + } else { + FAIL() << "Unexpected file name " << I->first << " in timing data."; + } + ++I; + EXPECT_EQ(T.timing_end(), I); +} |