Chromium Code Reviews| Index: chrome/browser/metrics/tracking_synchronizer.cc |
| =================================================================== |
| --- chrome/browser/metrics/tracking_synchronizer.cc (revision 110669) |
| +++ chrome/browser/metrics/tracking_synchronizer.cc (working copy) |
| @@ -14,6 +14,10 @@ |
| #include "chrome/browser/ui/webui/tracing_ui.h" |
| #include "chrome/common/chrome_constants.h" |
| #include "chrome/common/render_messages.h" |
| +#include "content/browser/browser_child_process_host.h" |
| +#include "content/browser/profiler_controller.h" |
| +#include "content/common/child_process_info.h" |
| +#include "content/common/child_process_messages.h" |
| #include "content/public/browser/browser_thread.h" |
| #include "content/public/browser/render_process_host.h" |
| @@ -33,9 +37,11 @@ |
| : last_used_sequence_number_(kNeverUsableSequenceNumber) { |
| DCHECK(tracking_synchronizer_ == NULL); |
| tracking_synchronizer_ = this; |
| + ProfilerController::GetInstance()->RegisterSubscriber(this); |
| } |
| TrackingSynchronizer::~TrackingSynchronizer() { |
| + ProfilerController::GetInstance()->CancelSubscriber(this); |
| // Just in case we have any pending tasks, clear them out. |
| while (!outstanding_requests_.empty()) { |
| RequestContextMap::iterator it = outstanding_requests_.begin(); |
| @@ -47,14 +53,7 @@ |
| } |
| // static |
| -TrackingSynchronizer* TrackingSynchronizer::CurrentSynchronizer() { |
| - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| - DCHECK(tracking_synchronizer_ != NULL); |
| - return tracking_synchronizer_; |
| -} |
| - |
| -// static |
| -void TrackingSynchronizer::FetchTrackingDataAsynchronously( |
| +void TrackingSynchronizer::FetchProfilerDataAsynchronously( |
| const base::WeakPtr<ProfilerUI>& callback_object) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| @@ -73,13 +72,13 @@ |
| BrowserThread::UI, FROM_HERE, |
| NewRunnableMethod( |
| current_synchronizer, |
| - &TrackingSynchronizer::ForceTrackingSynchronizationDoneCallback, |
| + &TrackingSynchronizer::ForceProfilerSynchronizationDoneCallback, |
| sequence_number), |
| 60000); |
| } |
| // static |
| -void TrackingSynchronizer::SetTrackingStatus(bool enable) { |
| +void TrackingSynchronizer::SetProfilerStatus(bool enable) { |
| // To iterate over all processes, or to send messages to the hosts, we need |
| // to be on the UI thread. |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| @@ -93,73 +92,73 @@ |
| if (!render_process_host->HasConnection()) |
| continue; |
| - render_process_host->Send(new ChromeViewMsg_SetTrackingStatus(enable)); |
| + render_process_host->Send(new ChromeViewMsg_SetProfilerStatus(enable)); |
| } |
| + |
| + BrowserThread::PostTask( |
| + BrowserThread::IO, FROM_HERE, |
| + base::Bind( |
| + &TrackingSynchronizer::SetProfilerStatusInChildProcesses, enable)); |
| } |
| // static |
| -void TrackingSynchronizer::IsTrackingEnabled(int process_id) { |
| +void TrackingSynchronizer::IsProfilerEnabledForRenderer( |
| + int renderer_process_id) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| // To find the process, or to send messages to the hosts, we need to be on the |
| // UI thread. |
| BrowserThread::PostTask( |
| BrowserThread::UI, FROM_HERE, |
| base::Bind( |
| - &TrackingSynchronizer::SetTrackingStatusInProcess, process_id)); |
| + &TrackingSynchronizer::SendRendererSetProfilerStatusOnUI, |
| + renderer_process_id)); |
| } |
| // static |
| -void TrackingSynchronizer::SetTrackingStatusInProcess(int process_id) { |
| - // To find the process, or to send messages to the hosts, we need to be on the |
| - // UI thread. |
| - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| - |
| - bool enable = tracked_objects::ThreadData::tracking_status(); |
| - |
| - content::RenderProcessHost* process = |
| - content::RenderProcessHost::FromID(process_id); |
| - // Ignore processes that don't have a connection, such as crashed tabs. |
| - if (!process || !process->HasConnection()) |
| - return; |
| - process->Send(new ChromeViewMsg_SetTrackingStatus(enable)); |
| -} |
| - |
| -// static |
| -void TrackingSynchronizer::DeserializeTrackingList( |
| +void TrackingSynchronizer::OnRendererProfilerDatatCollected( |
| int sequence_number, |
| - const std::string& tracking_data, |
| - ChildProcessInfo::ProcessType process_type) { |
| + const std::string& profiler_data) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| BrowserThread::PostTask( |
| BrowserThread::UI, FROM_HERE, |
| - base::Bind( |
| - &TrackingSynchronizer::DeserializeTrackingListOnUI, |
| - sequence_number, tracking_data, process_type)); |
| + base::Bind(&TrackingSynchronizer::OnRendererProfilerDatatCollectedOnUI, |
| + sequence_number, |
| + profiler_data)); |
| } |
| -// static |
| -void TrackingSynchronizer::DeserializeTrackingListOnUI( |
| +void TrackingSynchronizer::OnBrowserChildProfilerDataCollected( |
| int sequence_number, |
| - const std::string& tracking_data, |
| - ChildProcessInfo::ProcessType process_type) { |
| - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| + const std::string& profiler_data) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| - TrackingSynchronizer* current_synchronizer = CurrentSynchronizer(); |
| - if (current_synchronizer == NULL) |
| - return; |
| - |
| base::Value* value = |
| - base::JSONReader().JsonToValue(tracking_data, false, true); |
| + base::JSONReader().JsonToValue(profiler_data, false, true); |
| DCHECK(value->GetType() == base::Value::TYPE_DICTIONARY); |
| base::DictionaryValue* dictionary_value = |
| static_cast<DictionaryValue*>(value); |
| - dictionary_value->SetString( |
| - "process_type", ChildProcessInfo::GetTypeNameInEnglish(process_type)); |
| - current_synchronizer->DecrementPendingProcessesAndSendData( |
| - sequence_number, dictionary_value); |
| + DecrementPendingProcessesAndSendDataOnIO(sequence_number, dictionary_value); |
| } |
| +void TrackingSynchronizer::OnIsProfilerEnabledForChildProcess( |
| + base::ProcessId child_process_id) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| + // To find the process, or to send messages to the hosts, we need to be on the |
| + // IO thread. We post a task to set the status. |
| + BrowserThread::PostTask( |
| + BrowserThread::IO, FROM_HERE, |
| + base::Bind( |
| + &TrackingSynchronizer::SendChildSetProfilerStatusOnIO, |
| + child_process_id)); |
| +} |
| + |
| +// static |
| +TrackingSynchronizer* TrackingSynchronizer::CurrentSynchronizer() { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| + DCHECK(tracking_synchronizer_ != NULL); |
| + return tracking_synchronizer_; |
| +} |
| + |
| int TrackingSynchronizer::RegisterAndNotifyAllProcesses( |
| const base::WeakPtr<ProfilerUI>& callback_object) { |
| // To iterate over all processes, or to send messages to the hosts, we need |
| @@ -168,13 +167,41 @@ |
| int sequence_number = GetNextAvailableSequenceNumber(); |
| - // Initialize processes_pending with one because we are going to send |
| - // browser's ThreadData. |
| + // ui_processes_pending is initialized to 1 to send browser's data. |
| + // io_processes_pending is initialized to 1 for browser child processes. |
| + // threads_pending is set to 2 to wait for data from UI thread (for renderer |
| + // processes) and IO thread (for browser child processes). |
| RequestContext* request = new RequestContext( |
| - callback_object, sequence_number, 1, TimeTicks::Now()); |
| + callback_object, sequence_number, 1, 1, 2, TimeTicks::Now()); |
| outstanding_requests_[sequence_number] = request; |
| - DCHECK_GT(request->processes_pending_, 0); |
| + NotifyAllRendererProcesses(request); |
| + |
| + BrowserThread::PostTask( |
| + BrowserThread::IO, FROM_HERE, |
| + base::Bind( |
| + &TrackingSynchronizer::NotifyAllChildProcesses, |
| + base::Unretained(this), request)); |
| + |
| + // Get the ThreadData for the browser process and send it back. |
| + base::DictionaryValue* value = tracked_objects::ThreadData::ToValue(); |
| + const std::string process_type = |
| + ChildProcessInfo::GetTypeNameInEnglish(ChildProcessInfo::BROWSER_PROCESS); |
| + value->SetString("process_type", process_type); |
| + value->SetInteger("process_id", base::GetCurrentProcId()); |
| + DCHECK_GE(request->ui_processes_pending_, 1); |
| + DecrementPendingProcessesAndSendDataOnUI(sequence_number, value); |
| + |
| + return sequence_number; |
| +} |
| + |
| +void TrackingSynchronizer::NotifyAllRendererProcesses(RequestContext* request) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| + DCHECK_EQ(request->ui_processes_pending_, 1); |
| + |
| + const std::string render_process_type = |
| + ChildProcessInfo::GetTypeNameInEnglish(ChildProcessInfo::RENDER_PROCESS); |
| + |
| for (content::RenderProcessHost::iterator it( |
| content::RenderProcessHost::AllHostsIterator()); |
| !it.IsAtEnd(); it.Advance()) { |
| @@ -184,30 +211,104 @@ |
| if (!render_process_host->HasConnection()) |
| continue; |
| - ++request->processes_pending_; |
| - if (!render_process_host->Send( |
| - new ChromeViewMsg_GetRendererTrackedData(sequence_number))) { |
| - DecrementPendingProcesses(sequence_number); |
| + ++request->ui_processes_pending_; |
| + if (!render_process_host->Send(new ChromeViewMsg_GetRendererProfilerData( |
| + request->sequence_number_, render_process_type))) { |
| + DecrementPendingProcessesAndSendDataOnUI(request->sequence_number_, NULL); |
| } |
| } |
| + DCHECK_GE(request->ui_processes_pending_, 1); |
| +} |
| - // Get the ThreadData for the browser process and send it back. |
| - base::DictionaryValue* value = tracked_objects::ThreadData::ToValue(); |
| - const std::string process_type = |
| - ChildProcessInfo::GetTypeNameInEnglish(ChildProcessInfo::BROWSER_PROCESS); |
| - value->SetString("process_type", process_type); |
| - value->SetInteger("process_id", base::GetCurrentProcId()); |
| - DCHECK_GT(request->processes_pending_, 0); |
| - DecrementPendingProcessesAndSendData(sequence_number, value); |
| +void TrackingSynchronizer::NotifyAllChildProcesses(RequestContext* request) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| + DCHECK_EQ(1, request->io_processes_pending_); |
| - return sequence_number; |
| + // Default constr references a singleton. |
|
jam
2011/11/19 23:36:25
nit: this comment, and below, seem unnecessary. i.
ramant (doing other things)
2011/11/25 23:59:48
Done.
|
| + for (BrowserChildProcessHost::Iterator child_process_host; |
| + !child_process_host.Done(); ++child_process_host) { |
| + const std::string process_type = |
| + ChildProcessInfo::GetTypeNameInEnglish(child_process_host->type()); |
| + |
| + ++request->io_processes_pending_; |
| + if (!child_process_host->Send(new ChildProcessMsg_GetChildProfilerData( |
| + request->sequence_number_, process_type))) { |
| + DecrementPendingProcessesAndSendDataOnIO(request->sequence_number_, NULL); |
| + } |
| + } |
| + |
| + DCHECK_GE(request->io_processes_pending_, 1); |
| + if (--request->io_processes_pending_ == 0) { |
| + // We are done because we are not waiting for any browser child processes. |
| + BrowserThread::PostTask( |
| + BrowserThread::UI, FROM_HERE, |
| + base::Bind(&TrackingSynchronizer::DeleteIfAllDone, |
| + base::Unretained(this), request)); |
| + } |
| } |
| -void TrackingSynchronizer::DecrementPendingProcessesAndSendData( |
| +// static |
| +void TrackingSynchronizer::OnRendererProfilerDatatCollectedOnUI( |
| int sequence_number, |
| + const std::string& profiler_data) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| + |
| + TrackingSynchronizer* current_synchronizer = CurrentSynchronizer(); |
| + if (current_synchronizer == NULL) |
| + return; |
| + |
| + base::Value* value = |
| + base::JSONReader().JsonToValue(profiler_data, false, true); |
| + DCHECK(value->GetType() == base::Value::TYPE_DICTIONARY); |
| + base::DictionaryValue* dictionary_value = |
| + static_cast<DictionaryValue*>(value); |
| + |
| + current_synchronizer->DecrementPendingProcessesAndSendDataOnUI( |
| + sequence_number, dictionary_value); |
| +} |
| + |
| +void TrackingSynchronizer::DecrementPendingProcessesAndSendDataOnUI( |
| + int sequence_number, |
| base::DictionaryValue* value) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| + DecrementProcessesCallback decrement_pending_process_cb = |
| + base::Bind(&TrackingSynchronizer::DecrementUIProcesses, |
| + base::Unretained(this)); |
| + |
| + DecrementPendingProcessesAndSendData(sequence_number, |
| + value, |
| + MessageLoop::current(), |
| + decrement_pending_process_cb); |
| +} |
| + |
| +void TrackingSynchronizer::DecrementPendingProcessesAndSendDataOnIO( |
| + int sequence_number, |
| + base::DictionaryValue* value) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| + |
| + DecrementProcessesCallback decrement_pending_process_cb = |
| + base::Bind(&TrackingSynchronizer::DecrementIOProcesses, |
| + base::Unretained(this)); |
| + |
| + BrowserThread::PostTask( |
| + BrowserThread::UI, FROM_HERE, |
| + base::Bind( |
| + &TrackingSynchronizer::DecrementPendingProcessesAndSendData, |
| + base::Unretained(this), |
| + sequence_number, |
| + value, |
| + MessageLoop::current(), |
| + decrement_pending_process_cb)); |
| +} |
| + |
| +void TrackingSynchronizer::DecrementPendingProcessesAndSendData( |
| + int sequence_number, |
| + base::DictionaryValue* value, |
| + MessageLoop* callback_thread, |
| + const DecrementProcessesCallback& decrement_pending_process_cb) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| + |
| RequestContextMap::iterator it = |
| outstanding_requests_.find(sequence_number); |
| if (it == outstanding_requests_.end()) { |
| @@ -226,19 +327,48 @@ |
| delete value; |
| } |
| - if (--request->processes_pending_ <= 0) |
| - ForceTrackingSynchronizationDoneCallback(sequence_number); |
| + callback_thread->PostTask( |
| + FROM_HERE, |
| + base::Bind( |
| + &TrackingSynchronizer::RunDecrementProcessesCallback, |
| + this, decrement_pending_process_cb, request)); |
| } |
| -void TrackingSynchronizer::DecrementPendingProcesses(int sequence_number) { |
| - DecrementPendingProcessesAndSendData(sequence_number, NULL); |
| +void TrackingSynchronizer::DecrementUIProcesses(RequestContext* request) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| + DCHECK_GT(request->ui_processes_pending_, 0); |
| + if (--request->ui_processes_pending_ <= 0) { |
| + DeleteIfAllDone(request); |
| + } |
| } |
| -void TrackingSynchronizer::ForceTrackingSynchronizationDoneCallback( |
| +void TrackingSynchronizer::DecrementIOProcesses(RequestContext* request) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| + DCHECK_GT(request->io_processes_pending_, 0); |
| + if (--request->io_processes_pending_ <= 0) { |
| + BrowserThread::PostTask( |
| + BrowserThread::UI, FROM_HERE, |
| + base::Bind(&TrackingSynchronizer::DeleteIfAllDone, |
| + base::Unretained(this), request)); |
| + } |
| +} |
| + |
| +void TrackingSynchronizer::DeleteIfAllDone(RequestContext* request) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| + DCHECK(request); |
| + // Return if we still need to hear from other threads. |
| + if (--request->threads_pending_) |
| + return; |
| + |
| + DCHECK_EQ(0, request->ui_processes_pending_); |
| + DCHECK_EQ(0, request->io_processes_pending_); |
| + ForceProfilerSynchronizationDoneCallback(request->sequence_number_); |
| +} |
| + |
| +void TrackingSynchronizer::ForceProfilerSynchronizationDoneCallback( |
| int sequence_number) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| - int unresponsive_processes; |
| RequestContextMap::iterator it = |
| outstanding_requests_.find(sequence_number); |
| if (it == outstanding_requests_.end()) |
| @@ -248,12 +378,12 @@ |
| DCHECK(sequence_number == request->sequence_number_); |
| - unresponsive_processes = request->processes_pending_; |
| + int unresponsive_processes = request->ui_processes_pending_; |
| delete it->second; |
| outstanding_requests_.erase(it); |
| - UMA_HISTOGRAM_COUNTS("Tracking.ProcessNotRespondingAsynchronous", |
| + UMA_HISTOGRAM_COUNTS("Profiler.ProcessNotRespondingAsynchronous", |
| unresponsive_processes); |
| } |
| @@ -268,7 +398,56 @@ |
| return last_used_sequence_number_; |
| } |
| +void TrackingSynchronizer::RunDecrementProcessesCallback( |
| + const DecrementProcessesCallback& decrement_pending_process_cb, |
| + RequestContext* request) { |
| + decrement_pending_process_cb.Run(request); |
| +} |
| + |
| // static |
| +void TrackingSynchronizer::SetProfilerStatusInChildProcesses(bool enable) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| + |
| + // Default constr references a singleton. |
| + for (BrowserChildProcessHost::Iterator child_process_host; |
| + !child_process_host.Done(); ++child_process_host) { |
| + child_process_host->Send(new ChildProcessMsg_SetProfilerStatus(enable)); |
| + } |
| +} |
| + |
| +// static |
| +void TrackingSynchronizer::SendRendererSetProfilerStatusOnUI( |
| + int renderer_process_id) { |
| + // To find the process, or to send messages to the hosts, we need to be on the |
| + // UI thread. |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| + |
| + bool enable = tracked_objects::ThreadData::tracking_status(); |
| + |
| + content::RenderProcessHost* process = |
| + content::RenderProcessHost::FromID(renderer_process_id); |
| + // Ignore processes that don't have a connection, such as crashed tabs. |
| + if (!process || !process->HasConnection()) |
| + return; |
| + process->Send(new ChromeViewMsg_SetProfilerStatus(enable)); |
| +} |
| + |
| +// static |
| +void TrackingSynchronizer::SendChildSetProfilerStatusOnIO( |
| + base::ProcessId child_process_id) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| + |
| + bool enable = tracked_objects::ThreadData::tracking_status(); |
| + |
| + // Default constr references a singleton. |
| + for (BrowserChildProcessHost::Iterator child_process_host; |
| + !child_process_host.Done(); ++child_process_host) { |
| + if (base::GetProcId(child_process_host->handle()) == child_process_id) |
| + child_process_host->Send(new ChildProcessMsg_SetProfilerStatus(enable)); |
| + } |
| +} |
| + |
| +// static |
| TrackingSynchronizer* TrackingSynchronizer::tracking_synchronizer_ = NULL; |
| } // namespace chrome_browser_metrics |