diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 19:30:52 -0800 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 19:30:52 -0800 |
commit | 8e35f3cfc7fba1d1c829dc557ebad6409cbe16a2 (patch) | |
tree | 11425ea0b299d6fb89c6d3618a22d97d5bf68d0f /JavaScriptCore/profiler | |
parent | 648161bb0edfc3d43db63caed5cc5213bc6cb78f (diff) | |
download | external_webkit-8e35f3cfc7fba1d1c829dc557ebad6409cbe16a2.zip external_webkit-8e35f3cfc7fba1d1c829dc557ebad6409cbe16a2.tar.gz external_webkit-8e35f3cfc7fba1d1c829dc557ebad6409cbe16a2.tar.bz2 |
auto import from //depot/cupcake/@135843
Diffstat (limited to 'JavaScriptCore/profiler')
-rw-r--r-- | JavaScriptCore/profiler/CallIdentifier.h | 95 | ||||
-rw-r--r-- | JavaScriptCore/profiler/HeavyProfile.cpp | 115 | ||||
-rw-r--r-- | JavaScriptCore/profiler/HeavyProfile.h | 63 | ||||
-rw-r--r-- | JavaScriptCore/profiler/Profile.cpp | 157 | ||||
-rw-r--r-- | JavaScriptCore/profiler/Profile.h | 83 | ||||
-rw-r--r-- | JavaScriptCore/profiler/ProfileGenerator.cpp | 169 | ||||
-rw-r--r-- | JavaScriptCore/profiler/ProfileGenerator.h | 76 | ||||
-rw-r--r-- | JavaScriptCore/profiler/ProfileNode.cpp | 352 | ||||
-rw-r--r-- | JavaScriptCore/profiler/ProfileNode.h | 178 | ||||
-rw-r--r-- | JavaScriptCore/profiler/Profiler.cpp | 153 | ||||
-rw-r--r-- | JavaScriptCore/profiler/Profiler.h | 74 | ||||
-rw-r--r-- | JavaScriptCore/profiler/ProfilerServer.h | 35 | ||||
-rw-r--r-- | JavaScriptCore/profiler/ProfilerServer.mm | 106 | ||||
-rw-r--r-- | JavaScriptCore/profiler/TreeProfile.cpp | 51 | ||||
-rw-r--r-- | JavaScriptCore/profiler/TreeProfile.h | 51 |
15 files changed, 1758 insertions, 0 deletions
diff --git a/JavaScriptCore/profiler/CallIdentifier.h b/JavaScriptCore/profiler/CallIdentifier.h new file mode 100644 index 0000000..c24c44b --- /dev/null +++ b/JavaScriptCore/profiler/CallIdentifier.h @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#ifndef CallIdentifier_h +#define CallIdentifier_h + +#include <kjs/ustring.h> + +namespace JSC { + + struct CallIdentifier { + UString m_name; + UString m_url; + unsigned m_lineNumber; + + CallIdentifier() + : m_lineNumber(0) + { + } + + CallIdentifier(const UString& name, const UString& url, int lineNumber) + : m_name(name) + , m_url(url) + , m_lineNumber(lineNumber) + { + } + + inline bool operator==(const CallIdentifier& ci) const { return ci.m_lineNumber == m_lineNumber && ci.m_name == m_name && ci.m_url == m_url; } + inline bool operator!=(const CallIdentifier& ci) const { return !(*this == ci); } + +#ifndef NDEBUG + operator const char*() const { return c_str(); } + const char* c_str() const { return m_name.UTF8String().c_str(); } +#endif + }; + + struct CallIdentifierHash { + static unsigned hash(const CallIdentifier& key) + { + unsigned hashCodes[3] = { + key.m_name.rep()->hash(), + key.m_url.rep()->hash(), + key.m_lineNumber + }; + return UString::Rep::computeHash(reinterpret_cast<char*>(hashCodes), sizeof(hashCodes)); + } + + static bool equal(const CallIdentifier& a, const CallIdentifier& b) { return a == b; } + static const bool safeToCompareToEmptyOrDeleted = true; + }; + +} // namespace JSC + +namespace WTF { + + template<> struct DefaultHash<JSC::CallIdentifier> { typedef JSC::CallIdentifierHash Hash; }; + + template<> struct HashTraits<JSC::CallIdentifier> : GenericHashTraits<JSC::CallIdentifier> { + static void constructDeletedValue(JSC::CallIdentifier& slot) + { + new (&slot) JSC::CallIdentifier(JSC::UString(), JSC::UString(), std::numeric_limits<unsigned>::max()); + } + static bool isDeletedValue(const JSC::CallIdentifier& value) + { + return value.m_name.isNull() && value.m_url.isNull() && value.m_lineNumber == std::numeric_limits<unsigned>::max(); + } + }; + +} // namespace WTF + +#endif // CallIdentifier_h + diff --git a/JavaScriptCore/profiler/HeavyProfile.cpp b/JavaScriptCore/profiler/HeavyProfile.cpp new file mode 100644 index 0000000..5ea9d3b --- /dev/null +++ b/JavaScriptCore/profiler/HeavyProfile.cpp @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "HeavyProfile.h" + +#include "TreeProfile.h" + +namespace JSC { + +HeavyProfile::HeavyProfile(TreeProfile* treeProfile) + : Profile(treeProfile->title(), treeProfile->uid()) +{ + m_treeProfile = treeProfile; + head()->setTotalTime(m_treeProfile->head()->actualTotalTime()); + head()->setSelfTime(m_treeProfile->head()->actualSelfTime()); + generateHeavyStructure(); +} + +void HeavyProfile::generateHeavyStructure() +{ + ProfileNode* treeHead = m_treeProfile->head(); + ProfileNode* currentNode = treeHead->firstChild(); + for (ProfileNode* nextNode = currentNode; nextNode; nextNode = nextNode->firstChild()) + currentNode = nextNode; + + // For each node + HashMap<CallIdentifier, ProfileNode*> foundChildren; + while (currentNode && currentNode != treeHead) { + ProfileNode* child = foundChildren.get(currentNode->callIdentifier()); + if (child) // currentNode is in the set already + mergeProfiles(child, currentNode); + else { // currentNode is not in the set + child = addNode(currentNode); + foundChildren.set(currentNode->callIdentifier(), child); + } + + currentNode = currentNode->traverseNextNodePostOrder(); + } +} + +ProfileNode* HeavyProfile::addNode(ProfileNode* currentNode) +{ + RefPtr<ProfileNode> node = ProfileNode::create(head(), currentNode); + head()->addChild(node); + + addAncestorsAsChildren(currentNode->parent(), node.get()); + return node.get(); +} + +void HeavyProfile::mergeProfiles(ProfileNode* heavyProfileHead, ProfileNode* treeProfileHead) +{ + ASSERT_ARG(heavyProfileHead, heavyProfileHead); + ASSERT_ARG(treeProfileHead, treeProfileHead); + + ProfileNode* currentTreeNode = treeProfileHead; + ProfileNode* currentHeavyNode = heavyProfileHead; + ProfileNode* previousHeavyNode = 0; + + while (currentHeavyNode) { + previousHeavyNode = currentHeavyNode; + + currentHeavyNode->setTotalTime(currentHeavyNode->actualTotalTime() + currentTreeNode->actualTotalTime()); + currentHeavyNode->setSelfTime(currentHeavyNode->actualSelfTime() + currentTreeNode->actualSelfTime()); + currentHeavyNode->setNumberOfCalls(currentHeavyNode->numberOfCalls() + currentTreeNode->numberOfCalls()); + + currentTreeNode = currentTreeNode->parent(); + currentHeavyNode = currentHeavyNode->findChild(currentTreeNode); + } + + // If currentTreeNode is null then we already have the whole tree we wanted to copy. + // If not we need to copy the subset of the tree that remains different between the two. + if (currentTreeNode) + addAncestorsAsChildren(currentTreeNode, previousHeavyNode); +} + +void HeavyProfile::addAncestorsAsChildren(ProfileNode* getFrom, ProfileNode* addTo) +{ + ASSERT_ARG(getFrom, getFrom); + ASSERT_ARG(addTo, addTo); + + if (!getFrom->head()) + return; + + RefPtr<ProfileNode> currentNode = addTo; + for (ProfileNode* treeAncestor = getFrom; treeAncestor && treeAncestor != getFrom->head(); treeAncestor = treeAncestor->parent()) { + RefPtr<ProfileNode> newChild = ProfileNode::create(currentNode->head(), treeAncestor); + currentNode->addChild(newChild); + currentNode = newChild.release(); + } +} + +} // namespace JSC diff --git a/JavaScriptCore/profiler/HeavyProfile.h b/JavaScriptCore/profiler/HeavyProfile.h new file mode 100644 index 0000000..903d091 --- /dev/null +++ b/JavaScriptCore/profiler/HeavyProfile.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef HeavyProfile_h +#define HeavyProfile_h + +#include "Profile.h" +#include "ProfileNode.h" +#include "TreeProfile.h" + +namespace JSC { + + class UString; + + class HeavyProfile : public Profile { + public: + static PassRefPtr<HeavyProfile> create(TreeProfile* treeProfile) + { + return adoptRef(new HeavyProfile(treeProfile)); + } + + virtual Profile* heavyProfile() { return this; } + virtual Profile* treeProfile() + { + return m_treeProfile; + } + + + private: + HeavyProfile(TreeProfile*); + void generateHeavyStructure(); + ProfileNode* addNode(ProfileNode*); + void mergeProfiles(ProfileNode* heavyProfileHead, ProfileNode* treeProfileHead); + void addAncestorsAsChildren(ProfileNode* getFrom, ProfileNode* addTo); + + TreeProfile* m_treeProfile; + }; + +} // namespace JSC + +#endif // HeavyProfile_h diff --git a/JavaScriptCore/profiler/Profile.cpp b/JavaScriptCore/profiler/Profile.cpp new file mode 100644 index 0000000..fd32e1c --- /dev/null +++ b/JavaScriptCore/profiler/Profile.cpp @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "Profile.h" + +#include "ProfileNode.h" +#include "TreeProfile.h" +#include <stdio.h> + +#if PLATFORM(ANDROID) +typedef bool (* Comparator)(const void*, const void*); +namespace std { +extern void sort(const void** start, const void** end, Comparator comp); +} +#endif + +namespace JSC { + +PassRefPtr<Profile> Profile::create(const UString& title, unsigned uid) +{ + return TreeProfile::create(title, uid); +} + +Profile::Profile(const UString& title, unsigned uid) + : m_title(title) + , m_uid(uid) +{ + // FIXME: When multi-threading is supported this will be a vector and calls + // into the profiler will need to know which thread it is executing on. + m_head = ProfileNode::create(CallIdentifier("Thread_1", 0, 0), 0, 0); +} + +Profile::~Profile() +{ +} + +void Profile::forEach(void (ProfileNode::*function)()) +{ + ProfileNode* currentNode = m_head->firstChild(); + for (ProfileNode* nextNode = currentNode; nextNode; nextNode = nextNode->firstChild()) + currentNode = nextNode; + + if (!currentNode) + currentNode = m_head.get(); + + ProfileNode* endNode = m_head->traverseNextNodePostOrder(); + while (currentNode && currentNode != endNode) { + (currentNode->*function)(); + currentNode = currentNode->traverseNextNodePostOrder(); + } +} + +void Profile::focus(const ProfileNode* profileNode) +{ + if (!profileNode || !m_head) + return; + + bool processChildren; + const CallIdentifier& callIdentifier = profileNode->callIdentifier(); + for (ProfileNode* currentNode = m_head.get(); currentNode; currentNode = currentNode->traverseNextNodePreOrder(processChildren)) + processChildren = currentNode->focus(callIdentifier); + + // Set the visible time of all nodes so that the %s display correctly. + forEach(&ProfileNode::calculateVisibleTotalTime); +} + +void Profile::exclude(const ProfileNode* profileNode) +{ + if (!profileNode || !m_head) + return; + + const CallIdentifier& callIdentifier = profileNode->callIdentifier(); + + for (ProfileNode* currentNode = m_head.get(); currentNode; currentNode = currentNode->traverseNextNodePreOrder()) + currentNode->exclude(callIdentifier); + + // Set the visible time of the head so the %s display correctly. + m_head->setVisibleTotalTime(m_head->totalTime() - m_head->selfTime()); + m_head->setVisibleSelfTime(0.0); +} + +void Profile::restoreAll() +{ + forEach(&ProfileNode::restore); +} + +#ifndef NDEBUG +void Profile::debugPrintData() const +{ + printf("Call graph:\n"); + m_head->debugPrintData(0); +} + +typedef pair<UString::Rep*, unsigned> NameCountPair; + +#if PLATFORM(ANDROID) +typedef bool (* NameCountPairComparator)(const NameCountPair&, const NameCountPair&); + +inline void _sort(NameCountPair* start, NameCountPair* end, NameCountPairComparator comp) +{ + std::sort((const void**) start, (const void**) end, (Comparator) comp); +} +#endif + +static inline bool functionNameCountPairComparator(const NameCountPair& a, const NameCountPair& b) +{ + return a.second > b.second; +} + +void Profile::debugPrintDataSampleStyle() const +{ + typedef Vector<NameCountPair> NameCountPairVector; + + FunctionCallHashCount countedFunctions; + printf("Call graph:\n"); + m_head->debugPrintDataSampleStyle(0, countedFunctions); + + printf("\nTotal number in stack:\n"); + NameCountPairVector sortedFunctions(countedFunctions.size()); + copyToVector(countedFunctions, sortedFunctions); + +#if PLATFORM(ANDROID) + _sort(sortedFunctions.begin(), sortedFunctions.end(), functionNameCountPairComparator); +#else + std::sort(sortedFunctions.begin(), sortedFunctions.end(), functionNameCountPairComparator); +#endif + for (NameCountPairVector::iterator it = sortedFunctions.begin(); it != sortedFunctions.end(); ++it) + printf(" %-12d%s\n", (*it).second, UString((*it).first).UTF8String().c_str()); + + printf("\nSort by top of stack, same collapsed (when >= 5):\n"); +} +#endif + +} // namespace JSC diff --git a/JavaScriptCore/profiler/Profile.h b/JavaScriptCore/profiler/Profile.h new file mode 100644 index 0000000..c232c55 --- /dev/null +++ b/JavaScriptCore/profiler/Profile.h @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef Profile_h +#define Profile_h + +#include "ProfileNode.h" +#include <kjs/ustring.h> +#include <wtf/RefCounted.h> +#include <wtf/RefPtr.h> + +namespace JSC { + + class Profile : public RefCounted<Profile> { + public: + static PassRefPtr<Profile> create(const UString& title, unsigned uid); + virtual ~Profile(); + + const UString& title() const { return m_title; } + ProfileNode* head() const { return m_head.get(); } + void setHead(PassRefPtr<ProfileNode> head) { m_head = head; } + double totalTime() const { return m_head->totalTime(); } + unsigned int uid() const { return m_uid; } + + void forEach(void (ProfileNode::*)()); + void sortTotalTimeDescending() { forEach(&ProfileNode::sortTotalTimeDescending); } + void sortTotalTimeAscending() { forEach(&ProfileNode::sortTotalTimeAscending); } + void sortSelfTimeDescending() { forEach(&ProfileNode::sortSelfTimeDescending); } + void sortSelfTimeAscending() { forEach(&ProfileNode::sortSelfTimeAscending); } + void sortCallsDescending() { forEach(&ProfileNode::sortCallsDescending); } + void sortCallsAscending() { forEach(&ProfileNode::sortCallsAscending); } + void sortFunctionNameDescending() { forEach(&ProfileNode::sortFunctionNameDescending); } + void sortFunctionNameAscending() { forEach(&ProfileNode::sortFunctionNameAscending); } + + void focus(const ProfileNode*); + void exclude(const ProfileNode*); + void restoreAll(); + + virtual Profile* heavyProfile() = 0; + virtual Profile* treeProfile() = 0; + +#ifndef NDEBUG + void debugPrintData() const; + void debugPrintDataSampleStyle() const; +#endif + + protected: + Profile(const UString& title, unsigned uid); + + private: + void removeProfileStart(); + void removeProfileEnd(); + + UString m_title; + RefPtr<ProfileNode> m_head; + unsigned int m_uid; + }; + +} // namespace JSC + +#endif // Profile_h diff --git a/JavaScriptCore/profiler/ProfileGenerator.cpp b/JavaScriptCore/profiler/ProfileGenerator.cpp new file mode 100644 index 0000000..1506788 --- /dev/null +++ b/JavaScriptCore/profiler/ProfileGenerator.cpp @@ -0,0 +1,169 @@ +/* + * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "ProfileGenerator.h" + +#include "ExecState.h" +#include "JSGlobalObject.h" +#include "JSStringRef.h" +#include "JSFunction.h" +#include "Machine.h" +#include "Profile.h" +#include "Profiler.h" +#include "Tracing.h" + +namespace JSC { + +static const char* NonJSExecution = "(idle)"; + +PassRefPtr<ProfileGenerator> ProfileGenerator::create(const UString& title, ExecState* originatingExec, unsigned uid) +{ + return adoptRef(new ProfileGenerator(title, originatingExec, uid)); +} + +ProfileGenerator::ProfileGenerator(const UString& title, ExecState* originatingExec, unsigned uid) + : m_originatingGlobalExec(originatingExec ? originatingExec->lexicalGlobalObject()->globalExec() : 0) + , m_profileGroup(originatingExec ? originatingExec->lexicalGlobalObject()->profileGroup() : 0) +{ + m_profile = Profile::create(title, uid); + m_currentNode = m_head = m_profile->head(); + if (originatingExec) + addParentForConsoleStart(originatingExec); +} + +void ProfileGenerator::addParentForConsoleStart(ExecState* exec) +{ + int lineNumber; + intptr_t sourceID; + UString sourceURL; + JSValue* function; + + exec->machine()->retrieveLastCaller(exec, lineNumber, sourceID, sourceURL, function); + m_currentNode = ProfileNode::create(Profiler::createCallIdentifier(&exec->globalData(), function ? function->toThisObject(exec) : 0, sourceURL, lineNumber), m_head.get(), m_head.get()); + m_head->insertNode(m_currentNode.get()); +} + +const UString& ProfileGenerator::title() const +{ + return m_profile->title(); +} + +void ProfileGenerator::willExecute(const CallIdentifier& callIdentifier) +{ + if (JAVASCRIPTCORE_PROFILE_WILL_EXECUTE_ENABLED()) { + CString name = callIdentifier.m_name.UTF8String(); + CString url = callIdentifier.m_url.UTF8String(); + JAVASCRIPTCORE_PROFILE_WILL_EXECUTE(m_profileGroup, const_cast<char*>(name.c_str()), const_cast<char*>(url.c_str()), callIdentifier.m_lineNumber); + } + + if (!m_originatingGlobalExec) + return; + + ASSERT_ARG(m_currentNode, m_currentNode); + m_currentNode = m_currentNode->willExecute(callIdentifier); +} + +void ProfileGenerator::didExecute(const CallIdentifier& callIdentifier) +{ + if (JAVASCRIPTCORE_PROFILE_DID_EXECUTE_ENABLED()) { + CString name = callIdentifier.m_name.UTF8String(); + CString url = callIdentifier.m_url.UTF8String(); + JAVASCRIPTCORE_PROFILE_DID_EXECUTE(m_profileGroup, const_cast<char*>(name.c_str()), const_cast<char*>(url.c_str()), callIdentifier.m_lineNumber); + } + + if (!m_originatingGlobalExec) + return; + + ASSERT_ARG(m_currentNode, m_currentNode); + if (m_currentNode->callIdentifier() != callIdentifier) { + RefPtr<ProfileNode> returningNode = ProfileNode::create(callIdentifier, m_head.get(), m_currentNode.get()); + returningNode->setStartTime(m_currentNode->startTime()); + returningNode->didExecute(); + m_currentNode->insertNode(returningNode.release()); + return; + } + + m_currentNode = m_currentNode->didExecute(); +} + +void ProfileGenerator::stopProfiling() +{ + m_profile->forEach(&ProfileNode::stopProfiling); + + removeProfileStart(); + removeProfileEnd(); + + ASSERT_ARG(m_currentNode, m_currentNode); + + // Set the current node to the parent, because we are in a call that + // will not get didExecute call. + m_currentNode = m_currentNode->parent(); + + if (double headSelfTime = m_head->selfTime()) { + RefPtr<ProfileNode> idleNode = ProfileNode::create(CallIdentifier(NonJSExecution, 0, 0), m_head.get(), m_head.get()); + + idleNode->setTotalTime(headSelfTime); + idleNode->setSelfTime(headSelfTime); + idleNode->setVisible(true); + + m_head->setSelfTime(0.0); + m_head->addChild(idleNode.release()); + } +} + +// The console.ProfileGenerator that started this ProfileGenerator will be the first child. +void ProfileGenerator::removeProfileStart() +{ + ProfileNode* currentNode = 0; + for (ProfileNode* next = m_head.get(); next; next = next->firstChild()) + currentNode = next; + + if (currentNode->callIdentifier().m_name != "profile") + return; + + // Attribute the time of the node aobut to be removed to the self time of its parent + currentNode->parent()->setSelfTime(currentNode->parent()->selfTime() + currentNode->totalTime()); + currentNode->parent()->removeChild(currentNode); +} + +// The console.ProfileGeneratorEnd that stopped this ProfileGenerator will be the last child. +void ProfileGenerator::removeProfileEnd() +{ + ProfileNode* currentNode = 0; + for (ProfileNode* next = m_head.get(); next; next = next->lastChild()) + currentNode = next; + + if (currentNode->callIdentifier().m_name != "profileEnd") + return; + + // Attribute the time of the node aobut to be removed to the self time of its parent + currentNode->parent()->setSelfTime(currentNode->parent()->selfTime() + currentNode->totalTime()); + + ASSERT(currentNode->callIdentifier() == (currentNode->parent()->children()[currentNode->parent()->children().size() - 1])->callIdentifier()); + currentNode->parent()->removeChild(currentNode); +} + +} // namespace JSC diff --git a/JavaScriptCore/profiler/ProfileGenerator.h b/JavaScriptCore/profiler/ProfileGenerator.h new file mode 100644 index 0000000..54d4565 --- /dev/null +++ b/JavaScriptCore/profiler/ProfileGenerator.h @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef ProfileGenerator_h +#define ProfileGenerator_h + +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> +#include <wtf/RefPtr.h> + +namespace JSC { + + class CallIdentifier; + class ExecState; + class Profile; + class ProfileNode; + class UString; + + class ProfileGenerator : public RefCounted<ProfileGenerator> { + public: + static PassRefPtr<ProfileGenerator> create(const UString& title, ExecState* originatingExec, unsigned uid); + + // Members + const UString& title() const; + PassRefPtr<Profile> profile() const { return m_profile; } + ExecState* originatingGlobalExec() const { return m_originatingGlobalExec; } + unsigned profileGroup() const { return m_profileGroup; } + + // Collecting + void willExecute(const CallIdentifier&); + void didExecute(const CallIdentifier&); + + // Stopping Profiling + void stopProfiling(); + + typedef void (ProfileGenerator::*ProfileFunction)(const CallIdentifier& callIdentifier); + + private: + ProfileGenerator(const UString& title, ExecState* originatingExec, unsigned uid); + void addParentForConsoleStart(ExecState*); + + void removeProfileStart(); + void removeProfileEnd(); + + RefPtr<Profile> m_profile; + ExecState* m_originatingGlobalExec; + unsigned m_profileGroup; + RefPtr<ProfileNode> m_head; + RefPtr<ProfileNode> m_currentNode; + }; + +} // namespace JSC + +#endif // ProfileGenerator_h diff --git a/JavaScriptCore/profiler/ProfileNode.cpp b/JavaScriptCore/profiler/ProfileNode.cpp new file mode 100644 index 0000000..3458902 --- /dev/null +++ b/JavaScriptCore/profiler/ProfileNode.cpp @@ -0,0 +1,352 @@ +/* + * Copyright (C) 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "ProfileNode.h" + +#include "DateMath.h" +#include "Profiler.h" +#include <stdio.h> + +#if PLATFORM(WIN_OS) +#include <windows.h> +#endif + +namespace JSC { + +static double getCount() +{ +#if PLATFORM(WIN_OS) + static LARGE_INTEGER frequency = {0}; + if (!frequency.QuadPart) + QueryPerformanceFrequency(&frequency); + LARGE_INTEGER counter; + QueryPerformanceCounter(&counter); + return static_cast<double>(counter.QuadPart) / frequency.QuadPart; +#else + return getCurrentUTCTimeWithMicroseconds(); +#endif +} + +ProfileNode::ProfileNode(const CallIdentifier& callIdentifier, ProfileNode* headNode, ProfileNode* parentNode) + : m_callIdentifier(callIdentifier) + , m_head(headNode) + , m_parent(parentNode) + , m_nextSibling(0) + , m_startTime(0.0) + , m_actualTotalTime(0.0) + , m_visibleTotalTime(0.0) + , m_actualSelfTime(0.0) + , m_visibleSelfTime(0.0) + , m_numberOfCalls(0) + , m_visible(true) +{ + startTimer(); +} + +ProfileNode::ProfileNode(ProfileNode* headNode, ProfileNode* nodeToCopy) + : m_callIdentifier(nodeToCopy->callIdentifier()) + , m_head(headNode) + , m_parent(nodeToCopy->parent()) + , m_nextSibling(0) + , m_startTime(0.0) + , m_actualTotalTime(nodeToCopy->actualTotalTime()) + , m_visibleTotalTime(nodeToCopy->totalTime()) + , m_actualSelfTime(nodeToCopy->actualSelfTime()) + , m_visibleSelfTime(nodeToCopy->selfTime()) + , m_numberOfCalls(nodeToCopy->numberOfCalls()) + , m_visible(nodeToCopy->visible()) +{ +} + +ProfileNode* ProfileNode::willExecute(const CallIdentifier& callIdentifier) +{ + for (StackIterator currentChild = m_children.begin(); currentChild != m_children.end(); ++currentChild) { + if ((*currentChild)->callIdentifier() == callIdentifier) { + (*currentChild)->startTimer(); + return (*currentChild).get(); + } + } + + RefPtr<ProfileNode> newChild = ProfileNode::create(callIdentifier, m_head ? m_head : this, this); // If this ProfileNode has no head it is the head. + if (m_children.size()) + m_children.last()->setNextSibling(newChild.get()); + m_children.append(newChild.release()); + return m_children.last().get(); +} + +ProfileNode* ProfileNode::didExecute() +{ + endAndRecordCall(); + return m_parent; +} + +void ProfileNode::addChild(PassRefPtr<ProfileNode> prpChild) +{ + RefPtr<ProfileNode> child = prpChild; + child->setParent(this); + if (m_children.size()) + m_children.last()->setNextSibling(child.get()); + m_children.append(child.release()); +} + +ProfileNode* ProfileNode::findChild(ProfileNode* node) const +{ + if (!node) + return 0; + + for (size_t i = 0; i < m_children.size(); ++i) { + if (*node == m_children[i].get()) + return m_children[i].get(); + } + + return 0; +} + +void ProfileNode::removeChild(ProfileNode* node) +{ + if (!node) + return; + + for (size_t i = 0; i < m_children.size(); ++i) { + if (*node == m_children[i].get()) { + m_children.remove(i); + break; + } + } + + resetChildrensSiblings(); +} + +void ProfileNode::insertNode(PassRefPtr<ProfileNode> prpNode) +{ + RefPtr<ProfileNode> node = prpNode; + + for (unsigned i = 0; i < m_children.size(); ++i) + node->addChild(m_children[i].release()); + + m_children.clear(); + m_children.append(node.release()); +} + +void ProfileNode::stopProfiling() +{ + if (m_startTime) + endAndRecordCall(); + + m_visibleTotalTime = m_actualTotalTime; + + ASSERT(m_actualSelfTime == 0.0 && m_startTime == 0.0); + + // Because we iterate in post order all of our children have been stopped before us. + for (unsigned i = 0; i < m_children.size(); ++i) + m_actualSelfTime += m_children[i]->totalTime(); + + ASSERT(m_actualSelfTime <= m_actualTotalTime); + m_actualSelfTime = m_actualTotalTime - m_actualSelfTime; + m_visibleSelfTime = m_actualSelfTime; +} + +ProfileNode* ProfileNode::traverseNextNodePostOrder() const +{ + ProfileNode* next = m_nextSibling; + if (!next) + return m_parent; + while (ProfileNode* firstChild = next->firstChild()) + next = firstChild; + return next; +} + +ProfileNode* ProfileNode::traverseNextNodePreOrder(bool processChildren) const +{ + if (processChildren && m_children.size()) + return m_children[0].get(); + + if (m_nextSibling) + return m_nextSibling; + + ProfileNode* nextParent = m_parent; + if (!nextParent) + return 0; + + ProfileNode* next; + for (next = m_parent->nextSibling(); !next; next = nextParent->nextSibling()) { + nextParent = nextParent->parent(); + if (!nextParent) + return 0; + } + + return next; +} + +void ProfileNode::sort(bool comparator(const RefPtr<ProfileNode>& , const RefPtr<ProfileNode>& )) +{ + std::sort(childrenBegin(), childrenEnd(), comparator); + resetChildrensSiblings(); +} + +void ProfileNode::setTreeVisible(ProfileNode* node, bool visible) +{ + ProfileNode* nodeParent = node->parent(); + ProfileNode* nodeSibling = node->nextSibling(); + node->setParent(0); + node->setNextSibling(0); + + for (ProfileNode* currentNode = node; currentNode; currentNode = currentNode->traverseNextNodePreOrder()) + currentNode->setVisible(visible); + + node->setParent(nodeParent); + node->setNextSibling(nodeSibling); +} + +void ProfileNode::calculateVisibleTotalTime() +{ + double sumOfVisibleChildrensTime = 0.0; + + for (unsigned i = 0; i < m_children.size(); ++i) { + if (m_children[i]->visible()) + sumOfVisibleChildrensTime += m_children[i]->totalTime(); + } + + m_visibleTotalTime = m_visibleSelfTime + sumOfVisibleChildrensTime; +} + +bool ProfileNode::focus(const CallIdentifier& callIdentifier) +{ + if (!m_visible) + return false; + + if (m_callIdentifier != callIdentifier) { + m_visible = false; + return true; + } + + for (ProfileNode* currentParent = m_parent; currentParent; currentParent = currentParent->parent()) + currentParent->setVisible(true); + + return false; +} + +void ProfileNode::exclude(const CallIdentifier& callIdentifier) +{ + if (m_visible && m_callIdentifier == callIdentifier) { + setTreeVisible(this, false); + + m_parent->setVisibleSelfTime(m_parent->selfTime() + m_visibleTotalTime); + } +} + +void ProfileNode::restore() +{ + m_visibleTotalTime = m_actualTotalTime; + m_visibleSelfTime = m_actualSelfTime; + m_visible = true; +} + +void ProfileNode::endAndRecordCall() +{ + m_actualTotalTime += m_startTime ? getCount() - m_startTime : 0.0; + m_startTime = 0.0; + + ++m_numberOfCalls; +} + +void ProfileNode::startTimer() +{ + if (!m_startTime) + m_startTime = getCount(); +} + +void ProfileNode::resetChildrensSiblings() +{ + unsigned size = m_children.size(); + for (unsigned i = 0; i < size; ++i) + m_children[i]->setNextSibling(i + 1 == size ? 0 : m_children[i + 1].get()); +} + +#ifndef NDEBUG +void ProfileNode::debugPrintData(int indentLevel) const +{ + // Print function names + for (int i = 0; i < indentLevel; ++i) + printf(" "); + + printf("Function Name %s %d SelfTime %.3fms/%.3f%% TotalTime %.3fms/%.3f%% VSelf %.3fms VTotal %.3fms Visible %s Next Sibling %s\n", + functionName().UTF8String().c_str(), + m_numberOfCalls, m_actualSelfTime, selfPercent(), m_actualTotalTime, totalPercent(), + m_visibleSelfTime, m_visibleTotalTime, + (m_visible ? "True" : "False"), + m_nextSibling ? m_nextSibling->functionName().UTF8String().c_str() : ""); + + ++indentLevel; + + // Print children's names and information + for (StackIterator currentChild = m_children.begin(); currentChild != m_children.end(); ++currentChild) + (*currentChild)->debugPrintData(indentLevel); +} + +// print the profiled data in a format that matches the tool sample's output. +double ProfileNode::debugPrintDataSampleStyle(int indentLevel, FunctionCallHashCount& countedFunctions) const +{ + printf(" "); + + // Print function names + const char* name = functionName().UTF8String().c_str(); + double sampleCount = m_actualTotalTime * 1000; + if (indentLevel) { + for (int i = 0; i < indentLevel; ++i) + printf(" "); + + countedFunctions.add(functionName().rep()); + + printf("%.0f %s\n", sampleCount ? sampleCount : 1, name); + } else + printf("%s\n", name); + + ++indentLevel; + + // Print children's names and information + double sumOfChildrensCount = 0.0; + for (StackIterator currentChild = m_children.begin(); currentChild != m_children.end(); ++currentChild) + sumOfChildrensCount += (*currentChild)->debugPrintDataSampleStyle(indentLevel, countedFunctions); + + sumOfChildrensCount *= 1000; // + // Print remainder of samples to match sample's output + if (sumOfChildrensCount < sampleCount) { + printf(" "); + while (indentLevel--) + printf(" "); + + printf("%.0f %s\n", sampleCount - sumOfChildrensCount, functionName().UTF8String().c_str()); + } + + return m_actualTotalTime; +} +#endif + +} // namespace JSC diff --git a/JavaScriptCore/profiler/ProfileNode.h b/JavaScriptCore/profiler/ProfileNode.h new file mode 100644 index 0000000..b416011 --- /dev/null +++ b/JavaScriptCore/profiler/ProfileNode.h @@ -0,0 +1,178 @@ +/* + * Copyright (C) 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef ProfileNode_h +#define ProfileNode_h + +#include "CallIdentifier.h" +#include <wtf/Vector.h> +#include <wtf/RefCounted.h> +#include <wtf/RefPtr.h> + +namespace JSC { + + class ProfileNode; + + typedef Vector<RefPtr<ProfileNode> >::const_iterator StackIterator; + typedef HashCountedSet<UString::Rep*> FunctionCallHashCount; + + class ProfileNode : public RefCounted<ProfileNode> { + public: + static PassRefPtr<ProfileNode> create(const CallIdentifier& callIdentifier, ProfileNode* headNode, ProfileNode* parentNode) + { + return adoptRef(new ProfileNode(callIdentifier, headNode, parentNode)); + } + static PassRefPtr<ProfileNode> create(ProfileNode* headNode, ProfileNode* node) + { + return adoptRef(new ProfileNode(headNode, node)); + } + + bool operator==(ProfileNode* node) { return m_callIdentifier == node->callIdentifier(); } + + ProfileNode* willExecute(const CallIdentifier&); + ProfileNode* didExecute(); + + void stopProfiling(); + + // CallIdentifier members + const CallIdentifier& callIdentifier() const { return m_callIdentifier; } + const UString& functionName() const { return m_callIdentifier.m_name; } + const UString& url() const { return m_callIdentifier.m_url; } + unsigned lineNumber() const { return m_callIdentifier.m_lineNumber; } + + // Relationships + ProfileNode* head() const { return m_head; } + void setHead(ProfileNode* head) { m_head = head; } + ProfileNode* parent() const { return m_parent; } + void setParent(ProfileNode* parent) { m_parent = parent; } + ProfileNode* nextSibling() const { return m_nextSibling; } + void setNextSibling(ProfileNode* nextSibling) { m_nextSibling = nextSibling; } + + // Time members + double startTime() const { return m_startTime; } + void setStartTime(double startTime) { m_startTime = startTime; } + double totalTime() const { return m_visibleTotalTime; } + double actualTotalTime() const { return m_actualTotalTime; } + void setTotalTime(double time) { m_actualTotalTime = time; m_visibleTotalTime = time; } + void setActualTotalTime(double time) { m_actualTotalTime = time; } + void setVisibleTotalTime(double time) { m_visibleTotalTime = time; } + double selfTime() const { return m_visibleSelfTime; } + double actualSelfTime() const { return m_actualSelfTime; } + void setSelfTime(double time) {m_actualSelfTime = time; m_visibleSelfTime = time; } + void setActualSelfTime(double time) { m_actualSelfTime = time; } + void setVisibleSelfTime(double time) { m_visibleSelfTime = time; } + + double totalPercent() const { return (m_visibleTotalTime / (m_head ? m_head->totalTime() : totalTime())) * 100.0; } + double selfPercent() const { return (m_visibleSelfTime / (m_head ? m_head->totalTime() : totalTime())) * 100.0; } + + unsigned numberOfCalls() const { return m_numberOfCalls; } + void setNumberOfCalls(unsigned number) { m_numberOfCalls = number; } + + // Children members + const Vector<RefPtr<ProfileNode> >& children() const { return m_children; } + ProfileNode* firstChild() const { return m_children.size() ? m_children.first().get() : 0; } + ProfileNode* lastChild() const { return m_children.size() ? m_children.last().get() : 0; } + ProfileNode* findChild(ProfileNode*) const; + void removeChild(ProfileNode*); + void addChild(PassRefPtr<ProfileNode> prpChild); + void insertNode(PassRefPtr<ProfileNode> prpNode); + + // Visiblity + bool visible() const { return m_visible; } + void setVisible(bool visible) { m_visible = visible; } + + static void setTreeVisible(ProfileNode*, bool visible); + + // Sorting + ProfileNode* traverseNextNodePostOrder() const; + ProfileNode* traverseNextNodePreOrder(bool processChildren = true) const; + + void sort(bool (*)(const RefPtr<ProfileNode>&, const RefPtr<ProfileNode>&)); + void sortTotalTimeDescending() { sort(totalTimeDescendingComparator); } + void sortTotalTimeAscending() { sort(totalTimeAscendingComparator); } + void sortSelfTimeDescending() { sort(selfTimeDescendingComparator); } + void sortSelfTimeAscending() { sort(selfTimeAscendingComparator); } + void sortCallsDescending() { sort(callsDescendingComparator); } + void sortCallsAscending() { sort(callsAscendingComparator); } + void sortFunctionNameDescending() { sort(functionNameDescendingComparator); } + void sortFunctionNameAscending() { sort(functionNameAscendingComparator); } + + // Views + void calculateVisibleTotalTime(); + bool focus(const CallIdentifier&); + void exclude(const CallIdentifier&); + void restore(); + + void endAndRecordCall(); + +#ifndef NDEBUG + const char* c_str() const { return m_callIdentifier; } + void debugPrintData(int indentLevel) const; + double debugPrintDataSampleStyle(int indentLevel, FunctionCallHashCount&) const; +#endif + + private: + ProfileNode(const CallIdentifier&, ProfileNode* headNode, ProfileNode* parentNode); + ProfileNode(ProfileNode* headNode, ProfileNode* nodeToCopy); + + void startTimer(); + void resetChildrensSiblings(); + + RefPtr<ProfileNode>* childrenBegin() { return m_children.begin(); } + RefPtr<ProfileNode>* childrenEnd() { return m_children.end(); } + + // Sorting comparators + static inline bool totalTimeDescendingComparator(const RefPtr<ProfileNode>& a, const RefPtr<ProfileNode>& b) { return a->totalTime() > b->totalTime(); } + static inline bool totalTimeAscendingComparator(const RefPtr<ProfileNode>& a, const RefPtr<ProfileNode>& b) { return a->totalTime() < b->totalTime(); } + static inline bool selfTimeDescendingComparator(const RefPtr<ProfileNode>& a, const RefPtr<ProfileNode>& b) { return a->selfTime() > b->selfTime(); } + static inline bool selfTimeAscendingComparator(const RefPtr<ProfileNode>& a, const RefPtr<ProfileNode>& b) { return a->selfTime() < b->selfTime(); } + static inline bool callsDescendingComparator(const RefPtr<ProfileNode>& a, const RefPtr<ProfileNode>& b) { return a->numberOfCalls() > b->numberOfCalls(); } + static inline bool callsAscendingComparator(const RefPtr<ProfileNode>& a, const RefPtr<ProfileNode>& b) { return a->numberOfCalls() < b->numberOfCalls(); } + static inline bool functionNameDescendingComparator(const RefPtr<ProfileNode>& a, const RefPtr<ProfileNode>& b) { return a->functionName() > b->functionName(); } + static inline bool functionNameAscendingComparator(const RefPtr<ProfileNode>& a, const RefPtr<ProfileNode>& b) { return a->functionName() < b->functionName(); } + + CallIdentifier m_callIdentifier; + ProfileNode* m_head; + ProfileNode* m_parent; + ProfileNode* m_nextSibling; + + double m_startTime; + double m_actualTotalTime; + double m_visibleTotalTime; + double m_actualSelfTime; + double m_visibleSelfTime; + unsigned m_numberOfCalls; + + bool m_visible; + + Vector<RefPtr<ProfileNode> > m_children; + }; + +} // namespace JSC + +#endif // ProfileNode_h diff --git a/JavaScriptCore/profiler/Profiler.cpp b/JavaScriptCore/profiler/Profiler.cpp new file mode 100644 index 0000000..c68fa1a --- /dev/null +++ b/JavaScriptCore/profiler/Profiler.cpp @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "Profiler.h" + +#include "CommonIdentifiers.h" +#include "ExecState.h" +#include "JSFunction.h" +#include "JSGlobalObject.h" +#include "Profile.h" +#include "ProfileGenerator.h" +#include "ProfileNode.h" +#include <stdio.h> + +namespace JSC { + +static const char* GlobalCodeExecution = "(program)"; +static const char* AnonymousFunction = "(anonymous function)"; +static unsigned ProfilesUID = 0; + +static CallIdentifier createCallIdentifierFromFunctionImp(JSGlobalData*, JSFunction*); + +Profiler* Profiler::s_sharedProfiler = 0; +Profiler* Profiler::s_sharedEnabledProfilerReference = 0; + +Profiler* Profiler::profiler() +{ + if (!s_sharedProfiler) + s_sharedProfiler = new Profiler(); + return s_sharedProfiler; +} + +void Profiler::startProfiling(ExecState* exec, const UString& title) +{ + // Check if we currently have a Profile for this global ExecState and title. + // If so return early and don't create a new Profile. + ExecState* globalExec = exec ? exec->lexicalGlobalObject()->globalExec() : 0; + + for (size_t i = 0; i < m_currentProfiles.size(); ++i) { + ProfileGenerator* profileGenerator = m_currentProfiles[i].get(); + if (profileGenerator->originatingGlobalExec() == globalExec && profileGenerator->title() == title) + return; + } + + s_sharedEnabledProfilerReference = this; + RefPtr<ProfileGenerator> profileGenerator = ProfileGenerator::create(title, exec, ++ProfilesUID); + m_currentProfiles.append(profileGenerator); +} + +PassRefPtr<Profile> Profiler::stopProfiling(ExecState* exec, const UString& title) +{ + ExecState* globalExec = exec ? exec->lexicalGlobalObject()->globalExec() : 0; + for (ptrdiff_t i = m_currentProfiles.size() - 1; i >= 0; --i) { + ProfileGenerator* profileGenerator = m_currentProfiles[i].get(); + if (profileGenerator->originatingGlobalExec() == globalExec && (title.isNull() || profileGenerator->title() == title)) { + profileGenerator->stopProfiling(); + RefPtr<Profile> returnProfile = profileGenerator->profile(); + + m_currentProfiles.remove(i); + if (!m_currentProfiles.size()) + s_sharedEnabledProfilerReference = 0; + + return returnProfile; + } + } + + return 0; +} + +static inline void dispatchFunctionToProfiles(const Vector<RefPtr<ProfileGenerator> >& profiles, ProfileGenerator::ProfileFunction function, const CallIdentifier& callIdentifier, unsigned currentProfileTargetGroup) +{ + for (size_t i = 0; i < profiles.size(); ++i) { + if (profiles[i]->profileGroup() == currentProfileTargetGroup || !profiles[i]->originatingGlobalExec()) + (profiles[i].get()->*function)(callIdentifier); + } +} + +void Profiler::willExecute(ExecState* exec, JSValue* function) +{ + ASSERT(!m_currentProfiles.isEmpty()); + + dispatchFunctionToProfiles(m_currentProfiles, &ProfileGenerator::willExecute, createCallIdentifier(&exec->globalData(), function, "", 0), exec->lexicalGlobalObject()->profileGroup()); +} + +void Profiler::willExecute(ExecState* exec, const UString& sourceURL, int startingLineNumber) +{ + ASSERT(!m_currentProfiles.isEmpty()); + + CallIdentifier callIdentifier = createCallIdentifier(&exec->globalData(), noValue(), sourceURL, startingLineNumber); + + dispatchFunctionToProfiles(m_currentProfiles, &ProfileGenerator::willExecute, callIdentifier, exec->lexicalGlobalObject()->profileGroup()); +} + +void Profiler::didExecute(ExecState* exec, JSValue* function) +{ + ASSERT(!m_currentProfiles.isEmpty()); + + dispatchFunctionToProfiles(m_currentProfiles, &ProfileGenerator::didExecute, createCallIdentifier(&exec->globalData(), function, "", 0), exec->lexicalGlobalObject()->profileGroup()); +} + +void Profiler::didExecute(ExecState* exec, const UString& sourceURL, int startingLineNumber) +{ + ASSERT(!m_currentProfiles.isEmpty()); + + dispatchFunctionToProfiles(m_currentProfiles, &ProfileGenerator::didExecute, createCallIdentifier(&exec->globalData(), noValue(), sourceURL, startingLineNumber), exec->lexicalGlobalObject()->profileGroup()); +} + +CallIdentifier Profiler::createCallIdentifier(JSGlobalData* globalData, JSValue* function, const UString& defaultSourceURL, int defaultLineNumber) +{ + if (!function) + return CallIdentifier(GlobalCodeExecution, defaultSourceURL, defaultLineNumber); + if (!function->isObject()) + return CallIdentifier("(unknown)", defaultSourceURL, defaultLineNumber); + if (asObject(function)->inherits(&JSFunction::info)) + return createCallIdentifierFromFunctionImp(globalData, asFunction(function)); + if (asObject(function)->inherits(&InternalFunction::info)) + return CallIdentifier(static_cast<InternalFunction*>(asObject(function))->name(globalData), defaultSourceURL, defaultLineNumber); + return CallIdentifier("(" + asObject(function)->className() + " object)", defaultSourceURL, defaultLineNumber); +} + +CallIdentifier createCallIdentifierFromFunctionImp(JSGlobalData* globalData, JSFunction* function) +{ + const UString& name = function->name(globalData); + return CallIdentifier(name.isEmpty() ? AnonymousFunction : name, function->m_body->sourceURL(), function->m_body->lineNo()); +} + +} // namespace JSC diff --git a/JavaScriptCore/profiler/Profiler.h b/JavaScriptCore/profiler/Profiler.h new file mode 100644 index 0000000..b622fb2 --- /dev/null +++ b/JavaScriptCore/profiler/Profiler.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef Profiler_h +#define Profiler_h + +#include "Profile.h" +#include <wtf/PassRefPtr.h> +#include <wtf/RefPtr.h> +#include <wtf/Vector.h> + +namespace JSC { + + class CallIdentifier; + class ExecState; + class JSGlobalData; + class JSObject; + class ProfileGenerator; + class UString; + + class Profiler { + public: + static Profiler** enabledProfilerReference() + { + return &s_sharedEnabledProfilerReference; + } + + static Profiler* profiler(); + static CallIdentifier createCallIdentifier(JSGlobalData*, JSValue*, const UString& sourceURL, int lineNumber); + + void startProfiling(ExecState*, const UString& title); + PassRefPtr<Profile> stopProfiling(ExecState*, const UString& title); + + void willExecute(ExecState*, JSValue* function); + void willExecute(ExecState*, const UString& sourceURL, int startingLineNumber); + void didExecute(ExecState*, JSValue* function); + void didExecute(ExecState*, const UString& sourceURL, int startingLineNumber); + + const Vector<RefPtr<ProfileGenerator> >& currentProfiles() { return m_currentProfiles; }; + + private: + Vector<RefPtr<ProfileGenerator> > m_currentProfiles; + static Profiler* s_sharedProfiler; + static Profiler* s_sharedEnabledProfilerReference; + }; + +} // namespace JSC + +#endif // Profiler_h diff --git a/JavaScriptCore/profiler/ProfilerServer.h b/JavaScriptCore/profiler/ProfilerServer.h new file mode 100644 index 0000000..5b7cc46 --- /dev/null +++ b/JavaScriptCore/profiler/ProfilerServer.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef ProfileServer_h +#define ProfileServer_h + +namespace JSC { + +void startProfilerServerIfNeeded(); + +} // namespace JSC + +#endif // ProfileServer_h diff --git a/JavaScriptCore/profiler/ProfilerServer.mm b/JavaScriptCore/profiler/ProfilerServer.mm new file mode 100644 index 0000000..ef16f4c --- /dev/null +++ b/JavaScriptCore/profiler/ProfilerServer.mm @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "config.h" +#import "ProfilerServer.h" + +#import "JSProfilerPrivate.h" +#import "JSRetainPtr.h" + +#import <Foundation/Foundation.h> + +@interface ProfilerServer : NSObject { +@private + NSString *_serverName; + unsigned _listenerCount; +} ++ (ProfilerServer *)sharedProfileServer; +- (void)startProfiling; +- (void)stopProfiling; +@end + +@implementation ProfilerServer + ++ (ProfilerServer *)sharedProfileServer +{ + static ProfilerServer *sharedServer; + if (!sharedServer) + sharedServer = [[ProfilerServer alloc] init]; + return sharedServer; +} + +- (id)init +{ + if (!(self = [super init])) + return nil; + + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + if ([defaults boolForKey:@"EnableJSProfiling"]) + [self startProfiling]; + + // The catch-all notifications + [[NSDistributedNotificationCenter defaultCenter] addObserver:self selector:@selector(startProfiling) name:@"ProfilerServerStartNotification" object:nil]; + [[NSDistributedNotificationCenter defaultCenter] addObserver:self selector:@selector(stopProfiling) name:@"ProfilerServerStopNotification" object:nil]; + + // The specific notifications + NSProcessInfo *processInfo = [NSProcessInfo processInfo]; + _serverName = [[NSString alloc] initWithFormat:@"ProfilerServer-%d", [processInfo processIdentifier]]; + + [[NSDistributedNotificationCenter defaultCenter] addObserver:self selector:@selector(startProfiling) name:[_serverName stringByAppendingString:@"-Start"] object:nil]; + [[NSDistributedNotificationCenter defaultCenter] addObserver:self selector:@selector(stopProfiling) name:[_serverName stringByAppendingString:@"-Stop"] object:nil]; + + [pool drain]; + + return self; +} + +- (void)startProfiling +{ + if (++_listenerCount > 1) + return; + JSRetainPtr<JSStringRef> profileName(Adopt, JSStringCreateWithUTF8CString([_serverName UTF8String])); + JSStartProfiling(0, profileName.get()); +} + +- (void)stopProfiling +{ + if (!_listenerCount || --_listenerCount > 0) + return; + JSRetainPtr<JSStringRef> profileName(Adopt, JSStringCreateWithUTF8CString([_serverName UTF8String])); + JSEndProfiling(0, profileName.get()); +} + +@end + +namespace JSC { + +void startProfilerServerIfNeeded() +{ + [ProfilerServer sharedProfileServer]; +} + +} // namespace JSC diff --git a/JavaScriptCore/profiler/TreeProfile.cpp b/JavaScriptCore/profiler/TreeProfile.cpp new file mode 100644 index 0000000..0c7fedb --- /dev/null +++ b/JavaScriptCore/profiler/TreeProfile.cpp @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "TreeProfile.h" + +#include "HeavyProfile.h" + +namespace JSC { + +PassRefPtr<TreeProfile> TreeProfile::create(const UString& title, unsigned uid) +{ + return adoptRef(new TreeProfile(title, uid)); +} + +TreeProfile::TreeProfile(const UString& title, unsigned uid) + : Profile(title, uid) +{ +} + +Profile* TreeProfile::heavyProfile() +{ + if (!m_heavyProfile) + m_heavyProfile = HeavyProfile::create(this); + + return m_heavyProfile.get(); +} + +} // namespace JSC diff --git a/JavaScriptCore/profiler/TreeProfile.h b/JavaScriptCore/profiler/TreeProfile.h new file mode 100644 index 0000000..ebef4d8 --- /dev/null +++ b/JavaScriptCore/profiler/TreeProfile.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TreeProfile_h +#define TreeProfile_h + +#include "Profile.h" + +namespace JSC { + + class ExecState; + class HeavyProfile; + class UString; + + class TreeProfile : public Profile { + public: + static PassRefPtr<TreeProfile> create(const UString& title, unsigned uid); + + virtual Profile* heavyProfile(); + virtual Profile* treeProfile() { return this; } + + private: + TreeProfile(const UString& title, unsigned uid); + RefPtr<HeavyProfile> m_heavyProfile; + }; + +} // namespace JSC + +#endif // TreeProfiler_h |