2 * Copyright (C) 2008 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
29 #ifndef SamplingTool_h
30 #define SamplingTool_h
32 #include <wtf/Assertions.h>
33 #include <wtf/HashMap.h>
34 #include <wtf/Threading.h>
41 class ScriptExecutable
;
49 #if ENABLE(SAMPLING_FLAGS)
50 static void setFlag(unsigned flag
)
54 s_flags
|= 1u << (flag
- 1);
57 static void clearFlag(unsigned flag
)
61 s_flags
&= ~(1u << (flag
- 1));
85 static uint32_t s_flags
;
86 #if ENABLE(SAMPLING_FLAGS)
87 static uint64_t s_flagCounts
[33];
97 struct ScriptSampleRecord
{
98 ScriptSampleRecord(ScriptExecutable
* executable
)
99 : m_executable(executable
)
102 , m_opcodeSampleCount(0)
108 ~ScriptSampleRecord()
114 void sample(CodeBlock
*, Instruction
*);
116 RefPtr
<ScriptExecutable
> m_executable
;
117 CodeBlock
* m_codeBlock
;
119 int m_opcodeSampleCount
;
124 typedef WTF::HashMap
<ScriptExecutable
*, ScriptSampleRecord
*> ScriptSampleRecordMap
;
126 class SamplingThread
{
128 // Sampling thread state.
129 static bool s_running
;
130 static unsigned s_hertz
;
131 static ThreadIdentifier s_samplingThread
;
133 static void start(unsigned hertz
=10000);
136 static void* threadStartFunc(void*);
141 friend struct CallRecord
;
142 friend class HostCallRecord
;
144 #if ENABLE(OPCODE_SAMPLING)
145 class CallRecord
: public Noncopyable
{
147 CallRecord(SamplingTool
* samplingTool
)
148 : m_samplingTool(samplingTool
)
149 , m_savedSample(samplingTool
->m_sample
)
150 , m_savedCodeBlock(samplingTool
->m_codeBlock
)
156 m_samplingTool
->m_sample
= m_savedSample
;
157 m_samplingTool
->m_codeBlock
= m_savedCodeBlock
;
161 SamplingTool
* m_samplingTool
;
162 intptr_t m_savedSample
;
163 CodeBlock
* m_savedCodeBlock
;
166 class HostCallRecord
: public CallRecord
{
168 HostCallRecord(SamplingTool
* samplingTool
)
169 : CallRecord(samplingTool
)
171 samplingTool
->m_sample
|= 0x1;
175 class CallRecord
: public Noncopyable
{
177 CallRecord(SamplingTool
*)
182 class HostCallRecord
: public CallRecord
{
184 HostCallRecord(SamplingTool
* samplingTool
)
185 : CallRecord(samplingTool
)
191 SamplingTool(Interpreter
* interpreter
)
192 : m_interpreter(interpreter
)
196 , m_opcodeSampleCount(0)
197 #if ENABLE(CODEBLOCK_SAMPLING)
198 , m_scopeSampleMap(new ScriptSampleRecordMap())
201 memset(m_opcodeSamples
, 0, sizeof(m_opcodeSamples
));
202 memset(m_opcodeSamplesInCTIFunctions
, 0, sizeof(m_opcodeSamplesInCTIFunctions
));
207 #if ENABLE(CODEBLOCK_SAMPLING)
208 deleteAllValues(*m_scopeSampleMap
);
213 void dump(ExecState
*);
215 void notifyOfScope(ScriptExecutable
* scope
);
217 void sample(CodeBlock
* codeBlock
, Instruction
* vPC
)
219 ASSERT(!(reinterpret_cast<intptr_t>(vPC
) & 0x3));
220 m_codeBlock
= codeBlock
;
221 m_sample
= reinterpret_cast<intptr_t>(vPC
);
224 CodeBlock
** codeBlockSlot() { return &m_codeBlock
; }
225 intptr_t* sampleSlot() { return &m_sample
; }
227 void* encodeSample(Instruction
* vPC
, bool inCTIFunction
= false, bool inHostFunction
= false)
229 ASSERT(!(reinterpret_cast<intptr_t>(vPC
) & 0x3));
230 return reinterpret_cast<void*>(reinterpret_cast<intptr_t>(vPC
) | (static_cast<intptr_t>(inCTIFunction
) << 1) | static_cast<intptr_t>(inHostFunction
));
233 static void sample();
238 Sample(volatile intptr_t sample
, CodeBlock
* volatile codeBlock
)
240 , m_codeBlock(codeBlock
)
244 bool isNull() { return !m_sample
; }
245 CodeBlock
* codeBlock() { return m_codeBlock
; }
246 Instruction
* vPC() { return reinterpret_cast<Instruction
*>(m_sample
& ~0x3); }
247 bool inHostFunction() { return m_sample
& 0x1; }
248 bool inCTIFunction() { return m_sample
& 0x2; }
252 CodeBlock
* m_codeBlock
;
256 static SamplingTool
* s_samplingTool
;
258 Interpreter
* m_interpreter
;
260 // State tracked by the main thread, used by the sampling thread.
261 CodeBlock
* m_codeBlock
;
264 // Gathered sample data.
265 long long m_sampleCount
;
266 long long m_opcodeSampleCount
;
267 unsigned m_opcodeSamples
[numOpcodeIDs
];
268 unsigned m_opcodeSamplesInCTIFunctions
[numOpcodeIDs
];
270 #if ENABLE(CODEBLOCK_SAMPLING)
271 Mutex m_scriptSampleMapMutex
;
272 OwnPtr
<ScriptSampleRecordMap
> m_scopeSampleMap
;
276 // AbstractSamplingCounter:
278 // Implements a named set of counters, printed on exit if ENABLE(SAMPLING_COUNTERS).
279 // See subclasses below, SamplingCounter, GlobalSamplingCounter and DeletableSamplingCounter.
280 class AbstractSamplingCounter
{
282 friend class DeletableSamplingCounter
;
284 void count(uint32_t count
= 1)
292 // Effectively the contructor, however called lazily in the case of GlobalSamplingCounter.
293 void init(const char* name
)
298 // Set m_next to point to the head of the chain, and inform whatever is
299 // currently at the head that this node will now hold the pointer to it.
300 m_next
= s_abstractSamplingCounterChain
;
301 s_abstractSamplingCounterChain
->m_referer
= &m_next
;
302 // Add this node to the head of the list.
303 s_abstractSamplingCounterChain
= this;
304 m_referer
= &s_abstractSamplingCounterChain
;
309 AbstractSamplingCounter
* m_next
;
310 // This is a pointer to the pointer to this node in the chain; used to
311 // allow fast linked list deletion.
312 AbstractSamplingCounter
** m_referer
;
313 // Null object used to detect end of static chain.
314 static AbstractSamplingCounter s_abstractSamplingCounterChainEnd
;
315 static AbstractSamplingCounter
* s_abstractSamplingCounterChain
;
316 static bool s_completed
;
319 #if ENABLE(SAMPLING_COUNTERS)
322 // This class is suitable and (hopefully!) convenient for cases where a counter is
323 // required within the scope of a single function. It can be instantiated as a
324 // static variable since it contains a constructor but not a destructor (static
325 // variables in WebKit cannot have destructors).
329 // void someFunction()
331 // static SamplingCounter countMe("This is my counter. There are many like it, but this one is mine.");
336 class SamplingCounter
: public AbstractSamplingCounter
{
338 SamplingCounter(const char* name
) { init(name
); }
341 // GlobalSamplingCounter:
343 // This class is suitable for use where a counter is to be declared globally,
344 // since it contains neither a constructor nor destructor. Instead, ensure
345 // that 'name()' is called to provide the counter with a name (and also to
346 // allow it to be printed out on exit).
348 // GlobalSamplingCounter globalCounter;
350 // void firstFunction()
352 // // Put this within a function that is definitely called!
353 // // (Or alternatively alongside all calls to 'count()').
354 // globalCounter.name("I Name You Destroyer.");
355 // globalCounter.count();
359 // void secondFunction()
361 // globalCounter.count();
365 class GlobalSamplingCounter
: public AbstractSamplingCounter
{
367 void name(const char* name
)
369 // Global objects should be mapped in zero filled memory, so this should
370 // be a safe (albeit not necessarily threadsafe) check for 'first call'.
376 // DeletableSamplingCounter:
378 // The above classes (SamplingCounter, GlobalSamplingCounter), are intended for
379 // use within a global or static scope, and as such cannot have a destructor.
380 // This means there is no convenient way for them to remove themselves from the
381 // static list of counters, and should an instance of either class be freed
382 // before 'dump()' has walked over the list it will potentially walk over an
385 // This class is intended for use where the counter may possibly be deleted before
386 // the program exits. Should this occur, the counter will print it's value to
387 // stderr, and remove itself from the static list. Example:
389 // DeletableSamplingCounter* counter = new DeletableSamplingCounter("The Counter With No Name");
393 class DeletableSamplingCounter
: public AbstractSamplingCounter
{
395 DeletableSamplingCounter(const char* name
) { init(name
); }
397 ~DeletableSamplingCounter()
400 fprintf(stderr
, "DeletableSamplingCounter \"%s\" deleted early (with count %lld)\n", m_name
, m_counter
);
401 // Our m_referer pointer should know where the pointer to this node is,
402 // and m_next should know that this node is the previous node in the list.
403 ASSERT(*m_referer
== this);
404 ASSERT(m_next
->m_referer
== &m_next
);
405 // Remove this node from the list, and inform m_next that we have done so.
406 m_next
->m_referer
= m_referer
;
414 #endif // SamplingTool_h