Index: src/IceTimerTree.cpp |
diff --git a/src/IceTimerTree.cpp b/src/IceTimerTree.cpp |
new file mode 100644 |
index 0000000000000000000000000000000000000000..4bdb80ab91c34daeef2c439124d52c72f69353c5 |
--- /dev/null |
+++ b/src/IceTimerTree.cpp |
@@ -0,0 +1,142 @@ |
+//===- subzero/src/IceTimerTree.cpp - Pass timer defs ---------------------===// |
+// |
+// The Subzero Code Generator |
+// |
+// This file is distributed under the University of Illinois Open Source |
+// License. See LICENSE.TXT for details. |
+// |
+//===----------------------------------------------------------------------===// |
+// |
+// This file defines the TimerTree class, which tracks flat and |
+// cumulative execution time collection of call chains. |
+// |
+//===----------------------------------------------------------------------===// |
+ |
+#include "IceDefs.h" |
+#include "IceTimerTree.h" |
+ |
+namespace Ice { |
+ |
+std::vector<IceString> TimerStack::IDs; |
+ |
+TimerStack::TimerStack(const IceString &TopLevelName) |
+ : FirstTimestamp(timestamp()), LastTimestamp(FirstTimestamp), |
+ StateChangeCount(0), StackTop(0) { |
+ Nodes.resize(1); // Reserve Nodes[0] for the root node. |
+ push(getTimerID(TopLevelName)); |
+} |
+ |
+// Returns the unique timer ID for the given Name, creating a new ID |
+// if needed. For performance reasons, it's best to make only one |
+// call per Name and cache the result, e.g. via a static initializer. |
+TimerIdT TimerStack::getTimerID(const IceString &Name) { |
+ TimerIdT Size = IDs.size(); |
+ for (TimerIdT i = 0; i < Size; ++i) { |
+ if (IDs[i] == Name) |
+ return i; |
+ } |
+ IDs.push_back(Name); |
+ return Size; |
+} |
+ |
+// Pushes a new marker onto the timer stack. |
+void TimerStack::push(TimerIdT ID) { |
+ update(); |
+ if (Nodes[StackTop].Children.size() <= ID) |
+ Nodes[StackTop].Children.resize(ID + 1); |
+ if (Nodes[StackTop].Children[ID] == 0) { |
+ TTindex Size = Nodes.size(); |
+ Nodes[StackTop].Children[ID] = Size; |
+ Nodes.resize(Size + 1); |
+ Nodes[Size].Parent = StackTop; |
+ Nodes[Size].Interior = ID; |
+ } |
+ StackTop = Nodes[StackTop].Children[ID]; |
+} |
+ |
+// Pop the top marker from the timer stack. Validates via assert() |
+// that the expected marker is popped. |
+void TimerStack::pop(TimerIdT ID) { |
+ update(); |
+ assert(StackTop); |
+ assert(Nodes[StackTop].Parent < StackTop); |
+ // Verify that the expected ID is being popped. |
+ assert(Nodes[StackTop].Interior == ID); |
+ (void)ID; |
+ // Verify that the parent's child points to the current stack top. |
+ assert(Nodes[Nodes[StackTop].Parent].Children[ID] == StackTop); |
+ StackTop = Nodes[StackTop].Parent; |
+} |
+ |
+// At a state change (e.g. push or pop), updates the flat and |
+// cumulative timings for everything on the timer stack. |
+void TimerStack::update() { |
+ ++StateChangeCount; |
+ // Whenever the stack is about to change, we grab the time delta |
+ // since the last change and add it to all active cumulative |
+ // elements and to the flat element for the top of the stack. |
+ double Current = timestamp(); |
+ double Delta = Current - LastTimestamp; |
+ LastTimestamp = Current; |
+ if (StackTop) { |
+ TimerIdT Leaf = Nodes[StackTop].Interior; |
+ if (Leaf >= LeafTimes.size()) |
+ LeafTimes.resize(Leaf + 1); |
+ LeafTimes[Leaf] += Delta; |
+ } |
+ TTindex Prefix = StackTop; |
+ while (Prefix) { |
+ Nodes[Prefix].Time += Delta; |
+ TTindex Next = Nodes[Prefix].Parent; |
+ assert(Next < Prefix); |
+ Prefix = Next; |
+ } |
+} |
+ |
+namespace { |
+ |
+typedef std::multimap<double, IceString> DumpMapType; |
+ |
+// Dump the Map items in reverse order of their time contribution. |
+void dumpHelper(Ostream &Str, const DumpMapType &Map, double TotalTime) { |
+ for (DumpMapType::const_reverse_iterator I = Map.rbegin(), E = Map.rend(); |
+ I != E; ++I) { |
+ char buf[80]; |
+ snprintf(buf, llvm::array_lengthof(buf), " %10.6f (%4.1f%%): ", I->first, |
+ I->first * 100 / TotalTime); |
+ Str << buf << I->second << "\n"; |
+ } |
+} |
+ |
+} // end of anonymous namespace |
+ |
+void TimerStack::dump(Ostream &Str) { |
+ update(); |
+ double TotalTime = LastTimestamp - FirstTimestamp; |
+ assert(TotalTime); |
+ Str << "Cumulative function times:\n"; |
+ DumpMapType CumulativeMap; |
+ for (TTindex i = 1; i < Nodes.size(); ++i) { |
+ TTindex Prefix = i; |
+ IceString Suffix = ""; |
+ while (Prefix) { |
+ if (Suffix.empty()) |
+ Suffix = IDs[Nodes[Prefix].Interior]; |
+ else |
+ Suffix = IDs[Nodes[Prefix].Interior] + "." + Suffix; |
+ assert(Nodes[Prefix].Parent < Prefix); |
+ Prefix = Nodes[Prefix].Parent; |
+ } |
+ CumulativeMap.insert(std::make_pair(Nodes[i].Time, Suffix)); |
+ } |
+ dumpHelper(Str, CumulativeMap, TotalTime); |
+ Str << "Flat function times:\n"; |
+ DumpMapType FlatMap; |
+ for (TimerIdT i = 0; i < LeafTimes.size(); ++i) { |
+ FlatMap.insert(std::make_pair(LeafTimes[i], IDs[i])); |
+ } |
+ dumpHelper(Str, FlatMap, TotalTime); |
+ Str << "Number of timer updates: " << StateChangeCount << "\n"; |
+} |
+ |
+} // end of namespace Ice |