+2008-05-09 Kevin McCullough <kmccullough@apple.com>
+
+ Reviewed by Tim.
+
+ -<rdar://problem/5770054> JavaScript profiler (10928)
+ -Add Profile class so that all profiles can be stored and retrieved by
+ the WebInspector when that time comes.
+
+ * JavaScriptCore.exp: Export the new function signatures.
+ * JavaScriptCore.xcodeproj/project.pbxproj: Add the new files to the
+ project
+ * profiler/Profile.cpp: Added. This class represents a single run of the
+ profiler.
+ (KJS::Profile::Profile):
+ (KJS::Profile::willExecute):
+ (KJS::Profile::didExecute):
+ (KJS::Profile::printDataInspectorStyle):
+ (KJS::functionNameCountPairComparator):
+ (KJS::Profile::printDataSampleStyle):
+ * profiler/Profile.h: Added. Ditto
+ (KJS::Profile::stopProfiling):
+ * profiler/Profiler.cpp: Now the profiler keeps track of many profiles
+ but only runs one at a time.
+ (KJS::Profiler::startProfiling):
+ (KJS::Profiler::stopProfiling):
+ (KJS::Profiler::willExecute):
+ (KJS::Profiler::didExecute):
+ (KJS::Profiler::printDataInspectorStyle):
+ (KJS::Profiler::printDataSampleStyle):
+ * profiler/Profiler.h: Ditto.
+ (KJS::Profiler::~Profiler):
+ (KJS::Profiler::allProfiles):
+ (KJS::Profiler::clearProfiles):
+
2008-05-08 Anders Carlsson <andersca@apple.com>
Reviewed by Mark.
__ZN3KJS8jsStringEPNS_9ExecStateEPKc
__ZN3KJS8jsStringEPNS_9ExecStateERKNS_7UStringE
__ZN3KJS8Profiler13stopProfilingEv
-__ZN3KJS8Profiler14startProfilingEj
+__ZN3KJS8Profiler14startProfilingEjRKNS_7UStringE
__ZN3KJS8Profiler8profilerEv
__ZN3KJSeqERKNS_7UStringEPKc
__ZN3WTF10fastCallocEmm
__ZNK3KJS8JSObject9classInfoEv
__ZNK3KJS8JSObject9classNameEv
__ZNK3KJS8JSObject9toBooleanEPNS_9ExecStateE
-__ZNK3KJS8Profiler20printDataSampleStyleEv
-__ZNK3KJS8Profiler23printDataInspectorStyleEv
+__ZNK3KJS8Profiler23printDataInspectorStyleEj
__ZNK3KJS9ExecState19lexicalGlobalObjectEv
__ZNK3KJS9HashTable11createTableEv
__ZNK3WTF8Collator7collateEPKtmS2_m
93E26BE608B1517100F85226 /* pcre_internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 93E26BE508B1517100F85226 /* pcre_internal.h */; };
93E26BFE08B151D400F85226 /* ucpinternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 93E26BFC08B151D400F85226 /* ucpinternal.h */; };
93F0B3AC09BB4DC00068FCE3 /* Parser.h in Headers */ = {isa = PBXBuildFile; fileRef = 93F0B3AA09BB4DC00068FCE3 /* Parser.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ 95742F650DD11F5A000917FB /* Profile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 95742F630DD11F5A000917FB /* Profile.cpp */; };
+ 95742F660DD11F5A000917FB /* Profile.h in Headers */ = {isa = PBXBuildFile; fileRef = 95742F640DD11F5A000917FB /* Profile.h */; settings = {ATTRIBUTES = (Private, ); }; };
958D85830DC93230008ABF27 /* StrHash.h in Headers */ = {isa = PBXBuildFile; fileRef = 958D85820DC93230008ABF27 /* StrHash.h */; settings = {ATTRIBUTES = (Private, ); }; };
95AB83420DA4322500BC83F3 /* Profiler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 95AB832E0DA42CAD00BC83F3 /* Profiler.cpp */; };
95AB83480DA432EB00BC83F3 /* Profiler.h in Headers */ = {isa = PBXBuildFile; fileRef = 95AB832F0DA42CAD00BC83F3 /* Profiler.h */; settings = {ATTRIBUTES = (Private, ); }; };
93F0B3A909BB4DC00068FCE3 /* Parser.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Parser.cpp; sourceTree = "<group>"; };
93F0B3AA09BB4DC00068FCE3 /* Parser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Parser.h; sourceTree = "<group>"; };
93F1981A08245AAE001E9ABC /* keywords.table */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = text; path = keywords.table; sourceTree = "<group>"; tabWidth = 8; };
+ 95742F630DD11F5A000917FB /* Profile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Profile.cpp; path = profiler/Profile.cpp; sourceTree = "<group>"; };
+ 95742F640DD11F5A000917FB /* Profile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Profile.h; path = profiler/Profile.h; sourceTree = "<group>"; };
958D85820DC93230008ABF27 /* StrHash.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StrHash.h; sourceTree = "<group>"; };
95AB832E0DA42CAD00BC83F3 /* Profiler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Profiler.cpp; path = profiler/Profiler.cpp; sourceTree = "<group>"; };
95AB832F0DA42CAD00BC83F3 /* Profiler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Profiler.h; path = profiler/Profiler.h; sourceTree = "<group>"; };
children = (
95AB83540DA43B4400BC83F3 /* FunctionCallProfile.cpp */,
95AB83550DA43B4400BC83F3 /* FunctionCallProfile.h */,
+ 95742F630DD11F5A000917FB /* Profile.cpp */,
+ 95742F640DD11F5A000917FB /* Profile.h */,
95AB832E0DA42CAD00BC83F3 /* Profiler.cpp */,
95AB832F0DA42CAD00BC83F3 /* Profiler.h */,
);
E1B7C8BE0DA3A3360074B0DC /* ThreadSpecific.h in Headers */,
06D358B20DAADA93003B174E /* MainThread.h in Headers */,
958D85830DC93230008ABF27 /* StrHash.h in Headers */,
+ 95742F660DD11F5A000917FB /* Profile.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
95AB83560DA43C3000BC83F3 /* FunctionCallProfile.cpp in Sources */,
06D358B30DAADAA4003B174E /* MainThread.cpp in Sources */,
06D358B40DAADAAA003B174E /* MainThreadMac.mm in Sources */,
+ 95742F650DD11F5A000917FB /* Profile.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
--- /dev/null
+/*
+ * 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 "FunctionCallProfile.h"
+#include "JSGlobalObject.h"
+#include "ExecState.h"
+#include "function.h"
+
+#include <stdio.h>
+
+namespace KJS {
+
+typedef Vector<UString>::const_iterator NameIterator;
+
+Profile::Profile(const UString& title)
+ : m_title(title)
+{
+ // 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_callTree.set(new FunctionCallProfile("Thread_1"));
+}
+
+void Profile::willExecute(const Vector<UString>& callStackNames)
+{
+ FunctionCallProfile* callTreeInsertionPoint = 0;
+ FunctionCallProfile* foundNameInTree = m_callTree.get();
+ NameIterator callStackLocation = callStackNames.begin();
+
+ while (callStackLocation != callStackNames.end() && foundNameInTree) {
+ callTreeInsertionPoint = foundNameInTree;
+ foundNameInTree = callTreeInsertionPoint->findChild(*callStackLocation);
+ ++callStackLocation;
+ }
+
+ if (!foundNameInTree) { // Insert remains of the stack into the call tree.
+ --callStackLocation;
+ for (FunctionCallProfile* next; callStackLocation != callStackNames.end(); ++callStackLocation) {
+ next = new FunctionCallProfile(*callStackLocation);
+ callTreeInsertionPoint->addChild(next);
+ callTreeInsertionPoint = next;
+ }
+ } else // We are calling a function that is already in the call tree.
+ foundNameInTree->willExecute();
+}
+
+void Profile::didExecute(Vector<UString> stackNames)
+{
+ m_callTree->didExecute(stackNames, 0);
+}
+
+void Profile::printDataInspectorStyle() const
+{
+ printf("Call graph:\n");
+ m_callTree->printDataInspectorStyle(0);
+}
+
+typedef pair<UString::Rep*, unsigned> NameCountPair;
+
+static inline bool functionNameCountPairComparator(const NameCountPair a, const NameCountPair b)
+{
+ return a.second > b.second;
+}
+
+void Profile::printDataSampleStyle() const
+{
+ typedef Vector<NameCountPair> NameCountPairVector;
+
+ FunctionCallHashCount countedFunctions;
+ printf("Call graph:\n");
+ m_callTree->printDataSampleStyle(0, countedFunctions);
+
+ printf("\nTotal number in stack:\n");
+ NameCountPairVector sortedFunctions(countedFunctions.size());
+ copyToVector(countedFunctions, sortedFunctions);
+
+ std::sort(sortedFunctions.begin(), sortedFunctions.end(), functionNameCountPairComparator);
+ 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");
+}
+
+} // namespace KJS
--- /dev/null
+/*
+ * 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 "FunctionCallProfile.h"
+#include <wtf/OwnPtr.h>
+
+namespace KJS {
+
+ class ExecState;
+ class FunctionImp;
+ class JSObject;
+
+ class Profile {
+ public:
+ Profile(const UString& title);
+
+ void willExecute(const Vector<UString>& callStackNames);
+ void didExecute(Vector<UString> stackNames);
+
+ void stopProfiling() { m_callTree->stopProfiling(); };
+
+ void printDataInspectorStyle() const;
+ void printDataSampleStyle() const;
+
+ private:
+ const UString& m_title;
+
+ void insertStackNamesInTree(const Vector<UString>& callStackNames);
+
+ OwnPtr<FunctionCallProfile> m_callTree;
+ };
+
+} // namespace KJS
+
+#endif // Profiler_h
#include "config.h"
#include "Profiler.h"
-#include "FunctionCallProfile.h"
-#include "JSGlobalObject.h"
#include "ExecState.h"
#include "function.h"
+#include "FunctionCallProfile.h"
+#include "JSGlobalObject.h"
+#include "Profile.h"
#include <stdio.h>
return sharedProfiler;
}
-void Profiler::startProfiling(unsigned pageGroupIdentifier)
+void Profiler::startProfiling(unsigned pageGroupIdentifier, const UString& title)
{
if (m_profiling)
return;
m_pageGroupIdentifier = pageGroupIdentifier;
- // 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_callTree.set(new FunctionCallProfile("Thread_1"));
+ m_currentProfile.set(new Profile(title));
m_profiling = true;
}
void Profiler::stopProfiling()
{
m_profiling = false;
- m_callTree->stopProfiling();
+
+ if (!m_currentProfile)
+ return;
+
+ m_currentProfile->stopProfiling();
+ m_allProfiles.append(m_currentProfile.release());
}
void Profiler::willExecute(ExecState* exec, JSObject* calledFunction)
Vector<UString> callStackNames;
getStackNames(callStackNames, exec, calledFunction);
- insertStackNamesInTree(callStackNames);
+ m_currentProfile->willExecute(callStackNames);
}
void Profiler::willExecute(ExecState* exec, const UString& sourceURL, int startingLineNumber)
Vector<UString> callStackNames;
getStackNames(callStackNames, exec, sourceURL, startingLineNumber);
- insertStackNamesInTree(callStackNames);
+ m_currentProfile->willExecute(callStackNames);
}
void Profiler::didExecute(ExecState* exec, JSObject* calledFunction)
Vector<UString> callStackNames;
getStackNames(callStackNames, exec, calledFunction);
- m_callTree->didExecute(callStackNames, 0);
+ m_currentProfile->didExecute(callStackNames);
}
void Profiler::didExecute(ExecState* exec, const UString& sourceURL, int startingLineNumber)
Vector<UString> callStackNames;
getStackNames(callStackNames, exec, sourceURL, startingLineNumber);
- m_callTree->didExecute(callStackNames, 0);
-}
-
-void Profiler::insertStackNamesInTree(const Vector<UString>& callStackNames)
-{
- FunctionCallProfile* callTreeInsertionPoint = 0;
- FunctionCallProfile* foundNameInTree = m_callTree.get();
- NameIterator callStackLocation = callStackNames.begin();
-
- while (callStackLocation != callStackNames.end() && foundNameInTree) {
- callTreeInsertionPoint = foundNameInTree;
- foundNameInTree = callTreeInsertionPoint->findChild(*callStackLocation);
- ++callStackLocation;
- }
-
- if (!foundNameInTree) { // Insert remains of the stack into the call tree.
- --callStackLocation;
- for (FunctionCallProfile* next; callStackLocation != callStackNames.end(); ++callStackLocation) {
- next = new FunctionCallProfile(*callStackLocation);
- callTreeInsertionPoint->addChild(next);
- callTreeInsertionPoint = next;
- }
- } else // We are calling a function that is already in the call tree.
- foundNameInTree->willExecute();
+ m_currentProfile->didExecute(callStackNames);
}
void getStackNames(Vector<UString>& names, ExecState* exec)
return (name.isEmpty() ? "[anonymous function]" : name) + " " + URL + ": " + UString::from(lineNumber);
}
-void Profiler::printDataInspectorStyle() const
-{
- printf("Profiler Call graph:\n");
- m_callTree->printDataInspectorStyle(0);
-}
-
-typedef pair<UString::Rep*, unsigned> NameCountPair;
-
-static inline bool functionNameCountPairComparator(const NameCountPair a, const NameCountPair b)
+void Profiler::printDataInspectorStyle(unsigned whichProfile) const
{
- return a.second > b.second;
+ m_allProfiles[whichProfile]->printDataInspectorStyle();
}
-void Profiler::printDataSampleStyle() const
+void Profiler::printDataSampleStyle(unsigned whichProfile) const
{
- typedef Vector<NameCountPair> NameCountPairVector;
-
- FunctionCallHashCount countedFunctions;
- printf("Call graph:\n");
- m_callTree->printDataSampleStyle(0, countedFunctions);
-
- printf("\nTotal number in stack:\n");
- NameCountPairVector sortedFunctions(countedFunctions.size());
- copyToVector(countedFunctions, sortedFunctions);
-
- std::sort(sortedFunctions.begin(), sortedFunctions.end(), functionNameCountPairComparator);
- 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");
+ m_allProfiles[whichProfile]->printDataSampleStyle();
}
void Profiler::debugLog(UString message)
#ifndef Profiler_h
#define Profiler_h
-#include "FunctionCallProfile.h"
+#include "Profile.h"
#include <wtf/OwnPtr.h>
namespace KJS {
class JSObject;
class Profiler {
- typedef Vector<UString>::const_iterator NameIterator;
-
public:
static Profiler* profiler();
static void debugLog(UString);
- void startProfiling(unsigned Identifier);
+ ~Profiler() { deleteAllValues(m_allProfiles); }
+
+ void startProfiling(unsigned pageGroupIdentifier, const UString&);
void stopProfiling();
+
void willExecute(ExecState*, JSObject* calledFunction);
void willExecute(ExecState*, const UString& sourceURL, int startingLineNumber);
void didExecute(ExecState*, JSObject* calledFunction);
void didExecute(ExecState*, const UString& sourceURL, int startingLineNumber);
- void printDataInspectorStyle() const;
- void printDataSampleStyle() const;
+ Vector<Profile*>& allProfiles() { return m_allProfiles; };
+ void clearProfiles() { if (!m_profiling) deleteAllValues(m_allProfiles); };
+
+ void printDataInspectorStyle(unsigned whichProfile) const;
+ void printDataSampleStyle(unsigned whichProfile) const;
private:
Profiler()
{
}
- void insertStackNamesInTree(const Vector<UString>& callStackNames);
-
bool m_profiling;
unsigned m_pageGroupIdentifier;
- // FIXME: Make this a vector of FunctionCallProfiles where each one is the
- // root of a new thread.
- OwnPtr<FunctionCallProfile> m_callTree;
+ OwnPtr<Profile> m_currentProfile;
+ Vector<Profile*> m_allProfiles;
};
} // namespace KJS