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
* parentNode
)
42 : m_callerCallFrame(callerCallFrame
)
43 , m_callIdentifier(callIdentifier
)
44 , m_parent(parentNode
)
46 , m_nextSibling(nullptr)
51 ProfileNode::ProfileNode(ExecState
* callerCallFrame
, ProfileNode
* nodeToCopy
)
52 : m_callerCallFrame(callerCallFrame
)
53 , m_callIdentifier(nodeToCopy
->callIdentifier())
54 , m_parent(nodeToCopy
->parent())
55 , m_calls(nodeToCopy
->calls())
57 , m_nextSibling(nullptr)
62 void ProfileNode::addChild(PassRefPtr
<ProfileNode
> prpChild
)
64 RefPtr
<ProfileNode
> child
= prpChild
;
65 child
->setParent(this);
67 if (m_children
.size())
68 m_children
.last()->setNextSibling(child
.get());
70 m_children
.append(child
.release());
73 void ProfileNode::removeChild(ProfileNode
* node
)
78 m_children
.removeFirstMatching([node
] (const RefPtr
<ProfileNode
>& current
) {
79 return *node
== current
.get();
83 size_t size
= m_children
.size();
84 for (size_t i
= 0; i
< size
; ++i
)
85 m_children
[i
]->setNextSibling(i
+ 1 == size
? nullptr : m_children
[i
+ 1].get());
89 void ProfileNode::spliceNode(PassRefPtr
<ProfileNode
> prpNode
)
91 RefPtr
<ProfileNode
> node
= prpNode
;
93 for (unsigned i
= 0; i
< m_children
.size(); ++i
)
94 node
->addChild(m_children
[i
].release());
97 m_children
.append(node
.release());
101 ProfileNode
* ProfileNode::traverseNextNodePostOrder() const
103 ProfileNode
* next
= m_nextSibling
;
106 while (ProfileNode
* firstChild
= next
->firstChild())
111 void ProfileNode::debugPrint()
113 CalculateProfileSubtreeDataFunctor functor
;
114 forEachNodePostorder(functor
);
115 ProfileNode::ProfileSubtreeData data
= functor
.returnValue();
117 debugPrintRecursively(0, data
);
120 void ProfileNode::debugPrintSampleStyle()
122 FunctionCallHashCount countedFunctions
;
124 CalculateProfileSubtreeDataFunctor functor
;
125 forEachNodePostorder(functor
);
126 ProfileNode::ProfileSubtreeData data
= functor
.returnValue();
128 debugPrintSampleStyleRecursively(0, countedFunctions
, data
);
131 void ProfileNode::debugPrintRecursively(int indentLevel
, const ProfileSubtreeData
& data
)
133 // Print function names
134 for (int i
= 0; i
< indentLevel
; ++i
)
137 auto it
= data
.selfAndTotalTimes
.find(this);
138 ASSERT(it
!= data
.selfAndTotalTimes
.end());
140 double nodeSelfTime
= it
->value
.first
;
141 double nodeTotalTime
= it
->value
.second
;
142 double rootTotalTime
= data
.rootTotalTime
;
144 dataLogF("Function Name %s %zu SelfTime %.3fms/%.3f%% TotalTime %.3fms/%.3f%% Next Sibling %s\n",
145 functionName().utf8().data(),
146 m_calls
.size(), nodeSelfTime
, nodeSelfTime
/ rootTotalTime
* 100.0, nodeTotalTime
, nodeTotalTime
/ rootTotalTime
* 100.0,
147 m_nextSibling
? m_nextSibling
->functionName().utf8().data() : "");
151 // Print children's names and information
152 for (StackIterator currentChild
= m_children
.begin(); currentChild
!= m_children
.end(); ++currentChild
)
153 (*currentChild
)->debugPrintRecursively(indentLevel
, data
);
156 // print the profiled data in a format that matches the tool sample's output.
157 double ProfileNode::debugPrintSampleStyleRecursively(int indentLevel
, FunctionCallHashCount
& countedFunctions
, const ProfileSubtreeData
& data
)
161 auto it
= data
.selfAndTotalTimes
.find(this);
162 ASSERT(it
!= data
.selfAndTotalTimes
.end());
163 double nodeTotalTime
= it
->value
.second
;
165 // Print function names
166 const char* name
= functionName().utf8().data();
167 double sampleCount
= nodeTotalTime
* 1000;
169 for (int i
= 0; i
< indentLevel
; ++i
)
172 countedFunctions
.add(functionName().impl());
174 dataLogF("%.0f %s\n", sampleCount
? sampleCount
: 1, name
);
176 dataLogF("%s\n", name
);
180 // Print children's names and information
181 double sumOfChildrensCount
= 0.0;
182 for (StackIterator currentChild
= m_children
.begin(); currentChild
!= m_children
.end(); ++currentChild
)
183 sumOfChildrensCount
+= (*currentChild
)->debugPrintSampleStyleRecursively(indentLevel
, countedFunctions
, data
);
185 sumOfChildrensCount
*= 1000; //
186 // Print remainder of samples to match sample's output
187 if (sumOfChildrensCount
< sampleCount
) {
189 while (indentLevel
--)
192 dataLogF("%.0f %s\n", sampleCount
- sumOfChildrensCount
, functionName().utf8().data());
195 return nodeTotalTime
;