OLD | NEW |
(Empty) | |
| 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 //===----------------------------------------------------------------------===// |
| 9 // |
| 10 // This file defines the TimerTree class, which tracks flat and |
| 11 // cumulative execution time collection of call chains. |
| 12 // |
| 13 //===----------------------------------------------------------------------===// |
| 14 |
| 15 #include "IceDefs.h" |
| 16 #include "IceTimerTree.h" |
| 17 |
| 18 namespace Ice { |
| 19 |
| 20 std::vector<IceString> TimerStack::IDs; |
| 21 |
| 22 TimerStack::TimerStack(const IceString &TopLevelName) |
| 23 : FirstTimestamp(timestamp()), LastTimestamp(FirstTimestamp), |
| 24 StateChangeCount(0), StackTop(0) { |
| 25 Nodes.resize(1); // Reserve Nodes[0] for the root node. |
| 26 push(getTimerID(TopLevelName)); |
| 27 } |
| 28 |
| 29 // Returns the unique timer ID for the given Name, creating a new ID |
| 30 // if needed. For performance reasons, it's best to make only one |
| 31 // call per Name and cache the result, e.g. via a static initializer. |
| 32 TimerIdT TimerStack::getTimerID(const IceString &Name) { |
| 33 TimerIdT Size = IDs.size(); |
| 34 for (TimerIdT i = 0; i < Size; ++i) { |
| 35 if (IDs[i] == Name) |
| 36 return i; |
| 37 } |
| 38 IDs.push_back(Name); |
| 39 return Size; |
| 40 } |
| 41 |
| 42 // Pushes a new marker onto the timer stack. |
| 43 void TimerStack::push(TimerIdT ID) { |
| 44 update(); |
| 45 if (Nodes[StackTop].Children.size() <= ID) |
| 46 Nodes[StackTop].Children.resize(ID + 1); |
| 47 if (Nodes[StackTop].Children[ID] == 0) { |
| 48 TTindex Size = Nodes.size(); |
| 49 Nodes[StackTop].Children[ID] = Size; |
| 50 Nodes.resize(Size + 1); |
| 51 Nodes[Size].Parent = StackTop; |
| 52 Nodes[Size].Interior = ID; |
| 53 } |
| 54 StackTop = Nodes[StackTop].Children[ID]; |
| 55 } |
| 56 |
| 57 // Pop the top marker from the timer stack. Validates via assert() |
| 58 // that the expected marker is popped. |
| 59 void TimerStack::pop(TimerIdT ID) { |
| 60 update(); |
| 61 assert(StackTop); |
| 62 assert(Nodes[StackTop].Parent < StackTop); |
| 63 // Verify that the expected ID is being popped. |
| 64 assert(Nodes[StackTop].Interior == ID); |
| 65 (void)ID; |
| 66 // Verify that the parent's child points to the current stack top. |
| 67 assert(Nodes[Nodes[StackTop].Parent].Children[ID] == StackTop); |
| 68 StackTop = Nodes[StackTop].Parent; |
| 69 } |
| 70 |
| 71 // At a state change (e.g. push or pop), updates the flat and |
| 72 // cumulative timings for everything on the timer stack. |
| 73 void TimerStack::update() { |
| 74 ++StateChangeCount; |
| 75 // Whenever the stack is about to change, we grab the time delta |
| 76 // since the last change and add it to all active cumulative |
| 77 // elements and to the flat element for the top of the stack. |
| 78 double Current = timestamp(); |
| 79 double Delta = Current - LastTimestamp; |
| 80 LastTimestamp = Current; |
| 81 if (StackTop) { |
| 82 TimerIdT Leaf = Nodes[StackTop].Interior; |
| 83 if (Leaf >= LeafTimes.size()) |
| 84 LeafTimes.resize(Leaf + 1); |
| 85 LeafTimes[Leaf] += Delta; |
| 86 } |
| 87 TTindex Prefix = StackTop; |
| 88 while (Prefix) { |
| 89 Nodes[Prefix].Time += Delta; |
| 90 TTindex Next = Nodes[Prefix].Parent; |
| 91 assert(Next < Prefix); |
| 92 Prefix = Next; |
| 93 } |
| 94 } |
| 95 |
| 96 namespace { |
| 97 |
| 98 typedef std::multimap<double, IceString> DumpMapType; |
| 99 |
| 100 // Dump the Map items in reverse order of their time contribution. |
| 101 void dumpHelper(Ostream &Str, const DumpMapType &Map, double TotalTime) { |
| 102 for (DumpMapType::const_reverse_iterator I = Map.rbegin(), E = Map.rend(); |
| 103 I != E; ++I) { |
| 104 char buf[80]; |
| 105 snprintf(buf, llvm::array_lengthof(buf), " %10.6f (%4.1f%%): ", I->first, |
| 106 I->first * 100 / TotalTime); |
| 107 Str << buf << I->second << "\n"; |
| 108 } |
| 109 } |
| 110 |
| 111 } // end of anonymous namespace |
| 112 |
| 113 void TimerStack::dump(Ostream &Str) { |
| 114 update(); |
| 115 double TotalTime = LastTimestamp - FirstTimestamp; |
| 116 assert(TotalTime); |
| 117 Str << "Cumulative function times:\n"; |
| 118 DumpMapType CumulativeMap; |
| 119 for (TTindex i = 1; i < Nodes.size(); ++i) { |
| 120 TTindex Prefix = i; |
| 121 IceString Suffix = ""; |
| 122 while (Prefix) { |
| 123 if (Suffix.empty()) |
| 124 Suffix = IDs[Nodes[Prefix].Interior]; |
| 125 else |
| 126 Suffix = IDs[Nodes[Prefix].Interior] + "." + Suffix; |
| 127 assert(Nodes[Prefix].Parent < Prefix); |
| 128 Prefix = Nodes[Prefix].Parent; |
| 129 } |
| 130 CumulativeMap.insert(std::make_pair(Nodes[i].Time, Suffix)); |
| 131 } |
| 132 dumpHelper(Str, CumulativeMap, TotalTime); |
| 133 Str << "Flat function times:\n"; |
| 134 DumpMapType FlatMap; |
| 135 for (TimerIdT i = 0; i < LeafTimes.size(); ++i) { |
| 136 FlatMap.insert(std::make_pair(LeafTimes[i], IDs[i])); |
| 137 } |
| 138 dumpHelper(Str, FlatMap, TotalTime); |
| 139 Str << "Number of timer updates: " << StateChangeCount << "\n"; |
| 140 } |
| 141 |
| 142 } // end of namespace Ice |
OLD | NEW |