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 |