// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "content/browser/profiler_controller_impl.h" #include "base/bind.h" #include "base/process/process_handle.h" #include "base/tracked_objects.h" #include "content/common/child_process_messages.h" #include "content/public/browser/browser_child_process_host_iterator.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/child_process_data.h" #include "content/public/browser/profiler_subscriber.h" #include "content/public/browser/render_process_host.h" namespace content { ProfilerController* ProfilerController::GetInstance() { return ProfilerControllerImpl::GetInstance(); } ProfilerControllerImpl* ProfilerControllerImpl::GetInstance() { return base::Singleton::get(); } ProfilerControllerImpl::ProfilerControllerImpl() : subscriber_(NULL) { } ProfilerControllerImpl::~ProfilerControllerImpl() { } void ProfilerControllerImpl::OnPendingProcesses(int sequence_number, int pending_processes, bool end) { DCHECK_CURRENTLY_ON(BrowserThread::UI); if (subscriber_) subscriber_->OnPendingProcesses(sequence_number, pending_processes, end); } void ProfilerControllerImpl::OnProfilerDataCollected( int sequence_number, const tracked_objects::ProcessDataSnapshot& profiler_data, content::ProcessType process_type) { if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { BrowserThread::PostTask( BrowserThread::UI, FROM_HERE, base::Bind(&ProfilerControllerImpl::OnProfilerDataCollected, base::Unretained(this), sequence_number, profiler_data, process_type)); return; } DCHECK_CURRENTLY_ON(BrowserThread::UI); if (subscriber_) { subscriber_->OnProfilerDataCollected(sequence_number, profiler_data, process_type); } } void ProfilerControllerImpl::Register(ProfilerSubscriber* subscriber) { DCHECK_CURRENTLY_ON(BrowserThread::UI); DCHECK(!subscriber_); subscriber_ = subscriber; } void ProfilerControllerImpl::Unregister(const ProfilerSubscriber* subscriber) { DCHECK_EQ(subscriber_, subscriber); subscriber_ = NULL; } void ProfilerControllerImpl::GetProfilerDataFromChildProcesses( int sequence_number, int current_profiling_phase) { DCHECK_CURRENTLY_ON(BrowserThread::IO); int pending_processes = 0; for (BrowserChildProcessHostIterator iter; !iter.Done(); ++iter) { // In some cases, there may be no child process of the given type (for // example, the GPU process may not exist and there may instead just be a // GPU thread in the browser process). If that's the case, then the process // handle will be base::kNullProcessHandle and we shouldn't ask it for data. if (iter.GetData().handle == base::kNullProcessHandle) continue; ++pending_processes; if (!iter.Send(new ChildProcessMsg_GetChildProfilerData( sequence_number, current_profiling_phase))) { --pending_processes; } } BrowserThread::PostTask( BrowserThread::UI, FROM_HERE, base::Bind( &ProfilerControllerImpl::OnPendingProcesses, base::Unretained(this), sequence_number, pending_processes, true)); } // static void ProfilerControllerImpl::NotifyChildProcessesOfProfilingPhaseCompletion( int profiling_phase) { DCHECK_CURRENTLY_ON(BrowserThread::IO); for (BrowserChildProcessHostIterator iter; !iter.Done(); ++iter) { // In some cases, there may be no child process of the given type (for // example, the GPU process may not exist and there may instead just be a // GPU thread in the browser process). If that's the case, then the process // handle will be base::kNullProcessHandle and we shouldn't send it a // message. if (iter.GetData().handle == base::kNullProcessHandle) continue; iter.Send(new ChildProcessMsg_ProfilingPhaseCompleted(profiling_phase)); } } void ProfilerControllerImpl::GetProfilerData(int sequence_number, int current_profiling_phase) { DCHECK_CURRENTLY_ON(BrowserThread::UI); // Iterates through renderers in UI thread, and through other child processes // in IO thread, and send them GetChildProfilerData message. Renderers have to // be contacted from UI thread, and other processes - from IO thread. int pending_processes = 0; for (RenderProcessHost::iterator it(RenderProcessHost::AllHostsIterator()); !it.IsAtEnd(); it.Advance()) { ++pending_processes; if (!it.GetCurrentValue()->Send(new ChildProcessMsg_GetChildProfilerData( sequence_number, current_profiling_phase))) { --pending_processes; } } OnPendingProcesses(sequence_number, pending_processes, false); BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, base::Bind(&ProfilerControllerImpl::GetProfilerDataFromChildProcesses, base::Unretained(this), sequence_number, current_profiling_phase)); } void ProfilerControllerImpl::OnProfilingPhaseCompleted(int profiling_phase) { DCHECK_CURRENTLY_ON(BrowserThread::UI); // Iterates through renderers in UI thread, and through other child processes // in IO thread, and send them OnProfilingPhase message. Renderers have to be // contacted from UI thread, and other processes - from IO thread. for (RenderProcessHost::iterator it(RenderProcessHost::AllHostsIterator()); !it.IsAtEnd(); it.Advance()) { it.GetCurrentValue()->Send( new ChildProcessMsg_ProfilingPhaseCompleted(profiling_phase)); } BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, base::Bind(&ProfilerControllerImpl:: NotifyChildProcessesOfProfilingPhaseCompletion, profiling_phase)); } } // namespace content