Home | History | Annotate | Download | only in profiler
      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