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 352