Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(4032)

Unified Diff: chrome/browser/metrics/tracking_synchronizer.cc

Issue 8588023: Collect profiler stats from browser child processes. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 9 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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

Powered by Google App Engine
This is Rietveld 408576698