diff options
author | rtenneti@chromium.org <rtenneti@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-12-01 23:20:20 +0000 |
---|---|---|
committer | rtenneti@chromium.org <rtenneti@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-12-01 23:20:20 +0000 |
commit | 33047f18fb4d05e45a6a28e706a605ddccc591f6 (patch) | |
tree | fc79c483b777007677dcbdb843f300e602277978 /chrome/browser/metrics/tracking_synchronizer.cc | |
parent | b05df6b03e0d5dc552a96578ea6a8a7e47af407c (diff) | |
download | chromium_src-33047f18fb4d05e45a6a28e706a605ddccc591f6.zip chromium_src-33047f18fb4d05e45a6a28e706a605ddccc591f6.tar.gz chromium_src-33047f18fb4d05e45a6a28e706a605ddccc591f6.tar.bz2 |
Collect profiler stats from all browser child processes.
R=jar
Bug=104770
TEST=about:profiler after lauching a plug-in or GPU should show
tracking data for plugin-gpu processes
Review URL: http://codereview.chromium.org/8588023
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@112571 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/metrics/tracking_synchronizer.cc')
-rw-r--r-- | chrome/browser/metrics/tracking_synchronizer.cc | 343 |
1 files changed, 186 insertions, 157 deletions
diff --git a/chrome/browser/metrics/tracking_synchronizer.cc b/chrome/browser/metrics/tracking_synchronizer.cc index fa46d90..c97105c 100644 --- a/chrome/browser/metrics/tracking_synchronizer.cc +++ b/chrome/browser/metrics/tracking_synchronizer.cc @@ -5,17 +5,13 @@ #include "chrome/browser/metrics/tracking_synchronizer.h" #include "base/bind.h" -#include "base/json/json_reader.h" -#include "base/json/json_writer.h" -#include "base/logging.h" #include "base/metrics/histogram.h" +#include "base/process_util.h" #include "base/threading/thread.h" #include "base/tracked_objects.h" -#include "chrome/browser/ui/webui/tracing_ui.h" -#include "chrome/common/chrome_constants.h" -#include "chrome/common/render_messages.h" +#include "content/common/child_process_info.h" #include "content/public/browser/browser_thread.h" -#include "content/public/browser/render_process_host.h" +#include "content/public/browser/profiler_controller.h" #include "content/public/common/process_type.h" using base::TimeTicks; @@ -23,6 +19,142 @@ using content::BrowserThread; namespace chrome_browser_metrics { +// The "RequestContext" structure describes an individual request received +// from the UI. All methods are accessible on UI thread. +class RequestContext { + public: + // A map from sequence_number_ to the actual RequestContexts. + typedef std::map<int, RequestContext*> RequestContextMap; + + ~RequestContext() {} + + RequestContext(const base::WeakPtr<ProfilerUI>& callback_object, + int sequence_number) + : callback_object_(callback_object), + sequence_number_(sequence_number), + received_process_group_count_(0), + processes_pending_(0) { + } + + void SetReceivedProcessGroupCount(bool done) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + received_process_group_count_ = done; + } + + // Methods for book keeping of processes_pending_. + void IncrementProcessesPending() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + ++processes_pending_; + } + + void AddProcessesPending(int processes_pending) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + processes_pending_ += processes_pending; + } + + void DecrementProcessesPending() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + --processes_pending_; + } + + // Records that we are waiting for one less tracking data from a process for + // the given sequence number. If |received_process_group_count_| and + // |processes_pending_| are zero, then delete the current object by calling + // Unregister. + void DeleteIfAllDone() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + + if (processes_pending_ <= 0 && received_process_group_count_) { + RequestContext::Unregister(sequence_number_); + } + } + + + // Register |callback_object| in |outstanding_requests_| map for the given + // |sequence_number|. + static RequestContext* Register( + int sequence_number, + const base::WeakPtr<ProfilerUI>& callback_object) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + + RequestContext* request = new RequestContext( + callback_object, sequence_number); + outstanding_requests_.Get()[sequence_number] = request; + + return request; + } + + // Find the |RequestContext| in |outstanding_requests_| map for the given + // |sequence_number|. + static RequestContext* GetRequestContext(int sequence_number) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + + RequestContextMap::iterator it = + outstanding_requests_.Get().find(sequence_number); + if (it == outstanding_requests_.Get().end()) + return NULL; + + RequestContext* request = NULL; + request = it->second; + DCHECK(sequence_number == request->sequence_number_); + return request; + } + + // Delete the entry for the given sequence_number| from + // |outstanding_requests_| map. This method is called when all changes have + // been acquired, or when the wait time expires (whichever is sooner). + static void Unregister(int sequence_number) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + + RequestContextMap::iterator it = + outstanding_requests_.Get().find(sequence_number); + if (it == outstanding_requests_.Get().end()) + return; + + RequestContext* request = it->second; + DCHECK(sequence_number == request->sequence_number_); + bool received_process_group_count = request->received_process_group_count_; + int unresponsive_processes = request->processes_pending_; + + delete it->second; + outstanding_requests_.Get().erase(it); + + UMA_HISTOGRAM_BOOLEAN("Profiling.ReceivedProcessGroupCount", + received_process_group_count); + UMA_HISTOGRAM_COUNTS("Profiling.PendingProcessNotResponding", + unresponsive_processes); + } + + + // Delete all the entries in |outstanding_requests_| map. + static void OnShutdown() { + // Just in case we have any pending tasks, clear them out. + while (!outstanding_requests_.Get().empty()) { + RequestContextMap::iterator it = outstanding_requests_.Get().begin(); + delete it->second; + outstanding_requests_.Get().erase(it); + } + } + + // Requests are made to asynchronously send data to the |callback_object_|. + base::WeakPtr<ProfilerUI> callback_object_; + + // The sequence number used by the most recent update request to contact all + // processes. + int sequence_number_; + + // Indicates if we have received all pending processes count. + bool received_process_group_count_; + + // The number of pending processes (browser, all renderer processes and + // browser child processes) that have not yet responded to requests. + int processes_pending_; + + // Map of all outstanding RequestContexts, from sequence_number_ to + // RequestContext. + static base::LazyInstance<RequestContextMap> outstanding_requests_; +}; + // Negative numbers are never used as sequence numbers. We explicitly pick a // negative number that is "so negative" that even when we add one (as is done // when we generated the next sequence number) that it will still be negative. @@ -30,32 +162,29 @@ namespace chrome_browser_metrics { // territory. static const int kNeverUsableSequenceNumber = -2; +// TrackingSynchronizer methods and members. +// +// static +TrackingSynchronizer* TrackingSynchronizer::tracking_synchronizer_ = NULL; + TrackingSynchronizer::TrackingSynchronizer() : last_used_sequence_number_(kNeverUsableSequenceNumber) { DCHECK(tracking_synchronizer_ == NULL); tracking_synchronizer_ = this; + content::ProfilerController::GetInstance()->Register(this); } TrackingSynchronizer::~TrackingSynchronizer() { + content::ProfilerController::GetInstance()->Unregister(this); + // Just in case we have any pending tasks, clear them out. - while (!outstanding_requests_.empty()) { - RequestContextMap::iterator it = outstanding_requests_.begin(); - delete it->second; - outstanding_requests_.erase(it); - } + RequestContext::OnShutdown(); tracking_synchronizer_ = NULL; } // 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)); @@ -72,133 +201,56 @@ void TrackingSynchronizer::FetchTrackingDataAsynchronously( // as a watchdog, to cancel the requests for non-responsive processes. BrowserThread::PostDelayedTask( BrowserThread::UI, FROM_HERE, - NewRunnableMethod( - current_synchronizer, - &TrackingSynchronizer::ForceTrackingSynchronizationDoneCallback, - sequence_number), + base::Bind(&RequestContext::Unregister, sequence_number), 60000); } -// static -void TrackingSynchronizer::SetTrackingStatus(bool enable) { - // To iterate over all processes, or to send messages to the hosts, we need - // to be on the UI thread. +void TrackingSynchronizer::OnPendingProcesses(int sequence_number, + int pending_processes, + bool end) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - for (content::RenderProcessHost::iterator it( - content::RenderProcessHost::AllHostsIterator()); - !it.IsAtEnd(); it.Advance()) { - content::RenderProcessHost* render_process_host = it.GetCurrentValue(); - DCHECK(render_process_host); - // Ignore processes that don't have a connection, such as crashed tabs. - if (!render_process_host->HasConnection()) - continue; - - render_process_host->Send(new ChromeViewMsg_SetTrackingStatus(enable)); - } -} - -// static -void TrackingSynchronizer::IsTrackingEnabled(int 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)); -} - -// 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()) + RequestContext* request = RequestContext::GetRequestContext(sequence_number); + if (!request) return; - process->Send(new ChromeViewMsg_SetTrackingStatus(enable)); -} - -// static -void TrackingSynchronizer::DeserializeTrackingList( - int sequence_number, - const std::string& tracking_data, - content::ProcessType process_type) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - BrowserThread::PostTask( - BrowserThread::UI, FROM_HERE, - base::Bind( - &TrackingSynchronizer::DeserializeTrackingListOnUI, - sequence_number, tracking_data, process_type)); + request->AddProcessesPending(pending_processes); + request->SetReceivedProcessGroupCount(end); + request->DeleteIfAllDone(); } -// static -void TrackingSynchronizer::DeserializeTrackingListOnUI( +void TrackingSynchronizer::OnProfilerDataCollected( int sequence_number, - const std::string& tracking_data, - content::ProcessType process_type) { + base::DictionaryValue* profiler_data) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - TrackingSynchronizer* current_synchronizer = CurrentSynchronizer(); - if (current_synchronizer == NULL) + RequestContext* request = RequestContext::GetRequestContext(sequence_number); + if (!request) return; - base::Value* value = - base::JSONReader().JsonToValue(tracking_data, false, true); - DCHECK(value->GetType() == base::Value::TYPE_DICTIONARY); - base::DictionaryValue* dictionary_value = - static_cast<DictionaryValue*>(value); - dictionary_value->SetString( - "process_type", content::GetProcessTypeNameInEnglish(process_type)); - - current_synchronizer->DecrementPendingProcessesAndSendData( - sequence_number, dictionary_value); + DecrementPendingProcessesAndSendData(sequence_number, profiler_data); } int TrackingSynchronizer::RegisterAndNotifyAllProcesses( const base::WeakPtr<ProfilerUI>& callback_object) { - // 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)); int sequence_number = GetNextAvailableSequenceNumber(); - // Initialize processes_pending with one because we are going to send - // browser's ThreadData. - RequestContext* request = new RequestContext( - callback_object, sequence_number, 1, TimeTicks::Now()); - outstanding_requests_[sequence_number] = request; - - DCHECK_GT(request->processes_pending_, 0); - for (content::RenderProcessHost::iterator it( - content::RenderProcessHost::AllHostsIterator()); - !it.IsAtEnd(); it.Advance()) { - content::RenderProcessHost* render_process_host = it.GetCurrentValue(); - DCHECK(render_process_host); - // Ignore processes that don't have a connection, such as crashed tabs. - if (!render_process_host->HasConnection()) - continue; - - ++request->processes_pending_; - if (!render_process_host->Send( - new ChromeViewMsg_GetRendererTrackedData(sequence_number))) { - DecrementPendingProcesses(sequence_number); - } - } + RequestContext* request = + RequestContext::Register(sequence_number, callback_object); + + // Increment pending process count for sending browser's profiler data. + request->IncrementProcessesPending(); + + // Get profiler data from renderer and browser child processes. + content::ProfilerController::GetInstance()->GetProfilerData(sequence_number); - // Get the ThreadData for the browser process and send it back. + // Send profiler_data from browser process. base::DictionaryValue* value = tracked_objects::ThreadData::ToValue(); const std::string process_type = content::GetProcessTypeNameInEnglish(content::PROCESS_TYPE_BROWSER); value->SetString("process_type", process_type); value->SetInteger("process_id", base::GetCurrentProcId()); - DCHECK_GT(request->processes_pending_, 0); DecrementPendingProcessesAndSendData(sequence_number, value); return sequence_number; @@ -209,17 +261,12 @@ void TrackingSynchronizer::DecrementPendingProcessesAndSendData( base::DictionaryValue* value) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - RequestContextMap::iterator it = - outstanding_requests_.find(sequence_number); - if (it == outstanding_requests_.end()) { + RequestContext* request = RequestContext::GetRequestContext(sequence_number); + if (!request) { delete value; return; } - RequestContext* request = NULL; - request = it->second; - DCHECK(sequence_number == request->sequence_number_); - if (value && request->callback_object_) { // Transfers ownership of |value| to |callback_object_|. request->callback_object_->ReceivedData(value); @@ -227,35 +274,9 @@ void TrackingSynchronizer::DecrementPendingProcessesAndSendData( delete value; } - if (--request->processes_pending_ <= 0) - ForceTrackingSynchronizationDoneCallback(sequence_number); -} - -void TrackingSynchronizer::DecrementPendingProcesses(int sequence_number) { - DecrementPendingProcessesAndSendData(sequence_number, NULL); -} - -void TrackingSynchronizer::ForceTrackingSynchronizationDoneCallback( - int sequence_number) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - - int unresponsive_processes; - RequestContextMap::iterator it = - outstanding_requests_.find(sequence_number); - if (it == outstanding_requests_.end()) - return; - - RequestContext* request = it->second; - - DCHECK(sequence_number == request->sequence_number_); - - unresponsive_processes = request->processes_pending_; - - delete it->second; - outstanding_requests_.erase(it); - - UMA_HISTOGRAM_COUNTS("Tracking.ProcessNotRespondingAsynchronous", - unresponsive_processes); + // Delete request if we have heard back from all child processes. + request->DecrementProcessesPending(); + request->DeleteIfAllDone(); } int TrackingSynchronizer::GetNextAvailableSequenceNumber() { @@ -270,6 +291,14 @@ int TrackingSynchronizer::GetNextAvailableSequenceNumber() { } // static -TrackingSynchronizer* TrackingSynchronizer::tracking_synchronizer_ = NULL; +TrackingSynchronizer* TrackingSynchronizer::CurrentSynchronizer() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + DCHECK(tracking_synchronizer_ != NULL); + return tracking_synchronizer_; +} + +// static +base::LazyInstance<RequestContext::RequestContextMap> + RequestContext::outstanding_requests_ = LAZY_INSTANCE_INITIALIZER; } // namespace chrome_browser_metrics |