initial import
[vuplus_webkit] / Source / JavaScriptCore / profiler / ProfileNode.cpp
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 #include <wtf/text/StringHash.h>
36
37 #if OS(WINDOWS)
38 #include <windows.h>
39 #endif
40
41 using namespace WTF;
42
43 namespace JSC {
44
45 static double getCount()
46 {
47 #if OS(WINDOWS)
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;
54 #else
55     return currentTimeMS();
56 #endif
57 }
58
59 ProfileNode::ProfileNode(ExecState* callerCallFrame, const CallIdentifier& callIdentifier, ProfileNode* headNode, ProfileNode* parentNode)
60     : m_callerCallFrame(callerCallFrame)
61     , m_callIdentifier(callIdentifier)
62     , m_head(headNode)
63     , m_parent(parentNode)
64     , m_nextSibling(0)
65     , m_startTime(0.0)
66     , m_actualTotalTime(0.0)
67     , m_visibleTotalTime(0.0)
68     , m_actualSelfTime(0.0)
69     , m_visibleSelfTime(0.0)
70     , m_numberOfCalls(0)
71     , m_visible(true)
72 {
73     startTimer();
74 }
75
76 ProfileNode::ProfileNode(ExecState* callerCallFrame, ProfileNode* headNode, ProfileNode* nodeToCopy)
77     : m_callerCallFrame(callerCallFrame)
78     , m_callIdentifier(nodeToCopy->callIdentifier())
79     , m_head(headNode)
80     , m_parent(nodeToCopy->parent())
81     , m_nextSibling(0)
82     , m_startTime(0.0)
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())
89 {
90 }
91
92 ProfileNode* ProfileNode::willExecute(ExecState* callerCallFrame, const CallIdentifier& callIdentifier)
93 {
94     for (StackIterator currentChild = m_children.begin(); currentChild != m_children.end(); ++currentChild) {
95         if ((*currentChild)->callIdentifier() == callIdentifier) {
96             (*currentChild)->startTimer();
97             return (*currentChild).get();
98         }
99     }
100
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();
106 }
107
108 ProfileNode* ProfileNode::didExecute()
109 {
110     endAndRecordCall();
111     return m_parent;
112 }
113
114 void ProfileNode::addChild(PassRefPtr<ProfileNode> prpChild)
115 {
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());
121 }
122
123 ProfileNode* ProfileNode::findChild(ProfileNode* node) const
124 {
125     if (!node)
126         return 0;
127
128     for (size_t i = 0; i < m_children.size(); ++i) {
129         if (*node == m_children[i].get())
130             return m_children[i].get();
131     }
132
133     return 0;
134 }
135
136 void ProfileNode::removeChild(ProfileNode* node)
137 {
138     if (!node)
139         return;
140
141     for (size_t i = 0; i < m_children.size(); ++i) {
142         if (*node == m_children[i].get()) {
143             m_children.remove(i);
144             break;
145         }
146     }
147     
148     resetChildrensSiblings();
149 }
150
151 void ProfileNode::insertNode(PassRefPtr<ProfileNode> prpNode)
152 {
153     RefPtr<ProfileNode> node = prpNode;
154
155     for (unsigned i = 0; i < m_children.size(); ++i)
156         node->addChild(m_children[i].release());
157
158     m_children.clear();
159     m_children.append(node.release());
160 }
161
162 void ProfileNode::stopProfiling()
163 {
164     if (m_startTime)
165         endAndRecordCall();
166
167     m_visibleTotalTime = m_actualTotalTime;
168
169     ASSERT(m_actualSelfTime == 0.0 && m_startTime == 0.0);
170
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();
174
175     ASSERT(m_actualSelfTime <= m_actualTotalTime);
176     m_actualSelfTime = m_actualTotalTime - m_actualSelfTime;
177     m_visibleSelfTime = m_actualSelfTime;
178 }
179
180 ProfileNode* ProfileNode::traverseNextNodePostOrder() const
181 {
182     ProfileNode* next = m_nextSibling;
183     if (!next)
184         return m_parent;
185     while (ProfileNode* firstChild = next->firstChild())
186         next = firstChild;
187     return next;
188 }
189
190 ProfileNode* ProfileNode::traverseNextNodePreOrder(bool processChildren) const
191 {
192     if (processChildren && m_children.size())
193         return m_children[0].get();
194
195     if (m_nextSibling)
196         return m_nextSibling;
197
198     ProfileNode* nextParent = m_parent;
199     if (!nextParent)
200         return 0;
201
202     ProfileNode* next;
203     for (next = m_parent->nextSibling(); !next; next = nextParent->nextSibling()) {
204         nextParent = nextParent->parent();
205         if (!nextParent)
206             return 0;
207     }
208
209     return next;
210 }
211
212 void ProfileNode::setTreeVisible(ProfileNode* node, bool visible)
213 {
214     ProfileNode* nodeParent = node->parent();
215     ProfileNode* nodeSibling = node->nextSibling();
216     node->setParent(0);
217     node->setNextSibling(0);
218
219     for (ProfileNode* currentNode = node; currentNode; currentNode = currentNode->traverseNextNodePreOrder())
220         currentNode->setVisible(visible);
221
222     node->setParent(nodeParent);
223     node->setNextSibling(nodeSibling);
224 }
225
226 void ProfileNode::calculateVisibleTotalTime()
227 {
228     double sumOfVisibleChildrensTime = 0.0;
229
230     for (unsigned i = 0; i < m_children.size(); ++i) {
231         if (m_children[i]->visible())
232             sumOfVisibleChildrensTime += m_children[i]->totalTime();
233     }
234
235     m_visibleTotalTime = m_visibleSelfTime + sumOfVisibleChildrensTime;
236 }
237
238 bool ProfileNode::focus(const CallIdentifier& callIdentifier)
239 {
240     if (!m_visible)
241         return false;
242
243     if (m_callIdentifier != callIdentifier) {
244         m_visible = false;
245         return true;
246     }
247
248     for (ProfileNode* currentParent = m_parent; currentParent; currentParent = currentParent->parent())
249         currentParent->setVisible(true);
250
251     return false;
252 }
253
254 void ProfileNode::exclude(const CallIdentifier& callIdentifier)
255 {
256     if (m_visible && m_callIdentifier == callIdentifier) {
257         setTreeVisible(this, false);
258
259         m_parent->setVisibleSelfTime(m_parent->selfTime() + m_visibleTotalTime);
260     }
261 }
262
263 void ProfileNode::restore()
264 {
265     m_visibleTotalTime = m_actualTotalTime;
266     m_visibleSelfTime = m_actualSelfTime;
267     m_visible = true;
268 }
269
270 void ProfileNode::endAndRecordCall()
271 {
272     m_actualTotalTime += m_startTime ? getCount() - m_startTime : 0.0;
273     m_startTime = 0.0;
274
275     ++m_numberOfCalls;
276 }
277
278 void ProfileNode::startTimer()
279 {
280     if (!m_startTime)
281         m_startTime = getCount();
282 }
283
284 void ProfileNode::resetChildrensSiblings()
285 {
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());
289 }
290
291 #ifndef NDEBUG
292 void ProfileNode::debugPrintData(int indentLevel) const
293 {
294     // Print function names
295     for (int i = 0; i < indentLevel; ++i)
296         printf("  ");
297
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() : "");
304
305     ++indentLevel;
306
307     // Print children's names and information
308     for (StackIterator currentChild = m_children.begin(); currentChild != m_children.end(); ++currentChild)
309         (*currentChild)->debugPrintData(indentLevel);
310 }
311
312 // print the profiled data in a format that matches the tool sample's output.
313 double ProfileNode::debugPrintDataSampleStyle(int indentLevel, FunctionCallHashCount& countedFunctions) const
314 {
315     printf("    ");
316
317     // Print function names
318     const char* name = functionName().utf8().data();
319     double sampleCount = m_actualTotalTime * 1000;
320     if (indentLevel) {
321         for (int i = 0; i < indentLevel; ++i)
322             printf("  ");
323
324          countedFunctions.add(functionName().impl());
325
326         printf("%.0f %s\n", sampleCount ? sampleCount : 1, name);
327     } else
328         printf("%s\n", name);
329
330     ++indentLevel;
331
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);
336
337     sumOfChildrensCount *= 1000;    //
338     // Print remainder of samples to match sample's output
339     if (sumOfChildrensCount < sampleCount) {
340         printf("    ");
341         while (indentLevel--)
342             printf("  ");
343
344         printf("%.0f %s\n", sampleCount - sumOfChildrensCount, functionName().utf8().data());
345     }
346
347     return m_actualTotalTime;
348 }
349 #endif
350
351 } // namespace JSC