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) {}
 };