• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
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.
16  *
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.
27  */
28 
29 #include "config.h"
30 #include "ProfileNode.h"
31 
32 #include "Profiler.h"
33 #include <stdio.h>
34 #include <wtf/DateMath.h>
35 
36 #if OS(WINDOWS)
37 #include <windows.h>
38 #endif
39 
40 using namespace WTF;
41 
42 namespace JSC {
43 
getCount()44 static double getCount()
45 {
46 #if OS(WINDOWS)
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;
53 #else
54     return currentTimeMS();
55 #endif
56 }
57 
ProfileNode(const CallIdentifier & callIdentifier,ProfileNode * headNode,ProfileNode * parentNode)58 ProfileNode::ProfileNode(const CallIdentifier& callIdentifier, ProfileNode* headNode, ProfileNode* parentNode)
59     : m_callIdentifier(callIdentifier)
60     , m_head(headNode)
61     , m_parent(parentNode)
62     , m_nextSibling(0)
63     , m_startTime(0.0)
64     , m_actualTotalTime(0.0)
65     , m_visibleTotalTime(0.0)
66     , m_actualSelfTime(0.0)
67     , m_visibleSelfTime(0.0)
68     , m_numberOfCalls(0)
69     , m_visible(true)
70 {
71     startTimer();
72 }
73 
ProfileNode(ProfileNode * headNode,ProfileNode * nodeToCopy)74 ProfileNode::ProfileNode(ProfileNode* headNode, ProfileNode* nodeToCopy)
75     : m_callIdentifier(nodeToCopy->callIdentifier())
76     , m_head(headNode)
77     , m_parent(nodeToCopy->parent())
78     , m_nextSibling(0)
79     , m_startTime(0.0)
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())
86 {
87 }
88 
willExecute(const CallIdentifier & callIdentifier)89 ProfileNode* ProfileNode::willExecute(const CallIdentifier& callIdentifier)
90 {
91     for (StackIterator currentChild = m_children.begin(); currentChild != m_children.end(); ++currentChild) {
92         if ((*currentChild)->callIdentifier() == callIdentifier) {
93             (*currentChild)->startTimer();
94             return (*currentChild).get();
95         }
96     }
97 
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();
103 }
104 
didExecute()105 ProfileNode* ProfileNode::didExecute()
106 {
107     endAndRecordCall();
108     return m_parent;
109 }
110 
addChild(PassRefPtr<ProfileNode> prpChild)111 void ProfileNode::addChild(PassRefPtr<ProfileNode> prpChild)
112 {
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());
118 }
119 
findChild(ProfileNode * node) const120 ProfileNode* ProfileNode::findChild(ProfileNode* node) const
121 {
122     if (!node)
123         return 0;
124 
125     for (size_t i = 0; i < m_children.size(); ++i) {
126         if (*node == m_children[i].get())
127             return m_children[i].get();
128     }
129 
130     return 0;
131 }
132 
removeChild(ProfileNode * node)133 void ProfileNode::removeChild(ProfileNode* node)
134 {
135     if (!node)
136         return;
137 
138     for (size_t i = 0; i < m_children.size(); ++i) {
139         if (*node == m_children[i].get()) {
140             m_children.remove(i);
141             break;
142         }
143     }
144 
145     resetChildrensSiblings();
146 }
147 
insertNode(PassRefPtr<ProfileNode> prpNode)148 void ProfileNode::insertNode(PassRefPtr<ProfileNode> prpNode)
149 {
150     RefPtr<ProfileNode> node = prpNode;
151 
152     for (unsigned i = 0; i < m_children.size(); ++i)
153         node->addChild(m_children[i].release());
154 
155     m_children.clear();
156     m_children.append(node.release());
157 }
158 
stopProfiling()159 void ProfileNode::stopProfiling()
160 {
161     if (m_startTime)
162         endAndRecordCall();
163 
164     m_visibleTotalTime = m_actualTotalTime;
165 
166     ASSERT(m_actualSelfTime == 0.0 && m_startTime == 0.0);
167 
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();
171 
172     ASSERT(m_actualSelfTime <= m_actualTotalTime);
173     m_actualSelfTime = m_actualTotalTime - m_actualSelfTime;
174     m_visibleSelfTime = m_actualSelfTime;
175 }
176 
traverseNextNodePostOrder() const177 ProfileNode* ProfileNode::traverseNextNodePostOrder() const
178 {
179     ProfileNode* next = m_nextSibling;
180     if (!next)
181         return m_parent;
182     while (ProfileNode* firstChild = next->firstChild())
183         next = firstChild;
184     return next;
185 }
186 
traverseNextNodePreOrder(bool processChildren) const187 ProfileNode* ProfileNode::traverseNextNodePreOrder(bool processChildren) const
188 {
189     if (processChildren && m_children.size())
190         return m_children[0].get();
191 
192     if (m_nextSibling)
193         return m_nextSibling;
194 
195     ProfileNode* nextParent = m_parent;
196     if (!nextParent)
197         return 0;
198 
199     ProfileNode* next;
200     for (next = m_parent->nextSibling(); !next; next = nextParent->nextSibling()) {
201         nextParent = nextParent->parent();
202         if (!nextParent)
203             return 0;
204     }
205 
206     return next;
207 }
208 
setTreeVisible(ProfileNode * node,bool visible)209 void ProfileNode::setTreeVisible(ProfileNode* node, bool visible)
210 {
211     ProfileNode* nodeParent = node->parent();
212     ProfileNode* nodeSibling = node->nextSibling();
213     node->setParent(0);
214     node->setNextSibling(0);
215 
216     for (ProfileNode* currentNode = node; currentNode; currentNode = currentNode->traverseNextNodePreOrder())
217         currentNode->setVisible(visible);
218 
219     node->setParent(nodeParent);
220     node->setNextSibling(nodeSibling);
221 }
222 
calculateVisibleTotalTime()223 void ProfileNode::calculateVisibleTotalTime()
224 {
225     double sumOfVisibleChildrensTime = 0.0;
226 
227     for (unsigned i = 0; i < m_children.size(); ++i) {
228         if (m_children[i]->visible())
229             sumOfVisibleChildrensTime += m_children[i]->totalTime();
230     }
231 
232     m_visibleTotalTime = m_visibleSelfTime + sumOfVisibleChildrensTime;
233 }
234 
focus(const CallIdentifier & callIdentifier)235 bool ProfileNode::focus(const CallIdentifier& callIdentifier)
236 {
237     if (!m_visible)
238         return false;
239 
240     if (m_callIdentifier != callIdentifier) {
241         m_visible = false;
242         return true;
243     }
244 
245     for (ProfileNode* currentParent = m_parent; currentParent; currentParent = currentParent->parent())
246         currentParent->setVisible(true);
247 
248     return false;
249 }
250 
exclude(const CallIdentifier & callIdentifier)251 void ProfileNode::exclude(const CallIdentifier& callIdentifier)
252 {
253     if (m_visible && m_callIdentifier == callIdentifier) {
254         setTreeVisible(this, false);
255 
256         m_parent->setVisibleSelfTime(m_parent->selfTime() + m_visibleTotalTime);
257     }
258 }
259 
restore()260 void ProfileNode::restore()
261 {
262     m_visibleTotalTime = m_actualTotalTime;
263     m_visibleSelfTime = m_actualSelfTime;
264     m_visible = true;
265 }
266 
endAndRecordCall()267 void ProfileNode::endAndRecordCall()
268 {
269     m_actualTotalTime += m_startTime ? getCount() - m_startTime : 0.0;
270     m_startTime = 0.0;
271 
272     ++m_numberOfCalls;
273 }
274 
startTimer()275 void ProfileNode::startTimer()
276 {
277     if (!m_startTime)
278         m_startTime = getCount();
279 }
280 
resetChildrensSiblings()281 void ProfileNode::resetChildrensSiblings()
282 {
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());
286 }
287 
288 #ifndef NDEBUG
debugPrintData(int indentLevel) const289 void ProfileNode::debugPrintData(int indentLevel) const
290 {
291     // Print function names
292     for (int i = 0; i < indentLevel; ++i)
293         printf("  ");
294 
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() : "");
301 
302     ++indentLevel;
303 
304     // Print children's names and information
305     for (StackIterator currentChild = m_children.begin(); currentChild != m_children.end(); ++currentChild)
306         (*currentChild)->debugPrintData(indentLevel);
307 }
308 
309 // print the profiled data in a format that matches the tool sample's output.
debugPrintDataSampleStyle(int indentLevel,FunctionCallHashCount & countedFunctions) const310 double ProfileNode::debugPrintDataSampleStyle(int indentLevel, FunctionCallHashCount& countedFunctions) const
311 {
312     printf("    ");
313 
314     // Print function names
315     const char* name = functionName().UTF8String().c_str();
316     double sampleCount = m_actualTotalTime * 1000;
317     if (indentLevel) {
318         for (int i = 0; i < indentLevel; ++i)
319             printf("  ");
320 
321          countedFunctions.add(functionName().rep());
322 
323         printf("%.0f %s\n", sampleCount ? sampleCount : 1, name);
324     } else
325         printf("%s\n", name);
326 
327     ++indentLevel;
328 
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);
333 
334     sumOfChildrensCount *= 1000;    //
335     // Print remainder of samples to match sample's output
336     if (sumOfChildrensCount < sampleCount) {
337         printf("    ");
338         while (indentLevel--)
339             printf("  ");
340 
341         printf("%.0f %s\n", sampleCount - sumOfChildrensCount, functionName().UTF8String().c_str());
342     }
343 
344     return m_actualTotalTime;
345 }
346 #endif
347 
348 } // namespace JSC
349