X-Git-Url: https://git.saurik.com/apple/javascriptcore.git/blobdiff_plain/ba379fdc102753d6be2c4d937058fe40257329fe..cb9aa2694aba0ae4f946ed34b8e0f6c99c1cfe44:/bytecode/SamplingTool.h diff --git a/bytecode/SamplingTool.h b/bytecode/SamplingTool.h index 7d7dc9c..678af85 100644 --- a/bytecode/SamplingTool.h +++ b/bytecode/SamplingTool.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 Apple Inc. All rights reserved. + * Copyright (C) 2008, 2013 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -10,7 +10,7 @@ * 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 + * 3. Neither the name of Apple 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. * @@ -29,20 +29,24 @@ #ifndef SamplingTool_h #define SamplingTool_h +#include "Strong.h" +#include "Opcode.h" +#include "SamplingCounter.h" #include +#include #include +#include +#include #include -#include "Nodes.h" -#include "Opcode.h" - namespace JSC { + class ScriptExecutable; + class SamplingFlags { - friend class JIT; public: - static void start(); - static void stop(); + JS_EXPORT_PRIVATE static void start(); + JS_EXPORT_PRIVATE static void stop(); #if ENABLE(SAMPLING_FLAGS) static void setFlag(unsigned flag) @@ -78,23 +82,111 @@ namespace JSC { int m_flag; }; + static const void* addressOfFlags() + { + return &s_flags; + } + #endif private: - static uint32_t s_flags; + 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(VM& vm, ScriptExecutable* executable) + : m_executable(vm, executable) , m_codeBlock(0) , m_sampleCount(0) , m_opcodeSampleCount(0) @@ -103,7 +195,7 @@ namespace JSC { { } - ~ScopeSampleRecord() + ~ScriptSampleRecord() { if (m_samples) free(m_samples); @@ -111,7 +203,7 @@ namespace JSC { void sample(CodeBlock*, Instruction*); - RefPtr m_scope; + Strong m_executable; CodeBlock* m_codeBlock; int m_sampleCount; int m_opcodeSampleCount; @@ -119,7 +211,7 @@ namespace JSC { unsigned m_size; }; - typedef WTF::HashMap ScopeSampleRecordMap; + typedef HashMap> ScriptSampleRecordMap; class SamplingThread { public: @@ -128,25 +220,27 @@ namespace JSC { static unsigned s_hertz; static ThreadIdentifier s_samplingThread; - static void start(unsigned hertz=10000); - static void stop(); + JS_EXPORT_PRIVATE static void start(unsigned hertz=10000); + JS_EXPORT_PRIVATE static void stop(); - static void* threadStartFunc(void*); + static void threadStartFunc(void*); }; class SamplingTool { public: - friend class CallRecord; - friend class HostCallRecord; + friend struct CallRecord; #if ENABLE(OPCODE_SAMPLING) - class CallRecord : Noncopyable { + class CallRecord { + WTF_MAKE_NONCOPYABLE(CallRecord); public: - CallRecord(SamplingTool* samplingTool) + CallRecord(SamplingTool* samplingTool, bool isHostCall = false) : m_samplingTool(samplingTool) , m_savedSample(samplingTool->m_sample) , m_savedCodeBlock(samplingTool->m_codeBlock) { + if (isHostcall) + samplingTool->m_sample |= 0x1; } ~CallRecord() @@ -160,31 +254,15 @@ namespace JSC { intptr_t m_savedSample; CodeBlock* m_savedCodeBlock; }; - - class HostCallRecord : public CallRecord { - public: - HostCallRecord(SamplingTool* samplingTool) - : CallRecord(samplingTool) - { - samplingTool->m_sample |= 0x1; - } - }; #else - class CallRecord : Noncopyable { + class CallRecord { + WTF_MAKE_NONCOPYABLE(CallRecord); public: - CallRecord(SamplingTool*) + CallRecord(SamplingTool*, bool = false) { } }; - - class HostCallRecord : public CallRecord { - public: - HostCallRecord(SamplingTool* samplingTool) - : CallRecord(samplingTool) - { - } - }; -#endif +#endif SamplingTool(Interpreter* interpreter) : m_interpreter(interpreter) @@ -193,24 +271,17 @@ namespace JSC { , m_sampleCount(0) , m_opcodeSampleCount(0) #if ENABLE(CODEBLOCK_SAMPLING) - , m_scopeSampleMap(new ScopeSampleRecordMap()) + , m_scopeSampleMap(adoptPtr(new ScriptSampleRecordMap)) #endif { memset(m_opcodeSamples, 0, sizeof(m_opcodeSamples)); memset(m_opcodeSamplesInCTIFunctions, 0, sizeof(m_opcodeSamplesInCTIFunctions)); } - ~SamplingTool() - { -#if ENABLE(CODEBLOCK_SAMPLING) - deleteAllValues(*m_scopeSampleMap); -#endif - } - - void setup(); + JS_EXPORT_PRIVATE void setup(); void dump(ExecState*); - void notifyOfScope(ScopeNode* scope); + void notifyOfScope(VM&, ScriptExecutable* scope); void sample(CodeBlock* codeBlock, Instruction* vPC) { @@ -266,147 +337,11 @@ namespace JSC { unsigned m_opcodeSamplesInCTIFunctions[numOpcodeIDs]; #if ENABLE(CODEBLOCK_SAMPLING) - Mutex m_scopeSampleMapMutex; - OwnPtr m_scopeSampleMap; + Mutex m_scriptSampleMapMutex; + OwnPtr m_scopeSampleMap; #endif }; - // AbstractSamplingCounter: - // - // Implements a named set of counters, printed on exit if ENABLE(SAMPLING_COUNTERS). - // See subclasses below, SamplingCounter, GlobalSamplingCounter and DeletableSamplingCounter. - class AbstractSamplingCounter { - friend class JIT; - friend class DeletableSamplingCounter; - public: - void count(uint32_t count = 1) - { - m_counter += count; - } - - static void dump(); - - protected: - // Effectively the contructor, however called lazily in the case of GlobalSamplingCounter. - void init(const char* name) - { - m_counter = 0; - m_name = name; - - // Set m_next to point to the head of the chain, and inform whatever is - // currently at the head that this node will now hold the pointer to it. - m_next = s_abstractSamplingCounterChain; - s_abstractSamplingCounterChain->m_referer = &m_next; - // Add this node to the head of the list. - s_abstractSamplingCounterChain = this; - m_referer = &s_abstractSamplingCounterChain; - } - - int64_t m_counter; - const char* m_name; - AbstractSamplingCounter* m_next; - // This is a pointer to the pointer to this node in the chain; used to - // allow fast linked list deletion. - AbstractSamplingCounter** m_referer; - // Null object used to detect end of static chain. - static AbstractSamplingCounter s_abstractSamplingCounterChainEnd; - static AbstractSamplingCounter* s_abstractSamplingCounterChain; - static bool s_completed; - }; - -#if ENABLE(SAMPLING_COUNTERS) - // SamplingCounter: - // - // This class is suitable and (hopefully!) convenient for cases where a counter is - // required within the scope of a single function. It can be instantiated as a - // static variable since it contains a constructor but not a destructor (static - // variables in WebKit cannot have destructors). - // - // For example: - // - // void someFunction() - // { - // static SamplingCounter countMe("This is my counter. There are many like it, but this one is mine."); - // countMe.count(); - // // ... - // } - // - class SamplingCounter : public AbstractSamplingCounter { - public: - SamplingCounter(const char* name) { init(name); } - }; - - // GlobalSamplingCounter: - // - // This class is suitable for use where a counter is to be declared globally, - // since it contains neither a constructor nor destructor. Instead, ensure - // that 'name()' is called to provide the counter with a name (and also to - // allow it to be printed out on exit). - // - // GlobalSamplingCounter globalCounter; - // - // void firstFunction() - // { - // // Put this within a function that is definitely called! - // // (Or alternatively alongside all calls to 'count()'). - // globalCounter.name("I Name You Destroyer."); - // globalCounter.count(); - // // ... - // } - // - // void secondFunction() - // { - // globalCounter.count(); - // // ... - // } - // - class GlobalSamplingCounter : public AbstractSamplingCounter { - public: - void name(const char* name) - { - // Global objects should be mapped in zero filled memory, so this should - // be a safe (albeit not necessarily threadsafe) check for 'first call'. - if (!m_next) - init(name); - } - }; - - // DeletableSamplingCounter: - // - // The above classes (SamplingCounter, GlobalSamplingCounter), are intended for - // use within a global or static scope, and as such cannot have a destructor. - // This means there is no convenient way for them to remove themselves from the - // static list of counters, and should an instance of either class be freed - // before 'dump()' has walked over the list it will potentially walk over an - // invalid pointer. - // - // This class is intended for use where the counter may possibly be deleted before - // the program exits. Should this occur, the counter will print it's value to - // stderr, and remove itself from the static list. Example: - // - // DeletableSamplingCounter* counter = new DeletableSamplingCounter("The Counter With No Name"); - // counter->count(); - // delete counter; - // - class DeletableSamplingCounter : public AbstractSamplingCounter { - public: - DeletableSamplingCounter(const char* name) { init(name); } - - ~DeletableSamplingCounter() - { - if (!s_completed) - fprintf(stderr, "DeletableSamplingCounter \"%s\" deleted early (with count %lld)\n", m_name, m_counter); - // Our m_referer pointer should know where the pointer to this node is, - // and m_next should know that this node is the previous node in the list. - ASSERT(*m_referer == this); - ASSERT(m_next->m_referer == &m_next); - // Remove this node from the list, and inform m_next that we have done so. - m_next->m_referer = m_referer; - *m_referer = m_next; - } - }; -#endif - } // namespace JSC #endif // SamplingTool_h