X-Git-Url: https://git.saurik.com/apple/javascriptcore.git/blobdiff_plain/9dae56ea45a0f5f8136a5c93d6f3a7f99399ca73..a253471d7f8e4d91bf6ebabab00155c3b387d3d0:/bytecode/SamplingTool.h diff --git a/bytecode/SamplingTool.h b/bytecode/SamplingTool.h index d1cf2e8..52a6e35 100644 --- a/bytecode/SamplingTool.h +++ b/bytecode/SamplingTool.h @@ -29,24 +29,164 @@ #ifndef SamplingTool_h #define SamplingTool_h +#include "Strong.h" +#include "Nodes.h" +#include "Opcode.h" +#include "SamplingCounter.h" #include +#include #include +#include #include -#include "Nodes.h" -#include "Opcode.h" - namespace JSC { + class ScriptExecutable; + + class SamplingFlags { + public: + JS_EXPORT_PRIVATE static void start(); + JS_EXPORT_PRIVATE static void stop(); + +#if ENABLE(SAMPLING_FLAGS) + static void setFlag(unsigned flag) + { + ASSERT(flag >= 1); + ASSERT(flag <= 32); + s_flags |= 1u << (flag - 1); + } + + static void clearFlag(unsigned flag) + { + ASSERT(flag >= 1); + ASSERT(flag <= 32); + s_flags &= ~(1u << (flag - 1)); + } + + static void sample(); + + class ScopedFlag { + public: + ScopedFlag(int flag) + : m_flag(flag) + { + setFlag(flag); + } + + ~ScopedFlag() + { + clearFlag(m_flag); + } + + private: + int m_flag; + }; + + static const void* addressOfFlags() + { + return &s_flags; + } + +#endif + private: + JS_EXPORTDATA static uint32_t s_flags; +#if ENABLE(SAMPLING_FLAGS) + static uint64_t s_flagCounts[33]; +#endif + }; + +#if ENABLE(SAMPLING_REGIONS) + class SamplingRegion { + public: + // Create a scoped sampling region using a C string constant name that describes + // what you are doing. This must be a string constant that persists for the + // lifetime of the process and is immutable. + SamplingRegion(const char* name) + { + if (!isMainThread()) { + m_name = 0; + return; + } + + m_name = name; + exchangeCurrent(this, &m_previous); + ASSERT(!m_previous || m_previous > this); + } + + ~SamplingRegion() + { + if (!m_name) + return; + + ASSERT(bitwise_cast(s_currentOrReserved & ~1) == this); + exchangeCurrent(m_previous); + } + + static void sample(); + + JS_EXPORT_PRIVATE static void dump(); + + private: + const char* m_name; + SamplingRegion* m_previous; + + static void exchangeCurrent(SamplingRegion* current, SamplingRegion** previousPtr = 0) + { + uintptr_t previous; + while (true) { + previous = s_currentOrReserved; + + // If it's reserved (i.e. sampling thread is reading it), loop around. + if (previous & 1) { +#if OS(UNIX) + sched_yield(); +#endif + continue; + } + + // If we're going to CAS, then make sure previous is set. + if (previousPtr) + *previousPtr = bitwise_cast(previous); + + if (WTF::weakCompareAndSwapUIntPtr(&s_currentOrReserved, previous, bitwise_cast(current))) + break; + } + } + + static void dumpInternal(); + + class Locker { + public: + Locker(); + ~Locker(); + }; + + static volatile uintptr_t s_currentOrReserved; + + // rely on identity hashing of string constants + static Spectrum* s_spectrum; + + static unsigned long s_noneOfTheAbove; + + static unsigned s_numberOfSamplesSinceDump; + }; +#else // ENABLE(SAMPLING_REGIONS) + class SamplingRegion { + public: + SamplingRegion(const char*) { } + JS_EXPORT_PRIVATE void dump(); + }; +#endif // ENABLE(SAMPLING_REGIONS) + class CodeBlock; class ExecState; class Interpreter; class ScopeNode; struct Instruction; - struct ScopeSampleRecord { - ScopeSampleRecord(ScopeNode* scope) - : m_scope(scope) + struct ScriptSampleRecord { + ScriptSampleRecord(JSGlobalData& globalData, ScriptExecutable* executable) + : m_executable(globalData, executable) , m_codeBlock(0) , m_sampleCount(0) , m_opcodeSampleCount(0) @@ -55,7 +195,7 @@ namespace JSC { { } - ~ScopeSampleRecord() + ~ScriptSampleRecord() { if (m_samples) free(m_samples); @@ -63,7 +203,7 @@ namespace JSC { void sample(CodeBlock*, Instruction*); - RefPtr m_scope; + Strong m_executable; CodeBlock* m_codeBlock; int m_sampleCount; int m_opcodeSampleCount; @@ -71,15 +211,29 @@ namespace JSC { unsigned m_size; }; - typedef WTF::HashMap ScopeSampleRecordMap; + typedef HashMap > ScriptSampleRecordMap; + + class SamplingThread { + public: + // Sampling thread state. + static bool s_running; + static unsigned s_hertz; + static ThreadIdentifier s_samplingThread; + + JS_EXPORT_PRIVATE static void start(unsigned hertz=10000); + JS_EXPORT_PRIVATE static void stop(); + + static void threadStartFunc(void*); + }; class SamplingTool { public: - friend class CallRecord; + friend struct CallRecord; friend class HostCallRecord; #if ENABLE(OPCODE_SAMPLING) - class CallRecord : Noncopyable { + class CallRecord { + WTF_MAKE_NONCOPYABLE(CallRecord); public: CallRecord(SamplingTool* samplingTool) : m_samplingTool(samplingTool) @@ -109,7 +263,8 @@ namespace JSC { } }; #else - class CallRecord : Noncopyable { + class CallRecord { + WTF_MAKE_NONCOPYABLE(CallRecord); public: CallRecord(SamplingTool*) { @@ -127,27 +282,22 @@ namespace JSC { SamplingTool(Interpreter* interpreter) : m_interpreter(interpreter) - , m_running(false) , m_codeBlock(0) , m_sample(0) , m_sampleCount(0) , m_opcodeSampleCount(0) - , m_scopeSampleMap(new ScopeSampleRecordMap()) +#if ENABLE(CODEBLOCK_SAMPLING) + , m_scopeSampleMap(adoptPtr(new ScriptSampleRecordMap)) +#endif { memset(m_opcodeSamples, 0, sizeof(m_opcodeSamples)); memset(m_opcodeSamplesInCTIFunctions, 0, sizeof(m_opcodeSamplesInCTIFunctions)); } - ~SamplingTool() - { - deleteAllValues(*m_scopeSampleMap); - } - - void start(unsigned hertz=10000); - void stop(); + JS_EXPORT_PRIVATE void setup(); void dump(ExecState*); - void notifyOfScope(ScopeNode* scope); + void notifyOfScope(JSGlobalData&, ScriptExecutable* scope); void sample(CodeBlock* codeBlock, Instruction* vPC) { @@ -165,6 +315,8 @@ namespace JSC { return reinterpret_cast(reinterpret_cast(vPC) | (static_cast(inCTIFunction) << 1) | static_cast(inHostFunction)); } + static void sample(); + private: class Sample { public: @@ -174,7 +326,7 @@ namespace JSC { { } - bool isNull() { return !m_sample || !m_codeBlock; } + bool isNull() { return !m_sample; } CodeBlock* codeBlock() { return m_codeBlock; } Instruction* vPC() { return reinterpret_cast(m_sample & ~0x3); } bool inHostFunction() { return m_sample & 0x1; } @@ -184,17 +336,12 @@ namespace JSC { intptr_t m_sample; CodeBlock* m_codeBlock; }; - - static void* threadStartFunc(void*); - void run(); + + void doRun(); + static SamplingTool* s_samplingTool; Interpreter* m_interpreter; - // Sampling thread state. - bool m_running; - unsigned m_hertz; - ThreadIdentifier m_samplingThread; - // State tracked by the main thread, used by the sampling thread. CodeBlock* m_codeBlock; intptr_t m_sample; @@ -205,8 +352,10 @@ namespace JSC { unsigned m_opcodeSamples[numOpcodeIDs]; unsigned m_opcodeSamplesInCTIFunctions[numOpcodeIDs]; - Mutex m_scopeSampleMapMutex; - OwnPtr m_scopeSampleMap; +#if ENABLE(CODEBLOCK_SAMPLING) + Mutex m_scriptSampleMapMutex; + OwnPtr m_scopeSampleMap; +#endif }; } // namespace JSC