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

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

Issue 10454086: Histograms - Support histograms for Plugins, GPU (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Created 8 years, 7 months 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/histogram_synchronizer.cc
===================================================================
--- chrome/browser/metrics/histogram_synchronizer.cc (revision 139338)
+++ chrome/browser/metrics/histogram_synchronizer.cc (working copy)
@@ -5,20 +5,149 @@
#include "chrome/browser/metrics/histogram_synchronizer.h"
#include "base/bind.h"
+#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/metrics/histogram.h"
#include "base/threading/thread.h"
#include "base/threading/thread_restrictions.h"
#include "chrome/common/chrome_constants.h"
-#include "chrome/common/render_messages.h"
#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/render_process_host.h"
+#include "content/public/browser/histogram_controller.h"
using base::Time;
using base::TimeDelta;
using base::TimeTicks;
using content::BrowserThread;
+// The "HistogramRequestContext" structure describes an individual request
+// received from the UI. All methods are accessible on UI thread.
+class HistogramRequestContext {
+ public:
+ // A map from sequence_number_ to the actual HistogramRequestContexts.
+ typedef std::map<int, HistogramRequestContext*> HistogramRequestContextMap;
+
+ ~HistogramRequestContext() {}
+
+ HistogramRequestContext(const base::Closure& callback,
+ int sequence_number)
+ : callback_(callback),
+ 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;
+ }
+
+ 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 histogram 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_) {
+ HistogramRequestContext::Unregister(sequence_number_);
+ }
+ }
+
+ // Register a |HistogramRequestContext| in |outstanding_requests_| map for the
+ // given |sequence_number|.
+ static void Register(const base::Closure& callback, int sequence_number) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ HistogramRequestContext* request = new HistogramRequestContext(
+ callback, sequence_number);
+ outstanding_requests_.Get()[sequence_number] = request;
+ }
+
+ // Find the |HistogramRequestContext| in |outstanding_requests_| map for the
+ // given |sequence_number|.
+ static HistogramRequestContext* GetHistogramRequestContext(
+ int sequence_number) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ HistogramRequestContextMap::iterator it =
+ outstanding_requests_.Get().find(sequence_number);
+ if (it == outstanding_requests_.Get().end())
+ return NULL;
+
+ HistogramRequestContext* 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));
+
+ HistogramRequestContextMap::iterator it =
+ outstanding_requests_.Get().find(sequence_number);
+ if (it == outstanding_requests_.Get().end())
+ return;
+
+ HistogramRequestContext* 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_;
+
+ request->callback_.Run();
+
+ delete it->second;
+ outstanding_requests_.Get().erase(it);
+
+ UMA_HISTOGRAM_BOOLEAN("Histogram.ReceivedProcessGroupCount",
+ received_process_group_count);
+ UMA_HISTOGRAM_COUNTS("Histogram.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()) {
+ HistogramRequestContextMap::iterator it =
+ outstanding_requests_.Get().begin();
+ delete it->second;
+ outstanding_requests_.Get().erase(it);
+ }
+ }
+
+ // Requests are made to asynchronously send data to the |callback_|.
+ base::Closure callback_;
+
+ // 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 (all renderer processes and browser child
+ // processes) that have not yet responded to requests.
+ int processes_pending_;
+
+ // Map of all outstanding HistogramRequestContexts, from sequence_number_ to
+ // HistogramRequestContext.
+ static base::LazyInstance<HistogramRequestContextMap>::Leaky
+ 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.
@@ -28,56 +157,37 @@
HistogramSynchronizer::HistogramSynchronizer()
: lock_(),
- received_all_renderer_histograms_(&lock_),
callback_thread_(NULL),
last_used_sequence_number_(kNeverUsableSequenceNumber),
- async_sequence_number_(kNeverUsableSequenceNumber),
- async_renderers_pending_(0),
- synchronous_sequence_number_(kNeverUsableSequenceNumber),
- synchronous_renderers_pending_(0) {
- DCHECK(histogram_synchronizer_ == NULL);
- histogram_synchronizer_ = this;
+ async_sequence_number_(kNeverUsableSequenceNumber) {
+ DCHECK(g_histogram_synchronizer == NULL);
+ g_histogram_synchronizer = this;
+ content::HistogramController::GetInstance()->Register(this);
}
HistogramSynchronizer::~HistogramSynchronizer() {
+ HistogramRequestContext::OnShutdown();
+
// Just in case we have any pending tasks, clear them out.
SetCallbackTaskAndThread(NULL, base::Closure());
- histogram_synchronizer_ = NULL;
+ g_histogram_synchronizer = NULL;
}
// static
HistogramSynchronizer* HistogramSynchronizer::CurrentSynchronizer() {
- DCHECK(histogram_synchronizer_ != NULL);
- return histogram_synchronizer_;
+ DCHECK(g_histogram_synchronizer != NULL);
+ return g_histogram_synchronizer;
}
-void HistogramSynchronizer::FetchRendererHistogramsSynchronously(
+void HistogramSynchronizer::FetchHistogramsSynchronously(
TimeDelta wait_time) {
- NotifyAllRenderers(SYNCHRONOUS_HISTOGRAMS);
-
- TimeTicks start = TimeTicks::Now();
- TimeTicks end_time = start + wait_time;
- int unresponsive_renderer_count;
- {
- base::AutoLock auto_lock(lock_);
- while (synchronous_renderers_pending_ > 0 && TimeTicks::Now() < end_time) {
- wait_time = end_time - TimeTicks::Now();
- base::ThreadRestrictions::ScopedAllowWait allow_wait;
- received_all_renderer_histograms_.TimedWait(wait_time);
- }
- unresponsive_renderer_count = synchronous_renderers_pending_;
- synchronous_renderers_pending_ = 0;
- synchronous_sequence_number_ = kNeverUsableSequenceNumber;
- }
- UMA_HISTOGRAM_COUNTS("Histogram.RendersNotRespondingSynchronous",
- unresponsive_renderer_count);
- if (!unresponsive_renderer_count)
- UMA_HISTOGRAM_TIMES("Histogram.FetchRendererHistogramsSynchronously",
- TimeTicks::Now() - start);
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ RegisterAndNotifyAllProcesses(SYNCHRONOUS_HISTOGRAMS,
+ base::TimeDelta::FromMinutes(1));
}
// static
-void HistogramSynchronizer::FetchRendererHistogramsAsynchronously(
+void HistogramSynchronizer::FetchHistogramsAsynchronously(
MessageLoop* callback_thread,
const base::Closure& callback,
base::TimeDelta wait_time) {
@@ -95,84 +205,79 @@
current_synchronizer->SetCallbackTaskAndThread(callback_thread,
callback);
- int sequence_number =
- current_synchronizer->NotifyAllRenderers(ASYNC_HISTOGRAMS);
+ current_synchronizer->RegisterAndNotifyAllProcesses(ASYNC_HISTOGRAMS,
+ wait_time);
+}
+void HistogramSynchronizer::RegisterAndNotifyAllProcesses(
+ ProcessHistogramRequester requester,
+ base::TimeDelta wait_time) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ int sequence_number = GetNextAvailableSequenceNumber(requester);
+
+ base::Closure callback =
+ base::Bind(
+ &HistogramSynchronizer::ForceHistogramSynchronizationDoneCallback,
+ this,
+ sequence_number);
+
+ HistogramRequestContext::Register(callback, sequence_number);
+
+ // Get histogram data from renderer and browser child processes.
+ content::HistogramController::GetInstance()->GetHistogramData(
+ sequence_number);
+
// Post a task that would be called after waiting for wait_time. This acts
- // as a watchdog, to ensure that a non-responsive renderer won't block us from
- // making the callback.
+ // as a watchdog, to cancel the requests for non-responsive processes.
BrowserThread::PostDelayedTask(
BrowserThread::UI, FROM_HERE,
- base::Bind(
- &HistogramSynchronizer::ForceHistogramSynchronizationDoneCallback,
- current_synchronizer,
- sequence_number),
+ base::Bind(&HistogramRequestContext::Unregister, sequence_number),
wait_time);
}
-// static
-void HistogramSynchronizer::DeserializeHistogramList(
- int sequence_number,
- const std::vector<std::string>& histograms) {
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- for (std::vector<std::string>::const_iterator it = histograms.begin();
- it < histograms.end();
- ++it) {
- base::Histogram::DeserializeHistogramInfo(*it);
- }
+void HistogramSynchronizer::OnPendingProcesses(int sequence_number,
+ int pending_processes,
+ bool end) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- HistogramSynchronizer* current_synchronizer = CurrentSynchronizer();
- if (current_synchronizer == NULL)
+ HistogramRequestContext* request =
+ HistogramRequestContext::GetHistogramRequestContext(sequence_number);
+ if (!request)
return;
+ request->AddProcessesPending(pending_processes);
+ request->SetReceivedProcessGroupCount(end);
+ request->DeleteIfAllDone();
+}
- // Record that we have received a histogram from renderer process.
- current_synchronizer->DecrementPendingRenderers(sequence_number);
+void HistogramSynchronizer::OnHistogramDataCollected(
+ int sequence_number,
+ const std::vector<std::string>& histogram_data,
+ content::ProcessType process_type) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DecrementPendingProcessesAndSendData(sequence_number, histogram_data);
}
-int HistogramSynchronizer::NotifyAllRenderers(
- RendererHistogramRequester requester) {
- // To iterate over RenderProcessHosts, or to send messages to the hosts, we
- // need to be on the UI thread.
+void HistogramSynchronizer::DecrementPendingProcessesAndSendData(
+ int sequence_number,
+ const std::vector<std::string>& histograms) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- int notification_count = 0;
- for (content::RenderProcessHost::iterator it(
- content::RenderProcessHost::AllHostsIterator());
- !it.IsAtEnd(); it.Advance())
- ++notification_count;
+ HistogramRequestContext* request =
+ HistogramRequestContext::GetHistogramRequestContext(sequence_number);
- int sequence_number = GetNextAvailableSequenceNumber(requester,
- notification_count);
- for (content::RenderProcessHost::iterator it(
- content::RenderProcessHost::AllHostsIterator());
- !it.IsAtEnd(); it.Advance()) {
- if (!it.GetCurrentValue()->Send(
- new ChromeViewMsg_GetRendererHistograms(sequence_number)))
- DecrementPendingRenderers(sequence_number);
+ for (std::vector<std::string>::const_iterator it = histograms.begin();
+ it < histograms.end();
+ ++it) {
+ base::Histogram::DeserializeHistogramInfo(*it);
}
- return sequence_number;
-}
+ if (!request)
+ return;
-void HistogramSynchronizer::DecrementPendingRenderers(int sequence_number) {
- bool synchronous_completed = false;
- bool asynchronous_completed = false;
-
- {
- base::AutoLock auto_lock(lock_);
- if (sequence_number == async_sequence_number_) {
- if (--async_renderers_pending_ <= 0)
- asynchronous_completed = true;
- } else if (sequence_number == synchronous_sequence_number_) {
- if (--synchronous_renderers_pending_ <= 0)
- synchronous_completed = true;
- }
- }
-
- if (asynchronous_completed)
- ForceHistogramSynchronizationDoneCallback(sequence_number);
- else if (synchronous_completed)
- received_all_renderer_histograms_.Signal();
+ // Delete request if we have heard back from all child processes.
+ request->DecrementProcessesPending();
+ request->DeleteIfAllDone();
}
void HistogramSynchronizer::SetCallbackTaskAndThread(
@@ -180,32 +285,23 @@
const base::Closure& callback) {
base::Closure old_callback;
MessageLoop* old_thread = NULL;
- TimeTicks old_start_time;
- int unresponsive_renderers;
- const TimeTicks now = TimeTicks::Now();
{
base::AutoLock auto_lock(lock_);
old_callback = callback_;
callback_ = callback;
old_thread = callback_thread_;
callback_thread_ = callback_thread;
- unresponsive_renderers = async_renderers_pending_;
- old_start_time = async_callback_start_time_;
- async_callback_start_time_ = now;
// Prevent premature calling of our new callbacks.
async_sequence_number_ = kNeverUsableSequenceNumber;
}
// Just in case there was a task pending....
- InternalPostTask(old_thread, old_callback, unresponsive_renderers,
- old_start_time);
+ InternalPostTask(old_thread, old_callback);
}
void HistogramSynchronizer::ForceHistogramSynchronizationDoneCallback(
int sequence_number) {
base::Closure callback;
MessageLoop* thread = NULL;
- TimeTicks started;
- int unresponsive_renderers;
{
base::AutoLock lock(lock_);
if (sequence_number != async_sequence_number_)
@@ -214,31 +310,19 @@
thread = callback_thread_;
callback_.Reset();
callback_thread_ = NULL;
- started = async_callback_start_time_;
- unresponsive_renderers = async_renderers_pending_;
}
- InternalPostTask(thread, callback, unresponsive_renderers, started);
+ InternalPostTask(thread, callback);
}
void HistogramSynchronizer::InternalPostTask(MessageLoop* thread,
- const base::Closure& callback,
- int unresponsive_renderers,
- const base::TimeTicks& started) {
+ const base::Closure& callback) {
if (callback.is_null() || !thread)
return;
- UMA_HISTOGRAM_COUNTS("Histogram.RendersNotRespondingAsynchronous",
- unresponsive_renderers);
- if (!unresponsive_renderers) {
- UMA_HISTOGRAM_TIMES("Histogram.FetchRendererHistogramsAsynchronously",
- TimeTicks::Now() - started);
- }
-
thread->PostTask(FROM_HERE, callback);
}
int HistogramSynchronizer::GetNextAvailableSequenceNumber(
- RendererHistogramRequester requester,
- int renderer_count) {
+ ProcessHistogramRequester requester) {
base::AutoLock auto_lock(lock_);
++last_used_sequence_number_;
// Watch out for wrapping to a negative number.
@@ -250,15 +334,14 @@
}
DCHECK_NE(last_used_sequence_number_,
chrome::kHistogramSynchronizerReservedSequenceNumber);
- if (requester == ASYNC_HISTOGRAMS) {
+ if (requester == ASYNC_HISTOGRAMS)
async_sequence_number_ = last_used_sequence_number_;
- async_renderers_pending_ = renderer_count;
- } else if (requester == SYNCHRONOUS_HISTOGRAMS) {
- synchronous_sequence_number_ = last_used_sequence_number_;
- synchronous_renderers_pending_ = renderer_count;
- }
return last_used_sequence_number_;
}
// static
-HistogramSynchronizer* HistogramSynchronizer::histogram_synchronizer_ = NULL;
+HistogramSynchronizer* HistogramSynchronizer::g_histogram_synchronizer = NULL;
+
+// static
+base::LazyInstance<HistogramRequestContext::HistogramRequestContextMap>::Leaky
+ HistogramRequestContext::outstanding_requests_ = LAZY_INSTANCE_INITIALIZER;

Powered by Google App Engine
This is Rietveld 408576698