/*
- * Copyright (C) 2008 Apple Inc. All rights reserved.
+ * 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
* 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
+ * 3. Neither the name of Apple 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.
*
#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>
-#include "Nodes.h"
-#include "Opcode.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 ScopeSampleRecord {
- ScopeSampleRecord(ScopeNode* scope)
- : m_scope(scope)
+ struct ScriptSampleRecord {
+ ScriptSampleRecord(VM& vm, ScriptExecutable* executable)
+ : m_executable(vm, executable)
, m_codeBlock(0)
, m_sampleCount(0)
, m_opcodeSampleCount(0)
{
}
- ~ScopeSampleRecord()
+ ~ScriptSampleRecord()
{
if (m_samples)
free(m_samples);
void sample(CodeBlock*, Instruction*);
- RefPtr<ScopeNode> m_scope;
+ Strong<ScriptExecutable> m_executable;
CodeBlock* m_codeBlock;
int m_sampleCount;
int m_opcodeSampleCount;
unsigned m_size;
};
- typedef WTF::HashMap<ScopeNode*, ScopeSampleRecord*> ScopeSampleRecordMap;
+ typedef HashMap<ScriptExecutable*, std::unique_ptr<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 class CallRecord;
- friend class HostCallRecord;
+ friend struct CallRecord;
#if ENABLE(OPCODE_SAMPLING)
- class CallRecord : Noncopyable {
+ class CallRecord {
+ WTF_MAKE_NONCOPYABLE(CallRecord);
public:
- CallRecord(SamplingTool* samplingTool)
+ 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()
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 {
+ class CallRecord {
+ WTF_MAKE_NONCOPYABLE(CallRecord);
public:
- HostCallRecord(SamplingTool* samplingTool)
- : CallRecord(samplingTool)
+ CallRecord(SamplingTool*, bool = false)
{
}
};
-#endif
+#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())
+#if ENABLE(CODEBLOCK_SAMPLING)
+ , m_scopeSampleMap(adoptPtr(new ScriptSampleRecordMap))
+#endif
{
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();
+ JS_EXPORT_PRIVATE void setup();
void dump(ExecState*);
- void notifyOfScope(ScopeNode* scope);
+ void notifyOfScope(VM&, ScriptExecutable* scope);
void sample(CodeBlock* codeBlock, Instruction* vPC)
{
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:
{
}
- bool isNull() { return !m_sample || !m_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; }
intptr_t m_sample;
CodeBlock* m_codeBlock;
};
-
- static void* threadStartFunc(void*);
- void run();
+
+ void doRun();
+ static SamplingTool* s_samplingTool;
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;
unsigned m_opcodeSamples[numOpcodeIDs];
unsigned m_opcodeSamplesInCTIFunctions[numOpcodeIDs];
- Mutex m_scopeSampleMapMutex;
- OwnPtr<ScopeSampleRecordMap> m_scopeSampleMap;
+#if ENABLE(CODEBLOCK_SAMPLING)
+ Mutex m_scriptSampleMapMutex;
+ OwnPtr<ScriptSampleRecordMap> m_scopeSampleMap;
+#endif
};
} // namespace JSC