OLD | NEW |
1 //===- subzero/src/IceTimerTree.cpp - Pass timer defs ---------------------===// | 1 //===- subzero/src/IceTimerTree.cpp - Pass timer defs ---------------------===// |
2 // | 2 // |
3 // The Subzero Code Generator | 3 // The Subzero Code Generator |
4 // | 4 // |
5 // This file is distributed under the University of Illinois Open Source | 5 // This file is distributed under the University of Illinois Open Source |
6 // License. See LICENSE.TXT for details. | 6 // License. See LICENSE.TXT for details. |
7 // | 7 // |
8 //===----------------------------------------------------------------------===// | 8 //===----------------------------------------------------------------------===// |
9 // | 9 // |
10 // This file defines the TimerTree class, which tracks flat and | 10 // This file defines the TimerTree class, which tracks flat and |
11 // cumulative execution time collection of call chains. | 11 // cumulative execution time collection of call chains. |
12 // | 12 // |
13 //===----------------------------------------------------------------------===// | 13 //===----------------------------------------------------------------------===// |
14 | 14 |
15 #include "llvm/Support/Timer.h" | 15 #include "llvm/Support/Timer.h" |
16 | 16 |
17 #include "IceDefs.h" | 17 #include "IceDefs.h" |
18 #include "IceTimerTree.h" | 18 #include "IceTimerTree.h" |
19 | 19 |
20 namespace Ice { | 20 namespace Ice { |
21 | 21 |
22 TimerStack::TimerStack(const IceString &Name) | 22 TimerStack::TimerStack(const IceString &Name) |
23 : Name(Name), FirstTimestamp(timestamp()), LastTimestamp(FirstTimestamp) { | 23 : Name(Name), FirstTimestamp(timestamp()), LastTimestamp(FirstTimestamp) { |
24 if (!ALLOW_DUMP) | 24 if (!buildAllowsDump()) |
25 return; | 25 return; |
26 Nodes.resize(1); // Reserve Nodes[0] for the root node (sentinel). | 26 Nodes.resize(1); // Reserve Nodes[0] for the root node (sentinel). |
27 IDs.resize(TT__num); | 27 IDs.resize(TT__num); |
28 LeafTimes.resize(TT__num); | 28 LeafTimes.resize(TT__num); |
29 LeafCounts.resize(TT__num); | 29 LeafCounts.resize(TT__num); |
30 #define STR(s) #s | 30 #define STR(s) #s |
31 #define X(tag) \ | 31 #define X(tag) \ |
32 IDs[TT_##tag] = STR(tag); \ | 32 IDs[TT_##tag] = STR(tag); \ |
33 IDsIndex[STR(tag)] = TT_##tag; | 33 IDsIndex[STR(tag)] = TT_##tag; |
34 TIMERTREE_TABLE; | 34 TIMERTREE_TABLE; |
35 #undef X | 35 #undef X |
36 #undef STR | 36 #undef STR |
37 } | 37 } |
38 | 38 |
39 // Returns the unique timer ID for the given Name, creating a new ID | 39 // Returns the unique timer ID for the given Name, creating a new ID |
40 // if needed. | 40 // if needed. |
41 TimerIdT TimerStack::getTimerID(const IceString &Name) { | 41 TimerIdT TimerStack::getTimerID(const IceString &Name) { |
42 if (!ALLOW_DUMP) | 42 if (!buildAllowsDump()) |
43 return 0; | 43 return 0; |
44 if (IDsIndex.find(Name) == IDsIndex.end()) { | 44 if (IDsIndex.find(Name) == IDsIndex.end()) { |
45 IDsIndex[Name] = IDs.size(); | 45 IDsIndex[Name] = IDs.size(); |
46 IDs.push_back(Name); | 46 IDs.push_back(Name); |
47 LeafTimes.push_back(decltype(LeafTimes)::value_type()); | 47 LeafTimes.push_back(decltype(LeafTimes)::value_type()); |
48 LeafCounts.push_back(decltype(LeafCounts)::value_type()); | 48 LeafCounts.push_back(decltype(LeafCounts)::value_type()); |
49 } | 49 } |
50 return IDsIndex[Name]; | 50 return IDsIndex[Name]; |
51 } | 51 } |
52 | 52 |
53 // Creates a mapping from TimerIdT (leaf) values in the Src timer | 53 // Creates a mapping from TimerIdT (leaf) values in the Src timer |
54 // stack into TimerIdT values in this timer stack. Creates new | 54 // stack into TimerIdT values in this timer stack. Creates new |
55 // entries in this timer stack as needed. | 55 // entries in this timer stack as needed. |
56 TimerStack::TranslationType | 56 TimerStack::TranslationType |
57 TimerStack::translateIDsFrom(const TimerStack &Src) { | 57 TimerStack::translateIDsFrom(const TimerStack &Src) { |
58 size_t Size = Src.IDs.size(); | 58 size_t Size = Src.IDs.size(); |
59 TranslationType Mapping(Size); | 59 TranslationType Mapping(Size); |
60 for (TimerIdT i = 0; i < Size; ++i) { | 60 for (TimerIdT i = 0; i < Size; ++i) { |
61 Mapping[i] = getTimerID(Src.IDs[i]); | 61 Mapping[i] = getTimerID(Src.IDs[i]); |
62 } | 62 } |
63 return Mapping; | 63 return Mapping; |
64 } | 64 } |
65 | 65 |
66 // Merges two timer stacks, by combining and summing corresponding | 66 // Merges two timer stacks, by combining and summing corresponding |
67 // entries. This timer stack is updated from Src. | 67 // entries. This timer stack is updated from Src. |
68 void TimerStack::mergeFrom(const TimerStack &Src) { | 68 void TimerStack::mergeFrom(const TimerStack &Src) { |
69 if (!ALLOW_DUMP) | 69 if (!buildAllowsDump()) |
70 return; | 70 return; |
71 TranslationType Mapping = translateIDsFrom(Src); | 71 TranslationType Mapping = translateIDsFrom(Src); |
72 TTindex SrcIndex = 0; | 72 TTindex SrcIndex = 0; |
73 for (const TimerTreeNode &SrcNode : Src.Nodes) { | 73 for (const TimerTreeNode &SrcNode : Src.Nodes) { |
74 // The first node is reserved as a sentinel, so avoid it. | 74 // The first node is reserved as a sentinel, so avoid it. |
75 if (SrcIndex > 0) { | 75 if (SrcIndex > 0) { |
76 // Find the full path to the Src node, translated to path | 76 // Find the full path to the Src node, translated to path |
77 // components corresponding to this timer stack. | 77 // components corresponding to this timer stack. |
78 PathType MyPath = Src.getPath(SrcIndex, Mapping); | 78 PathType MyPath = Src.getPath(SrcIndex, Mapping); |
79 // Find a node in this timer stack corresponding to the given | 79 // Find a node in this timer stack corresponding to the given |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
130 // followed in reverse. | 130 // followed in reverse. |
131 for (TTindex Index : reverse_range(Path)) { | 131 for (TTindex Index : reverse_range(Path)) { |
132 CurIndex = getChildIndex(CurIndex, Index); | 132 CurIndex = getChildIndex(CurIndex, Index); |
133 } | 133 } |
134 assert(CurIndex); // shouldn't be the sentinel node | 134 assert(CurIndex); // shouldn't be the sentinel node |
135 return CurIndex; | 135 return CurIndex; |
136 } | 136 } |
137 | 137 |
138 // Pushes a new marker onto the timer stack. | 138 // Pushes a new marker onto the timer stack. |
139 void TimerStack::push(TimerIdT ID) { | 139 void TimerStack::push(TimerIdT ID) { |
140 if (!ALLOW_DUMP) | 140 if (!buildAllowsDump()) |
141 return; | 141 return; |
142 const bool UpdateCounts = false; | 142 const bool UpdateCounts = false; |
143 update(UpdateCounts); | 143 update(UpdateCounts); |
144 StackTop = getChildIndex(StackTop, ID); | 144 StackTop = getChildIndex(StackTop, ID); |
145 assert(StackTop); | 145 assert(StackTop); |
146 } | 146 } |
147 | 147 |
148 // Pops the top marker from the timer stack. Validates via assert() | 148 // Pops the top marker from the timer stack. Validates via assert() |
149 // that the expected marker is popped. | 149 // that the expected marker is popped. |
150 void TimerStack::pop(TimerIdT ID) { | 150 void TimerStack::pop(TimerIdT ID) { |
151 if (!ALLOW_DUMP) | 151 if (!buildAllowsDump()) |
152 return; | 152 return; |
153 const bool UpdateCounts = true; | 153 const bool UpdateCounts = true; |
154 update(UpdateCounts); | 154 update(UpdateCounts); |
155 assert(StackTop); | 155 assert(StackTop); |
156 assert(Nodes[StackTop].Parent < StackTop); | 156 assert(Nodes[StackTop].Parent < StackTop); |
157 // Verify that the expected ID is being popped. | 157 // Verify that the expected ID is being popped. |
158 assert(Nodes[StackTop].Interior == ID); | 158 assert(Nodes[StackTop].Interior == ID); |
159 (void)ID; | 159 (void)ID; |
160 // Verify that the parent's child points to the current stack top. | 160 // Verify that the parent's child points to the current stack top. |
161 assert(Nodes[Nodes[StackTop].Parent].Children[ID] == StackTop); | 161 assert(Nodes[Nodes[StackTop].Parent].Children[ID] == StackTop); |
162 StackTop = Nodes[StackTop].Parent; | 162 StackTop = Nodes[StackTop].Parent; |
163 } | 163 } |
164 | 164 |
165 // At a state change (e.g. push or pop), updates the flat and | 165 // At a state change (e.g. push or pop), updates the flat and |
166 // cumulative timings for everything on the timer stack. | 166 // cumulative timings for everything on the timer stack. |
167 void TimerStack::update(bool UpdateCounts) { | 167 void TimerStack::update(bool UpdateCounts) { |
168 if (!ALLOW_DUMP) | 168 if (!buildAllowsDump()) |
169 return; | 169 return; |
170 ++StateChangeCount; | 170 ++StateChangeCount; |
171 // Whenever the stack is about to change, we grab the time delta | 171 // Whenever the stack is about to change, we grab the time delta |
172 // since the last change and add it to all active cumulative | 172 // since the last change and add it to all active cumulative |
173 // elements and to the flat element for the top of the stack. | 173 // elements and to the flat element for the top of the stack. |
174 double Current = timestamp(); | 174 double Current = timestamp(); |
175 double Delta = Current - LastTimestamp; | 175 double Delta = Current - LastTimestamp; |
176 if (StackTop) { | 176 if (StackTop) { |
177 TimerIdT Leaf = Nodes[StackTop].Interior; | 177 TimerIdT Leaf = Nodes[StackTop].Interior; |
178 if (Leaf >= LeafTimes.size()) { | 178 if (Leaf >= LeafTimes.size()) { |
(...skipping 15 matching lines...) Expand all Loading... |
194 Prefix = Next; | 194 Prefix = Next; |
195 } | 195 } |
196 // Capture the next timestamp *after* the updates are finished. | 196 // Capture the next timestamp *after* the updates are finished. |
197 // This minimizes how much the timer can perturb the reported | 197 // This minimizes how much the timer can perturb the reported |
198 // timing. The numbers may not sum to 100%, and the missing amount | 198 // timing. The numbers may not sum to 100%, and the missing amount |
199 // is indicative of the overhead of timing. | 199 // is indicative of the overhead of timing. |
200 LastTimestamp = timestamp(); | 200 LastTimestamp = timestamp(); |
201 } | 201 } |
202 | 202 |
203 void TimerStack::reset() { | 203 void TimerStack::reset() { |
204 if (!ALLOW_DUMP) | 204 if (!buildAllowsDump()) |
205 return; | 205 return; |
206 StateChangeCount = 0; | 206 StateChangeCount = 0; |
207 FirstTimestamp = LastTimestamp = timestamp(); | 207 FirstTimestamp = LastTimestamp = timestamp(); |
208 LeafTimes.assign(LeafTimes.size(), 0); | 208 LeafTimes.assign(LeafTimes.size(), 0); |
209 LeafCounts.assign(LeafCounts.size(), 0); | 209 LeafCounts.assign(LeafCounts.size(), 0); |
210 for (TimerTreeNode &Node : Nodes) { | 210 for (TimerTreeNode &Node : Nodes) { |
211 Node.Time = 0; | 211 Node.Time = 0; |
212 Node.UpdateCount = 0; | 212 Node.UpdateCount = 0; |
213 } | 213 } |
214 } | 214 } |
215 | 215 |
216 namespace { | 216 namespace { |
217 | 217 |
218 typedef std::multimap<double, IceString> DumpMapType; | 218 typedef std::multimap<double, IceString> DumpMapType; |
219 | 219 |
220 // Dump the Map items in reverse order of their time contribution. | 220 // Dump the Map items in reverse order of their time contribution. |
221 void dumpHelper(Ostream &Str, const DumpMapType &Map, double TotalTime) { | 221 void dumpHelper(Ostream &Str, const DumpMapType &Map, double TotalTime) { |
222 if (!ALLOW_DUMP) | 222 if (!buildAllowsDump()) |
223 return; | 223 return; |
224 for (auto &I : reverse_range(Map)) { | 224 for (auto &I : reverse_range(Map)) { |
225 char buf[80]; | 225 char buf[80]; |
226 snprintf(buf, llvm::array_lengthof(buf), " %10.6f (%4.1f%%): ", I.first, | 226 snprintf(buf, llvm::array_lengthof(buf), " %10.6f (%4.1f%%): ", I.first, |
227 I.first * 100 / TotalTime); | 227 I.first * 100 / TotalTime); |
228 Str << buf << I.second << "\n"; | 228 Str << buf << I.second << "\n"; |
229 } | 229 } |
230 } | 230 } |
231 | 231 |
232 // Write a printf() format string into Buf[], in the format "[%5lu] ", | 232 // Write a printf() format string into Buf[], in the format "[%5lu] ", |
233 // where "5" is actually the number of digits in MaxVal. E.g., | 233 // where "5" is actually the number of digits in MaxVal. E.g., |
234 // MaxVal=0 ==> "[%1lu] " | 234 // MaxVal=0 ==> "[%1lu] " |
235 // MaxVal=5 ==> "[%1lu] " | 235 // MaxVal=5 ==> "[%1lu] " |
236 // MaxVal=9876 ==> "[%4lu] " | 236 // MaxVal=9876 ==> "[%4lu] " |
237 void makePrintfFormatString(char *Buf, size_t BufLen, size_t MaxVal) { | 237 void makePrintfFormatString(char *Buf, size_t BufLen, size_t MaxVal) { |
238 if (!ALLOW_DUMP) | 238 if (!buildAllowsDump()) |
239 return; | 239 return; |
240 int NumDigits = 0; | 240 int NumDigits = 0; |
241 do { | 241 do { |
242 ++NumDigits; | 242 ++NumDigits; |
243 MaxVal /= 10; | 243 MaxVal /= 10; |
244 } while (MaxVal); | 244 } while (MaxVal); |
245 snprintf(Buf, BufLen, "[%%%dlu] ", NumDigits); | 245 snprintf(Buf, BufLen, "[%%%dlu] ", NumDigits); |
246 } | 246 } |
247 | 247 |
248 } // end of anonymous namespace | 248 } // end of anonymous namespace |
249 | 249 |
250 void TimerStack::dump(Ostream &Str, bool DumpCumulative) { | 250 void TimerStack::dump(Ostream &Str, bool DumpCumulative) { |
251 if (!ALLOW_DUMP) | 251 if (!buildAllowsDump()) |
252 return; | 252 return; |
253 const bool UpdateCounts = true; | 253 const bool UpdateCounts = true; |
254 update(UpdateCounts); | 254 update(UpdateCounts); |
255 double TotalTime = LastTimestamp - FirstTimestamp; | 255 double TotalTime = LastTimestamp - FirstTimestamp; |
256 assert(TotalTime); | 256 assert(TotalTime); |
257 char FmtString[30], PrefixStr[30]; | 257 char FmtString[30], PrefixStr[30]; |
258 if (DumpCumulative) { | 258 if (DumpCumulative) { |
259 Str << Name << " - Cumulative times:\n"; | 259 Str << Name << " - Cumulative times:\n"; |
260 size_t MaxInternalCount = 0; | 260 size_t MaxInternalCount = 0; |
261 for (TimerTreeNode &Node : Nodes) | 261 for (TimerTreeNode &Node : Nodes) |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
298 dumpHelper(Str, FlatMap, TotalTime); | 298 dumpHelper(Str, FlatMap, TotalTime); |
299 Str << "Number of timer updates: " << StateChangeCount << "\n"; | 299 Str << "Number of timer updates: " << StateChangeCount << "\n"; |
300 } | 300 } |
301 | 301 |
302 double TimerStack::timestamp() { | 302 double TimerStack::timestamp() { |
303 // TODO: Implement in terms of std::chrono for C++11. | 303 // TODO: Implement in terms of std::chrono for C++11. |
304 return llvm::TimeRecord::getCurrentTime(false).getWallTime(); | 304 return llvm::TimeRecord::getCurrentTime(false).getWallTime(); |
305 } | 305 } |
306 | 306 |
307 } // end of namespace Ice | 307 } // end of namespace Ice |
OLD | NEW |