Add a new command line option for PassManager using utilities.
Now for llc, gccas, analyze, opt, etc you can specify the -time-passes
command line option that outputs a timing summary report that indicates
how long each pass takes to execute.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@2394 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/VMCore/Pass.cpp b/lib/VMCore/Pass.cpp
index c3c9d45..0344dd6 100644
--- a/lib/VMCore/Pass.cpp
+++ b/lib/VMCore/Pass.cpp
@@ -15,6 +15,8 @@
#include "Support/CommandLine.h"
#include <typeinfo>
#include <iostream>
+#include <sys/time.h>
+#include <stdio.h>
// Source of unique analysis ID #'s.
unsigned AnalysisID::NextID = 0;
@@ -50,6 +52,64 @@
//===----------------------------------------------------------------------===//
+// TimingInfo Class - This class is used to calculate information about the
+// amount of time each pass takes to execute. This only happens with
+// -time-passes is enabled on the command line.
+//
+static cl::Flag EnableTiming("time-passes", "Time each pass, printing elapsed"
+ " time for each on exit");
+
+static double getTime() {
+ struct timeval T;
+ gettimeofday(&T, 0);
+ return T.tv_sec + T.tv_usec/1000000.0;
+}
+
+// Create method. If Timing is enabled, this creates and returns a new timing
+// object, otherwise it returns null.
+//
+TimingInfo *TimingInfo::create() {
+ return EnableTiming ? new TimingInfo() : 0;
+}
+
+void TimingInfo::passStarted(Pass *P) { TimingData[P] -= getTime(); }
+void TimingInfo::passEnded(Pass *P) { TimingData[P] += getTime(); }
+
+// TimingDtor - Print out information about timing information
+TimingInfo::~TimingInfo() {
+ // Iterate over all of the data, converting it into the dual of the data map,
+ // so that the data is sorted by amount of time taken, instead of pointer.
+ //
+ std::vector<pair<double, Pass*> > Data;
+ double TotalTime = 0;
+ for (std::map<Pass*, double>::iterator I = TimingData.begin(),
+ E = TimingData.end(); I != E; ++I)
+ // Throw out results for "grouping" pass managers...
+ if (!dynamic_cast<AnalysisResolver*>(I->first)) {
+ Data.push_back(std::make_pair(I->second, I->first));
+ TotalTime += I->second;
+ }
+
+ // Sort the data by time as the primary key, in reverse order...
+ std::sort(Data.begin(), Data.end(), greater<pair<double, Pass*> >());
+
+ // Print out timing header...
+ cerr << std::string(79, '=') << "\n"
+ << " ... Pass execution timing report ...\n"
+ << std::string(79, '=') << "\n Total Execution Time: " << TotalTime
+ << " seconds\n\n % Time: Seconds:\tPass Name (mangled):\n";
+
+ // Loop through all of the timing data, printing it out...
+ for (unsigned i = 0, e = Data.size(); i != e; ++i) {
+ fprintf(stderr, " %6.2f%% %fs\t%s\n", Data[i].first*100 / TotalTime,
+ Data[i].first, typeid(*Data[i].second).name());
+ }
+ cerr << " 100.00% " << TotalTime << "s\tTOTAL\n"
+ << std::string(79, '=') << "\n";
+}
+
+
+//===----------------------------------------------------------------------===//
// Pass debugging information. Often it is useful to find out what pass is
// running when a crash occurs in a utility. When this library is compiled with
// debugging on, a command line option (--debug-pass) is enabled that causes the
diff --git a/lib/VMCore/PassManagerT.h b/lib/VMCore/PassManagerT.h
index eb80740..8d1716b 100644
--- a/lib/VMCore/PassManagerT.h
+++ b/lib/VMCore/PassManagerT.h
@@ -35,6 +35,28 @@
};
+//===----------------------------------------------------------------------===//
+// TimingInfo Class - This class is used to calculate information about the
+// amount of time each pass takes to execute. This only happens when
+// -time-passes is enabled on the command line.
+//
+class TimingInfo {
+ std::map<Pass*, double> TimingData;
+ TimingInfo() {} // Private ctor, must use create member
+public:
+ // Create method. If Timing is enabled, this creates and returns a new timing
+ // object, otherwise it returns null.
+ //
+ static TimingInfo *create();
+
+ // TimingDtor - Print out information about timing information
+ ~TimingInfo();
+
+ void passStarted(Pass *P);
+ void passEnded(Pass *P);
+};
+
+
//===----------------------------------------------------------------------===//
// Declare the PassManagerTraits which will be specialized...
@@ -49,15 +71,15 @@
//
template<typename UnitType>
class PassManagerT : public PassManagerTraits<UnitType>,public AnalysisResolver{
- typedef typename PassManagerTraits<UnitType>::PassClass PassClass;
- typedef typename PassManagerTraits<UnitType>::SubPassClass SubPassClass;
- typedef typename PassManagerTraits<UnitType>::BatcherClass BatcherClass;
- typedef typename PassManagerTraits<UnitType>::ParentClass ParentClass;
- typedef PassManagerTraits<UnitType> Traits;
+ typedef PassManagerTraits<UnitType> Traits;
+ typedef typename Traits::PassClass PassClass;
+ typedef typename Traits::SubPassClass SubPassClass;
+ typedef typename Traits::BatcherClass BatcherClass;
+ typedef typename Traits::ParentClass ParentClass;
- friend typename PassManagerTraits<UnitType>::PassClass;
- friend typename PassManagerTraits<UnitType>::SubPassClass;
- friend class PassManagerTraits<UnitType>;
+ friend typename Traits::PassClass;
+ friend typename Traits::SubPassClass;
+ friend class Traits;
std::vector<PassClass*> Passes; // List of pass's to run
@@ -128,7 +150,9 @@
#endif
// Run the sub pass!
- bool Changed = Traits::runPass(P, M);
+ startPass(P);
+ bool Changed = runPass(P, M);
+ endPass(P);
MadeChanges |= Changed;
if (Changed)
@@ -217,6 +241,20 @@
return I->second;
}
+ // {start/end}Pass - Called when a pass is started, it just propogates
+ // information up to the top level PassManagerT object to tell it that a pass
+ // has started or ended. This is used to gather timing information about
+ // passes.
+ //
+ void startPass(Pass *P) {
+ if (Parent) Parent->startPass(P);
+ else PassStarted(P);
+ }
+ void endPass(Pass *P) {
+ if (Parent) Parent->endPass(P);
+ else PassEnded(P);
+ }
+
// markPassUsed - Inform higher level pass managers (and ourselves)
// that these analyses are being used by this pass. This is used to
// make sure that analyses are not free'd before we have to use
@@ -389,6 +427,10 @@
return P->runOnBasicBlock(M);
}
+ // Dummy implementation of PassStarted/PassEnded
+ static void PassStarted(Pass *P) {}
+ static void PassEnded(Pass *P) {}
+
// getPMName() - Return the name of the unit the PassManager operates on for
// debugging.
const char *getPMName() const { return "BasicBlock"; }
@@ -428,6 +470,10 @@
return P->runOnFunction(F);
}
+ // Dummy implementation of PassStarted/PassEnded
+ static void PassStarted(Pass *P) {}
+ static void PassEnded(Pass *P) {}
+
// getPMName() - Return the name of the unit the PassManager operates on for
// debugging.
const char *getPMName() const { return "Function"; }
@@ -465,10 +511,37 @@
// debugging.
const char *getPMName() const { return "Module"; }
- // run - Implement the Pass interface...
- bool run(Module *M) {
- return ((PassManagerT<Module>*)this)->runOnUnit(M);
+ // TimingInformation - This data member maintains timing information for each
+ // of the passes that is executed.
+ //
+ TimingInfo *TimeInfo;
+
+ // PassStarted/Ended - This callback is notified any time a pass is started
+ // or stops. This is used to collect timing information about the different
+ // passes being executed.
+ //
+ void PassStarted(Pass *P) {
+ if (TimeInfo) TimeInfo->passStarted(P);
}
+ void PassEnded(Pass *P) {
+ if (TimeInfo) TimeInfo->passEnded(P);
+ }
+
+ // run - Implement the PassManager interface...
+ bool run(Module *M) {
+ TimeInfo = TimingInfo::create();
+ bool Result = ((PassManagerT<Module>*)this)->runOnUnit(M);
+ if (TimeInfo) {
+ delete TimeInfo;
+ TimeInfo = 0;
+ }
+ return Result;
+ }
+
+ // PassManagerTraits constructor - Create a timing info object if the user
+ // specified timing info should be collected on the command line.
+ //
+ PassManagerTraits() : TimeInfo(0) {}
};