123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348 |
- /*
- * 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
- * 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 SamplingTool_h
- #define SamplingTool_h
- #include "Strong.h"
- #include "Opcode.h"
- #include "SamplingCounter.h"
- #include <wtf/Assertions.h>
- #include <wtf/Atomics.h>
- #include <wtf/HashMap.h>
- #include <wtf/MainThread.h>
- #include <wtf/Spectrum.h>
- #include <wtf/Threading.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<SamplingRegion*>(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<SamplingRegion*>(previous);
-
- if (WTF::weakCompareAndSwapUIntPtr(&s_currentOrReserved, previous, bitwise_cast<uintptr_t>(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<const char*>* 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 ScriptSampleRecord {
- ScriptSampleRecord(VM& vm, ScriptExecutable* executable)
- : m_executable(vm, executable)
- , m_codeBlock(0)
- , m_sampleCount(0)
- , m_opcodeSampleCount(0)
- , m_samples(0)
- , m_size(0)
- {
- }
-
- ~ScriptSampleRecord()
- {
- if (m_samples)
- free(m_samples);
- }
-
- void sample(CodeBlock*, Instruction*);
- Strong<ScriptExecutable> m_executable;
- CodeBlock* m_codeBlock;
- int m_sampleCount;
- int m_opcodeSampleCount;
- int* m_samples;
- unsigned m_size;
- };
- typedef HashMap<ScriptExecutable*, OwnPtr<ScriptSampleRecord> > 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 struct CallRecord;
-
- #if ENABLE(OPCODE_SAMPLING)
- class CallRecord {
- WTF_MAKE_NONCOPYABLE(CallRecord);
- public:
- 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()
- {
- m_samplingTool->m_sample = m_savedSample;
- m_samplingTool->m_codeBlock = m_savedCodeBlock;
- }
- private:
- SamplingTool* m_samplingTool;
- intptr_t m_savedSample;
- CodeBlock* m_savedCodeBlock;
- };
- #else
- class CallRecord {
- WTF_MAKE_NONCOPYABLE(CallRecord);
- public:
- CallRecord(SamplingTool*, bool = false)
- {
- }
- };
- #endif
- SamplingTool(Interpreter* interpreter)
- : m_interpreter(interpreter)
- , m_codeBlock(0)
- , m_sample(0)
- , m_sampleCount(0)
- , m_opcodeSampleCount(0)
- #if ENABLE(CODEBLOCK_SAMPLING)
- , m_scopeSampleMap(adoptPtr(new ScriptSampleRecordMap))
- #endif
- {
- memset(m_opcodeSamples, 0, sizeof(m_opcodeSamples));
- memset(m_opcodeSamplesInCTIFunctions, 0, sizeof(m_opcodeSamplesInCTIFunctions));
- }
- JS_EXPORT_PRIVATE void setup();
- void dump(ExecState*);
- void notifyOfScope(VM&, ScriptExecutable* scope);
- void sample(CodeBlock* codeBlock, Instruction* vPC)
- {
- ASSERT(!(reinterpret_cast<intptr_t>(vPC) & 0x3));
- m_codeBlock = codeBlock;
- m_sample = reinterpret_cast<intptr_t>(vPC);
- }
- CodeBlock** codeBlockSlot() { return &m_codeBlock; }
- intptr_t* sampleSlot() { return &m_sample; }
- void* encodeSample(Instruction* vPC, bool inCTIFunction = false, bool inHostFunction = false)
- {
- ASSERT(!(reinterpret_cast<intptr_t>(vPC) & 0x3));
- return reinterpret_cast<void*>(reinterpret_cast<intptr_t>(vPC) | (static_cast<intptr_t>(inCTIFunction) << 1) | static_cast<intptr_t>(inHostFunction));
- }
- static void sample();
- private:
- class Sample {
- public:
- Sample(volatile intptr_t sample, CodeBlock* volatile codeBlock)
- : m_sample(sample)
- , m_codeBlock(codeBlock)
- {
- }
-
- bool isNull() { return !m_sample; }
- CodeBlock* codeBlock() { return m_codeBlock; }
- Instruction* vPC() { return reinterpret_cast<Instruction*>(m_sample & ~0x3); }
- bool inHostFunction() { return m_sample & 0x1; }
- bool inCTIFunction() { return m_sample & 0x2; }
- private:
- intptr_t m_sample;
- CodeBlock* m_codeBlock;
- };
- void doRun();
- static SamplingTool* s_samplingTool;
-
- Interpreter* m_interpreter;
-
- // State tracked by the main thread, used by the sampling thread.
- CodeBlock* m_codeBlock;
- intptr_t m_sample;
- // Gathered sample data.
- long long m_sampleCount;
- long long m_opcodeSampleCount;
- unsigned m_opcodeSamples[numOpcodeIDs];
- unsigned m_opcodeSamplesInCTIFunctions[numOpcodeIDs];
-
- #if ENABLE(CODEBLOCK_SAMPLING)
- Mutex m_scriptSampleMapMutex;
- OwnPtr<ScriptSampleRecordMap> m_scopeSampleMap;
- #endif
- };
- } // namespace JSC
- #endif // SamplingTool_h
|