/* * 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. * 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 <wtf/Assertions.h> #include <wtf/HashMap.h> #include <wtf/Threading.h> #include "Nodes.h" #include "Opcode.h" namespace JSC { class CodeBlock; class ExecState; class Interpreter; class ScopeNode; struct Instruction; struct ScopeSampleRecord { ScopeSampleRecord(ScopeNode* scope) : m_scope(scope) , m_codeBlock(0) , m_sampleCount(0) , m_opcodeSampleCount(0) , m_samples(0) , m_size(0) { } ~ScopeSampleRecord() { if (m_samples) free(m_samples); } void sample(CodeBlock*, Instruction*); RefPtr<ScopeNode> m_scope; CodeBlock* m_codeBlock; int m_sampleCount; int m_opcodeSampleCount; int* m_samples; unsigned m_size; }; typedef WTF::HashMap<ScopeNode*, ScopeSampleRecord*> ScopeSampleRecordMap; class SamplingTool { public: friend class CallRecord; friend class HostCallRecord; #if ENABLE(OPCODE_SAMPLING) class CallRecord : Noncopyable { public: CallRecord(SamplingTool* samplingTool) : m_samplingTool(samplingTool) , m_savedSample(samplingTool->m_sample) , m_savedCodeBlock(samplingTool->m_codeBlock) { } ~CallRecord() { m_samplingTool->m_sample = m_savedSample; m_samplingTool->m_codeBlock = m_savedCodeBlock; } private: SamplingTool* m_samplingTool; 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 { public: CallRecord(SamplingTool*) { } }; class HostCallRecord : public CallRecord { public: HostCallRecord(SamplingTool* samplingTool) : CallRecord(samplingTool) { } }; #endif 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()) { 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(); void dump(ExecState*); void notifyOfScope(ScopeNode* 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)); } private: class Sample { public: Sample(volatile intptr_t sample, CodeBlock* volatile codeBlock) : m_sample(sample) , m_codeBlock(codeBlock) { } bool isNull() { return !m_sample || !m_codeBlock; } 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; }; static void* threadStartFunc(void*); void run(); 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; // Gathered sample data. long long m_sampleCount; long long m_opcodeSampleCount; unsigned m_opcodeSamples[numOpcodeIDs]; unsigned m_opcodeSamplesInCTIFunctions[numOpcodeIDs]; Mutex m_scopeSampleMapMutex; OwnPtr<ScopeSampleRecordMap> m_scopeSampleMap; }; } // namespace JSC #endif // SamplingTool_h