1 /* 2 * Copyright (C) 2008 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of 14 * its contributors may be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #ifndef SamplingTool_h 30 #define SamplingTool_h 31 32 #include <wtf/Assertions.h> 33 #include <wtf/HashMap.h> 34 #include <wtf/Threading.h> 35 36 #include "Nodes.h" 37 #include "Opcode.h" 38 39 namespace JSC { 40 41 class CodeBlock; 42 class ExecState; 43 class Interpreter; 44 class ScopeNode; 45 struct Instruction; 46 47 struct ScopeSampleRecord { ScopeSampleRecordScopeSampleRecord48 ScopeSampleRecord(ScopeNode* scope) 49 : m_scope(scope) 50 , m_codeBlock(0) 51 , m_sampleCount(0) 52 , m_opcodeSampleCount(0) 53 , m_samples(0) 54 , m_size(0) 55 { 56 } 57 ~ScopeSampleRecordScopeSampleRecord58 ~ScopeSampleRecord() 59 { 60 if (m_samples) 61 free(m_samples); 62 } 63 64 void sample(CodeBlock*, Instruction*); 65 66 RefPtr<ScopeNode> m_scope; 67 CodeBlock* m_codeBlock; 68 int m_sampleCount; 69 int m_opcodeSampleCount; 70 int* m_samples; 71 unsigned m_size; 72 }; 73 74 typedef WTF::HashMap<ScopeNode*, ScopeSampleRecord*> ScopeSampleRecordMap; 75 76 class SamplingTool { 77 public: 78 friend class CallRecord; 79 friend class HostCallRecord; 80 81 #if ENABLE(OPCODE_SAMPLING) 82 class CallRecord : Noncopyable { 83 public: CallRecord(SamplingTool * samplingTool)84 CallRecord(SamplingTool* samplingTool) 85 : m_samplingTool(samplingTool) 86 , m_savedSample(samplingTool->m_sample) 87 , m_savedCodeBlock(samplingTool->m_codeBlock) 88 { 89 } 90 ~CallRecord()91 ~CallRecord() 92 { 93 m_samplingTool->m_sample = m_savedSample; 94 m_samplingTool->m_codeBlock = m_savedCodeBlock; 95 } 96 97 private: 98 SamplingTool* m_samplingTool; 99 intptr_t m_savedSample; 100 CodeBlock* m_savedCodeBlock; 101 }; 102 103 class HostCallRecord : public CallRecord { 104 public: HostCallRecord(SamplingTool * samplingTool)105 HostCallRecord(SamplingTool* samplingTool) 106 : CallRecord(samplingTool) 107 { 108 samplingTool->m_sample |= 0x1; 109 } 110 }; 111 #else 112 class CallRecord : Noncopyable { 113 public: CallRecord(SamplingTool *)114 CallRecord(SamplingTool*) 115 { 116 } 117 }; 118 119 class HostCallRecord : public CallRecord { 120 public: HostCallRecord(SamplingTool * samplingTool)121 HostCallRecord(SamplingTool* samplingTool) 122 : CallRecord(samplingTool) 123 { 124 } 125 }; 126 #endif 127 SamplingTool(Interpreter * interpreter)128 SamplingTool(Interpreter* interpreter) 129 : m_interpreter(interpreter) 130 , m_running(false) 131 , m_codeBlock(0) 132 , m_sample(0) 133 , m_sampleCount(0) 134 , m_opcodeSampleCount(0) 135 , m_scopeSampleMap(new ScopeSampleRecordMap()) 136 { 137 memset(m_opcodeSamples, 0, sizeof(m_opcodeSamples)); 138 memset(m_opcodeSamplesInCTIFunctions, 0, sizeof(m_opcodeSamplesInCTIFunctions)); 139 } 140 ~SamplingTool()141 ~SamplingTool() 142 { 143 deleteAllValues(*m_scopeSampleMap); 144 } 145 146 void start(unsigned hertz=10000); 147 void stop(); 148 void dump(ExecState*); 149 150 void notifyOfScope(ScopeNode* scope); 151 sample(CodeBlock * codeBlock,Instruction * vPC)152 void sample(CodeBlock* codeBlock, Instruction* vPC) 153 { 154 ASSERT(!(reinterpret_cast<intptr_t>(vPC) & 0x3)); 155 m_codeBlock = codeBlock; 156 m_sample = reinterpret_cast<intptr_t>(vPC); 157 } 158 codeBlockSlot()159 CodeBlock** codeBlockSlot() { return &m_codeBlock; } sampleSlot()160 intptr_t* sampleSlot() { return &m_sample; } 161 162 void* encodeSample(Instruction* vPC, bool inCTIFunction = false, bool inHostFunction = false) 163 { 164 ASSERT(!(reinterpret_cast<intptr_t>(vPC) & 0x3)); 165 return reinterpret_cast<void*>(reinterpret_cast<intptr_t>(vPC) | (static_cast<intptr_t>(inCTIFunction) << 1) | static_cast<intptr_t>(inHostFunction)); 166 } 167 168 private: 169 class Sample { 170 public: Sample(volatile intptr_t sample,CodeBlock * volatile codeBlock)171 Sample(volatile intptr_t sample, CodeBlock* volatile codeBlock) 172 : m_sample(sample) 173 , m_codeBlock(codeBlock) 174 { 175 } 176 isNull()177 bool isNull() { return !m_sample || !m_codeBlock; } codeBlock()178 CodeBlock* codeBlock() { return m_codeBlock; } vPC()179 Instruction* vPC() { return reinterpret_cast<Instruction*>(m_sample & ~0x3); } inHostFunction()180 bool inHostFunction() { return m_sample & 0x1; } inCTIFunction()181 bool inCTIFunction() { return m_sample & 0x2; } 182 183 private: 184 intptr_t m_sample; 185 CodeBlock* m_codeBlock; 186 }; 187 188 static void* threadStartFunc(void*); 189 void run(); 190 191 Interpreter* m_interpreter; 192 193 // Sampling thread state. 194 bool m_running; 195 unsigned m_hertz; 196 ThreadIdentifier m_samplingThread; 197 198 // State tracked by the main thread, used by the sampling thread. 199 CodeBlock* m_codeBlock; 200 intptr_t m_sample; 201 202 // Gathered sample data. 203 long long m_sampleCount; 204 long long m_opcodeSampleCount; 205 unsigned m_opcodeSamples[numOpcodeIDs]; 206 unsigned m_opcodeSamplesInCTIFunctions[numOpcodeIDs]; 207 208 Mutex m_scopeSampleMapMutex; 209 OwnPtr<ScopeSampleRecordMap> m_scopeSampleMap; 210 }; 211 212 } // namespace JSC 213 214 #endif // SamplingTool_h 215