blob: e9b584144741e432e09a651800f5dcc70ce1df96 [file] [log] [blame]
Jim Stichnothc4554d72014-09-30 16:49:38 -07001//===- 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 Scull9612d322015-07-06 14:53:25 -07009///
10/// \file
Jim Stichnoth92a6e5b2015-12-02 16:52:44 -080011/// \brief Defines the TimerTree class, which tracks flat and cumulative
Andrew Scull57e12682015-09-16 11:30:19 -070012/// execution time collection of call chains.
Andrew Scull9612d322015-07-06 14:53:25 -070013///
Jim Stichnothc4554d72014-09-30 16:49:38 -070014//===----------------------------------------------------------------------===//
15
John Porto67f8de92015-06-25 10:14:17 -070016#include "IceTimerTree.h"
Jim Stichnoth9c234e22014-10-01 09:28:21 -070017
Jim Stichnothc4554d72014-09-30 16:49:38 -070018#include "IceDefs.h"
Jim Stichnoth98da9662015-06-27 06:38:08 -070019
20#pragma clang diagnostic push
21#pragma clang diagnostic ignored "-Wunused-parameter"
John Porto67f8de92015-06-25 10:14:17 -070022#include "llvm/Support/Timer.h"
Jim Stichnoth98da9662015-06-27 06:38:08 -070023#pragma clang diagnostic pop
Jim Stichnothc4554d72014-09-30 16:49:38 -070024
25namespace Ice {
26
Jim Stichnoth8363a062014-10-07 10:02:38 -070027TimerStack::TimerStack(const IceString &Name)
Jim Stichnotheafb56c2015-06-22 10:35:22 -070028 : Name(Name), FirstTimestamp(timestamp()), LastTimestamp(FirstTimestamp) {
Jim Stichnoth20b71f52015-06-24 15:52:24 -070029 if (!BuildDefs::dump())
Jim Stichnoth1c44d812014-12-08 14:57:52 -080030 return;
Jim Stichnoth380d7b92015-01-30 13:10:39 -080031 Nodes.resize(1); // Reserve Nodes[0] for the root node (sentinel).
Jim Stichnoth8363a062014-10-07 10:02:38 -070032 IDs.resize(TT__num);
Jim Stichnoth380d7b92015-01-30 13:10:39 -080033 LeafTimes.resize(TT__num);
34 LeafCounts.resize(TT__num);
Jim Stichnoth8363a062014-10-07 10:02:38 -070035#define STR(s) #s
36#define X(tag) \
37 IDs[TT_##tag] = STR(tag); \
38 IDsIndex[STR(tag)] = TT_##tag;
39 TIMERTREE_TABLE;
40#undef X
41#undef STR
Jim Stichnothc4554d72014-09-30 16:49:38 -070042}
43
Andrew Scull57e12682015-09-16 11:30:19 -070044// Returns the unique timer ID for the given Name, creating a new ID if needed.
Jim Stichnothc4554d72014-09-30 16:49:38 -070045TimerIdT TimerStack::getTimerID(const IceString &Name) {
Jim Stichnoth20b71f52015-06-24 15:52:24 -070046 if (!BuildDefs::dump())
Jim Stichnoth1c44d812014-12-08 14:57:52 -080047 return 0;
Jim Stichnoth8363a062014-10-07 10:02:38 -070048 if (IDsIndex.find(Name) == IDsIndex.end()) {
49 IDsIndex[Name] = IDs.size();
50 IDs.push_back(Name);
Jim Stichnoth380d7b92015-01-30 13:10:39 -080051 LeafTimes.push_back(decltype(LeafTimes)::value_type());
52 LeafCounts.push_back(decltype(LeafCounts)::value_type());
Jim Stichnothc4554d72014-09-30 16:49:38 -070053 }
Jim Stichnoth8363a062014-10-07 10:02:38 -070054 return IDsIndex[Name];
Jim Stichnothc4554d72014-09-30 16:49:38 -070055}
56
Andrew Scull57e12682015-09-16 11:30:19 -070057// Creates a mapping from TimerIdT (leaf) values in the Src timer stack into
58// TimerIdT values in this timer stack. Creates new entries in this timer stack
59// as needed.
Jim Stichnoth380d7b92015-01-30 13:10:39 -080060TimerStack::TranslationType
61TimerStack::translateIDsFrom(const TimerStack &Src) {
62 size_t Size = Src.IDs.size();
63 TranslationType Mapping(Size);
64 for (TimerIdT i = 0; i < Size; ++i) {
65 Mapping[i] = getTimerID(Src.IDs[i]);
66 }
67 return Mapping;
68}
69
Andrew Scull57e12682015-09-16 11:30:19 -070070// Merges two timer stacks, by combining and summing corresponding entries.
71// This timer stack is updated from Src.
Jim Stichnoth380d7b92015-01-30 13:10:39 -080072void TimerStack::mergeFrom(const TimerStack &Src) {
Jim Stichnoth20b71f52015-06-24 15:52:24 -070073 if (!BuildDefs::dump())
Jim Stichnoth380d7b92015-01-30 13:10:39 -080074 return;
75 TranslationType Mapping = translateIDsFrom(Src);
76 TTindex SrcIndex = 0;
77 for (const TimerTreeNode &SrcNode : Src.Nodes) {
78 // The first node is reserved as a sentinel, so avoid it.
79 if (SrcIndex > 0) {
Andrew Scull57e12682015-09-16 11:30:19 -070080 // Find the full path to the Src node, translated to path components
81 // corresponding to this timer stack.
Jim Stichnoth380d7b92015-01-30 13:10:39 -080082 PathType MyPath = Src.getPath(SrcIndex, Mapping);
Andrew Scull57e12682015-09-16 11:30:19 -070083 // Find a node in this timer stack corresponding to the given path,
84 // creating new interior nodes as necessary.
Jim Stichnoth380d7b92015-01-30 13:10:39 -080085 TTindex MyIndex = findPath(MyPath);
86 Nodes[MyIndex].Time += SrcNode.Time;
87 Nodes[MyIndex].UpdateCount += SrcNode.UpdateCount;
88 }
89 ++SrcIndex;
90 }
91 for (TimerIdT i = 0; i < Src.LeafTimes.size(); ++i) {
92 LeafTimes[Mapping[i]] += Src.LeafTimes[i];
93 LeafCounts[Mapping[i]] += Src.LeafCounts[i];
94 }
95 StateChangeCount += Src.StateChangeCount;
96}
97
Andrew Scull57e12682015-09-16 11:30:19 -070098// Constructs a path consisting of the sequence of leaf values leading to a
99// given node, with the Mapping translation applied to the leaf values. The
100// path ends up being in "reverse" order, i.e. from leaf to root.
Jim Stichnoth380d7b92015-01-30 13:10:39 -0800101TimerStack::PathType TimerStack::getPath(TTindex Index,
102 const TranslationType &Mapping) const {
103 PathType Path;
104 while (Index) {
105 Path.push_back(Mapping[Nodes[Index].Interior]);
106 assert(Nodes[Index].Parent < Index);
107 Index = Nodes[Index].Parent;
108 }
109 return Path;
110}
111
Andrew Scull57e12682015-09-16 11:30:19 -0700112// Given a parent node and a leaf ID, returns the index of the parent's child
113// ID, creating a new node for the child as necessary.
Jim Stichnoth380d7b92015-01-30 13:10:39 -0800114TimerStack::TTindex TimerStack::getChildIndex(TimerStack::TTindex Parent,
115 TimerIdT ID) {
116 if (Nodes[Parent].Children.size() <= ID)
117 Nodes[Parent].Children.resize(ID + 1);
118 if (Nodes[Parent].Children[ID] == 0) {
119 TTindex Size = Nodes.size();
120 Nodes[Parent].Children[ID] = Size;
121 Nodes.resize(Size + 1);
122 Nodes[Size].Parent = Parent;
123 Nodes[Size].Interior = ID;
124 }
125 return Nodes[Parent].Children[ID];
126}
127
Andrew Scull57e12682015-09-16 11:30:19 -0700128// Finds a node in the timer stack corresponding to the given path, creating
129// new interior nodes as necessary.
Jim Stichnoth380d7b92015-01-30 13:10:39 -0800130TimerStack::TTindex TimerStack::findPath(const PathType &Path) {
131 TTindex CurIndex = 0;
Andrew Scull57e12682015-09-16 11:30:19 -0700132 // The path is in reverse order (leaf to root), so it needs to be followed in
133 // reverse.
Jim Stichnoth380d7b92015-01-30 13:10:39 -0800134 for (TTindex Index : reverse_range(Path)) {
135 CurIndex = getChildIndex(CurIndex, Index);
136 }
137 assert(CurIndex); // shouldn't be the sentinel node
138 return CurIndex;
139}
140
Jim Stichnothc4554d72014-09-30 16:49:38 -0700141// Pushes a new marker onto the timer stack.
142void TimerStack::push(TimerIdT ID) {
Jim Stichnoth20b71f52015-06-24 15:52:24 -0700143 if (!BuildDefs::dump())
Jim Stichnoth1c44d812014-12-08 14:57:52 -0800144 return;
Jim Stichnoth5bff61c2015-10-28 09:26:00 -0700145 constexpr bool UpdateCounts = false;
Jim Stichnothabce6e52014-10-14 11:09:27 -0700146 update(UpdateCounts);
Jim Stichnoth380d7b92015-01-30 13:10:39 -0800147 StackTop = getChildIndex(StackTop, ID);
148 assert(StackTop);
Jim Stichnothc4554d72014-09-30 16:49:38 -0700149}
150
Andrew Scull57e12682015-09-16 11:30:19 -0700151// Pops the top marker from the timer stack. Validates via assert() that the
152// expected marker is popped.
Jim Stichnothc4554d72014-09-30 16:49:38 -0700153void TimerStack::pop(TimerIdT ID) {
Jim Stichnoth20b71f52015-06-24 15:52:24 -0700154 if (!BuildDefs::dump())
Jim Stichnoth1c44d812014-12-08 14:57:52 -0800155 return;
Jim Stichnoth5bff61c2015-10-28 09:26:00 -0700156 constexpr bool UpdateCounts = true;
Jim Stichnothabce6e52014-10-14 11:09:27 -0700157 update(UpdateCounts);
Jim Stichnothc4554d72014-09-30 16:49:38 -0700158 assert(StackTop);
159 assert(Nodes[StackTop].Parent < StackTop);
160 // Verify that the expected ID is being popped.
161 assert(Nodes[StackTop].Interior == ID);
162 (void)ID;
163 // Verify that the parent's child points to the current stack top.
164 assert(Nodes[Nodes[StackTop].Parent].Children[ID] == StackTop);
165 StackTop = Nodes[StackTop].Parent;
166}
167
Andrew Scull57e12682015-09-16 11:30:19 -0700168// At a state change (e.g. push or pop), updates the flat and cumulative
169// timings for everything on the timer stack.
Jim Stichnothabce6e52014-10-14 11:09:27 -0700170void TimerStack::update(bool UpdateCounts) {
Jim Stichnoth20b71f52015-06-24 15:52:24 -0700171 if (!BuildDefs::dump())
Jim Stichnoth1c44d812014-12-08 14:57:52 -0800172 return;
Jim Stichnothc4554d72014-09-30 16:49:38 -0700173 ++StateChangeCount;
Andrew Scull57e12682015-09-16 11:30:19 -0700174 // Whenever the stack is about to change, we grab the time delta since the
175 // last change and add it to all active cumulative elements and to the flat
176 // element for the top of the stack.
Jim Stichnothc4554d72014-09-30 16:49:38 -0700177 double Current = timestamp();
178 double Delta = Current - LastTimestamp;
Jim Stichnothc4554d72014-09-30 16:49:38 -0700179 if (StackTop) {
180 TimerIdT Leaf = Nodes[StackTop].Interior;
Jim Stichnothabce6e52014-10-14 11:09:27 -0700181 if (Leaf >= LeafTimes.size()) {
Jim Stichnothc4554d72014-09-30 16:49:38 -0700182 LeafTimes.resize(Leaf + 1);
Jim Stichnothabce6e52014-10-14 11:09:27 -0700183 LeafCounts.resize(Leaf + 1);
184 }
Jim Stichnothc4554d72014-09-30 16:49:38 -0700185 LeafTimes[Leaf] += Delta;
Jim Stichnothabce6e52014-10-14 11:09:27 -0700186 if (UpdateCounts)
187 ++LeafCounts[Leaf];
Jim Stichnothc4554d72014-09-30 16:49:38 -0700188 }
189 TTindex Prefix = StackTop;
190 while (Prefix) {
191 Nodes[Prefix].Time += Delta;
Jim Stichnothabce6e52014-10-14 11:09:27 -0700192 // Only update a leaf node count, not the internal node counts.
193 if (UpdateCounts && Prefix == StackTop)
194 ++Nodes[Prefix].UpdateCount;
Jim Stichnothc4554d72014-09-30 16:49:38 -0700195 TTindex Next = Nodes[Prefix].Parent;
196 assert(Next < Prefix);
197 Prefix = Next;
198 }
Andrew Scull57e12682015-09-16 11:30:19 -0700199 // Capture the next timestamp *after* the updates are finished. This
200 // minimizes how much the timer can perturb the reported timing. The numbers
201 // may not sum to 100%, and the missing amount is indicative of the overhead
202 // of timing.
Jim Stichnoth47752552014-10-13 17:15:08 -0700203 LastTimestamp = timestamp();
Jim Stichnothc4554d72014-09-30 16:49:38 -0700204}
205
Jim Stichnothd14b1a02014-10-08 08:28:36 -0700206void TimerStack::reset() {
Jim Stichnoth20b71f52015-06-24 15:52:24 -0700207 if (!BuildDefs::dump())
Jim Stichnoth1c44d812014-12-08 14:57:52 -0800208 return;
Jim Stichnothd14b1a02014-10-08 08:28:36 -0700209 StateChangeCount = 0;
210 FirstTimestamp = LastTimestamp = timestamp();
211 LeafTimes.assign(LeafTimes.size(), 0);
Jim Stichnothabce6e52014-10-14 11:09:27 -0700212 LeafCounts.assign(LeafCounts.size(), 0);
Jim Stichnothd14b1a02014-10-08 08:28:36 -0700213 for (TimerTreeNode &Node : Nodes) {
214 Node.Time = 0;
Jim Stichnothabce6e52014-10-14 11:09:27 -0700215 Node.UpdateCount = 0;
Jim Stichnothd14b1a02014-10-08 08:28:36 -0700216 }
217}
218
Jim Stichnothc4554d72014-09-30 16:49:38 -0700219namespace {
220
Andrew Scull8072bae2015-09-14 16:01:26 -0700221using DumpMapType = std::multimap<double, IceString>;
Jim Stichnothc4554d72014-09-30 16:49:38 -0700222
223// Dump the Map items in reverse order of their time contribution.
224void dumpHelper(Ostream &Str, const DumpMapType &Map, double TotalTime) {
Jim Stichnoth20b71f52015-06-24 15:52:24 -0700225 if (!BuildDefs::dump())
Karl Schimpfb6c96af2014-11-17 10:58:39 -0800226 return;
Jim Stichnoth7e571362015-01-09 11:43:26 -0800227 for (auto &I : reverse_range(Map)) {
Jim Stichnothc4554d72014-09-30 16:49:38 -0700228 char buf[80];
Jim Stichnoth7e571362015-01-09 11:43:26 -0800229 snprintf(buf, llvm::array_lengthof(buf), " %10.6f (%4.1f%%): ", I.first,
230 I.first * 100 / TotalTime);
231 Str << buf << I.second << "\n";
Jim Stichnothc4554d72014-09-30 16:49:38 -0700232 }
233}
234
Andrew Scull57e12682015-09-16 11:30:19 -0700235// Write a printf() format string into Buf[], in the format "[%5lu] ", where
236// "5" is actually the number of digits in MaxVal. E.g.,
Jim Stichnothabce6e52014-10-14 11:09:27 -0700237// MaxVal=0 ==> "[%1lu] "
238// MaxVal=5 ==> "[%1lu] "
239// MaxVal=9876 ==> "[%4lu] "
240void makePrintfFormatString(char *Buf, size_t BufLen, size_t MaxVal) {
Jim Stichnoth20b71f52015-06-24 15:52:24 -0700241 if (!BuildDefs::dump())
Karl Schimpfb6c96af2014-11-17 10:58:39 -0800242 return;
Jim Stichnothabce6e52014-10-14 11:09:27 -0700243 int NumDigits = 0;
244 do {
245 ++NumDigits;
246 MaxVal /= 10;
247 } while (MaxVal);
248 snprintf(Buf, BufLen, "[%%%dlu] ", NumDigits);
249}
250
Jim Stichnothc4554d72014-09-30 16:49:38 -0700251} // end of anonymous namespace
252
Jim Stichnoth8363a062014-10-07 10:02:38 -0700253void TimerStack::dump(Ostream &Str, bool DumpCumulative) {
Jim Stichnoth20b71f52015-06-24 15:52:24 -0700254 if (!BuildDefs::dump())
Karl Schimpfb6c96af2014-11-17 10:58:39 -0800255 return;
Jim Stichnoth5bff61c2015-10-28 09:26:00 -0700256 constexpr bool UpdateCounts = true;
Jim Stichnothabce6e52014-10-14 11:09:27 -0700257 update(UpdateCounts);
Jim Stichnothc4554d72014-09-30 16:49:38 -0700258 double TotalTime = LastTimestamp - FirstTimestamp;
259 assert(TotalTime);
Jim Stichnothabce6e52014-10-14 11:09:27 -0700260 char FmtString[30], PrefixStr[30];
Jim Stichnoth8363a062014-10-07 10:02:38 -0700261 if (DumpCumulative) {
262 Str << Name << " - Cumulative times:\n";
Jim Stichnothabce6e52014-10-14 11:09:27 -0700263 size_t MaxInternalCount = 0;
264 for (TimerTreeNode &Node : Nodes)
265 MaxInternalCount = std::max(MaxInternalCount, Node.UpdateCount);
266 makePrintfFormatString(FmtString, llvm::array_lengthof(FmtString),
267 MaxInternalCount);
268
Jim Stichnoth8363a062014-10-07 10:02:38 -0700269 DumpMapType CumulativeMap;
270 for (TTindex i = 1; i < Nodes.size(); ++i) {
271 TTindex Prefix = i;
272 IceString Suffix = "";
273 while (Prefix) {
274 if (Suffix.empty())
275 Suffix = IDs[Nodes[Prefix].Interior];
276 else
277 Suffix = IDs[Nodes[Prefix].Interior] + "." + Suffix;
278 assert(Nodes[Prefix].Parent < Prefix);
279 Prefix = Nodes[Prefix].Parent;
280 }
Jim Stichnothabce6e52014-10-14 11:09:27 -0700281 snprintf(PrefixStr, llvm::array_lengthof(PrefixStr), FmtString,
282 Nodes[i].UpdateCount);
283 CumulativeMap.insert(std::make_pair(Nodes[i].Time, PrefixStr + Suffix));
Jim Stichnothc4554d72014-09-30 16:49:38 -0700284 }
Jim Stichnoth8363a062014-10-07 10:02:38 -0700285 dumpHelper(Str, CumulativeMap, TotalTime);
Jim Stichnothc4554d72014-09-30 16:49:38 -0700286 }
Jim Stichnoth8363a062014-10-07 10:02:38 -0700287 Str << Name << " - Flat times:\n";
Jim Stichnothabce6e52014-10-14 11:09:27 -0700288 size_t MaxLeafCount = 0;
289 for (size_t Count : LeafCounts)
290 MaxLeafCount = std::max(MaxLeafCount, Count);
291 makePrintfFormatString(FmtString, llvm::array_lengthof(FmtString),
292 MaxLeafCount);
Jim Stichnothc4554d72014-09-30 16:49:38 -0700293 DumpMapType FlatMap;
294 for (TimerIdT i = 0; i < LeafTimes.size(); ++i) {
Jim Stichnothabce6e52014-10-14 11:09:27 -0700295 if (LeafCounts[i]) {
296 snprintf(PrefixStr, llvm::array_lengthof(PrefixStr), FmtString,
297 LeafCounts[i]);
298 FlatMap.insert(std::make_pair(LeafTimes[i], PrefixStr + IDs[i]));
299 }
Jim Stichnothc4554d72014-09-30 16:49:38 -0700300 }
301 dumpHelper(Str, FlatMap, TotalTime);
302 Str << "Number of timer updates: " << StateChangeCount << "\n";
303}
304
Jim Stichnoth9c234e22014-10-01 09:28:21 -0700305double TimerStack::timestamp() {
306 // TODO: Implement in terms of std::chrono for C++11.
307 return llvm::TimeRecord::getCurrentTime(false).getWallTime();
308}
309
Jim Stichnothc4554d72014-09-30 16:49:38 -0700310} // end of namespace Ice