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/DataLog.h>
36 #include <wtf/text/StringHash.h>
46 static double getCount()
49 static LARGE_INTEGER frequency
;
50 if (!frequency
.QuadPart
)
51 QueryPerformanceFrequency(&frequency
);
52 LARGE_INTEGER counter
;
53 QueryPerformanceCounter(&counter
);
54 return static_cast<double>(counter
.QuadPart
) / frequency
.QuadPart
;
56 return currentTimeMS();
60 ProfileNode::ProfileNode(ExecState
* callerCallFrame
, const CallIdentifier
& callIdentifier
, ProfileNode
* headNode
, ProfileNode
* parentNode
)
61 : m_callerCallFrame(callerCallFrame
)
62 , m_callIdentifier(callIdentifier
)
64 , m_parent(parentNode
)
67 , m_actualTotalTime(0.0)
68 , m_visibleTotalTime(0.0)
69 , m_actualSelfTime(0.0)
70 , m_visibleSelfTime(0.0)
77 ProfileNode::ProfileNode(ExecState
* callerCallFrame
, ProfileNode
* headNode
, ProfileNode
* nodeToCopy
)
78 : m_callerCallFrame(callerCallFrame
)
79 , m_callIdentifier(nodeToCopy
->callIdentifier())
81 , m_parent(nodeToCopy
->parent())
84 , m_actualTotalTime(nodeToCopy
->actualTotalTime())
85 , m_visibleTotalTime(nodeToCopy
->totalTime())
86 , m_actualSelfTime(nodeToCopy
->actualSelfTime())
87 , m_visibleSelfTime(nodeToCopy
->selfTime())
88 , m_numberOfCalls(nodeToCopy
->numberOfCalls())
89 , m_visible(nodeToCopy
->visible())
93 ProfileNode
* ProfileNode::willExecute(ExecState
* callerCallFrame
, const CallIdentifier
& callIdentifier
)
95 for (StackIterator currentChild
= m_children
.begin(); currentChild
!= m_children
.end(); ++currentChild
) {
96 if ((*currentChild
)->callIdentifier() == callIdentifier
) {
97 (*currentChild
)->startTimer();
98 return (*currentChild
).get();
102 RefPtr
<ProfileNode
> newChild
= ProfileNode::create(callerCallFrame
, callIdentifier
, m_head
? m_head
: this, this); // If this ProfileNode has no head it is the head.
103 if (m_children
.size())
104 m_children
.last()->setNextSibling(newChild
.get());
105 m_children
.append(newChild
.release());
106 return m_children
.last().get();
109 ProfileNode
* ProfileNode::didExecute()
115 void ProfileNode::addChild(PassRefPtr
<ProfileNode
> prpChild
)
117 RefPtr
<ProfileNode
> child
= prpChild
;
118 child
->setParent(this);
119 if (m_children
.size())
120 m_children
.last()->setNextSibling(child
.get());
121 m_children
.append(child
.release());
124 ProfileNode
* ProfileNode::findChild(ProfileNode
* node
) const
129 for (size_t i
= 0; i
< m_children
.size(); ++i
) {
130 if (*node
== m_children
[i
].get())
131 return m_children
[i
].get();
137 void ProfileNode::removeChild(ProfileNode
* node
)
142 for (size_t i
= 0; i
< m_children
.size(); ++i
) {
143 if (*node
== m_children
[i
].get()) {
144 m_children
.remove(i
);
149 resetChildrensSiblings();
152 void ProfileNode::insertNode(PassRefPtr
<ProfileNode
> prpNode
)
154 RefPtr
<ProfileNode
> node
= prpNode
;
156 for (unsigned i
= 0; i
< m_children
.size(); ++i
)
157 node
->addChild(m_children
[i
].release());
160 m_children
.append(node
.release());
163 void ProfileNode::stopProfiling()
168 m_visibleTotalTime
= m_actualTotalTime
;
170 ASSERT(m_actualSelfTime
== 0.0 && m_startTime
== 0.0);
172 // Because we iterate in post order all of our children have been stopped before us.
173 for (unsigned i
= 0; i
< m_children
.size(); ++i
)
174 m_actualSelfTime
+= m_children
[i
]->totalTime();
176 ASSERT(m_actualSelfTime
<= m_actualTotalTime
);
177 m_actualSelfTime
= m_actualTotalTime
- m_actualSelfTime
;
178 m_visibleSelfTime
= m_actualSelfTime
;
181 ProfileNode
* ProfileNode::traverseNextNodePostOrder() const
183 ProfileNode
* next
= m_nextSibling
;
186 while (ProfileNode
* firstChild
= next
->firstChild())
191 ProfileNode
* ProfileNode::traverseNextNodePreOrder(bool processChildren
) const
193 if (processChildren
&& m_children
.size())
194 return m_children
[0].get();
197 return m_nextSibling
;
199 ProfileNode
* nextParent
= m_parent
;
204 for (next
= m_parent
->nextSibling(); !next
; next
= nextParent
->nextSibling()) {
205 nextParent
= nextParent
->parent();
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 dataLog("Function Name %s %d SelfTime %.3fms/%.3f%% TotalTime %.3fms/%.3f%% VSelf %.3fms VTotal %.3fms Visible %s Next Sibling %s\n",
300 functionName().utf8().data(),
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().utf8().data() : "");
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().utf8().data();
320 double sampleCount
= m_actualTotalTime
* 1000;
322 for (int i
= 0; i
< indentLevel
; ++i
)
325 countedFunctions
.add(functionName().impl());
327 dataLog("%.0f %s\n", sampleCount
? sampleCount
: 1, name
);
329 dataLog("%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 dataLog("%.0f %s\n", sampleCount
- sumOfChildrensCount
, functionName().utf8().data());
348 return m_actualTotalTime
;