diff options
Diffstat (limited to 'chrome/browser/metrics')
-rw-r--r-- | chrome/browser/metrics/tracking_synchronizer.cc | 343 | ||||
-rw-r--r-- | chrome/browser/metrics/tracking_synchronizer.h | 144 |
2 files changed, 233 insertions, 254 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 diff --git a/chrome/browser/metrics/tracking_synchronizer.h b/chrome/browser/metrics/tracking_synchronizer.h index 2647512..75fe3c9d 100644 --- a/chrome/browser/metrics/tracking_synchronizer.h +++ b/chrome/browser/metrics/tracking_synchronizer.h @@ -11,18 +11,17 @@ #include <vector> #include "base/basictypes.h" +#include "base/lazy_instance.h" #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" -#include "base/time.h" #include "base/values.h" #include "chrome/browser/ui/webui/profiler_ui.h" -#include "content/public/browser/browser_thread.h" -#include "content/public/common/process_type.h" +#include "content/public/browser/profiler_subscriber.h" -// This class maintains state that is used to upload tracking data from the +// This class maintains state that is used to upload profiler data from the // various processes, into the browser process. Such transactions are usually // instigated by the browser. In general, a process will respond by gathering -// tracking data, and transmitting the pickled tracking data. We collect the +// profiler data, and transmitting the pickled profiler data. We collect the // data in asynchronous mode that doesn't block the UI thread. // // To assure that all the processes have responded, a counter is maintained @@ -31,99 +30,60 @@ // create RequestContext object which stores the sequence number, pending // processes and the callback_object that needs to be notified when we receive // an update from processes. When an update arrives we find the RequestContext -// associated with sequence number and send the unpickled tracking data to the +// associated with sequence number and send the unpickled profiler data to the // |callback_object_|. namespace chrome_browser_metrics { -class TrackingSynchronizer : public - base::RefCountedThreadSafe<TrackingSynchronizer> { - public: - // The "RequestContext" structure describes an individual request received - // from the UI. - struct RequestContext { - RequestContext(const base::WeakPtr<ProfilerUI>& callback_object, - int sequence_number, - int processes_pending, - base::TimeTicks callback_start_time) - : callback_object_(callback_object), - sequence_number_(sequence_number), - processes_pending_(processes_pending), - request_start_time_(callback_start_time) { - } - - ~RequestContext() {} - - // 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_; - - // The number of processes that have not yet responded to requests. - int processes_pending_; - - // The time when we were told to start the fetching of data from processes. - base::TimeTicks request_start_time_; - }; - - // A map from sequence_number_ to the actual RequestContexts. - typedef std::map<int, RequestContext*> RequestContextMap; +class RequestContext; +class TrackingSynchronizer + : public content::ProfilerSubscriber, + public base::RefCountedThreadSafe<TrackingSynchronizer> { + public: // Construction also sets up the global singleton instance. This instance is // used to communicate between the IO and UI thread, and is destroyed only as // the main thread (browser_main) terminates, which means the IO thread has // already completed, and will not need this instance any further. TrackingSynchronizer(); - // Return pointer to the singleton instance, which is allocated and - // deallocated on the main UI thread (during system startup and teardown). - static TrackingSynchronizer* CurrentSynchronizer(); - // Contact all processes, and get them to upload to the browser any/all - // changes to tracking data. It calls |callback_object|'s SetData method with + // changes to profiler data. It calls |callback_object|'s SetData method with // the data received from each sub-process. // This method is accessible on UI thread. - static void FetchTrackingDataAsynchronously( + static void FetchProfilerDataAsynchronously( const base::WeakPtr<ProfilerUI>& callback_object); - // Contact all processes and set tracking status to |enable|. - // This method is accessible on UI thread. - static void SetTrackingStatus(bool enable); - - // Respond to this message from the renderer by setting the tracking status - // (SetTrackingStatusInProcess) in that renderer process. - // |process_id| is used to find the renderer process. - // This method is accessible on IO thread. - static void IsTrackingEnabled(int process_id); - - // Get the current tracking status from the browser process and set it in the - // renderer process. |process_id| is used to find the renderer process. - // This method is accessible on UI thread. - static void SetTrackingStatusInProcess(int process_id); - - // Deserialize the tracking data and record that we have received tracking - // data from a process. This method posts a task to call - // DeserializeTrackingListOnUI on UI thread to send the |tracking_data| to - // callback_object_. This method is accessible on IO thread. - static void DeserializeTrackingList( + // ------------------------------------------------------ + // ProfilerSubscriber methods for browser child processes + // ------------------------------------------------------ + + // Update the number of pending processes for the given |sequence_number|. + // This is called on UI thread. + virtual void OnPendingProcesses(int sequence_number, + int pending_processes, + bool end) OVERRIDE; + + // Send profiler_data back to callback_object_ by calling + // DecrementPendingProcessesAndSendData which records that we are waiting + // for one less profiler data from renderer or browser child process for the + // given sequence number. This method is accessible on UI thread. + virtual void OnProfilerDataCollected( int sequence_number, - const std::string& tracking_data, - content::ProcessType process_type); - - // Deserialize the tracking data and record that we have received tracking - // data from a process. This method is accessible on UI thread. - static void DeserializeTrackingListOnUI( - int sequence_number, - const std::string& tracking_data, - content::ProcessType process_type); + base::DictionaryValue* profiler_data) OVERRIDE; private: friend class base::RefCountedThreadSafe<TrackingSynchronizer>; + friend class RequestContext; virtual ~TrackingSynchronizer(); + // Send profiler_data back to callback_object_. It records that we are waiting + // for one less profiler data from renderer or browser child process for the + // given sequence number. This method is accessible on UI thread. + void OnProfilerDataCollectedOnUI(int sequence_number, + base::DictionaryValue* profiler_data); + // Establish a new sequence_number_, and use it to notify all the processes of // the need to supply, to the browser, their tracking data. It also registers // |callback_object| in |outstanding_requests_| map. Return the @@ -131,34 +91,24 @@ class TrackingSynchronizer : public int RegisterAndNotifyAllProcesses( const base::WeakPtr<ProfilerUI>& callback_object); - // It finds the |callback_object_| in |outstanding_requests_| map for the - // given |sequence_number| and notifies the |callback_object_| about the - // |value|. This is called whenever we receive tracked data from processes. It - // also records that we are waiting for one less tracking data from a process - // for the given sequence number. If we have received a response from all - // renderers, then it deletes the entry for sequence_number from - // |outstanding_requests_| map. This method is accessible on UI thread. + // It finds the RequestContext for the given |sequence_number| and notifies + // the RequestContext's |callback_object_| about the |value|. This is called + // whenever we receive profiler data from processes. It also records that we + // are waiting for one less profiler data from a process for the given + // sequence number. If we have received a response from all renderers and + // browser processes, then it calls RequestContext's DeleteIfAllDone to delete + // the entry for sequence_number. This method is accessible on UI thread. void DecrementPendingProcessesAndSendData(int sequence_number, base::DictionaryValue* value); - // Records that we are waiting for one less tracking data from a process for - // the given sequence number. - // This method is accessible on UI thread. - void DecrementPendingProcesses(int sequence_number); - - // When all changes have been acquired, or when the wait time expires - // (whichever is sooner), this method is called. This method deletes the entry - // for the given sequence_number from |outstanding_requests_| map. - // This method is accessible on UI thread. - void ForceTrackingSynchronizationDoneCallback(int sequence_number); - // Get a new sequence number to be sent to processes from browser process. // This method is accessible on UI thread. int GetNextAvailableSequenceNumber(); - // Map of all outstanding RequestContexts, from sequence_number_ to - // RequestContext. - RequestContextMap outstanding_requests_; + // Return pointer to the singleton instance, which is allocated and + // deallocated on the main UI thread (during system startup and teardown). + // This method is accessible on UI thread. + static TrackingSynchronizer* CurrentSynchronizer(); // We don't track the actual processes that are contacted for an update, only // the count of the number of processes, and we can sometimes time-out and @@ -173,7 +123,7 @@ class TrackingSynchronizer : public // portion of main(). It initializes globals to provide support for all future // calls. This object is created on the UI thread, and it is destroyed after // all the other threads have gone away. As a result, it is ok to call it - // from the UI thread, or for about:tracking. + // from the UI thread, or for about:profiler. static TrackingSynchronizer* tracking_synchronizer_; DISALLOW_COPY_AND_ASSIGN(TrackingSynchronizer); |