Index: src/IceTimerTree.cpp |
diff --git a/src/IceTimerTree.cpp b/src/IceTimerTree.cpp |
index 2c912e489d16884d9446560bddac0bc797636a8a..a730eff6b68bd60ca3feaf7d3f11d98051281b03 100644 |
--- a/src/IceTimerTree.cpp |
+++ b/src/IceTimerTree.cpp |
@@ -24,8 +24,10 @@ TimerStack::TimerStack(const IceString &Name) |
StateChangeCount(0), StackTop(0) { |
if (!ALLOW_DUMP) |
return; |
- Nodes.resize(1); // Reserve Nodes[0] for the root node. |
+ Nodes.resize(1); // Reserve Nodes[0] for the root node (sentinel). |
IDs.resize(TT__num); |
+ LeafTimes.resize(TT__num); |
+ LeafCounts.resize(TT__num); |
#define STR(s) #s |
#define X(tag) \ |
IDs[TT_##tag] = STR(tag); \ |
@@ -43,29 +45,108 @@ TimerIdT TimerStack::getTimerID(const IceString &Name) { |
if (IDsIndex.find(Name) == IDsIndex.end()) { |
IDsIndex[Name] = IDs.size(); |
IDs.push_back(Name); |
+ LeafTimes.push_back(decltype(LeafTimes)::value_type()); |
+ LeafCounts.push_back(decltype(LeafCounts)::value_type()); |
} |
return IDsIndex[Name]; |
} |
-// Pushes a new marker onto the timer stack. |
-void TimerStack::push(TimerIdT ID) { |
+// Creates a mapping from TimerIdT (leaf) values in the Src timer |
+// stack into TimerIdT values in this timer stack. Creates new |
+// entries in this timer stack as needed. |
+TimerStack::TranslationType |
+TimerStack::translateIDsFrom(const TimerStack &Src) { |
+ size_t Size = Src.IDs.size(); |
+ TranslationType Mapping(Size); |
+ for (TimerIdT i = 0; i < Size; ++i) { |
+ Mapping[i] = getTimerID(Src.IDs[i]); |
+ } |
+ return Mapping; |
+} |
+ |
+// Merges two timer stacks, by combining and summing corresponding |
+// entries. This timer stack is updated from Src. |
+void TimerStack::mergeFrom(const TimerStack &Src) { |
if (!ALLOW_DUMP) |
return; |
- const bool UpdateCounts = false; |
- update(UpdateCounts); |
- if (Nodes[StackTop].Children.size() <= ID) |
- Nodes[StackTop].Children.resize(ID + 1); |
- if (Nodes[StackTop].Children[ID] == 0) { |
+ TranslationType Mapping = translateIDsFrom(Src); |
+ TTindex Index = 0; |
jvoung (off chromium)
2015/01/30 18:42:56
So the TimerIDs might need mapping, but the TTinde
Jim Stichnoth
2015/01/30 20:22:25
No, they need mapping too.
The "Index" variable i
|
+ for (const TimerTreeNode &Node : Src.Nodes) { |
+ // The first node is reserved as a sentinel, so avoid it. |
+ if (Index > 0) { |
+ // Find the full path to the Src node, translated to path |
+ // components corresponding to this timer stack. |
+ PathType Path = Src.getPath(Index, Mapping); |
+ // Find a node in this timer stack corresponding to the given |
+ // path, creating new interior nodes as necessary. |
+ TTindex MyIndex = findPath(Path); |
+ Nodes[MyIndex].Time += Node.Time; |
+ Nodes[MyIndex].UpdateCount += Node.UpdateCount; |
+ } |
+ ++Index; |
+ } |
+ for (TimerIdT i = 0; i < Src.LeafTimes.size(); ++i) { |
+ LeafTimes[Mapping[i]] += Src.LeafTimes[i]; |
+ LeafCounts[Mapping[i]] += Src.LeafCounts[i]; |
+ } |
+ StateChangeCount += Src.StateChangeCount; |
+} |
+ |
+// Constructs a path consisting of the sequence of leaf values leading |
+// to a given node, with the Mapping translation applied to the leaf |
+// values. The path ends up being in "reverse" order, i.e. from leaf |
+// to root. |
+TimerStack::PathType TimerStack::getPath(TTindex Index, |
+ const TranslationType &Mapping) const { |
+ PathType Path; |
+ while (Index) { |
+ Path.push_back(Mapping[Nodes[Index].Interior]); |
+ assert(Nodes[Index].Parent < Index); |
+ Index = Nodes[Index].Parent; |
+ } |
+ return Path; |
+} |
+ |
+// Given a parent node and a leaf ID, returns the index of the |
+// parent's child ID, creating a new node for the child as necessary. |
+TimerStack::TTindex TimerStack::getChildIndex(TimerStack::TTindex Parent, |
+ TimerIdT ID) { |
+ if (Nodes[Parent].Children.size() <= ID) |
+ Nodes[Parent].Children.resize(ID + 1); |
+ if (Nodes[Parent].Children[ID] == 0) { |
TTindex Size = Nodes.size(); |
- Nodes[StackTop].Children[ID] = Size; |
+ Nodes[Parent].Children[ID] = Size; |
Nodes.resize(Size + 1); |
- Nodes[Size].Parent = StackTop; |
+ Nodes[Size].Parent = Parent; |
Nodes[Size].Interior = ID; |
} |
- StackTop = Nodes[StackTop].Children[ID]; |
+ return Nodes[Parent].Children[ID]; |
+} |
+ |
+// Finds a node in the timer stack corresponding to the given path, |
+// creating new interior nodes as necessary. |
+TimerStack::TTindex TimerStack::findPath(const PathType &Path) { |
+ TTindex CurIndex = 0; |
+ // The path is in reverse order (leaf to root), so it needs to be |
+ // followed in reverse. |
+ for (TTindex Index : reverse_range(Path)) { |
+ CurIndex = getChildIndex(CurIndex, Index); |
+ } |
+ assert(CurIndex); // shouldn't be the sentinel node |
+ return CurIndex; |
+} |
+ |
+// Pushes a new marker onto the timer stack. |
+void TimerStack::push(TimerIdT ID) { |
+ if (!ALLOW_DUMP) |
+ return; |
+ const bool UpdateCounts = false; |
+ update(UpdateCounts); |
+ StackTop = getChildIndex(StackTop, ID); |
+ assert(StackTop); |
} |
-// Pop the top marker from the timer stack. Validates via assert() |
+// Pops the top marker from the timer stack. Validates via assert() |
// that the expected marker is popped. |
void TimerStack::pop(TimerIdT ID) { |
if (!ALLOW_DUMP) |