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  * 1. Redistributions of source code must retain the above copyright
      8  *    notice, this list of conditions and the following disclaimer.
      9  * 2. Redistributions in binary form must reproduce the above copyright
     10  *    notice, this list of conditions and the following disclaimer in the
     11  *    documentation and/or other materials provided with the distribution.
     12  *
     13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
     14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
     17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     24  */
     25 
     26 #include "config.h"
     27 #include "ProfileGenerator.h"
     28 
     29 #include "CallFrame.h"
     30 #include "CodeBlock.h"
     31 #include "JSGlobalObject.h"
     32 #include "JSStringRef.h"
     33 #include "JSFunction.h"
     34 #include "Interpreter.h"
     35 #include "Profile.h"
     36 #include "Profiler.h"
     37 #include "Tracing.h"
     38 
     39 namespace JSC {
     40 
     41 static const char* NonJSExecution = "(idle)";
     42 
     43 PassRefPtr<ProfileGenerator> ProfileGenerator::create(ExecState* exec, const UString& title, unsigned uid)
     44 {
     45     return adoptRef(new ProfileGenerator(exec, title, uid));
     46 }
     47 
     48 ProfileGenerator::ProfileGenerator(ExecState* exec, const UString& title, unsigned uid)
     49     : m_origin(exec ? exec->lexicalGlobalObject() : 0)
     50     , m_profileGroup(exec ? exec->lexicalGlobalObject()->profileGroup() : 0)
     51 {
     52     m_profile = Profile::create(title, uid);
     53     m_currentNode = m_head = m_profile->head();
     54     if (exec)
     55         addParentForConsoleStart(exec);
     56 }
     57 
     58 void ProfileGenerator::addParentForConsoleStart(ExecState* exec)
     59 {
     60     int lineNumber;
     61     intptr_t sourceID;
     62     UString sourceURL;
     63     JSValue function;
     64 
     65     exec->interpreter()->retrieveLastCaller(exec, lineNumber, sourceID, sourceURL, function);
     66     m_currentNode = ProfileNode::create(exec, Profiler::createCallIdentifier(exec, function ? function.toThisObject(exec) : 0, sourceURL, lineNumber), m_head.get(), m_head.get());
     67     m_head->insertNode(m_currentNode.get());
     68 }
     69 
     70 const UString& ProfileGenerator::title() const
     71 {
     72     return m_profile->title();
     73 }
     74 
     75 void ProfileGenerator::willExecute(ExecState* callerCallFrame, const CallIdentifier& callIdentifier)
     76 {
     77     if (JAVASCRIPTCORE_PROFILE_WILL_EXECUTE_ENABLED()) {
     78         CString name = callIdentifier.m_name.utf8();
     79         CString url = callIdentifier.m_url.utf8();
     80         JAVASCRIPTCORE_PROFILE_WILL_EXECUTE(m_profileGroup, const_cast<char*>(name.data()), const_cast<char*>(url.data()), callIdentifier.m_lineNumber);
     81     }
     82 
     83     if (!m_origin)
     84         return;
     85 
     86     ASSERT(m_currentNode);
     87     m_currentNode = m_currentNode->willExecute(callerCallFrame, callIdentifier);
     88 }
     89 
     90 void ProfileGenerator::didExecute(ExecState* callerCallFrame, const CallIdentifier& callIdentifier)
     91 {
     92     if (JAVASCRIPTCORE_PROFILE_DID_EXECUTE_ENABLED()) {
     93         CString name = callIdentifier.m_name.utf8();
     94         CString url = callIdentifier.m_url.utf8();
     95         JAVASCRIPTCORE_PROFILE_DID_EXECUTE(m_profileGroup, const_cast<char*>(name.data()), const_cast<char*>(url.data()), callIdentifier.m_lineNumber);
     96     }
     97 
     98     if (!m_origin)
     99         return;
    100 
    101     ASSERT(m_currentNode);
    102     if (m_currentNode->callIdentifier() != callIdentifier) {
    103         RefPtr<ProfileNode> returningNode = ProfileNode::create(callerCallFrame, callIdentifier, m_head.get(), m_currentNode.get());
    104         returningNode->setStartTime(m_currentNode->startTime());
    105         returningNode->didExecute();
    106         m_currentNode->insertNode(returningNode.release());
    107         return;
    108     }
    109 
    110     m_currentNode = m_currentNode->didExecute();
    111 }
    112 
    113 void ProfileGenerator::exceptionUnwind(ExecState* handlerCallFrame, const CallIdentifier&)
    114 {
    115     // If the current node was called by the handler (==) or any
    116     // more nested function (>) the we have exited early from it.
    117     ASSERT(m_currentNode);
    118     while (m_currentNode->callerCallFrame() >= handlerCallFrame) {
    119         didExecute(m_currentNode->callerCallFrame(), m_currentNode->callIdentifier());
    120         ASSERT(m_currentNode);
    121     }
    122 }
    123 
    124 void ProfileGenerator::stopProfiling()
    125 {
    126     m_profile->forEach(&ProfileNode::stopProfiling);
    127 
    128     removeProfileStart();
    129     removeProfileEnd();
    130 
    131     ASSERT(m_currentNode);
    132 
    133     // Set the current node to the parent, because we are in a call that
    134     // will not get didExecute call.
    135     m_currentNode = m_currentNode->parent();
    136 
    137    if (double headSelfTime = m_head->selfTime()) {
    138         RefPtr<ProfileNode> idleNode = ProfileNode::create(0, CallIdentifier(NonJSExecution, UString(), 0), m_head.get(), m_head.get());
    139 
    140         idleNode->setTotalTime(headSelfTime);
    141         idleNode->setSelfTime(headSelfTime);
    142         idleNode->setVisible(true);
    143 
    144         m_head->setSelfTime(0.0);
    145         m_head->addChild(idleNode.release());
    146     }
    147 }
    148 
    149 // The console.ProfileGenerator that started this ProfileGenerator will be the first child.
    150 void ProfileGenerator::removeProfileStart()
    151 {
    152     ProfileNode* currentNode = 0;
    153     for (ProfileNode* next = m_head.get(); next; next = next->firstChild())
    154         currentNode = next;
    155 
    156     if (currentNode->callIdentifier().m_name != "profile")
    157         return;
    158 
    159     // Attribute the time of the node aobut to be removed to the self time of its parent
    160     currentNode->parent()->setSelfTime(currentNode->parent()->selfTime() + currentNode->totalTime());
    161     currentNode->parent()->removeChild(currentNode);
    162 }
    163 
    164 // The console.ProfileGeneratorEnd that stopped this ProfileGenerator will be the last child.
    165 void ProfileGenerator::removeProfileEnd()
    166 {
    167     ProfileNode* currentNode = 0;
    168     for (ProfileNode* next = m_head.get(); next; next = next->lastChild())
    169         currentNode = next;
    170 
    171     if (currentNode->callIdentifier().m_name != "profileEnd")
    172         return;
    173 
    174     // Attribute the time of the node aobut to be removed to the self time of its parent
    175     currentNode->parent()->setSelfTime(currentNode->parent()->selfTime() + currentNode->totalTime());
    176 
    177     ASSERT(currentNode->callIdentifier() == (currentNode->parent()->children()[currentNode->parent()->children().size() - 1])->callIdentifier());
    178     currentNode->parent()->removeChild(currentNode);
    179 }
    180 
    181 } // namespace JSC
    182