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>
44 static double getCount()
47 static LARGE_INTEGER frequency
= {0};
48 if (!frequency
.QuadPart
)
49 QueryPerformanceFrequency(&frequency
);
50 LARGE_INTEGER counter
;
51 QueryPerformanceCounter(&counter
);
52 return static_cast<double>(counter
.QuadPart
) / frequency
.QuadPart
;
54 return currentTimeMS();
58 ProfileNode::ProfileNode(const CallIdentifier
& callIdentifier
, ProfileNode
* headNode
, ProfileNode
* parentNode
)
59 : m_callIdentifier(callIdentifier
)
61 , m_parent(parentNode
)
64 , m_actualTotalTime(0.0)
65 , m_visibleTotalTime(0.0)
66 , m_actualSelfTime(0.0)
67 , m_visibleSelfTime(0.0)
74 ProfileNode::ProfileNode(ProfileNode
* headNode
, ProfileNode
* nodeToCopy
)
75 : m_callIdentifier(nodeToCopy
->callIdentifier())
77 , m_parent(nodeToCopy
->parent())
80 , m_actualTotalTime(nodeToCopy
->actualTotalTime())
81 , m_visibleTotalTime(nodeToCopy
->totalTime())
82 , m_actualSelfTime(nodeToCopy
->actualSelfTime())
83 , m_visibleSelfTime(nodeToCopy
->selfTime())
84 , m_numberOfCalls(nodeToCopy
->numberOfCalls())
85 , m_visible(nodeToCopy
->visible())
89 ProfileNode
* ProfileNode::willExecute(const CallIdentifier
& callIdentifier
)
91 for (StackIterator currentChild
= m_children
.begin(); currentChild
!= m_children
.end(); ++currentChild
) {
92 if ((*currentChild
)->callIdentifier() == callIdentifier
) {
93 (*currentChild
)->startTimer();
94 return (*currentChild
).get();
98 RefPtr
<ProfileNode
> newChild
= ProfileNode::create(callIdentifier
, m_head
? m_head
: this, this); // If this ProfileNode has no head it is the head.
99 if (m_children
.size())
100 m_children
.last()->setNextSibling(newChild
.get());
101 m_children
.append(newChild
.release());
102 return m_children
.last().get();
105 ProfileNode
* ProfileNode::didExecute()
111 void ProfileNode::addChild(PassRefPtr
<ProfileNode
> prpChild
)
113 RefPtr
<ProfileNode
> child
= prpChild
;
114 child
->setParent(this);
115 if (m_children
.size())
116 m_children
.last()->setNextSibling(child
.get());
117 m_children
.append(child
.release());
120 ProfileNode
* ProfileNode::findChild(ProfileNode
* node
) const
125 for (size_t i
= 0; i
< m_children
.size(); ++i
) {
126 if (*node
== m_children
[i
].get())
127 return m_children
[i
].get();
133 void ProfileNode::removeChild(ProfileNode
* node
)
138 for (size_t i
= 0; i
< m_children
.size(); ++i
) {
139 if (*node
== m_children
[i
].get()) {
140 m_children
.remove(i
);
145 resetChildrensSiblings();
148 void ProfileNode::insertNode(PassRefPtr
<ProfileNode
> prpNode
)
150 RefPtr
<ProfileNode
> node
= prpNode
;
152 for (unsigned i
= 0; i
< m_children
.size(); ++i
)
153 node
->addChild(m_children
[i
].release());
156 m_children
.append(node
.release());
159 void ProfileNode::stopProfiling()
164 m_visibleTotalTime
= m_actualTotalTime
;
166 ASSERT(m_actualSelfTime
== 0.0 && m_startTime
== 0.0);
168 // Because we iterate in post order all of our children have been stopped before us.
169 for (unsigned i
= 0; i
< m_children
.size(); ++i
)
170 m_actualSelfTime
+= m_children
[i
]->totalTime();
172 ASSERT(m_actualSelfTime
<= m_actualTotalTime
);
173 m_actualSelfTime
= m_actualTotalTime
- m_actualSelfTime
;
174 m_visibleSelfTime
= m_actualSelfTime
;
177 ProfileNode
* ProfileNode::traverseNextNodePostOrder() const
179 ProfileNode
* next
= m_nextSibling
;
182 while (ProfileNode
* firstChild
= next
->firstChild())
187 ProfileNode
* ProfileNode::traverseNextNodePreOrder(bool processChildren
) const
189 if (processChildren
&& m_children
.size())
190 return m_children
[0].get();
193 return m_nextSibling
;
195 ProfileNode
* nextParent
= m_parent
;
200 for (next
= m_parent
->nextSibling(); !next
; next
= nextParent
->nextSibling()) {
201 nextParent
= nextParent
->parent();
209 void ProfileNode::setTreeVisible(ProfileNode
* node
, bool visible
)
211 ProfileNode
* nodeParent
= node
->parent();
212 ProfileNode
* nodeSibling
= node
->nextSibling();
214 node
->setNextSibling(0);
216 for (ProfileNode
* currentNode
= node
; currentNode
; currentNode
= currentNode
->traverseNextNodePreOrder())
217 currentNode
->setVisible(visible
);
219 node
->setParent(nodeParent
);
220 node
->setNextSibling(nodeSibling
);
223 void ProfileNode::calculateVisibleTotalTime()
225 double sumOfVisibleChildrensTime
= 0.0;
227 for (unsigned i
= 0; i
< m_children
.size(); ++i
) {
228 if (m_children
[i
]->visible())
229 sumOfVisibleChildrensTime
+= m_children
[i
]->totalTime();
232 m_visibleTotalTime
= m_visibleSelfTime
+ sumOfVisibleChildrensTime
;
235 bool ProfileNode::focus(const CallIdentifier
& callIdentifier
)
240 if (m_callIdentifier
!= callIdentifier
) {
245 for (ProfileNode
* currentParent
= m_parent
; currentParent
; currentParent
= currentParent
->parent())
246 currentParent
->setVisible(true);
251 void ProfileNode::exclude(const CallIdentifier
& callIdentifier
)
253 if (m_visible
&& m_callIdentifier
== callIdentifier
) {
254 setTreeVisible(this, false);
256 m_parent
->setVisibleSelfTime(m_parent
->selfTime() + m_visibleTotalTime
);
260 void ProfileNode::restore()
262 m_visibleTotalTime
= m_actualTotalTime
;
263 m_visibleSelfTime
= m_actualSelfTime
;
267 void ProfileNode::endAndRecordCall()
269 m_actualTotalTime
+= m_startTime
? getCount() - m_startTime
: 0.0;
275 void ProfileNode::startTimer()
278 m_startTime
= getCount();
281 void ProfileNode::resetChildrensSiblings()
283 unsigned size
= m_children
.size();
284 for (unsigned i
= 0; i
< size
; ++i
)
285 m_children
[i
]->setNextSibling(i
+ 1 == size
? 0 : m_children
[i
+ 1].get());
289 void ProfileNode::debugPrintData(int indentLevel
) const
291 // Print function names
292 for (int i
= 0; i
< indentLevel
; ++i
)
295 printf("Function Name %s %d SelfTime %.3fms/%.3f%% TotalTime %.3fms/%.3f%% VSelf %.3fms VTotal %.3fms Visible %s Next Sibling %s\n",
296 functionName().UTF8String().c_str(),
297 m_numberOfCalls
, m_actualSelfTime
, selfPercent(), m_actualTotalTime
, totalPercent(),
298 m_visibleSelfTime
, m_visibleTotalTime
,
299 (m_visible
? "True" : "False"),
300 m_nextSibling
? m_nextSibling
->functionName().UTF8String().c_str() : "");
304 // Print children's names and information
305 for (StackIterator currentChild
= m_children
.begin(); currentChild
!= m_children
.end(); ++currentChild
)
306 (*currentChild
)->debugPrintData(indentLevel
);
309 // print the profiled data in a format that matches the tool sample's output.
310 double ProfileNode::debugPrintDataSampleStyle(int indentLevel
, FunctionCallHashCount
& countedFunctions
) const
314 // Print function names
315 const char* name
= functionName().UTF8String().c_str();
316 double sampleCount
= m_actualTotalTime
* 1000;
318 for (int i
= 0; i
< indentLevel
; ++i
)
321 countedFunctions
.add(functionName().rep());
323 printf("%.0f %s\n", sampleCount
? sampleCount
: 1, name
);
325 printf("%s\n", name
);
329 // Print children's names and information
330 double sumOfChildrensCount
= 0.0;
331 for (StackIterator currentChild
= m_children
.begin(); currentChild
!= m_children
.end(); ++currentChild
)
332 sumOfChildrensCount
+= (*currentChild
)->debugPrintDataSampleStyle(indentLevel
, countedFunctions
);
334 sumOfChildrensCount
*= 1000; //
335 // Print remainder of samples to match sample's output
336 if (sumOfChildrensCount
< sampleCount
) {
338 while (indentLevel
--)
341 printf("%.0f %s\n", sampleCount
- sumOfChildrensCount
, functionName().UTF8String().c_str());
344 return m_actualTotalTime
;