Jim Stichnoth | c4554d7 | 2014-09-30 16:49:38 -0700 | [diff] [blame] | 1 | //===- subzero/src/IceTimerTree.cpp - Pass timer defs ---------------------===// |
| 2 | // |
| 3 | // The Subzero Code Generator |
| 4 | // |
| 5 | // This file is distributed under the University of Illinois Open Source |
| 6 | // License. See LICENSE.TXT for details. |
| 7 | // |
| 8 | //===----------------------------------------------------------------------===// |
Andrew Scull | 9612d32 | 2015-07-06 14:53:25 -0700 | [diff] [blame] | 9 | /// |
| 10 | /// \file |
Jim Stichnoth | 92a6e5b | 2015-12-02 16:52:44 -0800 | [diff] [blame] | 11 | /// \brief Defines the TimerTree class, which tracks flat and cumulative |
Andrew Scull | 57e1268 | 2015-09-16 11:30:19 -0700 | [diff] [blame] | 12 | /// execution time collection of call chains. |
Andrew Scull | 9612d32 | 2015-07-06 14:53:25 -0700 | [diff] [blame] | 13 | /// |
Jim Stichnoth | c4554d7 | 2014-09-30 16:49:38 -0700 | [diff] [blame] | 14 | //===----------------------------------------------------------------------===// |
| 15 | |
John Porto | 67f8de9 | 2015-06-25 10:14:17 -0700 | [diff] [blame] | 16 | #include "IceTimerTree.h" |
Jim Stichnoth | 9c234e2 | 2014-10-01 09:28:21 -0700 | [diff] [blame] | 17 | |
Jim Stichnoth | c4554d7 | 2014-09-30 16:49:38 -0700 | [diff] [blame] | 18 | #include "IceDefs.h" |
Jim Stichnoth | 98da966 | 2015-06-27 06:38:08 -0700 | [diff] [blame] | 19 | |
Jim Stichnoth | b0051df | 2016-01-13 11:39:15 -0800 | [diff] [blame] | 20 | #ifdef __clang__ |
Jim Stichnoth | 98da966 | 2015-06-27 06:38:08 -0700 | [diff] [blame] | 21 | #pragma clang diagnostic push |
| 22 | #pragma clang diagnostic ignored "-Wunused-parameter" |
Jim Stichnoth | b0051df | 2016-01-13 11:39:15 -0800 | [diff] [blame] | 23 | #endif // __clang__ |
| 24 | |
Jim Stichnoth | d72385f | 2016-04-06 12:21:14 -0700 | [diff] [blame] | 25 | #include "llvm/Support/Format.h" |
John Porto | 67f8de9 | 2015-06-25 10:14:17 -0700 | [diff] [blame] | 26 | #include "llvm/Support/Timer.h" |
Jim Stichnoth | b0051df | 2016-01-13 11:39:15 -0800 | [diff] [blame] | 27 | |
| 28 | #ifdef __clang__ |
Jim Stichnoth | 98da966 | 2015-06-27 06:38:08 -0700 | [diff] [blame] | 29 | #pragma clang diagnostic pop |
Jim Stichnoth | b0051df | 2016-01-13 11:39:15 -0800 | [diff] [blame] | 30 | #endif // __clang__ |
Jim Stichnoth | c4554d7 | 2014-09-30 16:49:38 -0700 | [diff] [blame] | 31 | |
| 32 | namespace Ice { |
| 33 | |
Jim Stichnoth | 467ffe5 | 2016-03-29 15:01:06 -0700 | [diff] [blame] | 34 | TimerStack::TimerStack(const std::string &Name) |
Jim Stichnoth | eafb56c | 2015-06-22 10:35:22 -0700 | [diff] [blame] | 35 | : Name(Name), FirstTimestamp(timestamp()), LastTimestamp(FirstTimestamp) { |
Jim Stichnoth | b88d8c8 | 2016-03-11 15:33:00 -0800 | [diff] [blame] | 36 | if (!BuildDefs::timers()) |
Jim Stichnoth | 1c44d81 | 2014-12-08 14:57:52 -0800 | [diff] [blame] | 37 | return; |
Jim Stichnoth | 380d7b9 | 2015-01-30 13:10:39 -0800 | [diff] [blame] | 38 | Nodes.resize(1); // Reserve Nodes[0] for the root node (sentinel). |
Jim Stichnoth | 8363a06 | 2014-10-07 10:02:38 -0700 | [diff] [blame] | 39 | IDs.resize(TT__num); |
Jim Stichnoth | 380d7b9 | 2015-01-30 13:10:39 -0800 | [diff] [blame] | 40 | LeafTimes.resize(TT__num); |
| 41 | LeafCounts.resize(TT__num); |
Jim Stichnoth | 8363a06 | 2014-10-07 10:02:38 -0700 | [diff] [blame] | 42 | #define STR(s) #s |
| 43 | #define X(tag) \ |
| 44 | IDs[TT_##tag] = STR(tag); \ |
| 45 | IDsIndex[STR(tag)] = TT_##tag; |
| 46 | TIMERTREE_TABLE; |
| 47 | #undef X |
| 48 | #undef STR |
Jim Stichnoth | c4554d7 | 2014-09-30 16:49:38 -0700 | [diff] [blame] | 49 | } |
| 50 | |
Andrew Scull | 57e1268 | 2015-09-16 11:30:19 -0700 | [diff] [blame] | 51 | // Returns the unique timer ID for the given Name, creating a new ID if needed. |
Jim Stichnoth | 467ffe5 | 2016-03-29 15:01:06 -0700 | [diff] [blame] | 52 | TimerIdT TimerStack::getTimerID(const std::string &Name) { |
Jim Stichnoth | b88d8c8 | 2016-03-11 15:33:00 -0800 | [diff] [blame] | 53 | if (!BuildDefs::timers()) |
Jim Stichnoth | 1c44d81 | 2014-12-08 14:57:52 -0800 | [diff] [blame] | 54 | return 0; |
Jim Stichnoth | 8363a06 | 2014-10-07 10:02:38 -0700 | [diff] [blame] | 55 | if (IDsIndex.find(Name) == IDsIndex.end()) { |
| 56 | IDsIndex[Name] = IDs.size(); |
| 57 | IDs.push_back(Name); |
Jim Stichnoth | 380d7b9 | 2015-01-30 13:10:39 -0800 | [diff] [blame] | 58 | LeafTimes.push_back(decltype(LeafTimes)::value_type()); |
| 59 | LeafCounts.push_back(decltype(LeafCounts)::value_type()); |
Jim Stichnoth | c4554d7 | 2014-09-30 16:49:38 -0700 | [diff] [blame] | 60 | } |
Jim Stichnoth | 8363a06 | 2014-10-07 10:02:38 -0700 | [diff] [blame] | 61 | return IDsIndex[Name]; |
Jim Stichnoth | c4554d7 | 2014-09-30 16:49:38 -0700 | [diff] [blame] | 62 | } |
| 63 | |
Andrew Scull | 57e1268 | 2015-09-16 11:30:19 -0700 | [diff] [blame] | 64 | // Creates a mapping from TimerIdT (leaf) values in the Src timer stack into |
| 65 | // TimerIdT values in this timer stack. Creates new entries in this timer stack |
| 66 | // as needed. |
Jim Stichnoth | 380d7b9 | 2015-01-30 13:10:39 -0800 | [diff] [blame] | 67 | TimerStack::TranslationType |
| 68 | TimerStack::translateIDsFrom(const TimerStack &Src) { |
| 69 | size_t Size = Src.IDs.size(); |
| 70 | TranslationType Mapping(Size); |
| 71 | for (TimerIdT i = 0; i < Size; ++i) { |
| 72 | Mapping[i] = getTimerID(Src.IDs[i]); |
| 73 | } |
| 74 | return Mapping; |
| 75 | } |
| 76 | |
Andrew Scull | 57e1268 | 2015-09-16 11:30:19 -0700 | [diff] [blame] | 77 | // Merges two timer stacks, by combining and summing corresponding entries. |
| 78 | // This timer stack is updated from Src. |
Jim Stichnoth | 380d7b9 | 2015-01-30 13:10:39 -0800 | [diff] [blame] | 79 | void TimerStack::mergeFrom(const TimerStack &Src) { |
Jim Stichnoth | b88d8c8 | 2016-03-11 15:33:00 -0800 | [diff] [blame] | 80 | if (!BuildDefs::timers()) |
Jim Stichnoth | 380d7b9 | 2015-01-30 13:10:39 -0800 | [diff] [blame] | 81 | return; |
| 82 | TranslationType Mapping = translateIDsFrom(Src); |
| 83 | TTindex SrcIndex = 0; |
| 84 | for (const TimerTreeNode &SrcNode : Src.Nodes) { |
| 85 | // The first node is reserved as a sentinel, so avoid it. |
| 86 | if (SrcIndex > 0) { |
Andrew Scull | 57e1268 | 2015-09-16 11:30:19 -0700 | [diff] [blame] | 87 | // Find the full path to the Src node, translated to path components |
| 88 | // corresponding to this timer stack. |
Jim Stichnoth | 380d7b9 | 2015-01-30 13:10:39 -0800 | [diff] [blame] | 89 | PathType MyPath = Src.getPath(SrcIndex, Mapping); |
Andrew Scull | 57e1268 | 2015-09-16 11:30:19 -0700 | [diff] [blame] | 90 | // Find a node in this timer stack corresponding to the given path, |
| 91 | // creating new interior nodes as necessary. |
Jim Stichnoth | 380d7b9 | 2015-01-30 13:10:39 -0800 | [diff] [blame] | 92 | TTindex MyIndex = findPath(MyPath); |
| 93 | Nodes[MyIndex].Time += SrcNode.Time; |
| 94 | Nodes[MyIndex].UpdateCount += SrcNode.UpdateCount; |
| 95 | } |
| 96 | ++SrcIndex; |
| 97 | } |
| 98 | for (TimerIdT i = 0; i < Src.LeafTimes.size(); ++i) { |
| 99 | LeafTimes[Mapping[i]] += Src.LeafTimes[i]; |
| 100 | LeafCounts[Mapping[i]] += Src.LeafCounts[i]; |
| 101 | } |
| 102 | StateChangeCount += Src.StateChangeCount; |
| 103 | } |
| 104 | |
Andrew Scull | 57e1268 | 2015-09-16 11:30:19 -0700 | [diff] [blame] | 105 | // Constructs a path consisting of the sequence of leaf values leading to a |
| 106 | // given node, with the Mapping translation applied to the leaf values. The |
| 107 | // path ends up being in "reverse" order, i.e. from leaf to root. |
Jim Stichnoth | 380d7b9 | 2015-01-30 13:10:39 -0800 | [diff] [blame] | 108 | TimerStack::PathType TimerStack::getPath(TTindex Index, |
| 109 | const TranslationType &Mapping) const { |
| 110 | PathType Path; |
| 111 | while (Index) { |
| 112 | Path.push_back(Mapping[Nodes[Index].Interior]); |
| 113 | assert(Nodes[Index].Parent < Index); |
| 114 | Index = Nodes[Index].Parent; |
| 115 | } |
| 116 | return Path; |
| 117 | } |
| 118 | |
Andrew Scull | 57e1268 | 2015-09-16 11:30:19 -0700 | [diff] [blame] | 119 | // Given a parent node and a leaf ID, returns the index of the parent's child |
| 120 | // ID, creating a new node for the child as necessary. |
Jim Stichnoth | 380d7b9 | 2015-01-30 13:10:39 -0800 | [diff] [blame] | 121 | TimerStack::TTindex TimerStack::getChildIndex(TimerStack::TTindex Parent, |
| 122 | TimerIdT ID) { |
| 123 | if (Nodes[Parent].Children.size() <= ID) |
| 124 | Nodes[Parent].Children.resize(ID + 1); |
| 125 | if (Nodes[Parent].Children[ID] == 0) { |
| 126 | TTindex Size = Nodes.size(); |
| 127 | Nodes[Parent].Children[ID] = Size; |
| 128 | Nodes.resize(Size + 1); |
| 129 | Nodes[Size].Parent = Parent; |
| 130 | Nodes[Size].Interior = ID; |
| 131 | } |
| 132 | return Nodes[Parent].Children[ID]; |
| 133 | } |
| 134 | |
Andrew Scull | 57e1268 | 2015-09-16 11:30:19 -0700 | [diff] [blame] | 135 | // Finds a node in the timer stack corresponding to the given path, creating |
| 136 | // new interior nodes as necessary. |
Jim Stichnoth | 380d7b9 | 2015-01-30 13:10:39 -0800 | [diff] [blame] | 137 | TimerStack::TTindex TimerStack::findPath(const PathType &Path) { |
| 138 | TTindex CurIndex = 0; |
Andrew Scull | 57e1268 | 2015-09-16 11:30:19 -0700 | [diff] [blame] | 139 | // The path is in reverse order (leaf to root), so it needs to be followed in |
| 140 | // reverse. |
Jim Stichnoth | 380d7b9 | 2015-01-30 13:10:39 -0800 | [diff] [blame] | 141 | for (TTindex Index : reverse_range(Path)) { |
| 142 | CurIndex = getChildIndex(CurIndex, Index); |
| 143 | } |
| 144 | assert(CurIndex); // shouldn't be the sentinel node |
| 145 | return CurIndex; |
| 146 | } |
| 147 | |
Jim Stichnoth | c4554d7 | 2014-09-30 16:49:38 -0700 | [diff] [blame] | 148 | // Pushes a new marker onto the timer stack. |
| 149 | void TimerStack::push(TimerIdT ID) { |
Jim Stichnoth | b88d8c8 | 2016-03-11 15:33:00 -0800 | [diff] [blame] | 150 | if (!BuildDefs::timers()) |
Jim Stichnoth | 1c44d81 | 2014-12-08 14:57:52 -0800 | [diff] [blame] | 151 | return; |
Jim Stichnoth | 5bff61c | 2015-10-28 09:26:00 -0700 | [diff] [blame] | 152 | constexpr bool UpdateCounts = false; |
Jim Stichnoth | abce6e5 | 2014-10-14 11:09:27 -0700 | [diff] [blame] | 153 | update(UpdateCounts); |
Jim Stichnoth | 380d7b9 | 2015-01-30 13:10:39 -0800 | [diff] [blame] | 154 | StackTop = getChildIndex(StackTop, ID); |
| 155 | assert(StackTop); |
Jim Stichnoth | c4554d7 | 2014-09-30 16:49:38 -0700 | [diff] [blame] | 156 | } |
| 157 | |
Andrew Scull | 57e1268 | 2015-09-16 11:30:19 -0700 | [diff] [blame] | 158 | // Pops the top marker from the timer stack. Validates via assert() that the |
| 159 | // expected marker is popped. |
Jim Stichnoth | c4554d7 | 2014-09-30 16:49:38 -0700 | [diff] [blame] | 160 | void TimerStack::pop(TimerIdT ID) { |
Jim Stichnoth | b88d8c8 | 2016-03-11 15:33:00 -0800 | [diff] [blame] | 161 | if (!BuildDefs::timers()) |
Jim Stichnoth | 1c44d81 | 2014-12-08 14:57:52 -0800 | [diff] [blame] | 162 | return; |
Jim Stichnoth | 5bff61c | 2015-10-28 09:26:00 -0700 | [diff] [blame] | 163 | constexpr bool UpdateCounts = true; |
Jim Stichnoth | abce6e5 | 2014-10-14 11:09:27 -0700 | [diff] [blame] | 164 | update(UpdateCounts); |
Jim Stichnoth | c4554d7 | 2014-09-30 16:49:38 -0700 | [diff] [blame] | 165 | assert(StackTop); |
| 166 | assert(Nodes[StackTop].Parent < StackTop); |
| 167 | // Verify that the expected ID is being popped. |
| 168 | assert(Nodes[StackTop].Interior == ID); |
| 169 | (void)ID; |
| 170 | // Verify that the parent's child points to the current stack top. |
| 171 | assert(Nodes[Nodes[StackTop].Parent].Children[ID] == StackTop); |
| 172 | StackTop = Nodes[StackTop].Parent; |
| 173 | } |
| 174 | |
Andrew Scull | 57e1268 | 2015-09-16 11:30:19 -0700 | [diff] [blame] | 175 | // At a state change (e.g. push or pop), updates the flat and cumulative |
| 176 | // timings for everything on the timer stack. |
Jim Stichnoth | abce6e5 | 2014-10-14 11:09:27 -0700 | [diff] [blame] | 177 | void TimerStack::update(bool UpdateCounts) { |
Jim Stichnoth | b88d8c8 | 2016-03-11 15:33:00 -0800 | [diff] [blame] | 178 | if (!BuildDefs::timers()) |
Jim Stichnoth | 1c44d81 | 2014-12-08 14:57:52 -0800 | [diff] [blame] | 179 | return; |
Jim Stichnoth | c4554d7 | 2014-09-30 16:49:38 -0700 | [diff] [blame] | 180 | ++StateChangeCount; |
Andrew Scull | 57e1268 | 2015-09-16 11:30:19 -0700 | [diff] [blame] | 181 | // Whenever the stack is about to change, we grab the time delta since the |
| 182 | // last change and add it to all active cumulative elements and to the flat |
| 183 | // element for the top of the stack. |
Jim Stichnoth | c4554d7 | 2014-09-30 16:49:38 -0700 | [diff] [blame] | 184 | double Current = timestamp(); |
| 185 | double Delta = Current - LastTimestamp; |
Jim Stichnoth | c4554d7 | 2014-09-30 16:49:38 -0700 | [diff] [blame] | 186 | if (StackTop) { |
| 187 | TimerIdT Leaf = Nodes[StackTop].Interior; |
Jim Stichnoth | abce6e5 | 2014-10-14 11:09:27 -0700 | [diff] [blame] | 188 | if (Leaf >= LeafTimes.size()) { |
Jim Stichnoth | c4554d7 | 2014-09-30 16:49:38 -0700 | [diff] [blame] | 189 | LeafTimes.resize(Leaf + 1); |
Jim Stichnoth | abce6e5 | 2014-10-14 11:09:27 -0700 | [diff] [blame] | 190 | LeafCounts.resize(Leaf + 1); |
| 191 | } |
Jim Stichnoth | c4554d7 | 2014-09-30 16:49:38 -0700 | [diff] [blame] | 192 | LeafTimes[Leaf] += Delta; |
Jim Stichnoth | abce6e5 | 2014-10-14 11:09:27 -0700 | [diff] [blame] | 193 | if (UpdateCounts) |
| 194 | ++LeafCounts[Leaf]; |
Jim Stichnoth | c4554d7 | 2014-09-30 16:49:38 -0700 | [diff] [blame] | 195 | } |
| 196 | TTindex Prefix = StackTop; |
| 197 | while (Prefix) { |
| 198 | Nodes[Prefix].Time += Delta; |
Jim Stichnoth | abce6e5 | 2014-10-14 11:09:27 -0700 | [diff] [blame] | 199 | // Only update a leaf node count, not the internal node counts. |
| 200 | if (UpdateCounts && Prefix == StackTop) |
| 201 | ++Nodes[Prefix].UpdateCount; |
Jim Stichnoth | c4554d7 | 2014-09-30 16:49:38 -0700 | [diff] [blame] | 202 | TTindex Next = Nodes[Prefix].Parent; |
| 203 | assert(Next < Prefix); |
| 204 | Prefix = Next; |
| 205 | } |
Andrew Scull | 57e1268 | 2015-09-16 11:30:19 -0700 | [diff] [blame] | 206 | // Capture the next timestamp *after* the updates are finished. This |
| 207 | // minimizes how much the timer can perturb the reported timing. The numbers |
| 208 | // may not sum to 100%, and the missing amount is indicative of the overhead |
| 209 | // of timing. |
Jim Stichnoth | 4775255 | 2014-10-13 17:15:08 -0700 | [diff] [blame] | 210 | LastTimestamp = timestamp(); |
Jim Stichnoth | c4554d7 | 2014-09-30 16:49:38 -0700 | [diff] [blame] | 211 | } |
| 212 | |
Jim Stichnoth | d14b1a0 | 2014-10-08 08:28:36 -0700 | [diff] [blame] | 213 | void TimerStack::reset() { |
Jim Stichnoth | b88d8c8 | 2016-03-11 15:33:00 -0800 | [diff] [blame] | 214 | if (!BuildDefs::timers()) |
Jim Stichnoth | 1c44d81 | 2014-12-08 14:57:52 -0800 | [diff] [blame] | 215 | return; |
Jim Stichnoth | d14b1a0 | 2014-10-08 08:28:36 -0700 | [diff] [blame] | 216 | StateChangeCount = 0; |
| 217 | FirstTimestamp = LastTimestamp = timestamp(); |
| 218 | LeafTimes.assign(LeafTimes.size(), 0); |
Jim Stichnoth | abce6e5 | 2014-10-14 11:09:27 -0700 | [diff] [blame] | 219 | LeafCounts.assign(LeafCounts.size(), 0); |
Jim Stichnoth | d14b1a0 | 2014-10-08 08:28:36 -0700 | [diff] [blame] | 220 | for (TimerTreeNode &Node : Nodes) { |
| 221 | Node.Time = 0; |
Jim Stichnoth | abce6e5 | 2014-10-14 11:09:27 -0700 | [diff] [blame] | 222 | Node.UpdateCount = 0; |
Jim Stichnoth | d14b1a0 | 2014-10-08 08:28:36 -0700 | [diff] [blame] | 223 | } |
| 224 | } |
| 225 | |
Jim Stichnoth | c4554d7 | 2014-09-30 16:49:38 -0700 | [diff] [blame] | 226 | namespace { |
| 227 | |
Jim Stichnoth | 467ffe5 | 2016-03-29 15:01:06 -0700 | [diff] [blame] | 228 | using DumpMapType = std::multimap<double, std::string>; |
Jim Stichnoth | c4554d7 | 2014-09-30 16:49:38 -0700 | [diff] [blame] | 229 | |
Jim Stichnoth | 9a23e43 | 2016-04-08 17:09:29 -0700 | [diff] [blame] | 230 | // Dump the Map items in reverse order of their time contribution. If |
| 231 | // AddPercents is true (i.e. for printing "flat times"), it also prints a |
| 232 | // cumulative percentage column, and recalculates TotalTime as the sum of all |
| 233 | // the individual times so that cumulative percentage adds up to 100%. |
| 234 | void dumpHelper(Ostream &Str, const DumpMapType &Map, double TotalTime, |
| 235 | bool AddPercents) { |
Jim Stichnoth | b88d8c8 | 2016-03-11 15:33:00 -0800 | [diff] [blame] | 236 | if (!BuildDefs::timers()) |
Karl Schimpf | b6c96af | 2014-11-17 10:58:39 -0800 | [diff] [blame] | 237 | return; |
Jim Stichnoth | 9a23e43 | 2016-04-08 17:09:29 -0700 | [diff] [blame] | 238 | if (AddPercents) { |
| 239 | // Recalculate TotalTime as the sum of the individual times. This is |
| 240 | // because the individual times generally add up to less than 100% because |
| 241 | // of timer overhead. |
| 242 | TotalTime = 0; |
| 243 | for (const auto &I : Map) { |
| 244 | TotalTime += I.first; |
| 245 | } |
Jim Stichnoth | c4554d7 | 2014-09-30 16:49:38 -0700 | [diff] [blame] | 246 | } |
Jim Stichnoth | 9a23e43 | 2016-04-08 17:09:29 -0700 | [diff] [blame] | 247 | double Sum = 0; |
| 248 | for (const auto &I : reverse_range(Map)) { |
| 249 | Sum += I.first; |
| 250 | if (AddPercents) { |
| 251 | Str << llvm::format(" %10.6f %4.1f%% %5.1f%% ", I.first, |
| 252 | I.first * 100 / TotalTime, Sum * 100 / TotalTime) |
| 253 | << I.second << "\n"; |
| 254 | } else { |
| 255 | Str << llvm::format(" %10.6f %4.1f%% ", I.first, |
| 256 | I.first * 100 / TotalTime) << I.second << "\n"; |
| 257 | } |
| 258 | } |
Jim Stichnoth | abce6e5 | 2014-10-14 11:09:27 -0700 | [diff] [blame] | 259 | } |
| 260 | |
Jim Stichnoth | c4554d7 | 2014-09-30 16:49:38 -0700 | [diff] [blame] | 261 | } // end of anonymous namespace |
| 262 | |
Jim Stichnoth | 8363a06 | 2014-10-07 10:02:38 -0700 | [diff] [blame] | 263 | void TimerStack::dump(Ostream &Str, bool DumpCumulative) { |
Jim Stichnoth | b88d8c8 | 2016-03-11 15:33:00 -0800 | [diff] [blame] | 264 | if (!BuildDefs::timers()) |
Karl Schimpf | b6c96af | 2014-11-17 10:58:39 -0800 | [diff] [blame] | 265 | return; |
Jim Stichnoth | 5bff61c | 2015-10-28 09:26:00 -0700 | [diff] [blame] | 266 | constexpr bool UpdateCounts = true; |
Jim Stichnoth | abce6e5 | 2014-10-14 11:09:27 -0700 | [diff] [blame] | 267 | update(UpdateCounts); |
Jim Stichnoth | c4554d7 | 2014-09-30 16:49:38 -0700 | [diff] [blame] | 268 | double TotalTime = LastTimestamp - FirstTimestamp; |
| 269 | assert(TotalTime); |
Jim Stichnoth | 9a23e43 | 2016-04-08 17:09:29 -0700 | [diff] [blame] | 270 | char PrefixStr[30]; |
Jim Stichnoth | 8363a06 | 2014-10-07 10:02:38 -0700 | [diff] [blame] | 271 | if (DumpCumulative) { |
Jim Stichnoth | 9a23e43 | 2016-04-08 17:09:29 -0700 | [diff] [blame] | 272 | Str << Name << " - Cumulative times:\n" |
| 273 | " Seconds Pct EventCnt TimerPath\n"; |
Jim Stichnoth | 8363a06 | 2014-10-07 10:02:38 -0700 | [diff] [blame] | 274 | DumpMapType CumulativeMap; |
| 275 | for (TTindex i = 1; i < Nodes.size(); ++i) { |
| 276 | TTindex Prefix = i; |
Jim Stichnoth | 467ffe5 | 2016-03-29 15:01:06 -0700 | [diff] [blame] | 277 | std::string Suffix = ""; |
Jim Stichnoth | 8363a06 | 2014-10-07 10:02:38 -0700 | [diff] [blame] | 278 | while (Prefix) { |
| 279 | if (Suffix.empty()) |
| 280 | Suffix = IDs[Nodes[Prefix].Interior]; |
| 281 | else |
| 282 | Suffix = IDs[Nodes[Prefix].Interior] + "." + Suffix; |
| 283 | assert(Nodes[Prefix].Parent < Prefix); |
| 284 | Prefix = Nodes[Prefix].Parent; |
| 285 | } |
Jim Stichnoth | 9a23e43 | 2016-04-08 17:09:29 -0700 | [diff] [blame] | 286 | snprintf(PrefixStr, llvm::array_lengthof(PrefixStr), "%9zu ", |
Jim Stichnoth | abce6e5 | 2014-10-14 11:09:27 -0700 | [diff] [blame] | 287 | Nodes[i].UpdateCount); |
| 288 | CumulativeMap.insert(std::make_pair(Nodes[i].Time, PrefixStr + Suffix)); |
Jim Stichnoth | c4554d7 | 2014-09-30 16:49:38 -0700 | [diff] [blame] | 289 | } |
Jim Stichnoth | 9a23e43 | 2016-04-08 17:09:29 -0700 | [diff] [blame] | 290 | constexpr bool NoAddPercents = false; |
| 291 | dumpHelper(Str, CumulativeMap, TotalTime, NoAddPercents); |
Jim Stichnoth | c4554d7 | 2014-09-30 16:49:38 -0700 | [diff] [blame] | 292 | } |
Jim Stichnoth | 9a23e43 | 2016-04-08 17:09:29 -0700 | [diff] [blame] | 293 | Str << Name << " - Flat times:\n" |
| 294 | " Seconds Pct CumPct EventCnt TimerName\n"; |
Jim Stichnoth | c4554d7 | 2014-09-30 16:49:38 -0700 | [diff] [blame] | 295 | DumpMapType FlatMap; |
| 296 | for (TimerIdT i = 0; i < LeafTimes.size(); ++i) { |
Jim Stichnoth | abce6e5 | 2014-10-14 11:09:27 -0700 | [diff] [blame] | 297 | if (LeafCounts[i]) { |
Jim Stichnoth | 9a23e43 | 2016-04-08 17:09:29 -0700 | [diff] [blame] | 298 | snprintf(PrefixStr, llvm::array_lengthof(PrefixStr), "%9zu ", |
Jim Stichnoth | abce6e5 | 2014-10-14 11:09:27 -0700 | [diff] [blame] | 299 | LeafCounts[i]); |
| 300 | FlatMap.insert(std::make_pair(LeafTimes[i], PrefixStr + IDs[i])); |
| 301 | } |
Jim Stichnoth | c4554d7 | 2014-09-30 16:49:38 -0700 | [diff] [blame] | 302 | } |
Jim Stichnoth | 9a23e43 | 2016-04-08 17:09:29 -0700 | [diff] [blame] | 303 | constexpr bool AddPercents = true; |
| 304 | dumpHelper(Str, FlatMap, TotalTime, AddPercents); |
Jim Stichnoth | c4554d7 | 2014-09-30 16:49:38 -0700 | [diff] [blame] | 305 | Str << "Number of timer updates: " << StateChangeCount << "\n"; |
| 306 | } |
| 307 | |
Jim Stichnoth | 9c234e2 | 2014-10-01 09:28:21 -0700 | [diff] [blame] | 308 | double TimerStack::timestamp() { |
| 309 | // TODO: Implement in terms of std::chrono for C++11. |
| 310 | return llvm::TimeRecord::getCurrentTime(false).getWallTime(); |
| 311 | } |
| 312 | |
Jim Stichnoth | c4554d7 | 2014-09-30 16:49:38 -0700 | [diff] [blame] | 313 | } // end of namespace Ice |