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. 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. 1873a845be7SRiver Riddle void printResultsAsList(raw_ostream &os, Timer *root, TimeRecord totalTime); 1886558f80cSRiver Riddle 1896558f80cSRiver Riddle /// Print the timing result in pipeline mode. 1903a845be7SRiver Riddle void printResultsAsPipeline(raw_ostream &os, Timer *root, 1913a845be7SRiver 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) { 1953a845be7SRiver Riddle auto tid = llvm::get_threadid(); 1963a845be7SRiver Riddle 1973a845be7SRiver Riddle // If there is no active timer then add to the root timer. 1983a845be7SRiver Riddle auto &activeTimers = activeThreadTimers[tid]; 1993a845be7SRiver Riddle if (activeTimers.empty()) { 2003a845be7SRiver Riddle auto &rootTimer = rootTimers[tid]; 2013a845be7SRiver Riddle if (!rootTimer) 2023a845be7SRiver Riddle rootTimer.reset(new Timer("root")); 2033a845be7SRiver Riddle auto *timer = rootTimer->getChildTimer(id, std::move(nameBuilder)); 2043a845be7SRiver Riddle activeTimers.push_back(timer); 2053a845be7SRiver Riddle return timer; 2068e7b683dSRiver Riddle } 2076558f80cSRiver Riddle 2083a845be7SRiver Riddle // Otherwise, add this to the active timer. 2093a845be7SRiver Riddle auto timer = activeTimers.back()->getChildTimer(id, std::move(nameBuilder)); 2103a845be7SRiver Riddle activeTimers.push_back(timer); 2113a845be7SRiver Riddle return timer; 2123a845be7SRiver Riddle } 2136558f80cSRiver Riddle 2143a845be7SRiver Riddle /// The root top level timers for each thread. 2153a845be7SRiver Riddle DenseMap<uint64_t, std::unique_ptr<Timer>> rootTimers; 2163a845be7SRiver Riddle 2173a845be7SRiver Riddle /// A stack of the currently active pass timers per thread. 2183a845be7SRiver 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 &) { 2473a845be7SRiver Riddle auto tid = llvm::get_threadid(); 2483a845be7SRiver Riddle auto &activeTimers = activeThreadTimers[tid]; 2498e7b683dSRiver Riddle assert(!activeTimers.empty() && "expected active timer"); 2508e7b683dSRiver Riddle Timer *timer = activeTimers.pop_back_val(); 2518e7b683dSRiver Riddle 2523a845be7SRiver Riddle // If this is an ModuleToFunctionPassAdaptorParallel, then we need to merge in 2533a845be7SRiver Riddle // the timing data for the other threads. 254*a5ca314cSMehdi Amini if (isa<ModuleToFunctionPassAdaptorParallel>(pass)) { 2553a845be7SRiver Riddle // The asychronous pipeline timers should exist as children of root timers 2563a845be7SRiver Riddle // for other threads. 2573a845be7SRiver Riddle for (auto &rootTimer : llvm::make_early_inc_range(rootTimers)) { 2583a845be7SRiver Riddle // Skip the current thread. 2593a845be7SRiver Riddle if (rootTimer.first == tid) 2603a845be7SRiver Riddle continue; 2613a845be7SRiver Riddle // Check that this thread has no active timers. 2623a845be7SRiver Riddle assert(activeThreadTimers[tid].empty() && "expected no active timers"); 2633a845be7SRiver Riddle 2643a845be7SRiver Riddle // Structurally merge this timers children into the parallel 2653a845be7SRiver Riddle // module-to-function pass timer. 2663a845be7SRiver Riddle timer->mergeChildren(std::move(rootTimer.second->children), 2673a845be7SRiver Riddle /*isStructural=*/true); 2683a845be7SRiver Riddle rootTimers.erase(rootTimer.first); 2693a845be7SRiver Riddle } 2703a845be7SRiver Riddle return; 2713a845be7SRiver Riddle } 2723a845be7SRiver Riddle 2738e7b683dSRiver Riddle // Adapator passes aren't timed directly, so we don't need to stop their 2748e7b683dSRiver Riddle // timers. 2758e7b683dSRiver Riddle if (!isAdaptorPass(pass)) 2768e7b683dSRiver Riddle timer->stop(); 277e46ba31cSRiver Riddle } 278e46ba31cSRiver Riddle 2798e7b683dSRiver Riddle /// Stop a timer. 2808e7b683dSRiver Riddle void PassTiming::runAfterAnalysis(llvm::StringRef, AnalysisID *, 2818e7b683dSRiver Riddle const llvm::Any &) { 2823a845be7SRiver Riddle auto &activeTimers = activeThreadTimers[llvm::get_threadid()]; 2838e7b683dSRiver Riddle assert(!activeTimers.empty() && "expected active timer"); 2848e7b683dSRiver Riddle Timer *timer = activeTimers.pop_back_val(); 2858e7b683dSRiver Riddle timer->stop(); 286e46ba31cSRiver Riddle } 287e46ba31cSRiver Riddle 2888e7b683dSRiver Riddle /// Utility to print the timer heading information. 2893a845be7SRiver Riddle static void printTimerHeader(llvm::raw_ostream &os, TimeRecord total) { 290e46ba31cSRiver Riddle os << "===" << std::string(73, '-') << "===\n"; 291e46ba31cSRiver Riddle // Figure out how many spaces to description name. 292e46ba31cSRiver Riddle unsigned Padding = (80 - kPassTimingDescription.size()) / 2; 293e46ba31cSRiver Riddle os.indent(Padding) << kPassTimingDescription << '\n'; 294e46ba31cSRiver Riddle os << "===" << std::string(73, '-') << "===\n"; 295e46ba31cSRiver Riddle 2968e7b683dSRiver Riddle // Print the total time followed by the section headers. 2973a845be7SRiver Riddle os << llvm::format(" Total Execution Time: %5.4f seconds\n\n", total.wall); 2983a845be7SRiver Riddle if (total.user != total.wall) 2993a845be7SRiver Riddle os << " ---User Time---"; 3008e7b683dSRiver Riddle os << " ---Wall Time--- --- Name ---\n"; 3018e7b683dSRiver Riddle } 302e46ba31cSRiver Riddle 3038e7b683dSRiver Riddle /// Utility to print a single line entry in the timer output. 3048e7b683dSRiver Riddle static void printTimeEntry(raw_ostream &os, unsigned indent, StringRef name, 3053a845be7SRiver Riddle TimeRecord time, TimeRecord totalTime) { 3063a845be7SRiver Riddle time.print(os, totalTime); 3078e7b683dSRiver Riddle os.indent(indent) << name << "\n"; 3088e7b683dSRiver Riddle } 3098e7b683dSRiver Riddle 3108e7b683dSRiver Riddle /// Print out the current timing information. 3118e7b683dSRiver Riddle void PassTiming::print() { 3128e7b683dSRiver Riddle // Don't print anything if there is no timing data. 3133a845be7SRiver Riddle if (rootTimers.empty()) 3148e7b683dSRiver Riddle return; 3153a845be7SRiver Riddle 3163a845be7SRiver Riddle assert(rootTimers.size() == 1 && "expected one remaining root timer"); 3173a845be7SRiver Riddle auto &rootTimer = rootTimers.begin()->second; 3188e7b683dSRiver Riddle auto os = llvm::CreateInfoOutputFile(); 3198e7b683dSRiver Riddle 3208e7b683dSRiver Riddle // Print the timer header. 3213a845be7SRiver Riddle TimeRecord totalTime = rootTimer->getTotalTime(); 3228e7b683dSRiver Riddle printTimerHeader(*os, totalTime); 3238e7b683dSRiver Riddle 3248e7b683dSRiver Riddle // Defer to a specialized printer for each display mode. 3258e7b683dSRiver Riddle switch (displayMode) { 3268e7b683dSRiver Riddle case PassTimingDisplayMode::List: 3273a845be7SRiver Riddle printResultsAsList(*os, rootTimer.get(), totalTime); 3288e7b683dSRiver Riddle break; 3298e7b683dSRiver Riddle case PassTimingDisplayMode::Pipeline: 3303a845be7SRiver Riddle printResultsAsPipeline(*os, rootTimer.get(), totalTime); 3318e7b683dSRiver Riddle break; 3328e7b683dSRiver Riddle } 3338e7b683dSRiver Riddle printTimeEntry(*os, 0, "Total", totalTime, totalTime); 3348e7b683dSRiver Riddle os->flush(); 3358e7b683dSRiver Riddle 3363a845be7SRiver Riddle // Reset root timers. 3373a845be7SRiver Riddle rootTimers.clear(); 3383a845be7SRiver Riddle activeThreadTimers.clear(); 3398e7b683dSRiver Riddle } 3408e7b683dSRiver Riddle 3418e7b683dSRiver Riddle /// Print the timing result in list mode. 3423a845be7SRiver Riddle void PassTiming::printResultsAsList(raw_ostream &os, Timer *root, 3433a845be7SRiver Riddle TimeRecord totalTime) { 3443a845be7SRiver Riddle llvm::StringMap<TimeRecord> mergedTimings; 3458e7b683dSRiver Riddle 3468e7b683dSRiver Riddle std::function<void(Timer *)> addTimer = [&](Timer *timer) { 3478e7b683dSRiver Riddle // Check for timing information. 3483a845be7SRiver Riddle if (timer->wallTime.count()) 3498e7b683dSRiver Riddle mergedTimings[timer->name] += timer->getTotalTime(); 3508e7b683dSRiver Riddle for (auto &children : timer->children) 3518e7b683dSRiver Riddle addTimer(children.second.get()); 3528e7b683dSRiver Riddle }; 3538e7b683dSRiver Riddle 3548e7b683dSRiver Riddle // Add each of the top level timers. 3553a845be7SRiver Riddle for (auto &topLevelTimer : root->children) 3568e7b683dSRiver Riddle addTimer(topLevelTimer.second.get()); 3578e7b683dSRiver Riddle 3583a845be7SRiver Riddle // Sort the timing information by wall time. 3593a845be7SRiver Riddle std::vector<std::pair<StringRef, TimeRecord>> timerNameAndTime; 3608e7b683dSRiver Riddle for (auto &it : mergedTimings) 3618e7b683dSRiver Riddle timerNameAndTime.emplace_back(it.first(), it.second); 3628e7b683dSRiver Riddle llvm::array_pod_sort(timerNameAndTime.begin(), timerNameAndTime.end(), 3633a845be7SRiver Riddle [](const std::pair<StringRef, TimeRecord> *lhs, 3643a845be7SRiver Riddle const std::pair<StringRef, TimeRecord> *rhs) { 3658e7b683dSRiver Riddle return llvm::array_pod_sort_comparator<double>( 3663a845be7SRiver Riddle &rhs->second.wall, &lhs->second.wall); 3678e7b683dSRiver Riddle }); 3688e7b683dSRiver Riddle 3698e7b683dSRiver Riddle // Print the timing information sequentially. 3708e7b683dSRiver Riddle for (auto &timeData : timerNameAndTime) 3718e7b683dSRiver Riddle printTimeEntry(os, 0, timeData.first, timeData.second, totalTime); 372e46ba31cSRiver Riddle } 373e46ba31cSRiver Riddle 374e46ba31cSRiver Riddle /// Print the timing result in pipeline mode. 3753a845be7SRiver Riddle void PassTiming::printResultsAsPipeline(raw_ostream &os, Timer *root, 3763a845be7SRiver Riddle TimeRecord totalTime) { 3778e7b683dSRiver Riddle std::function<void(unsigned, Timer *)> printTimer = [&](unsigned indent, 3788e7b683dSRiver Riddle Timer *timer) { 3798e7b683dSRiver Riddle printTimeEntry(os, indent, timer->name, timer->getTotalTime(), totalTime); 3808e7b683dSRiver Riddle for (auto &children : timer->children) 3818e7b683dSRiver Riddle printTimer(indent + 2, children.second.get()); 382e46ba31cSRiver Riddle }; 383e46ba31cSRiver Riddle 3848e7b683dSRiver Riddle // Print each of the top level timers. 3853a845be7SRiver Riddle for (auto &topLevelTimer : root->children) 3868e7b683dSRiver Riddle printTimer(0, topLevelTimer.second.get()); 387e46ba31cSRiver Riddle } 3886558f80cSRiver Riddle 3896558f80cSRiver Riddle //===----------------------------------------------------------------------===// 3906558f80cSRiver Riddle // PassManager 3916558f80cSRiver Riddle //===----------------------------------------------------------------------===// 3926558f80cSRiver Riddle 3936558f80cSRiver Riddle /// Add an instrumentation to time the execution of passes and the computation 3946558f80cSRiver Riddle /// of analyses. 3956558f80cSRiver Riddle void PassManager::enableTiming(PassTimingDisplayMode displayMode) { 3966558f80cSRiver Riddle // Check if pass timing is already enabled. 3976558f80cSRiver Riddle if (passTiming) 3986558f80cSRiver Riddle return; 3996558f80cSRiver Riddle addInstrumentation(new PassTiming(displayMode)); 4006558f80cSRiver Riddle passTiming = true; 4016558f80cSRiver Riddle } 402