Commit f2bacea7 authored by barraclough@apple.com's avatar barraclough@apple.com

2008-07-23 Gavin Barraclough <barraclough@apple.com>

        Reviewed by Geoff Garen.

        Sampling tool to analyze cost of instruction execution and identify hot regions of JS code.
        Enable Switches by setting SAMPLING_TOOL_ENABLED in Opcode.h.

        * JavaScriptCore.exp: Export symbols for Shell.cpp.
        * VM/Machine.cpp:     Added sampling hooks.
        * VM/Machine.h:       Machine contains a pointer to a sampler, when sampling.
        * VM/Opcode.cpp:      Tool implementation.
        * VM/Opcode.h:        Tool declaration.
        * kjs/Shell.cpp:      Initialize the sampler, if enabled.
        * kjs/nodes.cpp:      Added sampling hooks.



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@35305 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 3c5f2760
2008-07-23 Gavin Barraclough <barraclough@apple.com>
Reviewed by Geoff Garen.
Sampling tool to analyze cost of instruction execution and identify hot regions of JS code.
Enable Switches by setting SAMPLING_TOOL_ENABLED in Opcode.h.
* JavaScriptCore.exp: Export symbols for Shell.cpp.
* VM/Machine.cpp: Added sampling hooks.
* VM/Machine.h: Machine contains a pointer to a sampler, when sampling.
* VM/Opcode.cpp: Tool implementation.
* VM/Opcode.h: Tool declaration.
* kjs/Shell.cpp: Initialize the sampler, if enabled.
* kjs/nodes.cpp: Added sampling hooks.
2008-07-23 Gabor Loki <loki@inf.u-szeged.hu>
Bug 20097: [Qt] 20% Sunspider slow-down
......@@ -322,3 +322,6 @@ __ZTVN3KJS16JSVariableObjectE
__ZTVN3KJS8JSObjectE
_jscore_fastmalloc_introspection
_kJSClassDefinitionEmpty
__ZN3KJS12SamplingTool4stopEv
__ZN3KJS12SamplingTool5startEj
__ZN3KJS12SamplingTool4dumpEPNS_9ExecStateE
......@@ -473,7 +473,8 @@ NEVER_INLINE JSValue* Machine::callEval(ExecState* exec, JSObject* thisObj, Scop
}
Machine::Machine()
: m_reentryDepth(0)
: m_sampler(0)
, m_reentryDepth(0)
, m_timeoutTime(0)
, m_timeAtLastCheckTimeout(0)
, m_timeExecuting(0)
......@@ -730,6 +731,8 @@ JSValue* Machine::execute(ProgramNode* programNode, ExecState* exec, ScopeChainN
JSValue* result = privateExecute(Normal, &newExec, &m_registerFile, r, scopeChain, codeBlock, exception);
m_reentryDepth--;
MACHINE_SAMPLING_privateExecuteReturned();
if (*profiler) {
(*profiler)->didExecute(exec, programNode->sourceURL(), programNode->lineNo());
if (!m_reentryDepth)
......@@ -791,6 +794,8 @@ JSValue* Machine::execute(FunctionBodyNode* functionBodyNode, ExecState* exec, J
JSValue* result = privateExecute(Normal, &newExec, &m_registerFile, r, scopeChain, newCodeBlock, exception);
m_reentryDepth--;
MACHINE_SAMPLING_privateExecuteReturned();
if (*profiler && !m_reentryDepth)
(*profiler)->didFinishAllExecution(exec);
......@@ -857,6 +862,8 @@ JSValue* Machine::execute(EvalNode* evalNode, ExecState* exec, JSObject* thisObj
JSValue* result = privateExecute(Normal, &newExec, &m_registerFile, r, scopeChain, codeBlock, exception);
m_reentryDepth--;
MACHINE_SAMPLING_privateExecuteReturned();
if (*profiler) {
(*profiler)->didExecute(exec, evalNode->sourceURL(), evalNode->lineNo());
if (!m_reentryDepth)
......@@ -1028,7 +1035,7 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFi
}
#if HAVE(COMPUTED_GOTO)
#define NEXT_OPCODE goto *vPC->u.opcode
#define NEXT_OPCODE MACHINE_SAMPLING_sample(codeBlock, vPC); goto *vPC->u.opcode
#if DUMP_OPCODE_STATS
#define BEGIN_OPCODE(opcode) opcode: OpcodeStats::recordInstruction(opcode);
#else
......@@ -1036,7 +1043,7 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFi
#endif
NEXT_OPCODE;
#else
#define NEXT_OPCODE continue
#define NEXT_OPCODE MACHINE_SAMPLING_sample(codeBlock, vPC); continue
#if DUMP_OPCODE_STATS
#define BEGIN_OPCODE(opcode) case opcode: OpcodeStats::recordInstruction(opcode);
#else
......@@ -2291,6 +2298,8 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFi
JSValue* thisValue = thisVal == missingThisObjectMarker() ? exec->globalThisValue() : r[thisVal].jsValue(exec);
ArgList args(r + firstArg + 1, argCount - 1);
MACHINE_SAMPLING_callingNativeFunction();
JSValue* returnValue = callData.native.function(exec, static_cast<JSObject*>(v), thisValue, args);
VM_CHECK_EXCEPTION();
......
......@@ -119,6 +119,8 @@ namespace KJS {
m_timeoutTime = 0;
m_timeoutCheckCount = 0;
}
SamplingTool* m_sampler;
private:
enum ExecutionFlag { Normal, InitializeAndReturn };
......
This diff is collapsed.
......@@ -31,9 +31,11 @@
#define Opcodes_h
#include <wtf/Assertions.h>
#include <wtf/HashMap.h>
namespace KJS {
#define SAMPLING_TOOL_ENABLED 0
#define DUMP_OPCODE_STATS 0
#define FOR_EACH_OPCODE_ID(macro) \
......@@ -143,6 +145,114 @@ namespace KJS {
typedef OpcodeID Opcode;
#endif
class ExecState;
class ScopeNode;
class CodeBlock;
struct Instruction;
struct ScopeSampleRecord
{
RefPtr<ScopeNode> m_scope;
CodeBlock* m_codeBlock;
int m_totalCount;
int* m_vpcCounts;
unsigned m_size;
ScopeSampleRecord(ScopeNode* scope)
: m_scope(scope)
, m_codeBlock(0)
, m_totalCount(0)
, m_vpcCounts(0)
, m_size(0)
{
}
~ScopeSampleRecord()
{
if (m_vpcCounts)
free(m_vpcCounts);
}
void sample(CodeBlock* codeBlock, Instruction* vPC);
};
typedef WTF::HashMap<ScopeNode*, ScopeSampleRecord*> ScopeSampleRecordMap;
class SamplingTool
{
public:
SamplingTool()
: m_running(false)
, m_recordedCodeBlock(0)
, m_recordedVPC(0)
, m_totalSamples(0)
, m_scopeSampleMap(new ScopeSampleRecordMap())
{
}
~SamplingTool()
{
for (ScopeSampleRecordMap::iterator iter = m_scopeSampleMap->begin(); iter != m_scopeSampleMap->end(); ++iter)
delete iter->second;
delete m_scopeSampleMap;
}
void start(unsigned hertz=1000);
void stop();
void dump(ExecState*);
void notifyOfScope(ScopeNode* scope);
void sample(CodeBlock* recordedCodeBlock, Instruction* recordedVPC)
{
m_recordedCodeBlock = recordedCodeBlock;
m_recordedVPC = recordedVPC;
}
void privateExecuteReturned()
{
m_recordedCodeBlock = 0;
m_recordedVPC = 0;
}
void callingNativeFunction()
{
m_recordedCodeBlock = 0;
m_recordedVPC = 0;
}
private:
static void* threadStartFunc(void*);
void run();
// Sampling thread state.
bool m_running;
unsigned m_hertz;
pthread_t m_samplingThread;
// State tracked by the main thread, used by the sampling thread.
CodeBlock* m_recordedCodeBlock;
Instruction* m_recordedVPC;
// Gathered sample data.
long long m_totalSamples;
ScopeSampleRecordMap* m_scopeSampleMap;
};
// SCOPENODE_ / MACHINE_ macros for use from within member methods on ScopeNode / Machine respectively.
#if SAMPLING_TOOL_ENABLED
#define SCOPENODE_SAMPLING_notifyOfScope(sampler) sampler->notifyOfScope(this)
#define MACHINE_SAMPLING_sample(codeBlock, vPC) m_sampler->sample(codeBlock, vPC)
#define MACHINE_SAMPLING_privateExecuteReturned() m_sampler->privateExecuteReturned()
#define MACHINE_SAMPLING_callingNativeFunction() m_sampler->callingNativeFunction()
#else
#define SCOPENODE_SAMPLING_notifyOfScope(sampler)
#define MACHINE_SAMPLING_sample(codeBlock, vPC)
#define MACHINE_SAMPLING_privateExecuteReturned()
#define MACHINE_SAMPLING_callingNativeFunction()
#endif
#if DUMP_OPCODE_STATS
struct OpcodeStats {
......
......@@ -339,6 +339,12 @@ static bool runWithScripts(GlobalObject* globalObject, const Vector<UString>& fi
if (prettyPrint)
prettyPrintScript(globalObject->globalExec(), fileName, script);
else {
#if SAMPLING_TOOL_ENABLED
Machine* machine = globalObject->globalData()->machine;
machine->m_sampler = new SamplingTool();
machine->m_sampler->start();
#endif
Completion completion = Interpreter::evaluate(globalObject->globalExec(), globalObject->globalScopeChain(), fileName, 1, script.data());
success = success && completion.complType() != Throw;
if (dump) {
......@@ -347,6 +353,12 @@ static bool runWithScripts(GlobalObject* globalObject, const Vector<UString>& fi
else
printf("Exception: %s\n", completion.value()->toString(globalObject->globalExec()).ascii());
}
#if SAMPLING_TOOL_ENABLED
machine->m_sampler->stop();
machine->m_sampler->dump(globalObject->globalExec());
delete machine->m_sampler;
#endif
}
}
return success;
......
......@@ -1548,7 +1548,7 @@ RegisterID* TryNode::emitCode(CodeGenerator& generator, RegisterID* dst)
}
// ------------------------------ FunctionBodyNode -----------------------------
// ------------------------------ ScopeNode -----------------------------
ScopeNode::ScopeNode(JSGlobalData* globalData, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, bool usesEval, bool needsClosure)
: BlockNode(globalData, children)
......@@ -1561,6 +1561,8 @@ ScopeNode::ScopeNode(JSGlobalData* globalData, SourceElements* children, VarStac
m_varStack = *varStack;
if (funcStack)
m_functionStack = *funcStack;
SCOPENODE_SAMPLING_notifyOfScope(globalData->machine->m_sampler);
}
// ------------------------------ ProgramNode -----------------------------
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment