Chromium Code Reviews| Index: src/platform-freebsd.cc |
| =================================================================== |
| --- src/platform-freebsd.cc (revision 7374) |
| +++ src/platform-freebsd.cc (working copy) |
| @@ -75,6 +75,9 @@ |
| } |
| +static Mutex* limit_mutex = NULL; |
| + |
| + |
| void OS::Setup() { |
| // Seed the random number generator. |
| // Convert the current time to a 64-bit integer first, before converting it |
| @@ -83,6 +86,7 @@ |
| // call this setup code within the same millisecond. |
| uint64_t seed = static_cast<uint64_t>(TimeCurrentMillis()); |
| srandom(static_cast<unsigned int>(seed)); |
| + limit_mutex = CreateMutex(); |
| } |
| @@ -131,6 +135,9 @@ |
| static void UpdateAllocatedSpaceLimits(void* address, int size) { |
| + ASSERT(limit_mutex != NULL); |
| + ScopedLock lock(limit_mutex); |
| + |
| lowest_ever_allocated = Min(lowest_ever_allocated, address); |
| highest_ever_allocated = |
| Max(highest_ever_allocated, |
| @@ -300,7 +307,7 @@ |
| // There may be no filename in this line. Skip to next. |
| if (start_of_path == NULL) continue; |
| buffer[bytes_read] = 0; |
| - LOG(SharedLibraryEvent(start_of_path, start, end)); |
| + LOG(i::Isolate::Current(), SharedLibraryEvent(start_of_path, start, end)); |
| } |
| close(fd); |
| #endif |
| @@ -619,10 +626,6 @@ |
| #ifdef ENABLE_LOGGING_AND_PROFILING |
| -static Sampler* active_sampler_ = NULL; |
| -static pthread_t vm_tid_ = NULL; |
| - |
| - |
| static pthread_t GetThreadID() { |
| pthread_t thread_id = pthread_self(); |
| return thread_id; |
| @@ -631,81 +634,34 @@ |
| class Sampler::PlatformData : public Malloced { |
| public: |
| - enum SleepInterval { |
| - FULL_INTERVAL, |
| - HALF_INTERVAL |
| - }; |
| + PlatformData() : vm_tid_(GetThreadID()) {} |
| - explicit PlatformData(Sampler* sampler) |
| - : sampler_(sampler), |
| - signal_handler_installed_(false), |
| - signal_sender_launched_(false) { |
| - } |
| + const pthread *vm_tid() const { return vm_tid_; } |
|
Vitaly Repeshko
2011/03/28 12:02:30
I think this should return "pthread_t" (no const).
Ben Laurie (Chromium)
2011/03/28 12:08:48
Done.
|
| - void SignalSender() { |
| - while (sampler_->IsActive()) { |
| - if (rate_limiter_.SuspendIfNecessary()) continue; |
| - if (sampler_->IsProfiling() && RuntimeProfiler::IsEnabled()) { |
| - Sleep(FULL_INTERVAL); |
| - RuntimeProfiler::NotifyTick(); |
| - } else { |
| - if (RuntimeProfiler::IsEnabled()) RuntimeProfiler::NotifyTick(); |
| - Sleep(FULL_INTERVAL); |
| - } |
| - } |
| - } |
| - |
| - void Sleep(SleepInterval full_or_half) { |
| - // Convert ms to us and subtract 100 us to compensate delays |
| - // occuring during signal delivery. |
| - useconds_t interval = sampler_->interval_ * 1000 - 100; |
| - if (full_or_half == HALF_INTERVAL) interval /= 2; |
| - int result = usleep(interval); |
| -#ifdef DEBUG |
| - if (result != 0 && errno != EINTR) { |
| - fprintf(stderr, |
| - "SignalSender usleep error; interval = %u, errno = %d\n", |
| - interval, |
| - errno); |
| - ASSERT(result == 0 || errno == EINTR); |
| - } |
| -#endif |
| - USE(result); |
| - } |
| - |
| - Sampler* sampler_; |
| - bool signal_handler_installed_; |
| - struct sigaction old_signal_handler_; |
| - struct itimerval old_timer_value_; |
| - bool signal_sender_launched_; |
| - pthread_t signal_sender_thread_; |
| - RuntimeProfilerRateLimiter rate_limiter_; |
| + private: |
| + const pthread *vm_tid_; |
|
Vitaly Repeshko
2011/03/28 12:02:30
pthread_t
Ben Laurie (Chromium)
2011/03/28 12:08:48
Done.
|
| }; |
| static void ProfilerSignalHandler(int signal, siginfo_t* info, void* context) { |
| USE(info); |
| if (signal != SIGPROF) return; |
| - if (active_sampler_ == NULL) return; |
| - if (!active_sampler_->IsActive()) { |
| - // Restore old signal handler |
| - Sampler::PlatformData* data = active_sampler_->data(); |
| - if (data->signal_handler_installed_) { |
| - sigaction(SIGPROF, &data->old_signal_handler_, 0); |
| - data->signal_handler_installed_ = false; |
| - } |
| + Isolate* isolate = Isolate::UncheckedCurrent(); |
| + if (isolate == NULL || !isolate->IsInitialized() || !isolate->IsInUse()) { |
| + // We require a fully initialized and entered isolate. |
| return; |
| } |
| + Sampler* sampler = isolate->logger()->sampler(); |
| + if (sampler == NULL || !sampler->IsActive()) return; |
| - if (vm_tid_ != GetThreadID()) return; |
| - |
| TickSample sample_obj; |
| - TickSample* sample = CpuProfiler::TickSampleEvent(); |
| + TickSample* sample = CpuProfiler::TickSampleEvent(isolate); |
| if (sample == NULL) sample = &sample_obj; |
| // Extracting the sample from the context is extremely machine dependent. |
| ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context); |
| mcontext_t& mcontext = ucontext->uc_mcontext; |
| + sample->state = isolate->current_vm_state(); |
| #if V8_HOST_ARCH_IA32 |
| sample->pc = reinterpret_cast<Address>(mcontext.mc_eip); |
| sample->sp = reinterpret_cast<Address>(mcontext.mc_esp); |
| @@ -719,81 +675,180 @@ |
| sample->sp = reinterpret_cast<Address>(mcontext.mc_r13); |
| sample->fp = reinterpret_cast<Address>(mcontext.mc_r11); |
| #endif |
| - active_sampler_->SampleStack(sample); |
| - active_sampler_->Tick(sample); |
| + sampler->SampleStack(sample); |
| + sampler->Tick(sample); |
| } |
| -static void* SenderEntry(void* arg) { |
| - Sampler::PlatformData* data = |
| - reinterpret_cast<Sampler::PlatformData*>(arg); |
| - data->SignalSender(); |
| - return 0; |
| -} |
| +class SignalSender : public Thread { |
| + public: |
| + enum SleepInterval { |
| + HALF_INTERVAL, |
| + FULL_INTERVAL |
| + }; |
| + explicit SignalSender(int interval) |
| + : Thread(NULL, "SignalSender"), |
| + thread_id_(pthread_self()), |
|
Vitaly Repeshko
2011/03/28 12:02:30
Should be unused -- see below.
Ben Laurie (Chromium)
2011/03/28 12:08:48
Done.
|
| + interval_(interval) {} |
| + static void AddActiveSampler(Sampler* sampler) { |
| + ScopedLock lock(mutex_); |
| + SamplerRegistry::AddActiveSampler(sampler); |
| + if (instance_ == NULL) { |
| + // Install a signal handler. |
| + struct sigaction sa; |
| + sa.sa_sigaction = ProfilerSignalHandler; |
| + sigemptyset(&sa.sa_mask); |
| + sa.sa_flags = SA_RESTART | SA_SIGINFO; |
| + signal_handler_installed_ = |
| + (sigaction(SIGPROF, &sa, &old_signal_handler_) == 0); |
| + |
| + // Start a thread that sends SIGPROF signal to VM threads. |
| + instance_ = new SignalSender(sampler->interval()); |
| + instance_->Start(); |
| + } else { |
| + ASSERT(instance_->interval_ == sampler->interval()); |
| + } |
| + } |
| + |
| + static void RemoveActiveSampler(Sampler* sampler) { |
| + ScopedLock lock(mutex_); |
| + SamplerRegistry::RemoveActiveSampler(sampler); |
| + if (SamplerRegistry::GetState() == SamplerRegistry::HAS_NO_SAMPLERS) { |
| + RuntimeProfiler::WakeUpRuntimeProfilerThreadBeforeShutdown(); |
| + instance_->Join(); |
| + delete instance_; |
| + instance_ = NULL; |
| + |
| + // Restore the old signal handler. |
| + if (signal_handler_installed_) { |
| + sigaction(SIGPROF, &old_signal_handler_, 0); |
| + signal_handler_installed_ = false; |
| + } |
| + } |
| + } |
| + |
| + // Implement Thread::Run(). |
| + virtual void Run() { |
| + SamplerRegistry::State state; |
| + while ((state = SamplerRegistry::GetState()) != |
| + SamplerRegistry::HAS_NO_SAMPLERS) { |
| + bool cpu_profiling_enabled = |
| + (state == SamplerRegistry::HAS_CPU_PROFILING_SAMPLERS); |
| + bool runtime_profiler_enabled = RuntimeProfiler::IsEnabled(); |
| + // When CPU profiling is enabled both JavaScript and C++ code is |
| + // profiled. We must not suspend. |
| + if (!cpu_profiling_enabled) { |
| + if (rate_limiter_.SuspendIfNecessary()) continue; |
| + } |
| + if (cpu_profiling_enabled && runtime_profiler_enabled) { |
| + if (!SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, this)) { |
| + return; |
| + } |
| + Sleep(HALF_INTERVAL); |
| + if (!SamplerRegistry::IterateActiveSamplers(&DoRuntimeProfile, NULL)) { |
| + return; |
| + } |
| + Sleep(HALF_INTERVAL); |
| + } else { |
| + if (cpu_profiling_enabled) { |
| + if (!SamplerRegistry::IterateActiveSamplers(&DoCpuProfile, |
| + this)) { |
| + return; |
| + } |
| + } |
| + if (runtime_profiler_enabled) { |
| + if (!SamplerRegistry::IterateActiveSamplers(&DoRuntimeProfile, |
| + NULL)) { |
| + return; |
| + } |
| + } |
| + Sleep(FULL_INTERVAL); |
| + } |
| + } |
| + } |
| + |
| + static void DoCpuProfile(Sampler* sampler, void* raw_sender) { |
| + if (!sampler->IsProfiling()) return; |
| + SignalSender* sender = reinterpret_cast<SignalSender*>(raw_sender); |
| + sender->SendProfilingSignal(sampler->platform_data()->vm_tid()); |
| + } |
| + |
| + static void DoRuntimeProfile(Sampler* sampler, void* ignored) { |
| + if (!sampler->isolate()->IsInitialized()) return; |
| + sampler->isolate()->runtime_profiler()->NotifyTick(); |
| + } |
| + |
| + void SendProfilingSignal(const pthread *tid) { |
|
Vitaly Repeshko
2011/03/28 12:02:30
pthread_t
Ben Laurie (Chromium)
2011/03/28 12:08:48
Done.
|
| + if (!signal_handler_installed_) return; |
| + pthread_kill(thread_id_, SIGPROF); |
|
Vitaly Repeshko
2011/03/28 12:02:30
Use the thread id parameter here.
Ben Laurie (Chromium)
2011/03/28 12:08:48
Done.
|
| + } |
| + |
| + void Sleep(SleepInterval full_or_half) { |
| + // Convert ms to us and subtract 100 us to compensate delays |
| + // occuring during signal delivery. |
| + useconds_t interval = interval_ * 1000 - 100; |
| + if (full_or_half == HALF_INTERVAL) interval /= 2; |
| + int result = usleep(interval); |
| +#ifdef DEBUG |
| + if (result != 0 && errno != EINTR) { |
| + fprintf(stderr, |
| + "SignalSender usleep error; interval = %u, errno = %d\n", |
| + interval, |
| + errno); |
| + ASSERT(result == 0 || errno == EINTR); |
| + } |
| +#endif |
| + USE(result); |
| + } |
| + |
| + const pthread_t thread_id_; |
| + const int interval_; |
| + RuntimeProfilerRateLimiter rate_limiter_; |
| + |
| + // Protects the process wide state below. |
| + static Mutex* mutex_; |
| + static SignalSender* instance_; |
| + static bool signal_handler_installed_; |
| + static struct sigaction old_signal_handler_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(SignalSender); |
| +}; |
| + |
| +Mutex* SignalSender::mutex_ = OS::CreateMutex(); |
| +SignalSender* SignalSender::instance_ = NULL; |
| +struct sigaction SignalSender::old_signal_handler_; |
| +bool SignalSender::signal_handler_installed_ = false; |
| + |
| + |
| Sampler::Sampler(Isolate* isolate, int interval) |
| : isolate_(isolate), |
| interval_(interval), |
| profiling_(false), |
| active_(false), |
| samples_taken_(0) { |
| - data_ = new PlatformData(this); |
| + data_ = new PlatformData; |
| } |
| Sampler::~Sampler() { |
| + ASSERT(!IsActive()); |
| delete data_; |
| } |
| void Sampler::Start() { |
| - // There can only be one active sampler at the time on POSIX |
| - // platforms. |
| ASSERT(!IsActive()); |
| - vm_tid_ = GetThreadID(); |
| - |
| - // Request profiling signals. |
| - struct sigaction sa; |
| - sa.sa_sigaction = ProfilerSignalHandler; |
| - sigemptyset(&sa.sa_mask); |
| - sa.sa_flags = SA_SIGINFO; |
| - if (sigaction(SIGPROF, &sa, &data_->old_signal_handler_) != 0) return; |
| - data_->signal_handler_installed_ = true; |
| - |
| - // Set the itimer to generate a tick for each interval. |
| - itimerval itimer; |
| - itimer.it_interval.tv_sec = interval_ / 1000; |
| - itimer.it_interval.tv_usec = (interval_ % 1000) * 1000; |
| - itimer.it_value.tv_sec = itimer.it_interval.tv_sec; |
| - itimer.it_value.tv_usec = itimer.it_interval.tv_usec; |
| - setitimer(ITIMER_PROF, &itimer, &data_->old_timer_value_); |
| - |
| - // Set this sampler as the active sampler. |
| - active_sampler_ = this; |
| SetActive(true); |
| - |
| - // There's no way to send a signal to a thread on FreeBSD, but we can |
| - // start a thread that uses the stack guard to interrupt the JS thread. |
| - if (pthread_create( |
| - &data_->signal_sender_thread_, NULL, SenderEntry, data_) == 0) { |
| - data_->signal_sender_launched_ = true; |
| - } |
| + SignalSender::AddActiveSampler(this); |
| } |
| void Sampler::Stop() { |
| - // This sampler is no longer the active sampler. |
| - active_sampler_ = NULL; |
| + ASSERT(IsActive()); |
| + SignalSender::RemoveActiveSampler(this); |
| SetActive(false); |
| - |
| - // Wait for signal sender termination (it will exit after setting |
| - // active_ to false). |
| - if (data_->signal_sender_launched_) { |
| - Top::WakeUpRuntimeProfilerThreadBeforeShutdown(); |
| - pthread_join(data_->signal_sender_thread_, NULL); |
| - data_->signal_sender_launched_ = false; |
| - } |
| } |
| #endif // ENABLE_LOGGING_AND_PROFILING |