Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(284)

Unified Diff: src/sampler.cc

Issue 14264009: Merge Windows, Mac OS X and Cygwin sampler implementations with the rest ones (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Fix Android build Created 7 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/platform-win32.cc ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/sampler.cc
diff --git a/src/sampler.cc b/src/sampler.cc
index 446f9963b48927a9c01df96b559500f8919f0c05..55b943c42da74f8f82ef4f0c7264db46f3c99b16 100644
--- a/src/sampler.cc
+++ b/src/sampler.cc
@@ -26,17 +26,19 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) \
- || defined(__NetBSD__) || defined(__sun)
+ || defined(__NetBSD__) || defined(__sun) || defined(__ANDROID__)
+
+#define USE_SIGNALS
#include <errno.h>
#include <pthread.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/syscall.h>
+#if !defined(__ANDROID__) || defined(__BIONIC_HAVE_UCONTEXT_T)
#include <ucontext.h>
-#include <unistd.h>
-
#endif
+#include <unistd.h>
// GLibc on ARM defines mcontext_t has a typedef for 'struct sigcontext'.
// Old versions of the C library <signal.h> didn't define the type.
@@ -45,6 +47,16 @@
#include <asm/sigcontext.h>
#endif
+#elif defined(__MACH__)
+
+#include <mach/mach.h>
+
+#elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
+
+#include "win32-headers.h"
+
+#endif
+
#include "v8.h"
#include "log.h"
@@ -58,7 +70,7 @@ namespace internal {
#if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) \
- || defined(__NetBSD__) || defined(__sun)
+ || defined(__NetBSD__) || defined(__sun) || defined(__ANDROID__)
#if defined(__ANDROID__) && !defined(__BIONIC_HAVE_UCONTEXT_T)
@@ -153,13 +165,16 @@ class Sampler::PlatformData : public Malloced {
public:
PlatformData()
: vm_tid_(GetThreadID()),
+ vm_tgid_(getpid()),
profiled_thread_id_(ThreadId::Current()) {}
pthread_t vm_tid() const { return vm_tid_; }
+ int vm_tgid() const { return vm_tgid_; }
ThreadId profiled_thread_id() { return profiled_thread_id_; }
private:
pthread_t vm_tid_;
+ const int vm_tgid_;
ThreadId profiled_thread_id_;
};
@@ -216,7 +231,7 @@ static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) {
ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
mcontext_t& mcontext = ucontext->uc_mcontext;
sample->state = isolate->current_vm_state();
-#if defined(__linux__)
+#if defined(__linux__) || defined(__ANDROID__)
#if V8_HOST_ARCH_IA32
sample->pc = reinterpret_cast<Address>(mcontext.gregs[REG_EIP]);
sample->sp = reinterpret_cast<Address>(mcontext.gregs[REG_ESP]);
@@ -291,19 +306,80 @@ static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) {
#endif // __native_client__
}
+#elif defined(__MACH__)
+class Sampler::PlatformData : public Malloced {
+ public:
+ PlatformData()
+ : profiled_thread_(mach_thread_self()),
+ profiled_thread_id_(ThreadId::Current()) {}
+
+ ~PlatformData() {
+ // Deallocate Mach port for thread.
+ mach_port_deallocate(mach_task_self(), profiled_thread_);
+ }
-class SignalSender : public Thread {
+ thread_act_t profiled_thread() { return profiled_thread_; }
+ ThreadId profiled_thread_id() { return profiled_thread_id_; }
+
+ private:
+ // Note: for profiled_thread_ Mach primitives are used instead of PThread's
+ // because the latter doesn't provide thread manipulation primitives required.
+ // For details, consult "Mac OS X Internals" book, Section 7.3.
+ thread_act_t profiled_thread_;
+ ThreadId profiled_thread_id_;
+};
+
+#elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
+
+// ----------------------------------------------------------------------------
+// Win32 profiler support. On Cygwin we use the same sampler implementation as
+// on Win32.
+
+class Sampler::PlatformData : public Malloced {
public:
- static const int kSignalSenderStackSize = 64 * KB;
+ // Get a handle to the calling thread. This is the thread that we are
+ // going to profile. We need to make a copy of the handle because we are
+ // going to use it in the sampler thread. Using GetThreadHandle() will
+ // not work in this case. We're using OpenThread because DuplicateHandle
+ // for some reason doesn't work in Chrome's sandbox.
+ PlatformData()
+ : profiled_thread_(OpenThread(THREAD_GET_CONTEXT |
+ THREAD_SUSPEND_RESUME |
+ THREAD_QUERY_INFORMATION,
+ false,
+ GetCurrentThreadId())),
+ profiled_thread_id_(ThreadId::Current()) {}
- explicit SignalSender(int interval)
- : Thread(Thread::Options("SignalSender", kSignalSenderStackSize)),
- vm_tgid_(getpid()),
+ ~PlatformData() {
+ if (profiled_thread_ != NULL) {
+ CloseHandle(profiled_thread_);
+ profiled_thread_ = NULL;
+ }
+ }
+
+ HANDLE profiled_thread() { return profiled_thread_; }
+ ThreadId profiled_thread_id() { return profiled_thread_id_; }
+
+ private:
+ HANDLE profiled_thread_;
+ ThreadId profiled_thread_id_;
+};
+
+#endif
+
+
+class SamplerThread : public Thread {
+ public:
+ static const int kSamplerThreadStackSize = 64 * KB;
+
+ explicit SamplerThread(int interval)
+ : Thread(Thread::Options("SamplerThread", kSamplerThreadStackSize)),
interval_(interval) {}
static void SetUp() { if (!mutex_) mutex_ = OS::CreateMutex(); }
static void TearDown() { delete mutex_; }
+#if defined(USE_SIGNALS)
static void InstallSignalHandler() {
struct sigaction sa;
sa.sa_sigaction = ProfilerSignalHandler;
@@ -319,6 +395,7 @@ class SignalSender : public Thread {
signal_handler_installed_ = false;
}
}
+#endif
static void AddActiveSampler(Sampler* sampler) {
ScopedLock lock(mutex_);
@@ -326,7 +403,7 @@ class SignalSender : public Thread {
if (instance_ == NULL) {
// Start a thread that will send SIGPROF signal to VM threads,
// when CPU profiling will be enabled.
- instance_ = new SignalSender(sampler->interval());
+ instance_ = new SamplerThread(sampler->interval());
instance_->StartSynchronously();
} else {
ASSERT(instance_->interval_ == sampler->interval());
@@ -340,7 +417,9 @@ class SignalSender : public Thread {
instance_->Join();
delete instance_;
instance_ = NULL;
+#if defined(USE_SIGNALS)
RestoreSignalHandler();
+#endif
}
}
@@ -352,31 +431,39 @@ class SignalSender : public Thread {
// When CPU profiling is enabled both JavaScript and C++ code is
// profiled. We must not suspend.
if (state == SamplerRegistry::HAS_CPU_PROFILING_SAMPLERS) {
+#if defined(USE_SIGNALS)
if (!signal_handler_installed_) InstallSignalHandler();
+#endif
SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, this);
} else {
+#if defined(USE_SIGNALS)
if (signal_handler_installed_) RestoreSignalHandler();
+#endif
}
Sleep(); // TODO(svenpanne) Figure out if OS:Sleep(interval_) is enough.
}
}
static void DoCpuProfile(Sampler* sampler, void* raw_sender) {
+ if (!sampler->isolate()->IsInitialized()) return;
if (!sampler->IsProfiling()) return;
- SignalSender* sender = reinterpret_cast<SignalSender*>(raw_sender);
- sender->SendProfilingSignal(sampler->platform_data()->vm_tid());
+ SamplerThread* sender = reinterpret_cast<SamplerThread*>(raw_sender);
+ sender->SampleContext(sampler);
}
- void SendProfilingSignal(int tid) {
+#if defined(USE_SIGNALS)
+ void SampleContext(Sampler* sampler) {
if (!signal_handler_installed_) return;
+ Sampler::PlatformData* platform_data = sampler->platform_data();
+ int tid = platform_data->vm_tid();
// Glibc doesn't provide a wrapper for tgkill(2).
#if defined(ANDROID)
- syscall(__NR_tgkill, vm_tgid_, tid, SIGPROF);
+ syscall(__NR_tgkill, platform_data->vm_tgid(), tid, SIGPROF);
#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) \
|| defined(__sun)
pthread_kill(tid, SIGPROF);
#else
- int result = syscall(SYS_tgkill, vm_tgid_, tid, SIGPROF);
+ int result = syscall(SYS_tgkill, platform_data->vm_tgid(), tid, SIGPROF);
USE(result);
ASSERT(result == 0);
#endif
@@ -393,7 +480,7 @@ class SignalSender : public Thread {
#ifdef DEBUG
if (result != 0 && errno != EINTR) {
fprintf(stderr,
- "SignalSender usleep error; interval = %u, errno = %d\n",
+ "SamplerThread usleep error; interval = %u, errno = %d\n",
interval,
errno);
ASSERT(result == 0 || errno == EINTR);
@@ -403,33 +490,176 @@ class SignalSender : public Thread {
#endif // ANDROID
}
- const int vm_tgid_;
+#elif defined(__MACH__)
+
+ void SampleContext(Sampler* sampler) {
+ thread_act_t profiled_thread = sampler->platform_data()->profiled_thread();
+ Isolate* isolate = sampler->isolate();
+#if defined(USE_SIMULATOR)
+#if V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_MIPS
+ ThreadId thread_id = sampler->platform_data()->profiled_thread_id();
+ Isolate::PerIsolateThreadData* per_thread_data = isolate->
+ FindPerThreadDataForThread(thread_id);
+ if (!per_thread_data) return;
+ Simulator* sim = per_thread_data->simulator();
+ // Check if there is active simulator before allocating TickSample.
+ if (!sim) return;
+#endif
+#endif // USE_SIMULATOR
+ TickSample sample_obj;
+ TickSample* sample = isolate->cpu_profiler()->TickSampleEvent();
+ if (sample == NULL) sample = &sample_obj;
+
+ if (KERN_SUCCESS != thread_suspend(profiled_thread)) return;
+
+#if V8_HOST_ARCH_X64
+ thread_state_flavor_t flavor = x86_THREAD_STATE64;
+ x86_thread_state64_t state;
+ mach_msg_type_number_t count = x86_THREAD_STATE64_COUNT;
+#if __DARWIN_UNIX03
+#define REGISTER_FIELD(name) __r ## name
+#else
+#define REGISTER_FIELD(name) r ## name
+#endif // __DARWIN_UNIX03
+#elif V8_HOST_ARCH_IA32
+ thread_state_flavor_t flavor = i386_THREAD_STATE;
+ i386_thread_state_t state;
+ mach_msg_type_number_t count = i386_THREAD_STATE_COUNT;
+#if __DARWIN_UNIX03
+#define REGISTER_FIELD(name) __e ## name
+#else
+#define REGISTER_FIELD(name) e ## name
+#endif // __DARWIN_UNIX03
+#else
+#error Unsupported Mac OS X host architecture.
+#endif // V8_HOST_ARCH
+
+ if (thread_get_state(profiled_thread,
+ flavor,
+ reinterpret_cast<natural_t*>(&state),
+ &count) == KERN_SUCCESS) {
+ sample->state = isolate->current_vm_state();
+#if defined(USE_SIMULATOR)
+#if V8_TARGET_ARCH_ARM
+ sample->pc = reinterpret_cast<Address>(sim->get_register(Simulator::pc));
+ sample->sp = reinterpret_cast<Address>(sim->get_register(Simulator::sp));
+ sample->fp = reinterpret_cast<Address>(sim->get_register(Simulator::r11));
+#elif V8_TARGET_ARCH_MIPS
+ sample->pc = reinterpret_cast<Address>(sim->get_register(Simulator::pc));
+ sample->sp = reinterpret_cast<Address>(sim->get_register(Simulator::sp));
+ sample->fp = reinterpret_cast<Address>(sim->get_register(Simulator::fp));
+#endif
+#else
+ sample->pc = reinterpret_cast<Address>(state.REGISTER_FIELD(ip));
+ sample->sp = reinterpret_cast<Address>(state.REGISTER_FIELD(sp));
+ sample->fp = reinterpret_cast<Address>(state.REGISTER_FIELD(bp));
+#endif // USE_SIMULATOR
+#undef REGISTER_FIELD
+ sampler->SampleStack(sample);
+ sampler->Tick(sample);
+ }
+ thread_resume(profiled_thread);
+ }
+
+ void Sleep() {
+ OS::Sleep(interval_);
+ }
+
+#elif defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)
+
+ void SampleContext(Sampler* sampler) {
+ HANDLE profiled_thread = sampler->platform_data()->profiled_thread();
+ if (profiled_thread == NULL) return;
+
+ // Context used for sampling the register state of the profiled thread.
+ CONTEXT context;
+ memset(&context, 0, sizeof(context));
+
+ Isolate* isolate = sampler->isolate();
+#if defined(USE_SIMULATOR)
+#if V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_MIPS
+ ThreadId thread_id = sampler->platform_data()->profiled_thread_id();
+ Isolate::PerIsolateThreadData* per_thread_data = isolate->
+ FindPerThreadDataForThread(thread_id);
+ if (!per_thread_data) return;
+ Simulator* sim = per_thread_data->simulator();
+ // Check if there is active simulator before allocating TickSample.
+ if (!sim) return;
+#endif
+#endif // USE_SIMULATOR
+ TickSample sample_obj;
+ TickSample* sample = isolate->cpu_profiler()->TickSampleEvent();
+ if (sample == NULL) sample = &sample_obj;
+
+ static const DWORD kSuspendFailed = static_cast<DWORD>(-1);
+ if (SuspendThread(profiled_thread) == kSuspendFailed) return;
+ sample->state = isolate->current_vm_state();
+
+ context.ContextFlags = CONTEXT_FULL;
+ if (GetThreadContext(profiled_thread, &context) != 0) {
+#if defined(USE_SIMULATOR)
+#if V8_TARGET_ARCH_ARM
+ sample->pc = reinterpret_cast<Address>(sim->get_register(Simulator::pc));
+ sample->sp = reinterpret_cast<Address>(sim->get_register(Simulator::sp));
+ sample->fp = reinterpret_cast<Address>(sim->get_register(Simulator::r11));
+#elif V8_TARGET_ARCH_MIPS
+ sample->pc = reinterpret_cast<Address>(sim->get_register(Simulator::pc));
+ sample->sp = reinterpret_cast<Address>(sim->get_register(Simulator::sp));
+ sample->fp = reinterpret_cast<Address>(sim->get_register(Simulator::fp));
+#endif
+#else
+#if V8_HOST_ARCH_X64
+ sample->pc = reinterpret_cast<Address>(context.Rip);
+ sample->sp = reinterpret_cast<Address>(context.Rsp);
+ sample->fp = reinterpret_cast<Address>(context.Rbp);
+#else
+ sample->pc = reinterpret_cast<Address>(context.Eip);
+ sample->sp = reinterpret_cast<Address>(context.Esp);
+ sample->fp = reinterpret_cast<Address>(context.Ebp);
+#endif
+#endif // USE_SIMULATOR
+ sampler->SampleStack(sample);
+ sampler->Tick(sample);
+ }
+ ResumeThread(profiled_thread);
+ }
+
+ void Sleep() {
+ OS::Sleep(interval_);
+ }
+
+#endif // USE_SIGNALS
+
const int interval_;
// Protects the process wide state below.
static Mutex* mutex_;
- static SignalSender* instance_;
+ static SamplerThread* instance_;
+#if defined(USE_SIGNALS)
static bool signal_handler_installed_;
static struct sigaction old_signal_handler_;
+#endif
private:
- DISALLOW_COPY_AND_ASSIGN(SignalSender);
+ DISALLOW_COPY_AND_ASSIGN(SamplerThread);
};
-Mutex* SignalSender::mutex_ = NULL;
-SignalSender* SignalSender::instance_ = NULL;
-struct sigaction SignalSender::old_signal_handler_;
-bool SignalSender::signal_handler_installed_ = false;
+Mutex* SamplerThread::mutex_ = NULL;
+SamplerThread* SamplerThread::instance_ = NULL;
+#if defined(USE_SIGNALS)
+struct sigaction SamplerThread::old_signal_handler_;
+bool SamplerThread::signal_handler_installed_ = false;
+#endif
void Sampler::SetUp() {
- SignalSender::SetUp();
+ SamplerThread::SetUp();
}
void Sampler::TearDown() {
- SignalSender::TearDown();
+ SamplerThread::TearDown();
}
@@ -451,27 +681,16 @@ Sampler::~Sampler() {
void Sampler::Start() {
ASSERT(!IsActive());
SetActive(true);
- SignalSender::AddActiveSampler(this);
+ SamplerThread::AddActiveSampler(this);
}
void Sampler::Stop() {
ASSERT(IsActive());
- SignalSender::RemoveActiveSampler(this);
+ SamplerThread::RemoveActiveSampler(this);
SetActive(false);
}
-#else
-
-void Sampler::SetUp() {
-}
-
-
-void Sampler::TearDown() {
-}
-
-#endif // __linux__ || _*BSD__ || __sun
-
void Sampler::SampleStack(TickSample* sample) {
StackTracer::Trace(isolate_, sample);
if (++samples_taken_ < 0) samples_taken_ = 0;
« no previous file with comments | « src/platform-win32.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698