1/* 2 * Copyright (C) 2008, 2014 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 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 "LegacyProfiler.h" 33#include <wtf/DateMath.h> 34#include <wtf/DataLog.h> 35#include <wtf/text/StringHash.h> 36 37using namespace WTF; 38 39namespace JSC { 40 41ProfileNode::ProfileNode(ExecState* callerCallFrame, const CallIdentifier& callIdentifier, ProfileNode* headNode, ProfileNode* parentNode) 42 : m_callerCallFrame(callerCallFrame) 43 , m_callIdentifier(callIdentifier) 44 , m_head(headNode) 45 , m_parent(parentNode) 46 , m_nextSibling(nullptr) 47 , m_totalTime(0) 48 , m_selfTime(0) 49{ 50 startTimer(); 51} 52 53ProfileNode::ProfileNode(ExecState* callerCallFrame, ProfileNode* headNode, ProfileNode* nodeToCopy) 54 : m_callerCallFrame(callerCallFrame) 55 , m_callIdentifier(nodeToCopy->callIdentifier()) 56 , m_head(headNode) 57 , m_parent(nodeToCopy->parent()) 58 , m_nextSibling(0) 59 , m_totalTime(nodeToCopy->totalTime()) 60 , m_selfTime(nodeToCopy->selfTime()) 61 , m_calls(nodeToCopy->calls()) 62{ 63} 64 65ProfileNode* ProfileNode::willExecute(ExecState* callerCallFrame, const CallIdentifier& callIdentifier) 66{ 67 for (StackIterator currentChild = m_children.begin(); currentChild != m_children.end(); ++currentChild) { 68 if ((*currentChild)->callIdentifier() == callIdentifier) { 69 (*currentChild)->startTimer(); 70 return (*currentChild).get(); 71 } 72 } 73 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(); 79} 80 81ProfileNode* ProfileNode::didExecute() 82{ 83 endAndRecordCall(); 84 return m_parent; 85} 86 87void ProfileNode::addChild(PassRefPtr<ProfileNode> prpChild) 88{ 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()); 94} 95 96void ProfileNode::removeChild(ProfileNode* node) 97{ 98 if (!node) 99 return; 100 101 for (size_t i = 0; i < m_children.size(); ++i) { 102 if (*node == m_children[i].get()) { 103 m_children.remove(i); 104 break; 105 } 106 } 107 108 resetChildrensSiblings(); 109} 110 111void ProfileNode::insertNode(PassRefPtr<ProfileNode> prpNode) 112{ 113 RefPtr<ProfileNode> node = prpNode; 114 115 for (unsigned i = 0; i < m_children.size(); ++i) 116 node->addChild(m_children[i].release()); 117 118 m_children.clear(); 119 m_children.append(node.release()); 120} 121 122void ProfileNode::stopProfiling() 123{ 124 ASSERT(!m_calls.isEmpty()); 125 126 if (isnan(m_calls.last().totalTime())) 127 endAndRecordCall(); 128 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(); 132 133 ASSERT(m_selfTime <= m_totalTime); 134 m_selfTime = m_totalTime - m_selfTime; 135} 136 137ProfileNode* ProfileNode::traverseNextNodePostOrder() const 138{ 139 ProfileNode* next = m_nextSibling; 140 if (!next) 141 return m_parent; 142 while (ProfileNode* firstChild = next->firstChild()) 143 next = firstChild; 144 return next; 145} 146 147void ProfileNode::endAndRecordCall() 148{ 149 Call& last = lastCall(); 150 ASSERT(isnan(last.totalTime())); 151 152 last.setTotalTime(currentTime() - last.startTime()); 153 154 m_totalTime += last.totalTime(); 155} 156 157void ProfileNode::startTimer() 158{ 159 m_calls.append(Call(currentTime())); 160} 161 162void ProfileNode::resetChildrensSiblings() 163{ 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()); 167} 168 169#ifndef NDEBUG 170void ProfileNode::debugPrintData(int indentLevel) const 171{ 172 // Print function names 173 for (int i = 0; i < indentLevel; ++i) 174 dataLogF(" "); 175 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() : ""); 180 181 ++indentLevel; 182 183 // Print children's names and information 184 for (StackIterator currentChild = m_children.begin(); currentChild != m_children.end(); ++currentChild) 185 (*currentChild)->debugPrintData(indentLevel); 186} 187 188// print the profiled data in a format that matches the tool sample's output. 189double ProfileNode::debugPrintDataSampleStyle(int indentLevel, FunctionCallHashCount& countedFunctions) const 190{ 191 dataLogF(" "); 192 193 // Print function names 194 const char* name = functionName().utf8().data(); 195 double sampleCount = m_totalTime * 1000; 196 if (indentLevel) { 197 for (int i = 0; i < indentLevel; ++i) 198 dataLogF(" "); 199 200 countedFunctions.add(functionName().impl()); 201 202 dataLogF("%.0f %s\n", sampleCount ? sampleCount : 1, name); 203 } else 204 dataLogF("%s\n", name); 205 206 ++indentLevel; 207 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); 212 213 sumOfChildrensCount *= 1000; // 214 // Print remainder of samples to match sample's output 215 if (sumOfChildrensCount < sampleCount) { 216 dataLogF(" "); 217 while (indentLevel--) 218 dataLogF(" "); 219 220 dataLogF("%.0f %s\n", sampleCount - sumOfChildrensCount, functionName().utf8().data()); 221 } 222 223 return m_totalTime; 224} 225#endif 226 227} // namespace JSC 228