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>
47 #if ENABLE(SAMPLING_FLAGS)
48 static void setFlag(unsigned flag
)
52 s_flags
|= 1u << (flag
- 1);
55 static void clearFlag(unsigned flag
)
59 s_flags
&= ~(1u << (flag
- 1));
83 static uint32_t s_flags
;
84 #if ENABLE(SAMPLING_FLAGS)
85 static uint64_t s_flagCounts
[33];
95 struct ScopeSampleRecord
{
96 ScopeSampleRecord(ScopeNode
* scope
)
100 , m_opcodeSampleCount(0)
112 void sample(CodeBlock
*, Instruction
*);
114 RefPtr
<ScopeNode
> m_scope
;
115 CodeBlock
* m_codeBlock
;
117 int m_opcodeSampleCount
;
122 typedef WTF::HashMap
<ScopeNode
*, ScopeSampleRecord
*> ScopeSampleRecordMap
;
124 class SamplingThread
{
126 // Sampling thread state.
127 static bool s_running
;
128 static unsigned s_hertz
;
129 static ThreadIdentifier s_samplingThread
;
131 static void start(unsigned hertz
=10000);
134 static void* threadStartFunc(void*);
139 friend class CallRecord
;
140 friend class HostCallRecord
;
142 #if ENABLE(OPCODE_SAMPLING)
143 class CallRecord
: Noncopyable
{
145 CallRecord(SamplingTool
* samplingTool
)
146 : m_samplingTool(samplingTool
)
147 , m_savedSample(samplingTool
->m_sample
)
148 , m_savedCodeBlock(samplingTool
->m_codeBlock
)
154 m_samplingTool
->m_sample
= m_savedSample
;
155 m_samplingTool
->m_codeBlock
= m_savedCodeBlock
;
159 SamplingTool
* m_samplingTool
;
160 intptr_t m_savedSample
;
161 CodeBlock
* m_savedCodeBlock
;
164 class HostCallRecord
: public CallRecord
{
166 HostCallRecord(SamplingTool
* samplingTool
)
167 : CallRecord(samplingTool
)
169 samplingTool
->m_sample
|= 0x1;
173 class CallRecord
: Noncopyable
{
175 CallRecord(SamplingTool
*)
180 class HostCallRecord
: public CallRecord
{
182 HostCallRecord(SamplingTool
* samplingTool
)
183 : CallRecord(samplingTool
)
189 SamplingTool(Interpreter
* interpreter
)
190 : m_interpreter(interpreter
)
194 , m_opcodeSampleCount(0)
195 #if ENABLE(CODEBLOCK_SAMPLING)
196 , m_scopeSampleMap(new ScopeSampleRecordMap())
199 memset(m_opcodeSamples
, 0, sizeof(m_opcodeSamples
));
200 memset(m_opcodeSamplesInCTIFunctions
, 0, sizeof(m_opcodeSamplesInCTIFunctions
));
205 #if ENABLE(CODEBLOCK_SAMPLING)
206 deleteAllValues(*m_scopeSampleMap
);
211 void dump(ExecState
*);
213 void notifyOfScope(ScopeNode
* scope
);
215 void sample(CodeBlock
* codeBlock
, Instruction
* vPC
)
217 ASSERT(!(reinterpret_cast<intptr_t>(vPC
) & 0x3));
218 m_codeBlock
= codeBlock
;
219 m_sample
= reinterpret_cast<intptr_t>(vPC
);
222 CodeBlock
** codeBlockSlot() { return &m_codeBlock
; }
223 intptr_t* sampleSlot() { return &m_sample
; }
225 void* encodeSample(Instruction
* vPC
, bool inCTIFunction
= false, bool inHostFunction
= false)
227 ASSERT(!(reinterpret_cast<intptr_t>(vPC
) & 0x3));
228 return reinterpret_cast<void*>(reinterpret_cast<intptr_t>(vPC
) | (static_cast<intptr_t>(inCTIFunction
) << 1) | static_cast<intptr_t>(inHostFunction
));
231 static void sample();
236 Sample(volatile intptr_t sample
, CodeBlock
* volatile codeBlock
)
238 , m_codeBlock(codeBlock
)
242 bool isNull() { return !m_sample
; }
243 CodeBlock
* codeBlock() { return m_codeBlock
; }
244 Instruction
* vPC() { return reinterpret_cast<Instruction
*>(m_sample
& ~0x3); }
245 bool inHostFunction() { return m_sample
& 0x1; }
246 bool inCTIFunction() { return m_sample
& 0x2; }
250 CodeBlock
* m_codeBlock
;
254 static SamplingTool
* s_samplingTool
;
256 Interpreter
* m_interpreter
;
258 // State tracked by the main thread, used by the sampling thread.
259 CodeBlock
* m_codeBlock
;
262 // Gathered sample data.
263 long long m_sampleCount
;
264 long long m_opcodeSampleCount
;
265 unsigned m_opcodeSamples
[numOpcodeIDs
];
266 unsigned m_opcodeSamplesInCTIFunctions
[numOpcodeIDs
];
268 #if ENABLE(CODEBLOCK_SAMPLING)
269 Mutex m_scopeSampleMapMutex
;
270 OwnPtr
<ScopeSampleRecordMap
> m_scopeSampleMap
;
274 // AbstractSamplingCounter:
276 // Implements a named set of counters, printed on exit if ENABLE(SAMPLING_COUNTERS).
277 // See subclasses below, SamplingCounter, GlobalSamplingCounter and DeletableSamplingCounter.
278 class AbstractSamplingCounter
{
280 friend class DeletableSamplingCounter
;
282 void count(uint32_t count
= 1)
290 // Effectively the contructor, however called lazily in the case of GlobalSamplingCounter.
291 void init(const char* name
)
296 // Set m_next to point to the head of the chain, and inform whatever is
297 // currently at the head that this node will now hold the pointer to it.
298 m_next
= s_abstractSamplingCounterChain
;
299 s_abstractSamplingCounterChain
->m_referer
= &m_next
;
300 // Add this node to the head of the list.
301 s_abstractSamplingCounterChain
= this;
302 m_referer
= &s_abstractSamplingCounterChain
;
307 AbstractSamplingCounter
* m_next
;
308 // This is a pointer to the pointer to this node in the chain; used to
309 // allow fast linked list deletion.
310 AbstractSamplingCounter
** m_referer
;
311 // Null object used to detect end of static chain.
312 static AbstractSamplingCounter s_abstractSamplingCounterChainEnd
;
313 static AbstractSamplingCounter
* s_abstractSamplingCounterChain
;
314 static bool s_completed
;
317 #if ENABLE(SAMPLING_COUNTERS)
320 // This class is suitable and (hopefully!) convenient for cases where a counter is
321 // required within the scope of a single function. It can be instantiated as a
322 // static variable since it contains a constructor but not a destructor (static
323 // variables in WebKit cannot have destructors).
327 // void someFunction()
329 // static SamplingCounter countMe("This is my counter. There are many like it, but this one is mine.");
334 class SamplingCounter
: public AbstractSamplingCounter
{
336 SamplingCounter(const char* name
) { init(name
); }
339 // GlobalSamplingCounter:
341 // This class is suitable for use where a counter is to be declared globally,
342 // since it contains neither a constructor nor destructor. Instead, ensure
343 // that 'name()' is called to provide the counter with a name (and also to
344 // allow it to be printed out on exit).
346 // GlobalSamplingCounter globalCounter;
348 // void firstFunction()
350 // // Put this within a function that is definitely called!
351 // // (Or alternatively alongside all calls to 'count()').
352 // globalCounter.name("I Name You Destroyer.");
353 // globalCounter.count();
357 // void secondFunction()
359 // globalCounter.count();
363 class GlobalSamplingCounter
: public AbstractSamplingCounter
{
365 void name(const char* name
)
367 // Global objects should be mapped in zero filled memory, so this should
368 // be a safe (albeit not necessarily threadsafe) check for 'first call'.
374 // DeletableSamplingCounter:
376 // The above classes (SamplingCounter, GlobalSamplingCounter), are intended for
377 // use within a global or static scope, and as such cannot have a destructor.
378 // This means there is no convenient way for them to remove themselves from the
379 // static list of counters, and should an instance of either class be freed
380 // before 'dump()' has walked over the list it will potentially walk over an
383 // This class is intended for use where the counter may possibly be deleted before
384 // the program exits. Should this occur, the counter will print it's value to
385 // stderr, and remove itself from the static list. Example:
387 // DeletableSamplingCounter* counter = new DeletableSamplingCounter("The Counter With No Name");
391 class DeletableSamplingCounter
: public AbstractSamplingCounter
{
393 DeletableSamplingCounter(const char* name
) { init(name
); }
395 ~DeletableSamplingCounter()
398 fprintf(stderr
, "DeletableSamplingCounter \"%s\" deleted early (with count %lld)\n", m_name
, m_counter
);
399 // Our m_referer pointer should know where the pointer to this node is,
400 // and m_next should know that this node is the previous node in the list.
401 ASSERT(*m_referer
== this);
402 ASSERT(m_next
->m_referer
== &m_next
);
403 // Remove this node from the list, and inform m_next that we have done so.
404 m_next
->m_referer
= m_referer
;
412 #endif // SamplingTool_h