2 * Copyright (C) 2008, 2014 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 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"
32 #include "LegacyProfiler.h"
33 #include <wtf/DateMath.h>
34 #include <wtf/DataLog.h>
35 #include <wtf/text/StringHash.h>
41 ProfileNode::ProfileNode(ExecState
* callerCallFrame
, const CallIdentifier
& callIdentifier
, ProfileNode
* headNode
, ProfileNode
* parentNode
)
42 : m_callerCallFrame(callerCallFrame
)
43 , m_callIdentifier(callIdentifier
)
45 , m_parent(parentNode
)
46 , m_nextSibling(nullptr)
53 ProfileNode::ProfileNode(ExecState
* callerCallFrame
, ProfileNode
* headNode
, ProfileNode
* nodeToCopy
)
54 : m_callerCallFrame(callerCallFrame
)
55 , m_callIdentifier(nodeToCopy
->callIdentifier())
57 , m_parent(nodeToCopy
->parent())
59 , m_totalTime(nodeToCopy
->totalTime())
60 , m_selfTime(nodeToCopy
->selfTime())
61 , m_calls(nodeToCopy
->calls())
65 ProfileNode
* ProfileNode::willExecute(ExecState
* callerCallFrame
, const CallIdentifier
& callIdentifier
)
67 for (StackIterator currentChild
= m_children
.begin(); currentChild
!= m_children
.end(); ++currentChild
) {
68 if ((*currentChild
)->callIdentifier() == callIdentifier
) {
69 (*currentChild
)->startTimer();
70 return (*currentChild
).get();
74 RefPtr
<ProfileNode
> newChild
= ProfileNode::create(callerCallFrame
, callIdentifier
, m_head
? m_head
: this, this); // If this ProfileNode has no head it is the head.
75 if (m_children
.size())
76 m_children
.last()->setNextSibling(newChild
.get());
77 m_children
.append(newChild
.release());
78 return m_children
.last().get();
81 ProfileNode
* ProfileNode::didExecute()
87 void ProfileNode::addChild(PassRefPtr
<ProfileNode
> prpChild
)
89 RefPtr
<ProfileNode
> child
= prpChild
;
90 child
->setParent(this);
91 if (m_children
.size())
92 m_children
.last()->setNextSibling(child
.get());
93 m_children
.append(child
.release());
96 void ProfileNode::removeChild(ProfileNode
* node
)
101 for (size_t i
= 0; i
< m_children
.size(); ++i
) {
102 if (*node
== m_children
[i
].get()) {
103 m_children
.remove(i
);
108 resetChildrensSiblings();
111 void ProfileNode::insertNode(PassRefPtr
<ProfileNode
> prpNode
)
113 RefPtr
<ProfileNode
> node
= prpNode
;
115 for (unsigned i
= 0; i
< m_children
.size(); ++i
)
116 node
->addChild(m_children
[i
].release());
119 m_children
.append(node
.release());
122 void ProfileNode::stopProfiling()
124 ASSERT(!m_calls
.isEmpty());
126 if (isnan(m_calls
.last().totalTime()))
129 // Because we iterate in post order all of our children have been stopped before us.
130 for (unsigned i
= 0; i
< m_children
.size(); ++i
)
131 m_selfTime
+= m_children
[i
]->totalTime();
133 ASSERT(m_selfTime
<= m_totalTime
);
134 m_selfTime
= m_totalTime
- m_selfTime
;
137 ProfileNode
* ProfileNode::traverseNextNodePostOrder() const
139 ProfileNode
* next
= m_nextSibling
;
142 while (ProfileNode
* firstChild
= next
->firstChild())
147 void ProfileNode::endAndRecordCall()
149 Call
& last
= lastCall();
150 ASSERT(isnan(last
.totalTime()));
152 last
.setTotalTime(currentTime() - last
.startTime());
154 m_totalTime
+= last
.totalTime();
157 void ProfileNode::startTimer()
159 m_calls
.append(Call(currentTime()));
162 void ProfileNode::resetChildrensSiblings()
164 unsigned size
= m_children
.size();
165 for (unsigned i
= 0; i
< size
; ++i
)
166 m_children
[i
]->setNextSibling(i
+ 1 == size
? 0 : m_children
[i
+ 1].get());
170 void ProfileNode::debugPrintData(int indentLevel
) const
172 // Print function names
173 for (int i
= 0; i
< indentLevel
; ++i
)
176 dataLogF("Function Name %s %zu SelfTime %.3fms/%.3f%% TotalTime %.3fms/%.3f%% Next Sibling %s\n",
177 functionName().utf8().data(),
178 numberOfCalls(), m_selfTime
, selfPercent(), m_totalTime
, totalPercent(),
179 m_nextSibling
? m_nextSibling
->functionName().utf8().data() : "");
183 // Print children's names and information
184 for (StackIterator currentChild
= m_children
.begin(); currentChild
!= m_children
.end(); ++currentChild
)
185 (*currentChild
)->debugPrintData(indentLevel
);
188 // print the profiled data in a format that matches the tool sample's output.
189 double ProfileNode::debugPrintDataSampleStyle(int indentLevel
, FunctionCallHashCount
& countedFunctions
) const
193 // Print function names
194 const char* name
= functionName().utf8().data();
195 double sampleCount
= m_totalTime
* 1000;
197 for (int i
= 0; i
< indentLevel
; ++i
)
200 countedFunctions
.add(functionName().impl());
202 dataLogF("%.0f %s\n", sampleCount
? sampleCount
: 1, name
);
204 dataLogF("%s\n", name
);
208 // Print children's names and information
209 double sumOfChildrensCount
= 0.0;
210 for (StackIterator currentChild
= m_children
.begin(); currentChild
!= m_children
.end(); ++currentChild
)
211 sumOfChildrensCount
+= (*currentChild
)->debugPrintDataSampleStyle(indentLevel
, countedFunctions
);
213 sumOfChildrensCount
*= 1000; //
214 // Print remainder of samples to match sample's output
215 if (sumOfChildrensCount
< sampleCount
) {
217 while (indentLevel
--)
220 dataLogF("%.0f %s\n", sampleCount
- sumOfChildrensCount
, functionName().utf8().data());