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;
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(ExecState* callerCallFrame, const CallIdentifier& callIdentifier, ProfileNode* headNode, ProfileNode* parentNode)
60 : m_callerCallFrame(callerCallFrame)
61 , m_callIdentifier(callIdentifier)
63 , m_parent(parentNode)
66 , m_actualTotalTime(0.0)
67 , m_visibleTotalTime(0.0)
68 , m_actualSelfTime(0.0)
69 , m_visibleSelfTime(0.0)
76 ProfileNode::ProfileNode(ExecState* callerCallFrame, ProfileNode* headNode, ProfileNode* nodeToCopy)
77 : m_callerCallFrame(callerCallFrame)
78 , m_callIdentifier(nodeToCopy->callIdentifier())
80 , m_parent(nodeToCopy->parent())
83 , m_actualTotalTime(nodeToCopy->actualTotalTime())
84 , m_visibleTotalTime(nodeToCopy->totalTime())
85 , m_actualSelfTime(nodeToCopy->actualSelfTime())
86 , m_visibleSelfTime(nodeToCopy->selfTime())
87 , m_numberOfCalls(nodeToCopy->numberOfCalls())
88 , m_visible(nodeToCopy->visible())
92 ProfileNode* ProfileNode::willExecute(ExecState* callerCallFrame, const CallIdentifier& callIdentifier)
94 for (StackIterator currentChild = m_children.begin(); currentChild != m_children.end(); ++currentChild) {
95 if ((*currentChild)->callIdentifier() == callIdentifier) {
96 (*currentChild)->startTimer();
97 return (*currentChild).get();
101 RefPtr<ProfileNode> newChild = ProfileNode::create(callerCallFrame, callIdentifier, m_head ? m_head : this, this); // If this ProfileNode has no head it is the head.
102 if (m_children.size())
103 m_children.last()->setNextSibling(newChild.get());
104 m_children.append(newChild.release());
105 return m_children.last().get();
108 ProfileNode* ProfileNode::didExecute()
114 void ProfileNode::addChild(PassRefPtr<ProfileNode> prpChild)
116 RefPtr<ProfileNode> child = prpChild;
117 child->setParent(this);
118 if (m_children.size())
119 m_children.last()->setNextSibling(child.get());
120 m_children.append(child.release());
123 ProfileNode* ProfileNode::findChild(ProfileNode* node) const
128 for (size_t i = 0; i < m_children.size(); ++i) {
129 if (*node == m_children[i].get())
130 return m_children[i].get();
136 void ProfileNode::removeChild(ProfileNode* node)
141 for (size_t i = 0; i < m_children.size(); ++i) {
142 if (*node == m_children[i].get()) {
143 m_children.remove(i);
148 resetChildrensSiblings();
151 void ProfileNode::insertNode(PassRefPtr<ProfileNode> prpNode)
153 RefPtr<ProfileNode> node = prpNode;
155 for (unsigned i = 0; i < m_children.size(); ++i)
156 node->addChild(m_children[i].release());
159 m_children.append(node.release());
162 void ProfileNode::stopProfiling()
167 m_visibleTotalTime = m_actualTotalTime;
169 ASSERT(m_actualSelfTime == 0.0 && m_startTime == 0.0);
171 // Because we iterate in post order all of our children have been stopped before us.
172 for (unsigned i = 0; i < m_children.size(); ++i)
173 m_actualSelfTime += m_children[i]->totalTime();
175 ASSERT(m_actualSelfTime <= m_actualTotalTime);
176 m_actualSelfTime = m_actualTotalTime - m_actualSelfTime;
177 m_visibleSelfTime = m_actualSelfTime;
180 ProfileNode* ProfileNode::traverseNextNodePostOrder() const
182 ProfileNode* next = m_nextSibling;
185 while (ProfileNode* firstChild = next->firstChild())
190 ProfileNode* ProfileNode::traverseNextNodePreOrder(bool processChildren) const
192 if (processChildren && m_children.size())
193 return m_children[0].get();
196 return m_nextSibling;
198 ProfileNode* nextParent = m_parent;
203 for (next = m_parent->nextSibling(); !next; next = nextParent->nextSibling()) {
204 nextParent = nextParent->parent();
212 void ProfileNode::setTreeVisible(ProfileNode* node, bool visible)
214 ProfileNode* nodeParent = node->parent();
215 ProfileNode* nodeSibling = node->nextSibling();
217 node->setNextSibling(0);
219 for (ProfileNode* currentNode = node; currentNode; currentNode = currentNode->traverseNextNodePreOrder())
220 currentNode->setVisible(visible);
222 node->setParent(nodeParent);
223 node->setNextSibling(nodeSibling);
226 void ProfileNode::calculateVisibleTotalTime()
228 double sumOfVisibleChildrensTime = 0.0;
230 for (unsigned i = 0; i < m_children.size(); ++i) {
231 if (m_children[i]->visible())
232 sumOfVisibleChildrensTime += m_children[i]->totalTime();
235 m_visibleTotalTime = m_visibleSelfTime + sumOfVisibleChildrensTime;
238 bool ProfileNode::focus(const CallIdentifier& callIdentifier)
243 if (m_callIdentifier != callIdentifier) {
248 for (ProfileNode* currentParent = m_parent; currentParent; currentParent = currentParent->parent())
249 currentParent->setVisible(true);
254 void ProfileNode::exclude(const CallIdentifier& callIdentifier)
256 if (m_visible && m_callIdentifier == callIdentifier) {
257 setTreeVisible(this, false);
259 m_parent->setVisibleSelfTime(m_parent->selfTime() + m_visibleTotalTime);
263 void ProfileNode::restore()
265 m_visibleTotalTime = m_actualTotalTime;
266 m_visibleSelfTime = m_actualSelfTime;
270 void ProfileNode::endAndRecordCall()
272 m_actualTotalTime += m_startTime ? getCount() - m_startTime : 0.0;
278 void ProfileNode::startTimer()
281 m_startTime = getCount();
284 void ProfileNode::resetChildrensSiblings()
286 unsigned size = m_children.size();
287 for (unsigned i = 0; i < size; ++i)
288 m_children[i]->setNextSibling(i + 1 == size ? 0 : m_children[i + 1].get());
292 void ProfileNode::debugPrintData(int indentLevel) const
294 // Print function names
295 for (int i = 0; i < indentLevel; ++i)
298 printf("Function Name %s %d SelfTime %.3fms/%.3f%% TotalTime %.3fms/%.3f%% VSelf %.3fms VTotal %.3fms Visible %s Next Sibling %s\n",
299 functionName().utf8().data(),
300 m_numberOfCalls, m_actualSelfTime, selfPercent(), m_actualTotalTime, totalPercent(),
301 m_visibleSelfTime, m_visibleTotalTime,
302 (m_visible ? "True" : "False"),
303 m_nextSibling ? m_nextSibling->functionName().utf8().data() : "");
307 // Print children's names and information
308 for (StackIterator currentChild = m_children.begin(); currentChild != m_children.end(); ++currentChild)
309 (*currentChild)->debugPrintData(indentLevel);
312 // print the profiled data in a format that matches the tool sample's output.
313 double ProfileNode::debugPrintDataSampleStyle(int indentLevel, FunctionCallHashCount& countedFunctions) const
317 // Print function names
318 const char* name = functionName().utf8().data();
319 double sampleCount = m_actualTotalTime * 1000;
321 for (int i = 0; i < indentLevel; ++i)
324 countedFunctions.add(functionName().impl());
326 printf("%.0f %s\n", sampleCount ? sampleCount : 1, name);
328 printf("%s\n", name);
332 // Print children's names and information
333 double sumOfChildrensCount = 0.0;
334 for (StackIterator currentChild = m_children.begin(); currentChild != m_children.end(); ++currentChild)
335 sumOfChildrensCount += (*currentChild)->debugPrintDataSampleStyle(indentLevel, countedFunctions);
337 sumOfChildrensCount *= 1000; //
338 // Print remainder of samples to match sample's output
339 if (sumOfChildrensCount < sampleCount) {
341 while (indentLevel--)
344 printf("%.0f %s\n", sampleCount - sumOfChildrensCount, functionName().utf8().data());
347 return m_actualTotalTime;