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" 253a845be7SRiver 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 { 353a845be7SRiver Riddle /// Simple record class to record timing information. 363a845be7SRiver Riddle struct TimeRecord { 373a845be7SRiver Riddle TimeRecord(double wall = 0.0, double user = 0.0) : wall(wall), user(user) {} 383a845be7SRiver Riddle 393a845be7SRiver Riddle TimeRecord &operator+=(const TimeRecord &other) { 403a845be7SRiver Riddle wall += other.wall; 413a845be7SRiver Riddle user += other.user; 423a845be7SRiver Riddle return *this; 433a845be7SRiver Riddle } 443a845be7SRiver Riddle 453a845be7SRiver Riddle /// Print the current time record to 'os', with a breakdown showing 463a845be7SRiver Riddle /// contributions to the give 'total' time record. 473a845be7SRiver Riddle void print(raw_ostream &os, const TimeRecord &total) { 483a845be7SRiver Riddle if (total.user != total.wall) 493a845be7SRiver Riddle os << llvm::format(" %7.4f (%5.1f%%) ", user, 503a845be7SRiver Riddle 100.0 * user / total.user); 513a845be7SRiver Riddle os << llvm::format(" %7.4f (%5.1f%%) ", wall, 100.0 * wall / total.wall); 523a845be7SRiver Riddle } 533a845be7SRiver Riddle 543a845be7SRiver Riddle double wall, user; 553a845be7SRiver Riddle }; 563a845be7SRiver 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. 643a845be7SRiver Riddle void stop() { 653a845be7SRiver Riddle auto newTime = std::chrono::system_clock::now() - startTime; 663a845be7SRiver Riddle wallTime += newTime; 673a845be7SRiver Riddle userTime += newTime; 683a845be7SRiver 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. 803a845be7SRiver Riddle TimeRecord getTotalTime() { 813a845be7SRiver Riddle // If we have a valid wall time, then we directly compute the seconds. 823a845be7SRiver Riddle if (wallTime.count()) { 833a845be7SRiver Riddle return TimeRecord( 843a845be7SRiver Riddle std::chrono::duration_cast<std::chrono::duration<double>>(wallTime) 853a845be7SRiver Riddle .count(), 863a845be7SRiver Riddle std::chrono::duration_cast<std::chrono::duration<double>>(userTime) 873a845be7SRiver Riddle .count()); 888e7b683dSRiver Riddle } 898e7b683dSRiver Riddle 908e7b683dSRiver Riddle // Otheriwse, accumulate the timing from each of the children. 913a845be7SRiver Riddle TimeRecord totalTime; 928e7b683dSRiver Riddle for (auto &child : children) 938e7b683dSRiver Riddle totalTime += child.second->getTotalTime(); 948e7b683dSRiver Riddle return totalTime; 958e7b683dSRiver Riddle } 968e7b683dSRiver Riddle 973a845be7SRiver Riddle /// A map of unique identifiers to child timers. 983a845be7SRiver Riddle using ChildrenMap = llvm::MapVector<const void *, std::unique_ptr<Timer>>; 993a845be7SRiver Riddle 1003a845be7SRiver Riddle /// Merge the timing data from 'other' into this timer. 1013a845be7SRiver Riddle void merge(Timer &&other) { 1023a845be7SRiver Riddle if (wallTime < other.wallTime) 1033a845be7SRiver Riddle wallTime = other.wallTime; 1043a845be7SRiver Riddle userTime += other.userTime; 1053a845be7SRiver Riddle mergeChildren(std::move(other.children), /*isStructural=*/false); 1063a845be7SRiver Riddle } 1073a845be7SRiver Riddle 1083a845be7SRiver Riddle /// Merge the timer chilren in 'otherChildren' with the children of this 1093a845be7SRiver Riddle /// timer. If 'isStructural' is true, the children are merged lexographically 1103a845be7SRiver Riddle /// and 'otherChildren' must have the same number of elements as the children 1113a845be7SRiver Riddle /// of this timer. Otherwise, the timer children are merged based upon the 1123a845be7SRiver Riddle /// given timer key. 1133a845be7SRiver Riddle void mergeChildren(ChildrenMap &&otherChildren, bool isStructural) { 1143a845be7SRiver Riddle // Check for an empty children list. 1153a845be7SRiver Riddle if (children.empty()) { 1163a845be7SRiver Riddle children = std::move(otherChildren); 1173a845be7SRiver Riddle return; 1183a845be7SRiver Riddle } 1193a845be7SRiver Riddle 1203a845be7SRiver Riddle if (isStructural) { 1213a845be7SRiver Riddle // If this is a structural merge, the number of children must be the same. 1223a845be7SRiver Riddle assert(children.size() == otherChildren.size() && 1233a845be7SRiver Riddle "structural merge requires the same number of children"); 1243a845be7SRiver Riddle auto it = children.begin(), otherIt = otherChildren.begin(); 1253a845be7SRiver Riddle for (auto e = children.end(); it != e; ++it, ++otherIt) 1263a845be7SRiver Riddle it->second->merge(std::move(*otherIt->second)); 1273a845be7SRiver Riddle return; 1283a845be7SRiver Riddle } 1293a845be7SRiver Riddle 1303a845be7SRiver Riddle // Otherwise, we merge based upon the child timers key. 1313a845be7SRiver Riddle for (auto &otherChild : otherChildren) { 1323a845be7SRiver Riddle auto &child = children[otherChild.first]; 1333a845be7SRiver Riddle if (!child) 1343a845be7SRiver Riddle child = std::move(otherChild.second); 1353a845be7SRiver Riddle else 1363a845be7SRiver Riddle child->merge(std::move(*otherChild.second)); 1373a845be7SRiver Riddle } 1383a845be7SRiver Riddle } 1393a845be7SRiver Riddle 1408e7b683dSRiver Riddle /// Raw timing information. 141ff05e9daSRiver Riddle std::chrono::time_point<std::chrono::system_clock> startTime; 1423a845be7SRiver Riddle std::chrono::nanoseconds wallTime = std::chrono::nanoseconds(0); 1433a845be7SRiver Riddle std::chrono::nanoseconds userTime = std::chrono::nanoseconds(0); 1448e7b683dSRiver Riddle 1458e7b683dSRiver Riddle /// A map of unique identifiers to child timers. 1463a845be7SRiver 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. 157*4fb971a9SRiver Riddle void runBeforePass(Pass *pass, Operation *) override { startPassTimer(pass); } 158*4fb971a9SRiver Riddle void runAfterPass(Pass *pass, Operation *) override; 159*4fb971a9SRiver Riddle void runAfterPassFailed(Pass *pass, Operation *op) override { 160*4fb971a9SRiver Riddle runAfterPass(pass, op); 1616558f80cSRiver Riddle } 1626558f80cSRiver Riddle void runBeforeAnalysis(llvm::StringRef name, AnalysisID *id, 163*4fb971a9SRiver Riddle Operation *) override { 1646558f80cSRiver Riddle startAnalysisTimer(name, id); 1656558f80cSRiver Riddle } 166*4fb971a9SRiver Riddle void runAfterAnalysis(llvm::StringRef, AnalysisID *, Operation *) override; 1676558f80cSRiver Riddle 1686558f80cSRiver Riddle /// Print and clear the timing results. 1696558f80cSRiver Riddle void print(); 1706558f80cSRiver Riddle 1716558f80cSRiver Riddle /// Start a new timer for the given pass. 1726558f80cSRiver Riddle void startPassTimer(Pass *pass); 1736558f80cSRiver Riddle 1746558f80cSRiver Riddle /// Start a new timer for the given analysis. 1756558f80cSRiver Riddle void startAnalysisTimer(llvm::StringRef name, AnalysisID *id); 1766558f80cSRiver Riddle 1778e7b683dSRiver Riddle /// Stop a pass timer. 1788e7b683dSRiver Riddle void stopPassTimer(Pass *pass); 1798e7b683dSRiver Riddle 1808e7b683dSRiver Riddle /// Stop the last active timer. 1818e7b683dSRiver Riddle void stopTimer(); 1826558f80cSRiver Riddle 1836558f80cSRiver Riddle /// Print the timing result in list mode. 1843a845be7SRiver Riddle void printResultsAsList(raw_ostream &os, Timer *root, TimeRecord totalTime); 1856558f80cSRiver Riddle 1866558f80cSRiver Riddle /// Print the timing result in pipeline mode. 1873a845be7SRiver Riddle void printResultsAsPipeline(raw_ostream &os, Timer *root, 1883a845be7SRiver Riddle TimeRecord totalTime); 1896558f80cSRiver Riddle 1908e7b683dSRiver Riddle /// Returns a timer for the provided identifier and name. 1918e7b683dSRiver Riddle Timer *getTimer(const void *id, std::function<std::string()> &&nameBuilder) { 1923a845be7SRiver Riddle auto tid = llvm::get_threadid(); 1933a845be7SRiver Riddle 1943a845be7SRiver Riddle // If there is no active timer then add to the root timer. 1953a845be7SRiver Riddle auto &activeTimers = activeThreadTimers[tid]; 1963a845be7SRiver Riddle if (activeTimers.empty()) { 1973a845be7SRiver Riddle auto &rootTimer = rootTimers[tid]; 1983a845be7SRiver Riddle if (!rootTimer) 1993a845be7SRiver Riddle rootTimer.reset(new Timer("root")); 2003a845be7SRiver Riddle auto *timer = rootTimer->getChildTimer(id, std::move(nameBuilder)); 2013a845be7SRiver Riddle activeTimers.push_back(timer); 2023a845be7SRiver Riddle return timer; 2038e7b683dSRiver Riddle } 2046558f80cSRiver Riddle 2053a845be7SRiver Riddle // Otherwise, add this to the active timer. 2063a845be7SRiver Riddle auto timer = activeTimers.back()->getChildTimer(id, std::move(nameBuilder)); 2073a845be7SRiver Riddle activeTimers.push_back(timer); 2083a845be7SRiver Riddle return timer; 2093a845be7SRiver Riddle } 2106558f80cSRiver Riddle 2113a845be7SRiver Riddle /// The root top level timers for each thread. 2123a845be7SRiver Riddle DenseMap<uint64_t, std::unique_ptr<Timer>> rootTimers; 2133a845be7SRiver Riddle 2143a845be7SRiver Riddle /// A stack of the currently active pass timers per thread. 2153a845be7SRiver Riddle DenseMap<uint64_t, SmallVector<Timer *, 4>> activeThreadTimers; 2166558f80cSRiver Riddle 2176558f80cSRiver Riddle /// The display mode to use when printing the timing results. 2186558f80cSRiver Riddle PassTimingDisplayMode displayMode; 2196558f80cSRiver Riddle }; 2206558f80cSRiver Riddle } // end anonymous namespace 221e46ba31cSRiver Riddle 222e46ba31cSRiver Riddle /// Start a new timer for the given pass. 223e46ba31cSRiver Riddle void PassTiming::startPassTimer(Pass *pass) { 2248e7b683dSRiver Riddle Timer *timer = getTimer(pass, [pass] { 225af45236cSRiver Riddle if (isModuleToFunctionAdaptorPass(pass)) 2268e7b683dSRiver Riddle return StringRef("Function Pipeline"); 2278e7b683dSRiver Riddle return pass->getName(); 2288e7b683dSRiver Riddle }); 229e46ba31cSRiver Riddle 2308e7b683dSRiver Riddle // We don't actually want to time the adaptor passes, they gather their total 2318e7b683dSRiver Riddle // from their held passes. 2328e7b683dSRiver Riddle if (!isAdaptorPass(pass)) 2338e7b683dSRiver Riddle timer->start(); 234e46ba31cSRiver Riddle } 235e46ba31cSRiver Riddle 236e46ba31cSRiver Riddle /// Start a new timer for the given analysis. 237e46ba31cSRiver Riddle void PassTiming::startAnalysisTimer(llvm::StringRef name, AnalysisID *id) { 2388e7b683dSRiver Riddle Timer *timer = getTimer(id, [name] { return "(A) " + name.str(); }); 2398e7b683dSRiver Riddle timer->start(); 240e46ba31cSRiver Riddle } 241e46ba31cSRiver Riddle 2428e7b683dSRiver Riddle /// Stop a pass timer. 243*4fb971a9SRiver Riddle void PassTiming::runAfterPass(Pass *pass, Operation *) { 2443a845be7SRiver Riddle auto tid = llvm::get_threadid(); 2453a845be7SRiver Riddle auto &activeTimers = activeThreadTimers[tid]; 2468e7b683dSRiver Riddle assert(!activeTimers.empty() && "expected active timer"); 2478e7b683dSRiver Riddle Timer *timer = activeTimers.pop_back_val(); 2488e7b683dSRiver Riddle 2493a845be7SRiver Riddle // If this is an ModuleToFunctionPassAdaptorParallel, then we need to merge in 2503a845be7SRiver Riddle // the timing data for the other threads. 251a5ca314cSMehdi Amini if (isa<ModuleToFunctionPassAdaptorParallel>(pass)) { 2523a845be7SRiver Riddle // The asychronous pipeline timers should exist as children of root timers 2533a845be7SRiver Riddle // for other threads. 2543a845be7SRiver Riddle for (auto &rootTimer : llvm::make_early_inc_range(rootTimers)) { 2553a845be7SRiver Riddle // Skip the current thread. 2563a845be7SRiver Riddle if (rootTimer.first == tid) 2573a845be7SRiver Riddle continue; 2583a845be7SRiver Riddle // Check that this thread has no active timers. 2593a845be7SRiver Riddle assert(activeThreadTimers[tid].empty() && "expected no active timers"); 2603a845be7SRiver Riddle 2613a845be7SRiver Riddle // Structurally merge this timers children into the parallel 2623a845be7SRiver Riddle // module-to-function pass timer. 2633a845be7SRiver Riddle timer->mergeChildren(std::move(rootTimer.second->children), 2643a845be7SRiver Riddle /*isStructural=*/true); 2653a845be7SRiver Riddle rootTimers.erase(rootTimer.first); 2663a845be7SRiver Riddle } 2673a845be7SRiver Riddle return; 2683a845be7SRiver Riddle } 2693a845be7SRiver Riddle 2708e7b683dSRiver Riddle // Adapator passes aren't timed directly, so we don't need to stop their 2718e7b683dSRiver Riddle // timers. 2728e7b683dSRiver Riddle if (!isAdaptorPass(pass)) 2738e7b683dSRiver Riddle timer->stop(); 274e46ba31cSRiver Riddle } 275e46ba31cSRiver Riddle 2768e7b683dSRiver Riddle /// Stop a timer. 277*4fb971a9SRiver Riddle void PassTiming::runAfterAnalysis(llvm::StringRef, AnalysisID *, Operation *) { 2783a845be7SRiver Riddle auto &activeTimers = activeThreadTimers[llvm::get_threadid()]; 2798e7b683dSRiver Riddle assert(!activeTimers.empty() && "expected active timer"); 2808e7b683dSRiver Riddle Timer *timer = activeTimers.pop_back_val(); 2818e7b683dSRiver Riddle timer->stop(); 282e46ba31cSRiver Riddle } 283e46ba31cSRiver Riddle 2848e7b683dSRiver Riddle /// Utility to print the timer heading information. 2853a845be7SRiver Riddle static void printTimerHeader(llvm::raw_ostream &os, TimeRecord total) { 286e46ba31cSRiver Riddle os << "===" << std::string(73, '-') << "===\n"; 287e46ba31cSRiver Riddle // Figure out how many spaces to description name. 288e46ba31cSRiver Riddle unsigned Padding = (80 - kPassTimingDescription.size()) / 2; 289e46ba31cSRiver Riddle os.indent(Padding) << kPassTimingDescription << '\n'; 290e46ba31cSRiver Riddle os << "===" << std::string(73, '-') << "===\n"; 291e46ba31cSRiver Riddle 2928e7b683dSRiver Riddle // Print the total time followed by the section headers. 2933a845be7SRiver Riddle os << llvm::format(" Total Execution Time: %5.4f seconds\n\n", total.wall); 2943a845be7SRiver Riddle if (total.user != total.wall) 2953a845be7SRiver Riddle os << " ---User Time---"; 2968e7b683dSRiver Riddle os << " ---Wall Time--- --- Name ---\n"; 2978e7b683dSRiver Riddle } 298e46ba31cSRiver Riddle 2998e7b683dSRiver Riddle /// Utility to print a single line entry in the timer output. 3008e7b683dSRiver Riddle static void printTimeEntry(raw_ostream &os, unsigned indent, StringRef name, 3013a845be7SRiver Riddle TimeRecord time, TimeRecord totalTime) { 3023a845be7SRiver Riddle time.print(os, totalTime); 3038e7b683dSRiver Riddle os.indent(indent) << name << "\n"; 3048e7b683dSRiver Riddle } 3058e7b683dSRiver Riddle 3068e7b683dSRiver Riddle /// Print out the current timing information. 3078e7b683dSRiver Riddle void PassTiming::print() { 3088e7b683dSRiver Riddle // Don't print anything if there is no timing data. 3093a845be7SRiver Riddle if (rootTimers.empty()) 3108e7b683dSRiver Riddle return; 3113a845be7SRiver Riddle 3123a845be7SRiver Riddle assert(rootTimers.size() == 1 && "expected one remaining root timer"); 3133a845be7SRiver Riddle auto &rootTimer = rootTimers.begin()->second; 3148e7b683dSRiver Riddle auto os = llvm::CreateInfoOutputFile(); 3158e7b683dSRiver Riddle 3168e7b683dSRiver Riddle // Print the timer header. 3173a845be7SRiver Riddle TimeRecord totalTime = rootTimer->getTotalTime(); 3188e7b683dSRiver Riddle printTimerHeader(*os, totalTime); 3198e7b683dSRiver Riddle 3208e7b683dSRiver Riddle // Defer to a specialized printer for each display mode. 3218e7b683dSRiver Riddle switch (displayMode) { 3228e7b683dSRiver Riddle case PassTimingDisplayMode::List: 3233a845be7SRiver Riddle printResultsAsList(*os, rootTimer.get(), totalTime); 3248e7b683dSRiver Riddle break; 3258e7b683dSRiver Riddle case PassTimingDisplayMode::Pipeline: 3263a845be7SRiver Riddle printResultsAsPipeline(*os, rootTimer.get(), totalTime); 3278e7b683dSRiver Riddle break; 3288e7b683dSRiver Riddle } 3298e7b683dSRiver Riddle printTimeEntry(*os, 0, "Total", totalTime, totalTime); 3308e7b683dSRiver Riddle os->flush(); 3318e7b683dSRiver Riddle 3323a845be7SRiver Riddle // Reset root timers. 3333a845be7SRiver Riddle rootTimers.clear(); 3343a845be7SRiver Riddle activeThreadTimers.clear(); 3358e7b683dSRiver Riddle } 3368e7b683dSRiver Riddle 3378e7b683dSRiver Riddle /// Print the timing result in list mode. 3383a845be7SRiver Riddle void PassTiming::printResultsAsList(raw_ostream &os, Timer *root, 3393a845be7SRiver Riddle TimeRecord totalTime) { 3403a845be7SRiver Riddle llvm::StringMap<TimeRecord> mergedTimings; 3418e7b683dSRiver Riddle 3428e7b683dSRiver Riddle std::function<void(Timer *)> addTimer = [&](Timer *timer) { 3438e7b683dSRiver Riddle // Check for timing information. 3443a845be7SRiver Riddle if (timer->wallTime.count()) 3458e7b683dSRiver Riddle mergedTimings[timer->name] += timer->getTotalTime(); 3468e7b683dSRiver Riddle for (auto &children : timer->children) 3478e7b683dSRiver Riddle addTimer(children.second.get()); 3488e7b683dSRiver Riddle }; 3498e7b683dSRiver Riddle 3508e7b683dSRiver Riddle // Add each of the top level timers. 3513a845be7SRiver Riddle for (auto &topLevelTimer : root->children) 3528e7b683dSRiver Riddle addTimer(topLevelTimer.second.get()); 3538e7b683dSRiver Riddle 3543a845be7SRiver Riddle // Sort the timing information by wall time. 3553a845be7SRiver Riddle std::vector<std::pair<StringRef, TimeRecord>> timerNameAndTime; 3568e7b683dSRiver Riddle for (auto &it : mergedTimings) 3578e7b683dSRiver Riddle timerNameAndTime.emplace_back(it.first(), it.second); 3588e7b683dSRiver Riddle llvm::array_pod_sort(timerNameAndTime.begin(), timerNameAndTime.end(), 3593a845be7SRiver Riddle [](const std::pair<StringRef, TimeRecord> *lhs, 3603a845be7SRiver Riddle const std::pair<StringRef, TimeRecord> *rhs) { 3618e7b683dSRiver Riddle return llvm::array_pod_sort_comparator<double>( 3623a845be7SRiver Riddle &rhs->second.wall, &lhs->second.wall); 3638e7b683dSRiver Riddle }); 3648e7b683dSRiver Riddle 3658e7b683dSRiver Riddle // Print the timing information sequentially. 3668e7b683dSRiver Riddle for (auto &timeData : timerNameAndTime) 3678e7b683dSRiver Riddle printTimeEntry(os, 0, timeData.first, timeData.second, totalTime); 368e46ba31cSRiver Riddle } 369e46ba31cSRiver Riddle 370e46ba31cSRiver Riddle /// Print the timing result in pipeline mode. 3713a845be7SRiver Riddle void PassTiming::printResultsAsPipeline(raw_ostream &os, Timer *root, 3723a845be7SRiver Riddle TimeRecord totalTime) { 3738e7b683dSRiver Riddle std::function<void(unsigned, Timer *)> printTimer = [&](unsigned indent, 3748e7b683dSRiver Riddle Timer *timer) { 3758e7b683dSRiver Riddle printTimeEntry(os, indent, timer->name, timer->getTotalTime(), totalTime); 3768e7b683dSRiver Riddle for (auto &children : timer->children) 3778e7b683dSRiver Riddle printTimer(indent + 2, children.second.get()); 378e46ba31cSRiver Riddle }; 379e46ba31cSRiver Riddle 3808e7b683dSRiver Riddle // Print each of the top level timers. 3813a845be7SRiver Riddle for (auto &topLevelTimer : root->children) 3828e7b683dSRiver Riddle printTimer(0, topLevelTimer.second.get()); 383e46ba31cSRiver Riddle } 3846558f80cSRiver Riddle 3856558f80cSRiver Riddle //===----------------------------------------------------------------------===// 3866558f80cSRiver Riddle // PassManager 3876558f80cSRiver Riddle //===----------------------------------------------------------------------===// 3886558f80cSRiver Riddle 3896558f80cSRiver Riddle /// Add an instrumentation to time the execution of passes and the computation 3906558f80cSRiver Riddle /// of analyses. 3916558f80cSRiver Riddle void PassManager::enableTiming(PassTimingDisplayMode displayMode) { 3926558f80cSRiver Riddle // Check if pass timing is already enabled. 3936558f80cSRiver Riddle if (passTiming) 3946558f80cSRiver Riddle return; 3956558f80cSRiver Riddle addInstrumentation(new PassTiming(displayMode)); 3966558f80cSRiver Riddle passTiming = true; 3976558f80cSRiver Riddle } 398