Chromium Code Reviews| Index: src/profiler/sampler.cc |
| diff --git a/src/profiler/sampler.cc b/src/profiler/sampler.cc |
| index a34042453c902d25a2ced72494a47fe4896e9263..383ca38bd70ea0b7de0ff8fd4b9b4a0034261ed1 100644 |
| --- a/src/profiler/sampler.cc |
| +++ b/src/profiler/sampler.cc |
| @@ -42,6 +42,7 @@ |
| #endif |
| +#include "src/atomic-utils.h" |
| #include "src/base/platform/platform.h" |
| #include "src/flags.h" |
| #include "src/frames-inl.h" |
| @@ -236,6 +237,59 @@ bool IsNoFrameRegion(Address address) { |
| return false; |
| } |
| +typedef List<Sampler*> SamplerList; |
| + |
| +#if defined(USE_SIGNALS) |
| +class ThreadSamplersPair { |
| + public: |
| + ThreadSamplersPair(pthread_t thread_id, SamplerList* samplers) |
| + : thread_id_(thread_id), samplers_(samplers) {} |
| + ~ThreadSamplersPair() { |
| + delete samplers_; |
| + } |
| + pthread_t thread_id() const { return thread_id_; } |
| + SamplerList* samplers() const { return samplers_; } |
| + bool operator==(const ThreadSamplersPair& rhs) { |
| + return thread_id_ == rhs.thread_id(); |
| + } |
| + private: |
| + pthread_t thread_id_; |
| + SamplerList* samplers_; |
| + ThreadSamplersPair() {} |
| +}; |
| + |
| +typedef List<ThreadSamplersPair*> ThreadSamplersList; |
| + |
| +template <typename T> |
|
fmeawad
2016/04/06 20:07:56
I do not think you need this class, I think you sh
fmeawad
2016/04/06 20:13:34
lpy@ explained offline that it is a scoped context
|
| +class AtomicGuard { |
| + public: |
| + explicit AtomicGuard(AtomicValue<T>* atomic, T expected, T desired, |
| + bool is_block) |
| + : atomic_(atomic), |
| + expected_(expected), |
| + desired_(desired), |
| + is_success_(false) { |
| + do { |
| + is_success_ = atomic_->TrySetValue(expected, desired); |
| + if (is_success_) break; |
| + } while (is_block); |
| + } |
| + |
| + bool is_success() { return is_success_; } |
| + |
| + ~AtomicGuard() { |
| + atomic_->SetValue(expected_); |
| + atomic_ = NULL; |
|
fmeawad
2016/04/06 20:13:34
If you failed to set it, you should not reset it.
lpy
2016/04/06 20:19:58
Done.
|
| + } |
| + |
| + private: |
| + AtomicValue<T>* atomic_; |
| + T expected_; |
| + T desired_; |
| + bool is_success_; |
| +}; |
| +#endif // USE_SIGNALS |
| + |
| } // namespace |
| #if defined(USE_SIGNALS) |
| @@ -374,6 +428,10 @@ class SignalHandler : public AllStatic { |
| return signal_handler_installed_; |
| } |
| +#if !V8_OS_NACL |
| + static void CollectSample(void* context, Sampler* sampler); |
| +#endif |
| + |
| private: |
| static void Install() { |
| #if !V8_OS_NACL |
| @@ -418,23 +476,19 @@ bool SignalHandler::signal_handler_installed_ = false; |
| // As Native Client does not support signal handling, profiling is disabled. |
| #if !V8_OS_NACL |
| -void SignalHandler::HandleProfilerSignal(int signal, siginfo_t* info, |
| - void* context) { |
| - USE(info); |
| - if (signal != SIGPROF) return; |
| - Isolate* isolate = Isolate::UnsafeCurrent(); |
| - if (isolate == NULL || !isolate->IsInUse()) { |
| - // We require a fully initialized and entered isolate. |
| +void SignalHandler::CollectSample(void* context, Sampler* sampler) { |
| + if (sampler == NULL || (!sampler->IsProfiling() && !sampler->IsRegistered())) |
| return; |
| - } |
| + Isolate* isolate = sampler->isolate(); |
| + |
| + // We require a fully initialized and entered isolate. |
| + if (isolate == NULL || !isolate->IsInUse()) return; |
| + |
| if (v8::Locker::IsActive() && |
| !isolate->thread_manager()->IsLockedByCurrentThread()) { |
| return; |
| } |
| - Sampler* sampler = isolate->logger()->sampler(); |
| - if (sampler == NULL) return; |
| - |
| v8::RegisterState state; |
| #if defined(USE_SIMULATOR) |
| @@ -607,19 +661,52 @@ class SamplerThread : public base::Thread { |
| } |
| DCHECK(sampler->IsActive()); |
| - DCHECK(!instance_->active_samplers_.Contains(sampler)); |
| DCHECK(instance_->interval_ == sampler->interval()); |
| + |
| +#if defined(USE_SIGNALS) |
| + AddSampler(sampler); |
| +#else |
| + DCHECK(!instance_->active_samplers_.Contains(sampler)); |
| instance_->active_samplers_.Add(sampler); |
| +#endif // USE_SIGNALS |
| if (need_to_start) instance_->StartSynchronously(); |
| } |
| - static void RemoveActiveSampler(Sampler* sampler) { |
| + static void RemoveSampler(Sampler* sampler) { |
| SamplerThread* instance_to_remove = NULL; |
| { |
| base::LockGuard<base::Mutex> lock_guard(mutex_); |
| - DCHECK(sampler->IsActive()); |
| + DCHECK(sampler->IsActive() || sampler->IsRegistered()); |
| +#if defined(USE_SIGNALS) |
| + { |
| + AtomicGuard<int> atomic_guard(&sampler_list_access_counter_, |
| + 0, 1, true); |
| + // Remove sampler from map. |
| + pthread_t thread_id = sampler->platform_data()->vm_tid(); |
| + SamplerList* samplers = NULL; |
| + int i = 0; |
| + for (; i < thread_id_to_samplers_.length(); ++i) { |
| + ThreadSamplersPair* tsp = thread_id_to_samplers_.at(i); |
| + if (pthread_equal(tsp->thread_id(), thread_id) != 0) { |
| + samplers = tsp->samplers(); |
| + break; |
| + } |
| + } |
| + if (samplers != NULL) { |
| + samplers->RemoveElement(sampler); |
| + if (samplers->is_empty()) { |
| + ThreadSamplersPair* tsp = thread_id_to_samplers_.Remove(i); |
| + delete tsp; |
| + } |
| + } |
| + if (thread_id_to_samplers_.is_empty()) { |
| + instance_to_remove = instance_; |
| + instance_ = NULL; |
| + } |
| + } |
| +#else |
| bool removed = instance_->active_samplers_.RemoveElement(sampler); |
| DCHECK(removed); |
| USE(removed); |
| @@ -630,6 +717,7 @@ class SamplerThread : public base::Thread { |
| instance_to_remove = instance_; |
| instance_ = NULL; |
| } |
| +#endif // USE_SIGNALS |
| } |
| if (!instance_to_remove) return; |
| @@ -637,11 +725,29 @@ class SamplerThread : public base::Thread { |
| delete instance_to_remove; |
| } |
| + // Unlike AddActiveSampler, this method only adds a sampler, |
| + // but won't start the sampler thread. |
| + static void RegisterSampler(Sampler* sampler) { |
| + base::LockGuard<base::Mutex> lock_guard(mutex_); |
| +#if defined(USE_SIGNALS) |
| + AddSampler(sampler); |
| +#endif // USE_SIGNALS |
| + } |
| + |
| // Implement Thread::Run(). |
| virtual void Run() { |
| while (true) { |
| { |
| base::LockGuard<base::Mutex> lock_guard(mutex_); |
| +#if defined(USE_SIGNALS) |
| + if (thread_id_to_samplers_.is_empty()) break; |
| + if (SignalHandler::Installed()) { |
| + for (int i = 0; i < thread_id_to_samplers_.length(); ++i) { |
| + pthread_t thread_id = thread_id_to_samplers_.at(i)->thread_id(); |
| + pthread_kill(thread_id, SIGPROF); |
| + } |
| + } |
| +#else |
| if (active_samplers_.is_empty()) break; |
| // When CPU profiling is enabled both JavaScript and C++ code is |
| // profiled. We must not suspend. |
| @@ -650,6 +756,7 @@ class SamplerThread : public base::Thread { |
| if (!sampler->IsProfiling()) continue; |
| sampler->DoSample(); |
| } |
| +#endif // USE_SIGNALS |
| } |
| base::OS::Sleep(base::TimeDelta::FromMilliseconds(interval_)); |
| } |
| @@ -661,7 +768,36 @@ class SamplerThread : public base::Thread { |
| static SamplerThread* instance_; |
| const int interval_; |
| - List<Sampler*> active_samplers_; |
| + |
| +#if defined(USE_SIGNALS) |
| + friend class SignalHandler; |
| + static ThreadSamplersList thread_id_to_samplers_; |
| + static AtomicValue<int> sampler_list_access_counter_; |
| + static void AddSampler(Sampler* sampler) { |
| + AtomicGuard<int> atomic_guard(&SamplerThread::sampler_list_access_counter_, |
| + 0, 1, true); |
| + // Add sampler into map if needed. |
| + pthread_t thread_id = sampler->platform_data()->vm_tid(); |
| + SamplerList* samplers = NULL; |
| + for (int i = 0; i < thread_id_to_samplers_.length(); ++i) { |
| + ThreadSamplersPair* tsp = thread_id_to_samplers_.at(i); |
| + if (pthread_equal(tsp->thread_id(), thread_id) != 0) { |
| + samplers = tsp->samplers(); |
| + break; |
| + } |
| + } |
| + if (samplers != NULL) { |
| + if (!samplers->Contains(sampler)) |
| + samplers->Add(sampler); |
| + } else { |
| + samplers = new SamplerList(); |
| + samplers->Add(sampler); |
| + thread_id_to_samplers_.Add(new ThreadSamplersPair(thread_id, samplers)); |
| + } |
| + } |
| +#else |
| + SamplerList active_samplers_; |
| +#endif // USE_SIGNALS |
| DISALLOW_COPY_AND_ASSIGN(SamplerThread); |
| }; |
| @@ -669,6 +805,38 @@ class SamplerThread : public base::Thread { |
| base::Mutex* SamplerThread::mutex_ = NULL; |
| SamplerThread* SamplerThread::instance_ = NULL; |
| +#if defined(USE_SIGNALS) |
| +ThreadSamplersList SamplerThread::thread_id_to_samplers_; |
| +AtomicValue<int> SamplerThread::sampler_list_access_counter_(0); |
| +#endif // USE_SIGNALS |
| + |
| +// As Native Client does not support signal handling, profiling is disabled. |
| +#if defined(USE_SIGNALS) |
| +#if !V8_OS_NACL |
| +void SignalHandler::HandleProfilerSignal(int signal, siginfo_t* info, |
| + void* context) { |
| + USE(info); |
| + if (signal != SIGPROF) return; |
| + AtomicGuard<int> atomic_guard(&SamplerThread::sampler_list_access_counter_, |
| + 0, 1, false); |
| + if (!atomic_guard.is_success()) return; |
| + pthread_t thread_id = pthread_self(); |
| + SamplerList* samplers = NULL; |
| + for (int i = 0; i < SamplerThread::thread_id_to_samplers_.length(); ++i) { |
| + ThreadSamplersPair* tsp = SamplerThread::thread_id_to_samplers_.at(i); |
| + if (pthread_equal(tsp->thread_id(), thread_id) != 0) { |
| + samplers = tsp->samplers(); |
| + break; |
| + } |
| + } |
| + DCHECK(samplers != NULL); |
| + for (int i = 0; i < samplers->length(); ++i) { |
| + Sampler* sampler = samplers->at(i); |
| + SignalHandler::CollectSample(context, sampler); |
| + } |
| +} |
| +#endif // !V8_OS_NACL |
| +#endif // USE_SIGNALs |
| // |
| @@ -789,6 +957,7 @@ Sampler::Sampler(Isolate* isolate, int interval) |
| profiling_(false), |
| has_processing_thread_(false), |
| active_(false), |
| + registered_(false), |
| is_counting_samples_(false), |
| js_sample_count_(0), |
| external_sample_count_(0) { |
| @@ -797,6 +966,8 @@ Sampler::Sampler(Isolate* isolate, int interval) |
| Sampler::~Sampler() { |
| DCHECK(!IsActive()); |
| + if (IsRegistered()) |
| + SamplerThread::RemoveSampler(this); |
| delete data_; |
| } |
| @@ -809,8 +980,9 @@ void Sampler::Start() { |
| void Sampler::Stop() { |
| DCHECK(IsActive()); |
| - SamplerThread::RemoveActiveSampler(this); |
| + SamplerThread::RemoveSampler(this); |
| SetActive(false); |
| + SetRegistered(false); |
| } |
| @@ -850,6 +1022,10 @@ void Sampler::SampleStack(const v8::RegisterState& state) { |
| void Sampler::DoSample() { |
| if (!SignalHandler::Installed()) return; |
| + if (!IsActive() && !IsRegistered()) { |
| + SamplerThread::RegisterSampler(this); |
| + SetRegistered(true); |
| + } |
| pthread_kill(platform_data()->vm_tid(), SIGPROF); |
| } |