1e46ba31cSRiver Riddle //===- PassTiming.cpp -----------------------------------------------------===//
2e46ba31cSRiver Riddle //
3e46ba31cSRiver Riddle // Copyright 2019 The MLIR Authors.
4e46ba31cSRiver Riddle //
5e46ba31cSRiver Riddle // Licensed under the Apache License, Version 2.0 (the "License");
6e46ba31cSRiver Riddle // you may not use this file except in compliance with the License.
7e46ba31cSRiver Riddle // You may obtain a copy of the License at
8e46ba31cSRiver Riddle //
9e46ba31cSRiver Riddle //   http://www.apache.org/licenses/LICENSE-2.0
10e46ba31cSRiver Riddle //
11e46ba31cSRiver Riddle // Unless required by applicable law or agreed to in writing, software
12e46ba31cSRiver Riddle // distributed under the License is distributed on an "AS IS" BASIS,
13e46ba31cSRiver Riddle // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14e46ba31cSRiver Riddle // See the License for the specific language governing permissions and
15e46ba31cSRiver Riddle // limitations under the License.
16e46ba31cSRiver Riddle // =============================================================================
17e46ba31cSRiver Riddle 
18e46ba31cSRiver Riddle #include "PassDetail.h"
196558f80cSRiver Riddle #include "mlir/Pass/PassManager.h"
206558f80cSRiver Riddle #include "llvm/ADT/MapVector.h"
21e46ba31cSRiver Riddle #include "llvm/ADT/SmallVector.h"
22e46ba31cSRiver Riddle #include "llvm/ADT/Statistic.h"
23e46ba31cSRiver Riddle #include "llvm/Support/Format.h"
24e46ba31cSRiver Riddle #include "llvm/Support/FormatVariadic.h"
25*3a845be7SRiver Riddle #include "llvm/Support/Threading.h"
268e7b683dSRiver Riddle #include <chrono>
27e46ba31cSRiver Riddle 
28e46ba31cSRiver Riddle using namespace mlir;
29e46ba31cSRiver Riddle using namespace mlir::detail;
30e46ba31cSRiver Riddle 
31e46ba31cSRiver Riddle constexpr llvm::StringLiteral kPassTimingDescription =
32e46ba31cSRiver Riddle     "... Pass execution timing report ...";
33e46ba31cSRiver Riddle 
346558f80cSRiver Riddle namespace {
35*3a845be7SRiver Riddle /// Simple record class to record timing information.
36*3a845be7SRiver Riddle struct TimeRecord {
37*3a845be7SRiver Riddle   TimeRecord(double wall = 0.0, double user = 0.0) : wall(wall), user(user) {}
38*3a845be7SRiver Riddle 
39*3a845be7SRiver Riddle   TimeRecord &operator+=(const TimeRecord &other) {
40*3a845be7SRiver Riddle     wall += other.wall;
41*3a845be7SRiver Riddle     user += other.user;
42*3a845be7SRiver Riddle     return *this;
43*3a845be7SRiver Riddle   }
44*3a845be7SRiver Riddle 
45*3a845be7SRiver Riddle   /// Print the current time record to 'os', with a breakdown showing
46*3a845be7SRiver Riddle   /// contributions to the give 'total' time record.
47*3a845be7SRiver Riddle   void print(raw_ostream &os, const TimeRecord &total) {
48*3a845be7SRiver Riddle     if (total.user != total.wall)
49*3a845be7SRiver Riddle       os << llvm::format("  %7.4f (%5.1f%%)  ", user,
50*3a845be7SRiver Riddle                          100.0 * user / total.user);
51*3a845be7SRiver Riddle     os << llvm::format("  %7.4f (%5.1f%%)  ", wall, 100.0 * wall / total.wall);
52*3a845be7SRiver Riddle   }
53*3a845be7SRiver Riddle 
54*3a845be7SRiver Riddle   double wall, user;
55*3a845be7SRiver Riddle };
56*3a845be7SRiver Riddle 
578e7b683dSRiver Riddle struct Timer {
588e7b683dSRiver Riddle   explicit Timer(std::string &&name) : name(std::move(name)) {}
598e7b683dSRiver Riddle 
608e7b683dSRiver Riddle   /// Start the timer.
618e7b683dSRiver Riddle   void start() { startTime = std::chrono::system_clock::now(); }
628e7b683dSRiver Riddle 
638e7b683dSRiver Riddle   /// Stop the timer.
64*3a845be7SRiver Riddle   void stop() {
65*3a845be7SRiver Riddle     auto newTime = std::chrono::system_clock::now() - startTime;
66*3a845be7SRiver Riddle     wallTime += newTime;
67*3a845be7SRiver Riddle     userTime += newTime;
68*3a845be7SRiver Riddle   }
698e7b683dSRiver Riddle 
708e7b683dSRiver Riddle   /// Get or create a child timer with the provided name and id.
718e7b683dSRiver Riddle   Timer *getChildTimer(const void *id,
728e7b683dSRiver Riddle                        std::function<std::string()> &&nameBuilder) {
738e7b683dSRiver Riddle     auto &child = children[id];
748e7b683dSRiver Riddle     if (!child)
758e7b683dSRiver Riddle       child.reset(new Timer(nameBuilder()));
768e7b683dSRiver Riddle     return child.get();
778e7b683dSRiver Riddle   }
788e7b683dSRiver Riddle 
798e7b683dSRiver Riddle   /// Returns the total time for this timer in seconds.
80*3a845be7SRiver Riddle   TimeRecord getTotalTime() {
81*3a845be7SRiver Riddle     // If we have a valid wall time, then we directly compute the seconds.
82*3a845be7SRiver Riddle     if (wallTime.count()) {
83*3a845be7SRiver Riddle       return TimeRecord(
84*3a845be7SRiver Riddle           std::chrono::duration_cast<std::chrono::duration<double>>(wallTime)
85*3a845be7SRiver Riddle               .count(),
86*3a845be7SRiver Riddle           std::chrono::duration_cast<std::chrono::duration<double>>(userTime)
87*3a845be7SRiver Riddle               .count());
888e7b683dSRiver Riddle     }
898e7b683dSRiver Riddle 
908e7b683dSRiver Riddle     // Otheriwse, accumulate the timing from each of the children.
91*3a845be7SRiver Riddle     TimeRecord totalTime;
928e7b683dSRiver Riddle     for (auto &child : children)
938e7b683dSRiver Riddle       totalTime += child.second->getTotalTime();
948e7b683dSRiver Riddle     return totalTime;
958e7b683dSRiver Riddle   }
968e7b683dSRiver Riddle 
97*3a845be7SRiver Riddle   /// A map of unique identifiers to child timers.
98*3a845be7SRiver Riddle   using ChildrenMap = llvm::MapVector<const void *, std::unique_ptr<Timer>>;
99*3a845be7SRiver Riddle 
100*3a845be7SRiver Riddle   /// Merge the timing data from 'other' into this timer.
101*3a845be7SRiver Riddle   void merge(Timer &&other) {
102*3a845be7SRiver Riddle     if (wallTime < other.wallTime)
103*3a845be7SRiver Riddle       wallTime = other.wallTime;
104*3a845be7SRiver Riddle     userTime += other.userTime;
105*3a845be7SRiver Riddle     mergeChildren(std::move(other.children), /*isStructural=*/false);
106*3a845be7SRiver Riddle   }
107*3a845be7SRiver Riddle 
108*3a845be7SRiver Riddle   /// Merge the timer chilren in 'otherChildren' with the children of this
109*3a845be7SRiver Riddle   /// timer. If 'isStructural' is true, the children are merged lexographically
110*3a845be7SRiver Riddle   /// and 'otherChildren' must have the same number of elements as the children
111*3a845be7SRiver Riddle   /// of this timer. Otherwise, the timer children are merged based upon the
112*3a845be7SRiver Riddle   /// given timer key.
113*3a845be7SRiver Riddle   void mergeChildren(ChildrenMap &&otherChildren, bool isStructural) {
114*3a845be7SRiver Riddle     // Check for an empty children list.
115*3a845be7SRiver Riddle     if (children.empty()) {
116*3a845be7SRiver Riddle       children = std::move(otherChildren);
117*3a845be7SRiver Riddle       return;
118*3a845be7SRiver Riddle     }
119*3a845be7SRiver Riddle 
120*3a845be7SRiver Riddle     if (isStructural) {
121*3a845be7SRiver Riddle       // If this is a structural merge, the number of children must be the same.
122*3a845be7SRiver Riddle       assert(children.size() == otherChildren.size() &&
123*3a845be7SRiver Riddle              "structural merge requires the same number of children");
124*3a845be7SRiver Riddle       auto it = children.begin(), otherIt = otherChildren.begin();
125*3a845be7SRiver Riddle       for (auto e = children.end(); it != e; ++it, ++otherIt)
126*3a845be7SRiver Riddle         it->second->merge(std::move(*otherIt->second));
127*3a845be7SRiver Riddle       return;
128*3a845be7SRiver Riddle     }
129*3a845be7SRiver Riddle 
130*3a845be7SRiver Riddle     // Otherwise, we merge based upon the child timers key.
131*3a845be7SRiver Riddle     for (auto &otherChild : otherChildren) {
132*3a845be7SRiver Riddle       auto &child = children[otherChild.first];
133*3a845be7SRiver Riddle       if (!child)
134*3a845be7SRiver Riddle         child = std::move(otherChild.second);
135*3a845be7SRiver Riddle       else
136*3a845be7SRiver Riddle         child->merge(std::move(*otherChild.second));
137*3a845be7SRiver Riddle     }
138*3a845be7SRiver Riddle   }
139*3a845be7SRiver Riddle 
1408e7b683dSRiver Riddle   /// Raw timing information.
1418e7b683dSRiver Riddle   std::chrono::time_point<std::chrono::high_resolution_clock> startTime;
142*3a845be7SRiver Riddle   std::chrono::nanoseconds wallTime = std::chrono::nanoseconds(0);
143*3a845be7SRiver Riddle   std::chrono::nanoseconds userTime = std::chrono::nanoseconds(0);
1448e7b683dSRiver Riddle 
1458e7b683dSRiver Riddle   /// A map of unique identifiers to child timers.
146*3a845be7SRiver Riddle   ChildrenMap children;
1478e7b683dSRiver Riddle 
1488e7b683dSRiver Riddle   /// A descriptive name for this timer.
1498e7b683dSRiver Riddle   std::string name;
1508e7b683dSRiver Riddle };
1518e7b683dSRiver Riddle 
1526558f80cSRiver Riddle struct PassTiming : public PassInstrumentation {
1536558f80cSRiver Riddle   PassTiming(PassTimingDisplayMode displayMode) : displayMode(displayMode) {}
1546558f80cSRiver Riddle   ~PassTiming() { print(); }
155e46ba31cSRiver Riddle 
1566558f80cSRiver Riddle   /// Setup the instrumentation hooks.
1576558f80cSRiver Riddle   void runBeforePass(Pass *pass, const llvm::Any &) override {
1586558f80cSRiver Riddle     startPassTimer(pass);
1596558f80cSRiver Riddle   }
1608e7b683dSRiver Riddle   void runAfterPass(Pass *pass, const llvm::Any &) override;
1618e7b683dSRiver Riddle   void runAfterPassFailed(Pass *pass, const llvm::Any &ir) override {
1628e7b683dSRiver Riddle     runAfterPass(pass, ir);
1636558f80cSRiver Riddle   }
1646558f80cSRiver Riddle   void runBeforeAnalysis(llvm::StringRef name, AnalysisID *id,
1656558f80cSRiver Riddle                          const llvm::Any &) override {
1666558f80cSRiver Riddle     startAnalysisTimer(name, id);
1676558f80cSRiver Riddle   }
1688e7b683dSRiver Riddle   void runAfterAnalysis(llvm::StringRef, AnalysisID *,
1698e7b683dSRiver Riddle                         const llvm::Any &) override;
1706558f80cSRiver Riddle 
1716558f80cSRiver Riddle   /// Print and clear the timing results.
1726558f80cSRiver Riddle   void print();
1736558f80cSRiver Riddle 
1746558f80cSRiver Riddle   /// Start a new timer for the given pass.
1756558f80cSRiver Riddle   void startPassTimer(Pass *pass);
1766558f80cSRiver Riddle 
1776558f80cSRiver Riddle   /// Start a new timer for the given analysis.
1786558f80cSRiver Riddle   void startAnalysisTimer(llvm::StringRef name, AnalysisID *id);
1796558f80cSRiver Riddle 
1808e7b683dSRiver Riddle   /// Stop a pass timer.
1818e7b683dSRiver Riddle   void stopPassTimer(Pass *pass);
1828e7b683dSRiver Riddle 
1838e7b683dSRiver Riddle   /// Stop the last active timer.
1848e7b683dSRiver Riddle   void stopTimer();
1856558f80cSRiver Riddle 
1866558f80cSRiver Riddle   /// Print the timing result in list mode.
187*3a845be7SRiver Riddle   void printResultsAsList(raw_ostream &os, Timer *root, TimeRecord totalTime);
1886558f80cSRiver Riddle 
1896558f80cSRiver Riddle   /// Print the timing result in pipeline mode.
190*3a845be7SRiver Riddle   void printResultsAsPipeline(raw_ostream &os, Timer *root,
191*3a845be7SRiver Riddle                               TimeRecord totalTime);
1926558f80cSRiver Riddle 
1938e7b683dSRiver Riddle   /// Returns a timer for the provided identifier and name.
1948e7b683dSRiver Riddle   Timer *getTimer(const void *id, std::function<std::string()> &&nameBuilder) {
195*3a845be7SRiver Riddle     auto tid = llvm::get_threadid();
196*3a845be7SRiver Riddle 
197*3a845be7SRiver Riddle     // If there is no active timer then add to the root timer.
198*3a845be7SRiver Riddle     auto &activeTimers = activeThreadTimers[tid];
199*3a845be7SRiver Riddle     if (activeTimers.empty()) {
200*3a845be7SRiver Riddle       auto &rootTimer = rootTimers[tid];
201*3a845be7SRiver Riddle       if (!rootTimer)
202*3a845be7SRiver Riddle         rootTimer.reset(new Timer("root"));
203*3a845be7SRiver Riddle       auto *timer = rootTimer->getChildTimer(id, std::move(nameBuilder));
204*3a845be7SRiver Riddle       activeTimers.push_back(timer);
205*3a845be7SRiver Riddle       return timer;
2068e7b683dSRiver Riddle     }
2076558f80cSRiver Riddle 
208*3a845be7SRiver Riddle     // Otherwise, add this to the active timer.
209*3a845be7SRiver Riddle     auto timer = activeTimers.back()->getChildTimer(id, std::move(nameBuilder));
210*3a845be7SRiver Riddle     activeTimers.push_back(timer);
211*3a845be7SRiver Riddle     return timer;
212*3a845be7SRiver Riddle   }
2136558f80cSRiver Riddle 
214*3a845be7SRiver Riddle   /// The root top level timers for each thread.
215*3a845be7SRiver Riddle   DenseMap<uint64_t, std::unique_ptr<Timer>> rootTimers;
216*3a845be7SRiver Riddle 
217*3a845be7SRiver Riddle   /// A stack of the currently active pass timers per thread.
218*3a845be7SRiver Riddle   DenseMap<uint64_t, SmallVector<Timer *, 4>> activeThreadTimers;
2196558f80cSRiver Riddle 
2206558f80cSRiver Riddle   /// The display mode to use when printing the timing results.
2216558f80cSRiver Riddle   PassTimingDisplayMode displayMode;
2226558f80cSRiver Riddle };
2236558f80cSRiver Riddle } // end anonymous namespace
224e46ba31cSRiver Riddle 
225e46ba31cSRiver Riddle /// Start a new timer for the given pass.
226e46ba31cSRiver Riddle void PassTiming::startPassTimer(Pass *pass) {
2278e7b683dSRiver Riddle   Timer *timer = getTimer(pass, [pass] {
228af45236cSRiver Riddle     if (isModuleToFunctionAdaptorPass(pass))
2298e7b683dSRiver Riddle       return StringRef("Function Pipeline");
2308e7b683dSRiver Riddle     return pass->getName();
2318e7b683dSRiver Riddle   });
232e46ba31cSRiver Riddle 
2338e7b683dSRiver Riddle   // We don't actually want to time the adaptor passes, they gather their total
2348e7b683dSRiver Riddle   // from their held passes.
2358e7b683dSRiver Riddle   if (!isAdaptorPass(pass))
2368e7b683dSRiver Riddle     timer->start();
237e46ba31cSRiver Riddle }
238e46ba31cSRiver Riddle 
239e46ba31cSRiver Riddle /// Start a new timer for the given analysis.
240e46ba31cSRiver Riddle void PassTiming::startAnalysisTimer(llvm::StringRef name, AnalysisID *id) {
2418e7b683dSRiver Riddle   Timer *timer = getTimer(id, [name] { return "(A) " + name.str(); });
2428e7b683dSRiver Riddle   timer->start();
243e46ba31cSRiver Riddle }
244e46ba31cSRiver Riddle 
2458e7b683dSRiver Riddle /// Stop a pass timer.
2468e7b683dSRiver Riddle void PassTiming::runAfterPass(Pass *pass, const llvm::Any &) {
247*3a845be7SRiver Riddle   auto tid = llvm::get_threadid();
248*3a845be7SRiver Riddle   auto &activeTimers = activeThreadTimers[tid];
2498e7b683dSRiver Riddle   assert(!activeTimers.empty() && "expected active timer");
2508e7b683dSRiver Riddle   Timer *timer = activeTimers.pop_back_val();
2518e7b683dSRiver Riddle 
252*3a845be7SRiver Riddle   // If this is an ModuleToFunctionPassAdaptorParallel, then we need to merge in
253*3a845be7SRiver Riddle   // the timing data for the other threads.
254*3a845be7SRiver Riddle   if (auto *asyncMTFPass =
255*3a845be7SRiver Riddle           dyn_cast<ModuleToFunctionPassAdaptorParallel>(pass)) {
256*3a845be7SRiver Riddle     // The asychronous pipeline timers should exist as children of root timers
257*3a845be7SRiver Riddle     // for other threads.
258*3a845be7SRiver Riddle     for (auto &rootTimer : llvm::make_early_inc_range(rootTimers)) {
259*3a845be7SRiver Riddle       // Skip the current thread.
260*3a845be7SRiver Riddle       if (rootTimer.first == tid)
261*3a845be7SRiver Riddle         continue;
262*3a845be7SRiver Riddle       // Check that this thread has no active timers.
263*3a845be7SRiver Riddle       assert(activeThreadTimers[tid].empty() && "expected no active timers");
264*3a845be7SRiver Riddle 
265*3a845be7SRiver Riddle       // Structurally merge this timers children into the parallel
266*3a845be7SRiver Riddle       // module-to-function pass timer.
267*3a845be7SRiver Riddle       timer->mergeChildren(std::move(rootTimer.second->children),
268*3a845be7SRiver Riddle                            /*isStructural=*/true);
269*3a845be7SRiver Riddle       rootTimers.erase(rootTimer.first);
270*3a845be7SRiver Riddle     }
271*3a845be7SRiver Riddle     return;
272*3a845be7SRiver Riddle   }
273*3a845be7SRiver Riddle 
2748e7b683dSRiver Riddle   // Adapator passes aren't timed directly, so we don't need to stop their
2758e7b683dSRiver Riddle   // timers.
2768e7b683dSRiver Riddle   if (!isAdaptorPass(pass))
2778e7b683dSRiver Riddle     timer->stop();
278e46ba31cSRiver Riddle }
279e46ba31cSRiver Riddle 
2808e7b683dSRiver Riddle /// Stop a timer.
2818e7b683dSRiver Riddle void PassTiming::runAfterAnalysis(llvm::StringRef, AnalysisID *,
2828e7b683dSRiver Riddle                                   const llvm::Any &) {
283*3a845be7SRiver Riddle   auto &activeTimers = activeThreadTimers[llvm::get_threadid()];
2848e7b683dSRiver Riddle   assert(!activeTimers.empty() && "expected active timer");
2858e7b683dSRiver Riddle   Timer *timer = activeTimers.pop_back_val();
2868e7b683dSRiver Riddle   timer->stop();
287e46ba31cSRiver Riddle }
288e46ba31cSRiver Riddle 
2898e7b683dSRiver Riddle /// Utility to print the timer heading information.
290*3a845be7SRiver Riddle static void printTimerHeader(llvm::raw_ostream &os, TimeRecord total) {
291e46ba31cSRiver Riddle   os << "===" << std::string(73, '-') << "===\n";
292e46ba31cSRiver Riddle   // Figure out how many spaces to description name.
293e46ba31cSRiver Riddle   unsigned Padding = (80 - kPassTimingDescription.size()) / 2;
294e46ba31cSRiver Riddle   os.indent(Padding) << kPassTimingDescription << '\n';
295e46ba31cSRiver Riddle   os << "===" << std::string(73, '-') << "===\n";
296e46ba31cSRiver Riddle 
2978e7b683dSRiver Riddle   // Print the total time followed by the section headers.
298*3a845be7SRiver Riddle   os << llvm::format("  Total Execution Time: %5.4f seconds\n\n", total.wall);
299*3a845be7SRiver Riddle   if (total.user != total.wall)
300*3a845be7SRiver Riddle     os << "   ---User Time---";
3018e7b683dSRiver Riddle   os << "   ---Wall Time---  --- Name ---\n";
3028e7b683dSRiver Riddle }
303e46ba31cSRiver Riddle 
3048e7b683dSRiver Riddle /// Utility to print a single line entry in the timer output.
3058e7b683dSRiver Riddle static void printTimeEntry(raw_ostream &os, unsigned indent, StringRef name,
306*3a845be7SRiver Riddle                            TimeRecord time, TimeRecord totalTime) {
307*3a845be7SRiver Riddle   time.print(os, totalTime);
3088e7b683dSRiver Riddle   os.indent(indent) << name << "\n";
3098e7b683dSRiver Riddle }
3108e7b683dSRiver Riddle 
3118e7b683dSRiver Riddle /// Print out the current timing information.
3128e7b683dSRiver Riddle void PassTiming::print() {
3138e7b683dSRiver Riddle   // Don't print anything if there is no timing data.
314*3a845be7SRiver Riddle   if (rootTimers.empty())
3158e7b683dSRiver Riddle     return;
316*3a845be7SRiver Riddle 
317*3a845be7SRiver Riddle   assert(rootTimers.size() == 1 && "expected one remaining root timer");
318*3a845be7SRiver Riddle   auto &rootTimer = rootTimers.begin()->second;
3198e7b683dSRiver Riddle   auto os = llvm::CreateInfoOutputFile();
3208e7b683dSRiver Riddle 
3218e7b683dSRiver Riddle   // Print the timer header.
322*3a845be7SRiver Riddle   TimeRecord totalTime = rootTimer->getTotalTime();
3238e7b683dSRiver Riddle   printTimerHeader(*os, totalTime);
3248e7b683dSRiver Riddle 
3258e7b683dSRiver Riddle   // Defer to a specialized printer for each display mode.
3268e7b683dSRiver Riddle   switch (displayMode) {
3278e7b683dSRiver Riddle   case PassTimingDisplayMode::List:
328*3a845be7SRiver Riddle     printResultsAsList(*os, rootTimer.get(), totalTime);
3298e7b683dSRiver Riddle     break;
3308e7b683dSRiver Riddle   case PassTimingDisplayMode::Pipeline:
331*3a845be7SRiver Riddle     printResultsAsPipeline(*os, rootTimer.get(), totalTime);
3328e7b683dSRiver Riddle     break;
3338e7b683dSRiver Riddle   }
3348e7b683dSRiver Riddle   printTimeEntry(*os, 0, "Total", totalTime, totalTime);
3358e7b683dSRiver Riddle   os->flush();
3368e7b683dSRiver Riddle 
337*3a845be7SRiver Riddle   // Reset root timers.
338*3a845be7SRiver Riddle   rootTimers.clear();
339*3a845be7SRiver Riddle   activeThreadTimers.clear();
3408e7b683dSRiver Riddle }
3418e7b683dSRiver Riddle 
3428e7b683dSRiver Riddle /// Print the timing result in list mode.
343*3a845be7SRiver Riddle void PassTiming::printResultsAsList(raw_ostream &os, Timer *root,
344*3a845be7SRiver Riddle                                     TimeRecord totalTime) {
345*3a845be7SRiver Riddle   llvm::StringMap<TimeRecord> mergedTimings;
3468e7b683dSRiver Riddle 
3478e7b683dSRiver Riddle   std::function<void(Timer *)> addTimer = [&](Timer *timer) {
3488e7b683dSRiver Riddle     // Check for timing information.
349*3a845be7SRiver Riddle     if (timer->wallTime.count())
3508e7b683dSRiver Riddle       mergedTimings[timer->name] += timer->getTotalTime();
3518e7b683dSRiver Riddle     for (auto &children : timer->children)
3528e7b683dSRiver Riddle       addTimer(children.second.get());
3538e7b683dSRiver Riddle   };
3548e7b683dSRiver Riddle 
3558e7b683dSRiver Riddle   // Add each of the top level timers.
356*3a845be7SRiver Riddle   for (auto &topLevelTimer : root->children)
3578e7b683dSRiver Riddle     addTimer(topLevelTimer.second.get());
3588e7b683dSRiver Riddle 
359*3a845be7SRiver Riddle   // Sort the timing information by wall time.
360*3a845be7SRiver Riddle   std::vector<std::pair<StringRef, TimeRecord>> timerNameAndTime;
3618e7b683dSRiver Riddle   for (auto &it : mergedTimings)
3628e7b683dSRiver Riddle     timerNameAndTime.emplace_back(it.first(), it.second);
3638e7b683dSRiver Riddle   llvm::array_pod_sort(timerNameAndTime.begin(), timerNameAndTime.end(),
364*3a845be7SRiver Riddle                        [](const std::pair<StringRef, TimeRecord> *lhs,
365*3a845be7SRiver Riddle                           const std::pair<StringRef, TimeRecord> *rhs) {
3668e7b683dSRiver Riddle                          return llvm::array_pod_sort_comparator<double>(
367*3a845be7SRiver Riddle                              &rhs->second.wall, &lhs->second.wall);
3688e7b683dSRiver Riddle                        });
3698e7b683dSRiver Riddle 
3708e7b683dSRiver Riddle   // Print the timing information sequentially.
3718e7b683dSRiver Riddle   for (auto &timeData : timerNameAndTime)
3728e7b683dSRiver Riddle     printTimeEntry(os, 0, timeData.first, timeData.second, totalTime);
373e46ba31cSRiver Riddle }
374e46ba31cSRiver Riddle 
375e46ba31cSRiver Riddle /// Print the timing result in pipeline mode.
376*3a845be7SRiver Riddle void PassTiming::printResultsAsPipeline(raw_ostream &os, Timer *root,
377*3a845be7SRiver Riddle                                         TimeRecord totalTime) {
3788e7b683dSRiver Riddle   std::function<void(unsigned, Timer *)> printTimer = [&](unsigned indent,
3798e7b683dSRiver Riddle                                                           Timer *timer) {
3808e7b683dSRiver Riddle     printTimeEntry(os, indent, timer->name, timer->getTotalTime(), totalTime);
3818e7b683dSRiver Riddle     for (auto &children : timer->children)
3828e7b683dSRiver Riddle       printTimer(indent + 2, children.second.get());
383e46ba31cSRiver Riddle   };
384e46ba31cSRiver Riddle 
3858e7b683dSRiver Riddle   // Print each of the top level timers.
386*3a845be7SRiver Riddle   for (auto &topLevelTimer : root->children)
3878e7b683dSRiver Riddle     printTimer(0, topLevelTimer.second.get());
388e46ba31cSRiver Riddle }
3896558f80cSRiver Riddle 
3906558f80cSRiver Riddle //===----------------------------------------------------------------------===//
3916558f80cSRiver Riddle // PassManager
3926558f80cSRiver Riddle //===----------------------------------------------------------------------===//
3936558f80cSRiver Riddle 
3946558f80cSRiver Riddle /// Add an instrumentation to time the execution of passes and the computation
3956558f80cSRiver Riddle /// of analyses.
3966558f80cSRiver Riddle void PassManager::enableTiming(PassTimingDisplayMode displayMode) {
3976558f80cSRiver Riddle   // Check if pass timing is already enabled.
3986558f80cSRiver Riddle   if (passTiming)
3996558f80cSRiver Riddle     return;
4006558f80cSRiver Riddle   addInstrumentation(new PassTiming(displayMode));
4016558f80cSRiver Riddle   passTiming = true;
4026558f80cSRiver Riddle }
403