2 * Copyright (C) 2008 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14 * its contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 #include "ProfileNode.h"
42 static double getCount()
45 static LARGE_INTEGER frequency
= {0};
46 if (!frequency
.QuadPart
)
47 QueryPerformanceFrequency(&frequency
);
48 LARGE_INTEGER counter
;
49 QueryPerformanceCounter(&counter
);
50 return static_cast<double>(counter
.QuadPart
) / frequency
.QuadPart
;
52 return getCurrentUTCTimeWithMicroseconds();
56 ProfileNode::ProfileNode(const CallIdentifier
& callIdentifier
, ProfileNode
* headNode
, ProfileNode
* parentNode
)
57 : m_callIdentifier(callIdentifier
)
59 , m_parent(parentNode
)
62 , m_actualTotalTime(0.0)
63 , m_visibleTotalTime(0.0)
64 , m_actualSelfTime(0.0)
65 , m_visibleSelfTime(0.0)
72 ProfileNode::ProfileNode(ProfileNode
* headNode
, ProfileNode
* nodeToCopy
)
73 : m_callIdentifier(nodeToCopy
->callIdentifier())
75 , m_parent(nodeToCopy
->parent())
78 , m_actualTotalTime(nodeToCopy
->actualTotalTime())
79 , m_visibleTotalTime(nodeToCopy
->totalTime())
80 , m_actualSelfTime(nodeToCopy
->actualSelfTime())
81 , m_visibleSelfTime(nodeToCopy
->selfTime())
82 , m_numberOfCalls(nodeToCopy
->numberOfCalls())
83 , m_visible(nodeToCopy
->visible())
87 ProfileNode
* ProfileNode::willExecute(const CallIdentifier
& callIdentifier
)
89 for (StackIterator currentChild
= m_children
.begin(); currentChild
!= m_children
.end(); ++currentChild
) {
90 if ((*currentChild
)->callIdentifier() == callIdentifier
) {
91 (*currentChild
)->startTimer();
92 return (*currentChild
).get();
96 RefPtr
<ProfileNode
> newChild
= ProfileNode::create(callIdentifier
, m_head
? m_head
: this, this); // If this ProfileNode has no head it is the head.
97 if (m_children
.size())
98 m_children
.last()->setNextSibling(newChild
.get());
99 m_children
.append(newChild
.release());
100 return m_children
.last().get();
103 ProfileNode
* ProfileNode::didExecute()
109 void ProfileNode::addChild(PassRefPtr
<ProfileNode
> prpChild
)
111 RefPtr
<ProfileNode
> child
= prpChild
;
112 child
->setParent(this);
113 if (m_children
.size())
114 m_children
.last()->setNextSibling(child
.get());
115 m_children
.append(child
.release());
118 ProfileNode
* ProfileNode::findChild(ProfileNode
* node
) const
123 for (size_t i
= 0; i
< m_children
.size(); ++i
) {
124 if (*node
== m_children
[i
].get())
125 return m_children
[i
].get();
131 void ProfileNode::removeChild(ProfileNode
* node
)
136 for (size_t i
= 0; i
< m_children
.size(); ++i
) {
137 if (*node
== m_children
[i
].get()) {
138 m_children
.remove(i
);
143 resetChildrensSiblings();
146 void ProfileNode::insertNode(PassRefPtr
<ProfileNode
> prpNode
)
148 RefPtr
<ProfileNode
> node
= prpNode
;
150 for (unsigned i
= 0; i
< m_children
.size(); ++i
)
151 node
->addChild(m_children
[i
].release());
154 m_children
.append(node
.release());
157 void ProfileNode::stopProfiling()
162 m_visibleTotalTime
= m_actualTotalTime
;
164 ASSERT(m_actualSelfTime
== 0.0 && m_startTime
== 0.0);
166 // Because we iterate in post order all of our children have been stopped before us.
167 for (unsigned i
= 0; i
< m_children
.size(); ++i
)
168 m_actualSelfTime
+= m_children
[i
]->totalTime();
170 ASSERT(m_actualSelfTime
<= m_actualTotalTime
);
171 m_actualSelfTime
= m_actualTotalTime
- m_actualSelfTime
;
172 m_visibleSelfTime
= m_actualSelfTime
;
175 ProfileNode
* ProfileNode::traverseNextNodePostOrder() const
177 ProfileNode
* next
= m_nextSibling
;
180 while (ProfileNode
* firstChild
= next
->firstChild())
185 ProfileNode
* ProfileNode::traverseNextNodePreOrder(bool processChildren
) const
187 if (processChildren
&& m_children
.size())
188 return m_children
[0].get();
191 return m_nextSibling
;
193 ProfileNode
* nextParent
= m_parent
;
198 for (next
= m_parent
->nextSibling(); !next
; next
= nextParent
->nextSibling()) {
199 nextParent
= nextParent
->parent();
207 void ProfileNode::sort(bool comparator(const RefPtr
<ProfileNode
>& , const RefPtr
<ProfileNode
>& ))
209 std::sort(childrenBegin(), childrenEnd(), comparator
);
210 resetChildrensSiblings();
213 void ProfileNode::setTreeVisible(ProfileNode
* node
, bool visible
)
215 ProfileNode
* nodeParent
= node
->parent();
216 ProfileNode
* nodeSibling
= node
->nextSibling();
218 node
->setNextSibling(0);
220 for (ProfileNode
* currentNode
= node
; currentNode
; currentNode
= currentNode
->traverseNextNodePreOrder())
221 currentNode
->setVisible(visible
);
223 node
->setParent(nodeParent
);
224 node
->setNextSibling(nodeSibling
);
227 void ProfileNode::calculateVisibleTotalTime()
229 double sumOfVisibleChildrensTime
= 0.0;
231 for (unsigned i
= 0; i
< m_children
.size(); ++i
) {
232 if (m_children
[i
]->visible())
233 sumOfVisibleChildrensTime
+= m_children
[i
]->totalTime();
236 m_visibleTotalTime
= m_visibleSelfTime
+ sumOfVisibleChildrensTime
;
239 bool ProfileNode::focus(const CallIdentifier
& callIdentifier
)
244 if (m_callIdentifier
!= callIdentifier
) {
249 for (ProfileNode
* currentParent
= m_parent
; currentParent
; currentParent
= currentParent
->parent())
250 currentParent
->setVisible(true);
255 void ProfileNode::exclude(const CallIdentifier
& callIdentifier
)
257 if (m_visible
&& m_callIdentifier
== callIdentifier
) {
258 setTreeVisible(this, false);
260 m_parent
->setVisibleSelfTime(m_parent
->selfTime() + m_visibleTotalTime
);
264 void ProfileNode::restore()
266 m_visibleTotalTime
= m_actualTotalTime
;
267 m_visibleSelfTime
= m_actualSelfTime
;
271 void ProfileNode::endAndRecordCall()
273 m_actualTotalTime
+= m_startTime
? getCount() - m_startTime
: 0.0;
279 void ProfileNode::startTimer()
282 m_startTime
= getCount();
285 void ProfileNode::resetChildrensSiblings()
287 unsigned size
= m_children
.size();
288 for (unsigned i
= 0; i
< size
; ++i
)
289 m_children
[i
]->setNextSibling(i
+ 1 == size
? 0 : m_children
[i
+ 1].get());
293 void ProfileNode::debugPrintData(int indentLevel
) const
295 // Print function names
296 for (int i
= 0; i
< indentLevel
; ++i
)
299 printf("Function Name %s %d SelfTime %.3fms/%.3f%% TotalTime %.3fms/%.3f%% VSelf %.3fms VTotal %.3fms Visible %s Next Sibling %s\n",
300 functionName().UTF8String().c_str(),
301 m_numberOfCalls
, m_actualSelfTime
, selfPercent(), m_actualTotalTime
, totalPercent(),
302 m_visibleSelfTime
, m_visibleTotalTime
,
303 (m_visible
? "True" : "False"),
304 m_nextSibling
? m_nextSibling
->functionName().UTF8String().c_str() : "");
308 // Print children's names and information
309 for (StackIterator currentChild
= m_children
.begin(); currentChild
!= m_children
.end(); ++currentChild
)
310 (*currentChild
)->debugPrintData(indentLevel
);
313 // print the profiled data in a format that matches the tool sample's output.
314 double ProfileNode::debugPrintDataSampleStyle(int indentLevel
, FunctionCallHashCount
& countedFunctions
) const
318 // Print function names
319 const char* name
= functionName().UTF8String().c_str();
320 double sampleCount
= m_actualTotalTime
* 1000;
322 for (int i
= 0; i
< indentLevel
; ++i
)
325 countedFunctions
.add(functionName().rep());
327 printf("%.0f %s\n", sampleCount
? sampleCount
: 1, name
);
329 printf("%s\n", name
);
333 // Print children's names and information
334 double sumOfChildrensCount
= 0.0;
335 for (StackIterator currentChild
= m_children
.begin(); currentChild
!= m_children
.end(); ++currentChild
)
336 sumOfChildrensCount
+= (*currentChild
)->debugPrintDataSampleStyle(indentLevel
, countedFunctions
);
338 sumOfChildrensCount
*= 1000; //
339 // Print remainder of samples to match sample's output
340 if (sumOfChildrensCount
< sampleCount
) {
342 while (indentLevel
--)
345 printf("%.0f %s\n", sampleCount
- sumOfChildrensCount
, functionName().UTF8String().c_str());
348 return m_actualTotalTime
;