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