JavaScriptCore/profiler/ProfileNode.cpp
changeset 0 4f2f89ce4247
equal deleted inserted replaced
-1:000000000000 0:4f2f89ce4247
       
     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(const CallIdentifier& callIdentifier, ProfileNode* headNode, ProfileNode* parentNode)
       
    60     : m_callIdentifier(callIdentifier)
       
    61     , m_head(headNode)
       
    62     , m_parent(parentNode)
       
    63     , m_nextSibling(0)
       
    64     , m_startTime(0.0)
       
    65     , m_actualTotalTime(0.0)
       
    66     , m_visibleTotalTime(0.0)
       
    67     , m_actualSelfTime(0.0)
       
    68     , m_visibleSelfTime(0.0)
       
    69     , m_numberOfCalls(0)
       
    70     , m_visible(true)
       
    71 {
       
    72     startTimer();
       
    73 }
       
    74 
       
    75 ProfileNode::ProfileNode(ProfileNode* headNode, ProfileNode* nodeToCopy)
       
    76     : m_callIdentifier(nodeToCopy->callIdentifier())
       
    77     , m_head(headNode)
       
    78     , m_parent(nodeToCopy->parent())
       
    79     , m_nextSibling(0)
       
    80     , m_startTime(0.0)
       
    81     , m_actualTotalTime(nodeToCopy->actualTotalTime())
       
    82     , m_visibleTotalTime(nodeToCopy->totalTime())
       
    83     , m_actualSelfTime(nodeToCopy->actualSelfTime())
       
    84     , m_visibleSelfTime(nodeToCopy->selfTime())
       
    85     , m_numberOfCalls(nodeToCopy->numberOfCalls())
       
    86     , m_visible(nodeToCopy->visible())
       
    87 {
       
    88 }
       
    89 
       
    90 ProfileNode* ProfileNode::willExecute(const CallIdentifier& callIdentifier)
       
    91 {
       
    92     for (StackIterator currentChild = m_children.begin(); currentChild != m_children.end(); ++currentChild) {
       
    93         if ((*currentChild)->callIdentifier() == callIdentifier) {
       
    94             (*currentChild)->startTimer();
       
    95             return (*currentChild).get();
       
    96         }
       
    97     }
       
    98 
       
    99     RefPtr<ProfileNode> newChild = ProfileNode::create(callIdentifier, m_head ? m_head : this, this); // If this ProfileNode has no head it is the head.
       
   100     if (m_children.size())
       
   101         m_children.last()->setNextSibling(newChild.get());
       
   102     m_children.append(newChild.release());
       
   103     return m_children.last().get();
       
   104 }
       
   105 
       
   106 ProfileNode* ProfileNode::didExecute()
       
   107 {
       
   108     endAndRecordCall();
       
   109     return m_parent;
       
   110 }
       
   111 
       
   112 void ProfileNode::addChild(PassRefPtr<ProfileNode> prpChild)
       
   113 {
       
   114     RefPtr<ProfileNode> child = prpChild;
       
   115     child->setParent(this);
       
   116     if (m_children.size())
       
   117         m_children.last()->setNextSibling(child.get());
       
   118     m_children.append(child.release());
       
   119 }
       
   120 
       
   121 ProfileNode* ProfileNode::findChild(ProfileNode* node) const
       
   122 {
       
   123     if (!node)
       
   124         return 0;
       
   125 
       
   126     for (size_t i = 0; i < m_children.size(); ++i) {
       
   127         if (*node == m_children[i].get())
       
   128             return m_children[i].get();
       
   129     }
       
   130 
       
   131     return 0;
       
   132 }
       
   133 
       
   134 void ProfileNode::removeChild(ProfileNode* node)
       
   135 {
       
   136     if (!node)
       
   137         return;
       
   138 
       
   139     for (size_t i = 0; i < m_children.size(); ++i) {
       
   140         if (*node == m_children[i].get()) {
       
   141             m_children.remove(i);
       
   142             break;
       
   143         }
       
   144     }
       
   145     
       
   146     resetChildrensSiblings();
       
   147 }
       
   148 
       
   149 void ProfileNode::insertNode(PassRefPtr<ProfileNode> prpNode)
       
   150 {
       
   151     RefPtr<ProfileNode> node = prpNode;
       
   152 
       
   153     for (unsigned i = 0; i < m_children.size(); ++i)
       
   154         node->addChild(m_children[i].release());
       
   155 
       
   156     m_children.clear();
       
   157     m_children.append(node.release());
       
   158 }
       
   159 
       
   160 void ProfileNode::stopProfiling()
       
   161 {
       
   162     if (m_startTime)
       
   163         endAndRecordCall();
       
   164 
       
   165     m_visibleTotalTime = m_actualTotalTime;
       
   166 
       
   167     ASSERT(m_actualSelfTime == 0.0 && m_startTime == 0.0);
       
   168 
       
   169     // Because we iterate in post order all of our children have been stopped before us.
       
   170     for (unsigned i = 0; i < m_children.size(); ++i)
       
   171         m_actualSelfTime += m_children[i]->totalTime();
       
   172 
       
   173     ASSERT(m_actualSelfTime <= m_actualTotalTime);
       
   174     m_actualSelfTime = m_actualTotalTime - m_actualSelfTime;
       
   175     m_visibleSelfTime = m_actualSelfTime;
       
   176 }
       
   177 
       
   178 ProfileNode* ProfileNode::traverseNextNodePostOrder() const
       
   179 {
       
   180     ProfileNode* next = m_nextSibling;
       
   181     if (!next)
       
   182         return m_parent;
       
   183     while (ProfileNode* firstChild = next->firstChild())
       
   184         next = firstChild;
       
   185     return next;
       
   186 }
       
   187 
       
   188 ProfileNode* ProfileNode::traverseNextNodePreOrder(bool processChildren) const
       
   189 {
       
   190     if (processChildren && m_children.size())
       
   191         return m_children[0].get();
       
   192 
       
   193     if (m_nextSibling)
       
   194         return m_nextSibling;
       
   195 
       
   196     ProfileNode* nextParent = m_parent;
       
   197     if (!nextParent)
       
   198         return 0;
       
   199 
       
   200     ProfileNode* next;
       
   201     for (next = m_parent->nextSibling(); !next; next = nextParent->nextSibling()) {
       
   202         nextParent = nextParent->parent();
       
   203         if (!nextParent)
       
   204             return 0;
       
   205     }
       
   206 
       
   207     return next;
       
   208 }
       
   209 
       
   210 void ProfileNode::setTreeVisible(ProfileNode* node, bool visible)
       
   211 {
       
   212     ProfileNode* nodeParent = node->parent();
       
   213     ProfileNode* nodeSibling = node->nextSibling();
       
   214     node->setParent(0);
       
   215     node->setNextSibling(0);
       
   216 
       
   217     for (ProfileNode* currentNode = node; currentNode; currentNode = currentNode->traverseNextNodePreOrder())
       
   218         currentNode->setVisible(visible);
       
   219 
       
   220     node->setParent(nodeParent);
       
   221     node->setNextSibling(nodeSibling);
       
   222 }
       
   223 
       
   224 void ProfileNode::calculateVisibleTotalTime()
       
   225 {
       
   226     double sumOfVisibleChildrensTime = 0.0;
       
   227 
       
   228     for (unsigned i = 0; i < m_children.size(); ++i) {
       
   229         if (m_children[i]->visible())
       
   230             sumOfVisibleChildrensTime += m_children[i]->totalTime();
       
   231     }
       
   232 
       
   233     m_visibleTotalTime = m_visibleSelfTime + sumOfVisibleChildrensTime;
       
   234 }
       
   235 
       
   236 bool ProfileNode::focus(const CallIdentifier& callIdentifier)
       
   237 {
       
   238     if (!m_visible)
       
   239         return false;
       
   240 
       
   241     if (m_callIdentifier != callIdentifier) {
       
   242         m_visible = false;
       
   243         return true;
       
   244     }
       
   245 
       
   246     for (ProfileNode* currentParent = m_parent; currentParent; currentParent = currentParent->parent())
       
   247         currentParent->setVisible(true);
       
   248 
       
   249     return false;
       
   250 }
       
   251 
       
   252 void ProfileNode::exclude(const CallIdentifier& callIdentifier)
       
   253 {
       
   254     if (m_visible && m_callIdentifier == callIdentifier) {
       
   255         setTreeVisible(this, false);
       
   256 
       
   257         m_parent->setVisibleSelfTime(m_parent->selfTime() + m_visibleTotalTime);
       
   258     }
       
   259 }
       
   260 
       
   261 void ProfileNode::restore()
       
   262 {
       
   263     m_visibleTotalTime = m_actualTotalTime;
       
   264     m_visibleSelfTime = m_actualSelfTime;
       
   265     m_visible = true;
       
   266 }
       
   267 
       
   268 void ProfileNode::endAndRecordCall()
       
   269 {
       
   270     m_actualTotalTime += m_startTime ? getCount() - m_startTime : 0.0;
       
   271     m_startTime = 0.0;
       
   272 
       
   273     ++m_numberOfCalls;
       
   274 }
       
   275 
       
   276 void ProfileNode::startTimer()
       
   277 {
       
   278     if (!m_startTime)
       
   279         m_startTime = getCount();
       
   280 }
       
   281 
       
   282 void ProfileNode::resetChildrensSiblings()
       
   283 {
       
   284     unsigned size = m_children.size();
       
   285     for (unsigned i = 0; i < size; ++i)
       
   286         m_children[i]->setNextSibling(i + 1 == size ? 0 : m_children[i + 1].get());
       
   287 }
       
   288 
       
   289 #ifndef NDEBUG
       
   290 void ProfileNode::debugPrintData(int indentLevel) const
       
   291 {
       
   292     // Print function names
       
   293     for (int i = 0; i < indentLevel; ++i)
       
   294         printf("  ");
       
   295 
       
   296     printf("Function Name %s %d SelfTime %.3fms/%.3f%% TotalTime %.3fms/%.3f%% VSelf %.3fms VTotal %.3fms Visible %s Next Sibling %s\n",
       
   297         functionName().UTF8String().data(), 
       
   298         m_numberOfCalls, m_actualSelfTime, selfPercent(), m_actualTotalTime, totalPercent(),
       
   299         m_visibleSelfTime, m_visibleTotalTime, 
       
   300         (m_visible ? "True" : "False"),
       
   301         m_nextSibling ? m_nextSibling->functionName().UTF8String().data() : "");
       
   302 
       
   303     ++indentLevel;
       
   304 
       
   305     // Print children's names and information
       
   306     for (StackIterator currentChild = m_children.begin(); currentChild != m_children.end(); ++currentChild)
       
   307         (*currentChild)->debugPrintData(indentLevel);
       
   308 }
       
   309 
       
   310 // print the profiled data in a format that matches the tool sample's output.
       
   311 double ProfileNode::debugPrintDataSampleStyle(int indentLevel, FunctionCallHashCount& countedFunctions) const
       
   312 {
       
   313     printf("    ");
       
   314 
       
   315     // Print function names
       
   316     const char* name = functionName().UTF8String().data();
       
   317     double sampleCount = m_actualTotalTime * 1000;
       
   318     if (indentLevel) {
       
   319         for (int i = 0; i < indentLevel; ++i)
       
   320             printf("  ");
       
   321 
       
   322          countedFunctions.add(functionName().rep());
       
   323 
       
   324         printf("%.0f %s\n", sampleCount ? sampleCount : 1, name);
       
   325     } else
       
   326         printf("%s\n", name);
       
   327 
       
   328     ++indentLevel;
       
   329 
       
   330     // Print children's names and information
       
   331     double sumOfChildrensCount = 0.0;
       
   332     for (StackIterator currentChild = m_children.begin(); currentChild != m_children.end(); ++currentChild)
       
   333         sumOfChildrensCount += (*currentChild)->debugPrintDataSampleStyle(indentLevel, countedFunctions);
       
   334 
       
   335     sumOfChildrensCount *= 1000;    //
       
   336     // Print remainder of samples to match sample's output
       
   337     if (sumOfChildrensCount < sampleCount) {
       
   338         printf("    ");
       
   339         while (indentLevel--)
       
   340             printf("  ");
       
   341 
       
   342         printf("%.0f %s\n", sampleCount - sumOfChildrensCount, functionName().UTF8String().data());
       
   343     }
       
   344 
       
   345     return m_actualTotalTime;
       
   346 }
       
   347 #endif
       
   348 
       
   349 } // namespace JSC