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"
34 #include <wtf/DateMath.h>
35 #include <wtf/text/StringHash.h>
45 static double getCount()
48 static LARGE_INTEGER frequency
= {0};
49 if (!frequency
.QuadPart
)
50 QueryPerformanceFrequency(&frequency
);
51 LARGE_INTEGER counter
;
52 QueryPerformanceCounter(&counter
);
53 return static_cast<double>(counter
.QuadPart
) / frequency
.QuadPart
;
55 return currentTimeMS();
59 ProfileNode::ProfileNode(const CallIdentifier
& callIdentifier
, ProfileNode
* headNode
, ProfileNode
* parentNode
)
60 : m_callIdentifier(callIdentifier
)
62 , m_parent(parentNode
)
65 , m_actualTotalTime(0.0)
66 , m_visibleTotalTime(0.0)
67 , m_actualSelfTime(0.0)
68 , m_visibleSelfTime(0.0)
75 ProfileNode::ProfileNode(ProfileNode
* headNode
, ProfileNode
* nodeToCopy
)
76 : m_callIdentifier(nodeToCopy
->callIdentifier())
78 , m_parent(nodeToCopy
->parent())
81 , m_actualTotalTime(nodeToCopy
->actualTotalTime())
82 , m_visibleTotalTime(nodeToCopy
->totalTime())
83 , m_actualSelfTime(nodeToCopy
->actualSelfTime())
84 , m_visibleSelfTime(nodeToCopy
->selfTime())
85 , m_numberOfCalls(nodeToCopy
->numberOfCalls())
86 , m_visible(nodeToCopy
->visible())
90 ProfileNode
* ProfileNode::willExecute(const CallIdentifier
& callIdentifier
)
92 for (StackIterator currentChild
= m_children
.begin(); currentChild
!= m_children
.end(); ++currentChild
) {
93 if ((*currentChild
)->callIdentifier() == callIdentifier
) {
94 (*currentChild
)->startTimer();
95 return (*currentChild
).get();
99 RefPtr
<ProfileNode
> newChild
= ProfileNode::create(callIdentifier
, m_head
? m_head
: this, this); // If this ProfileNode has no head it is the head.
100 if (m_children
.size())
101 m_children
.last()->setNextSibling(newChild
.get());
102 m_children
.append(newChild
.release());
103 return m_children
.last().get();
106 ProfileNode
* ProfileNode::didExecute()
112 void ProfileNode::addChild(PassRefPtr
<ProfileNode
> prpChild
)
114 RefPtr
<ProfileNode
> child
= prpChild
;
115 child
->setParent(this);
116 if (m_children
.size())
117 m_children
.last()->setNextSibling(child
.get());
118 m_children
.append(child
.release());
121 ProfileNode
* ProfileNode::findChild(ProfileNode
* node
) const
126 for (size_t i
= 0; i
< m_children
.size(); ++i
) {
127 if (*node
== m_children
[i
].get())
128 return m_children
[i
].get();
134 void ProfileNode::removeChild(ProfileNode
* node
)
139 for (size_t i
= 0; i
< m_children
.size(); ++i
) {
140 if (*node
== m_children
[i
].get()) {
141 m_children
.remove(i
);
146 resetChildrensSiblings();
149 void ProfileNode::insertNode(PassRefPtr
<ProfileNode
> prpNode
)
151 RefPtr
<ProfileNode
> node
= prpNode
;
153 for (unsigned i
= 0; i
< m_children
.size(); ++i
)
154 node
->addChild(m_children
[i
].release());
157 m_children
.append(node
.release());
160 void ProfileNode::stopProfiling()
165 m_visibleTotalTime
= m_actualTotalTime
;
167 ASSERT(m_actualSelfTime
== 0.0 && m_startTime
== 0.0);
169 // Because we iterate in post order all of our children have been stopped before us.
170 for (unsigned i
= 0; i
< m_children
.size(); ++i
)
171 m_actualSelfTime
+= m_children
[i
]->totalTime();
173 ASSERT(m_actualSelfTime
<= m_actualTotalTime
);
174 m_actualSelfTime
= m_actualTotalTime
- m_actualSelfTime
;
175 m_visibleSelfTime
= m_actualSelfTime
;
178 ProfileNode
* ProfileNode::traverseNextNodePostOrder() const
180 ProfileNode
* next
= m_nextSibling
;
183 while (ProfileNode
* firstChild
= next
->firstChild())
188 ProfileNode
* ProfileNode::traverseNextNodePreOrder(bool processChildren
) const
190 if (processChildren
&& m_children
.size())
191 return m_children
[0].get();
194 return m_nextSibling
;
196 ProfileNode
* nextParent
= m_parent
;
201 for (next
= m_parent
->nextSibling(); !next
; next
= nextParent
->nextSibling()) {
202 nextParent
= nextParent
->parent();
210 void ProfileNode::setTreeVisible(ProfileNode
* node
, bool visible
)
212 ProfileNode
* nodeParent
= node
->parent();
213 ProfileNode
* nodeSibling
= node
->nextSibling();
215 node
->setNextSibling(0);
217 for (ProfileNode
* currentNode
= node
; currentNode
; currentNode
= currentNode
->traverseNextNodePreOrder())
218 currentNode
->setVisible(visible
);
220 node
->setParent(nodeParent
);
221 node
->setNextSibling(nodeSibling
);
224 void ProfileNode::calculateVisibleTotalTime()
226 double sumOfVisibleChildrensTime
= 0.0;
228 for (unsigned i
= 0; i
< m_children
.size(); ++i
) {
229 if (m_children
[i
]->visible())
230 sumOfVisibleChildrensTime
+= m_children
[i
]->totalTime();
233 m_visibleTotalTime
= m_visibleSelfTime
+ sumOfVisibleChildrensTime
;
236 bool ProfileNode::focus(const CallIdentifier
& callIdentifier
)
241 if (m_callIdentifier
!= callIdentifier
) {
246 for (ProfileNode
* currentParent
= m_parent
; currentParent
; currentParent
= currentParent
->parent())
247 currentParent
->setVisible(true);
252 void ProfileNode::exclude(const CallIdentifier
& callIdentifier
)
254 if (m_visible
&& m_callIdentifier
== callIdentifier
) {
255 setTreeVisible(this, false);
257 m_parent
->setVisibleSelfTime(m_parent
->selfTime() + m_visibleTotalTime
);
261 void ProfileNode::restore()
263 m_visibleTotalTime
= m_actualTotalTime
;
264 m_visibleSelfTime
= m_actualSelfTime
;
268 void ProfileNode::endAndRecordCall()
270 m_actualTotalTime
+= m_startTime
? getCount() - m_startTime
: 0.0;
276 void ProfileNode::startTimer()
279 m_startTime
= getCount();
282 void ProfileNode::resetChildrensSiblings()
284 unsigned size
= m_children
.size();
285 for (unsigned i
= 0; i
< size
; ++i
)
286 m_children
[i
]->setNextSibling(i
+ 1 == size
? 0 : m_children
[i
+ 1].get());
290 void ProfileNode::debugPrintData(int indentLevel
) const
292 // Print function names
293 for (int i
= 0; i
< indentLevel
; ++i
)
296 printf("Function Name %s %d SelfTime %.3fms/%.3f%% TotalTime %.3fms/%.3f%% VSelf %.3fms VTotal %.3fms Visible %s Next Sibling %s\n",
297 functionName().UTF8String().data(),
298 m_numberOfCalls
, m_actualSelfTime
, selfPercent(), m_actualTotalTime
, totalPercent(),
299 m_visibleSelfTime
, m_visibleTotalTime
,
300 (m_visible
? "True" : "False"),
301 m_nextSibling
? m_nextSibling
->functionName().UTF8String().data() : "");
305 // Print children's names and information
306 for (StackIterator currentChild
= m_children
.begin(); currentChild
!= m_children
.end(); ++currentChild
)
307 (*currentChild
)->debugPrintData(indentLevel
);
310 // print the profiled data in a format that matches the tool sample's output.
311 double ProfileNode::debugPrintDataSampleStyle(int indentLevel
, FunctionCallHashCount
& countedFunctions
) const
315 // Print function names
316 const char* name
= functionName().UTF8String().data();
317 double sampleCount
= m_actualTotalTime
* 1000;
319 for (int i
= 0; i
< indentLevel
; ++i
)
322 countedFunctions
.add(functionName().rep());
324 printf("%.0f %s\n", sampleCount
? sampleCount
: 1, name
);
326 printf("%s\n", name
);
330 // Print children's names and information
331 double sumOfChildrensCount
= 0.0;
332 for (StackIterator currentChild
= m_children
.begin(); currentChild
!= m_children
.end(); ++currentChild
)
333 sumOfChildrensCount
+= (*currentChild
)->debugPrintDataSampleStyle(indentLevel
, countedFunctions
);
335 sumOfChildrensCount
*= 1000; //
336 // Print remainder of samples to match sample's output
337 if (sumOfChildrensCount
< sampleCount
) {
339 while (indentLevel
--)
342 printf("%.0f %s\n", sampleCount
- sumOfChildrensCount
, functionName().UTF8String().data());
345 return m_actualTotalTime
;