diff options
author | rtenneti@google.com <rtenneti@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-07-12 18:19:45 +0000 |
---|---|---|
committer | rtenneti@google.com <rtenneti@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-07-12 18:19:45 +0000 |
commit | 83ab4a28583780761ec6e3cddd4418c2c16c049c (patch) | |
tree | 7c0ae2b3048546848331bb46ec14f493954eb8fc | |
parent | 447a5b6333539c309e015ee8f98ff6d9e131fa85 (diff) | |
download | chromium_src-83ab4a28583780761ec6e3cddd4418c2c16c049c.zip chromium_src-83ab4a28583780761ec6e3cddd4418c2c16c049c.tar.gz chromium_src-83ab4a28583780761ec6e3cddd4418c2c16c049c.tar.bz2 |
Histograms - Support histograms for Plugins, GPU
and all child processes. Renderer processes also
use this new method to send histograms to browser.
This code is similar to the code that gets profiler
data from all processes.
R=jar@chromium.org,jam@chromium.org
TEST=browser unit tests, interactive UI tests
BUG=114013
Review URL: https://chromiumcodereview.appspot.com/10454086
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@146394 0039d316-1c4b-4281-b951-d872f2087c98
61 files changed, 1330 insertions, 798 deletions
diff --git a/base/base.gypi b/base/base.gypi index b605ae5..cfc904c 100644 --- a/base/base.gypi +++ b/base/base.gypi @@ -235,6 +235,9 @@ 'message_pump_win.h', 'metrics/histogram.cc', 'metrics/histogram.h', + 'metrics/histogram_flattener.h', + 'metrics/histogram_snapshot_manager.cc', + 'metrics/histogram_snapshot_manager.h', 'metrics/stats_counters.cc', 'metrics/stats_counters.h', 'metrics/stats_table.cc', diff --git a/base/metrics/histogram_flattener.h b/base/metrics/histogram_flattener.h new file mode 100644 index 0000000..edb1511 --- /dev/null +++ b/base/metrics/histogram_flattener.h @@ -0,0 +1,40 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_METRICS_HISTOGRAM_FLATTENER_H_ +#define BASE_METRICS_HISTOGRAM_FLATTENER_H_ + +#include <map> +#include <string> + +#include "base/basictypes.h" +#include "base/memory/scoped_ptr.h" +#include "base/metrics/histogram.h" + +namespace base { + +// HistogramFlattener is an interface for the logistics of gathering up +// available histograms for recording. The implementors handle the exact lower +// level recording mechanism, or error report mechanism. +class BASE_EXPORT HistogramFlattener { + public: + virtual void RecordDelta(const base::Histogram& histogram, + const base::Histogram::SampleSet& snapshot) = 0; + + // Record various errors found during attempts to record histograms. + virtual void InconsistencyDetected(int problem) = 0; + virtual void UniqueInconsistencyDetected(int problem) = 0; + virtual void SnapshotProblemResolved(int amount) = 0; + + protected: + HistogramFlattener() {} + virtual ~HistogramFlattener() {} + + private: + DISALLOW_COPY_AND_ASSIGN(HistogramFlattener); +}; + +} // namespace base + +#endif // BASE_METRICS_HISTOGRAM_FLATTENER_H_ diff --git a/chrome/common/metrics/histogram_sender.cc b/base/metrics/histogram_snapshot_manager.cc index dfb513a..b325f73 100644 --- a/chrome/common/metrics/histogram_sender.cc +++ b/base/metrics/histogram_snapshot_manager.cc @@ -2,31 +2,39 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/common/metrics/histogram_sender.h" +#include "base/metrics/histogram_snapshot_manager.h" using base::Histogram; using base::StatisticsRecorder; -HistogramSender::HistogramSender() {} +namespace base { -HistogramSender::~HistogramSender() {} +HistogramSnapshotManager::HistogramSnapshotManager( + HistogramFlattener* histogram_flattener) + : histogram_flattener_(histogram_flattener) { + DCHECK(histogram_flattener_); +} + +HistogramSnapshotManager::~HistogramSnapshotManager() {} -void HistogramSender::TransmitAllHistograms(Histogram::Flags flag_to_set, - bool send_only_uma) { +void HistogramSnapshotManager::PrepareDeltas(Histogram::Flags flag_to_set, + bool record_only_uma) { StatisticsRecorder::Histograms histograms; StatisticsRecorder::GetHistograms(&histograms); for (StatisticsRecorder::Histograms::const_iterator it = histograms.begin(); histograms.end() != it; ++it) { (*it)->SetFlags(flag_to_set); - if (send_only_uma && + if (record_only_uma && 0 == ((*it)->flags() & Histogram::kUmaTargetedHistogramFlag)) continue; - TransmitHistogram(**it); + PrepareDelta(**it); } } -void HistogramSender::TransmitHistogram(const Histogram& histogram) { +void HistogramSnapshotManager::PrepareDelta(const Histogram& histogram) { + DCHECK(histogram_flattener_); + // Get up-to-date snapshot of sample stats. Histogram::SampleSet snapshot; histogram.SnapshotSample(&snapshot); @@ -47,20 +55,20 @@ void HistogramSender::TransmitHistogram(const Histogram& histogram) { if (corruption) { NOTREACHED(); - InconsistencyDetected(corruption); - // Don't send corrupt data to metrics survices. + histogram_flattener_->InconsistencyDetected(corruption); + // Don't record corrupt data to metrics survices. if (NULL == inconsistencies_.get()) inconsistencies_.reset(new ProblemMap); int old_corruption = (*inconsistencies_)[histogram_name]; if (old_corruption == (corruption | old_corruption)) return; // We've already seen this corruption for this histogram. (*inconsistencies_)[histogram_name] |= corruption; - UniqueInconsistencyDetected(corruption); + histogram_flattener_->UniqueInconsistencyDetected(corruption); return; } - // Find the already sent stats, or create an empty set. Remove from our - // snapshot anything that we've already sent. + // Find the already recorded stats, or create an empty set. Remove from our + // snapshot anything that we've already recorded. LoggedSampleMap::iterator it = logged_samples_.find(histogram_name); Histogram::SampleSet* already_logged; if (logged_samples_.end() == it) { @@ -70,14 +78,14 @@ void HistogramSender::TransmitHistogram(const Histogram& histogram) { } else { already_logged = &(it->second); int64 discrepancy(already_logged->TotalCount() - - already_logged->redundant_count()); + already_logged->redundant_count()); if (discrepancy) { NOTREACHED(); // Already_logged has become corrupt. int problem = static_cast<int>(discrepancy); if (problem != discrepancy) problem = INT_MAX; - SnapshotProblemResolved(problem); - // With no valid baseline, we'll act like we've sent everything in our + histogram_flattener_->SnapshotProblemResolved(problem); + // With no valid baseline, we'll act like we've recorded everything in our // snapshot. already_logged->Subtract(*already_logged); already_logged->Add(snapshot); @@ -88,8 +96,9 @@ void HistogramSender::TransmitHistogram(const Histogram& histogram) { // Snapshot now contains only a delta to what we've already_logged. if (snapshot.redundant_count() > 0) { - TransmitHistogramDelta(histogram, snapshot); + histogram_flattener_->RecordDelta(histogram, snapshot); // Add new data into our running total. already_logged->Add(snapshot); } } +} // namespace base diff --git a/base/metrics/histogram_snapshot_manager.h b/base/metrics/histogram_snapshot_manager.h new file mode 100644 index 0000000..a945ac7 --- /dev/null +++ b/base/metrics/histogram_snapshot_manager.h @@ -0,0 +1,60 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_METRICS_HISTOGRAM_SNAPSHOT_MANAGER_H_ +#define BASE_METRICS_HISTOGRAM_SNAPSHOT_MANAGER_H_ + +#include <map> +#include <string> + +#include "base/basictypes.h" +#include "base/memory/scoped_ptr.h" +#include "base/metrics/histogram.h" +#include "base/metrics/histogram_flattener.h" + +namespace base { + +// HistogramSnapshotManager handles the logistics of gathering up available +// histograms for recording either to disk or for transmission (such as from +// renderer to browser, or from browser to UMA upload). Since histograms can sit +// in memory for an extended period of time, and are vulnerable to memory +// corruption, this class also validates as much rendundancy as it can before +// calling for the marginal change (a.k.a., delta) in a histogram to be +// recorded. +class BASE_EXPORT HistogramSnapshotManager { + public: + explicit HistogramSnapshotManager(HistogramFlattener* histogram_flattener); + virtual ~HistogramSnapshotManager(); + + // Snapshot all histograms, and ask |histogram_flattener_| to record the + // delta. The arguments allow selecting only a subset of histograms for + // recording, or to set a flag in each recorded histogram. + void PrepareDeltas(base::Histogram::Flags flags_to_set, bool record_only_uma); + + private: + // Maintain a map of histogram names to the sample stats we've recorded. + typedef std::map<std::string, base::Histogram::SampleSet> LoggedSampleMap; + // List of histograms names, and their encontered corruptions. + typedef std::map<std::string, int> ProblemMap; + + // Snapshot this histogram, and record the delta. + void PrepareDelta(const base::Histogram& histogram); + + // For histograms, track what we've already recorded (as a sample for + // each histogram) so that we can record only the delta with the next log. + LoggedSampleMap logged_samples_; + + // List of histograms found corrupt to be corrupt, and their problems. + scoped_ptr<ProblemMap> inconsistencies_; + + // |histogram_flattener_| handles the logistics of recording the histogram + // deltas. + HistogramFlattener* histogram_flattener_; // Weak. + + DISALLOW_COPY_AND_ASSIGN(HistogramSnapshotManager); +}; + +} // namespace base + +#endif // BASE_METRICS_HISTOGRAM_SNAPSHOT_MANAGER_H_ diff --git a/chrome/browser/browser_about_handler.cc b/chrome/browser/browser_about_handler.cc index e371c06..40d5bae 100644 --- a/chrome/browser/browser_about_handler.cc +++ b/chrome/browser/browser_about_handler.cc @@ -33,7 +33,6 @@ const char* const kChromePaths[] = { chrome::kChromeUIFlagsHost, chrome::kChromeUIFlashHost, chrome::kChromeUIGpuInternalsHost, - chrome::kChromeUIHistogramsHost, chrome::kChromeUIHistoryHost, chrome::kChromeUIIPCHost, chrome::kChromeUIInspectHost, diff --git a/chrome/browser/chrome_browser_main.cc b/chrome/browser/chrome_browser_main.cc index 37fb0c0..c984994 100644 --- a/chrome/browser/chrome_browser_main.cc +++ b/chrome/browser/chrome_browser_main.cc @@ -52,7 +52,6 @@ #include "chrome/browser/language_usage_metrics.h" #include "chrome/browser/managed_mode.h" #include "chrome/browser/metrics/field_trial_synchronizer.h" -#include "chrome/browser/metrics/histogram_synchronizer.h" #include "chrome/browser/metrics/metrics_log.h" #include "chrome/browser/metrics/metrics_service.h" #include "chrome/browser/metrics/thread_watcher.h" @@ -1402,11 +1401,7 @@ int ChromeBrowserMainParts::PreCreateThreadsImpl() { InitializeNetworkOptions(parsed_command_line()); - // Initialize histogram synchronizer system. This is a singleton and is used - // for posting tasks via base::Bind. Its deleted when it goes out of scope. - // Even though base::Bind does AddRef and Release, the object will not - // be deleted after the Task is executed. - histogram_synchronizer_ = new HistogramSynchronizer(); + // Initialize tracking synchronizer system. tracking_synchronizer_ = new chrome_browser_metrics::TrackingSynchronizer(); // Now that all preferences have been registered, set the install date diff --git a/chrome/browser/chrome_browser_main.h b/chrome/browser/chrome_browser_main.h index ab96517..00c05d0 100644 --- a/chrome/browser/chrome_browser_main.h +++ b/chrome/browser/chrome_browser_main.h @@ -21,7 +21,6 @@ class BrowserProcessImpl; class ChromeBrowserMainExtraParts; class FieldTrialSynchronizer; -class HistogramSynchronizer; class MetricsService; class PrefService; class Profile; @@ -195,7 +194,6 @@ class ChromeBrowserMainParts : public content::BrowserMainParts { scoped_ptr<StartupBrowserCreator> browser_creator_; scoped_ptr<BrowserProcessImpl> browser_process_; - scoped_refptr<HistogramSynchronizer> histogram_synchronizer_; scoped_refptr<chrome_browser_metrics::TrackingSynchronizer> tracking_synchronizer_; scoped_ptr<ProcessSingleton> process_singleton_; diff --git a/chrome/browser/metrics/histogram_synchronizer.cc b/chrome/browser/metrics/histogram_synchronizer.cc deleted file mode 100644 index a5e2047..0000000 --- a/chrome/browser/metrics/histogram_synchronizer.cc +++ /dev/null @@ -1,264 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/metrics/histogram_synchronizer.h" - -#include "base/bind.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" - -using base::Time; -using base::TimeDelta; -using base::TimeTicks; -using content::BrowserThread; - -// 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. -// We have code that handles wrapping around on an overflow into negative -// territory. -static const int kNeverUsableSequenceNumber = -2; - -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; -} - -HistogramSynchronizer::~HistogramSynchronizer() { - // Just in case we have any pending tasks, clear them out. - SetCallbackTaskAndThread(NULL, base::Closure()); - histogram_synchronizer_ = NULL; -} - -// static -HistogramSynchronizer* HistogramSynchronizer::CurrentSynchronizer() { - DCHECK(histogram_synchronizer_ != NULL); - return histogram_synchronizer_; -} - -void HistogramSynchronizer::FetchRendererHistogramsSynchronously( - 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); -} - -// static -void HistogramSynchronizer::FetchRendererHistogramsAsynchronously( - MessageLoop* callback_thread, - const base::Closure& callback, - base::TimeDelta wait_time) { - DCHECK(callback_thread != NULL); - DCHECK(!callback.is_null()); - - HistogramSynchronizer* current_synchronizer = CurrentSynchronizer(); - - if (current_synchronizer == NULL) { - // System teardown is happening. - callback_thread->PostTask(FROM_HERE, callback); - return; - } - - current_synchronizer->SetCallbackTaskAndThread(callback_thread, - callback); - - int sequence_number = - current_synchronizer->NotifyAllRenderers(ASYNC_HISTOGRAMS); - - // 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. - BrowserThread::PostDelayedTask( - BrowserThread::UI, FROM_HERE, - base::Bind( - &HistogramSynchronizer::ForceHistogramSynchronizationDoneCallback, - current_synchronizer, - 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); - } - - HistogramSynchronizer* current_synchronizer = CurrentSynchronizer(); - if (current_synchronizer == NULL) - return; - - // Record that we have received a histogram from renderer process. - current_synchronizer->DecrementPendingRenderers(sequence_number); -} - -int HistogramSynchronizer::NotifyAllRenderers( - RendererHistogramRequester requester) { - // To iterate over RenderProcessHosts, or to send messages to the hosts, we - // need to be on the UI thread. - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - - int notification_count = 0; - for (content::RenderProcessHost::iterator it( - content::RenderProcessHost::AllHostsIterator()); - !it.IsAtEnd(); it.Advance()) - ++notification_count; - - 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); - } - - return sequence_number; -} - -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(); -} - -void HistogramSynchronizer::SetCallbackTaskAndThread( - MessageLoop* callback_thread, - 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); -} - -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_) - return; - callback = callback_; - thread = callback_thread_; - callback_.Reset(); - callback_thread_ = NULL; - started = async_callback_start_time_; - unresponsive_renderers = async_renderers_pending_; - } - InternalPostTask(thread, callback, unresponsive_renderers, started); -} - -void HistogramSynchronizer::InternalPostTask(MessageLoop* thread, - const base::Closure& callback, - int unresponsive_renderers, - const base::TimeTicks& started) { - 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) { - base::AutoLock auto_lock(lock_); - ++last_used_sequence_number_; - // Watch out for wrapping to a negative number. - if (last_used_sequence_number_ < 0) { - // Bypass the reserved number, which is used when a renderer spontaneously - // decides to send some histogram data. - last_used_sequence_number_ = - chrome::kHistogramSynchronizerReservedSequenceNumber + 1; - } - DCHECK_NE(last_used_sequence_number_, - chrome::kHistogramSynchronizerReservedSequenceNumber); - 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; diff --git a/chrome/browser/metrics/histogram_synchronizer.h b/chrome/browser/metrics/histogram_synchronizer.h deleted file mode 100644 index 8bcf641..0000000 --- a/chrome/browser/metrics/histogram_synchronizer.h +++ /dev/null @@ -1,180 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_METRICS_HISTOGRAM_SYNCHRONIZER_H_ -#define CHROME_BROWSER_METRICS_HISTOGRAM_SYNCHRONIZER_H_ - -#include <string> -#include <vector> - -#include "base/basictypes.h" -#include "base/callback.h" -#include "base/memory/ref_counted.h" -#include "base/synchronization/condition_variable.h" -#include "base/synchronization/lock.h" -#include "base/time.h" - -class MessageLoop; - -// This class maintains state that is used to upload histogram data from the -// various renderer processes, into the browser process. Such transactions are -// usually instigated by the browser. In general, a renderer process will -// respond by gathering snapshots of all internal histograms, calculating what -// has changed since its last upload, and transmitting a pickled collection of -// deltas. -// -// There are actually two modes of update request. One is synchronous (and -// blocks the UI thread, waiting to populate an about:histograms tab) and the -// other is asynchronous, and used by the metrics services in preparation for a -// log upload. -// -// To assure that all the renderers have responded, a counter is maintained (for -// each mode) to indicate the number of pending (not yet responsive) renderers. -// To avoid confusion about a response (i.e., is the renderer responding to a -// current request for an update, or to an old request for an update) we tag -// each group of requests with a sequence number. When an update arrives we can -// ignore it (relative to the counter) if it does not relate to a current -// outstanding sequence number. -// -// There is one final mode of use, where a renderer spontaneously decides to -// transmit a collection of histogram data. This is designed for use when the -// renderer is terminating. Unfortunately, renders may be terminated without -// warning, and the best we can do is periodically acquire data from a tab, such -// as when a page load has completed. In this mode, the renderer uses a -// reserved sequence number, different from any sequence number that might be -// specified by a browser request. Since this sequence number can't match an -// outstanding sequence number, the pickled data is accepted into the browser, -// but there is no impact on the counters. - -class HistogramSynchronizer : public - base::RefCountedThreadSafe<HistogramSynchronizer> { - public: - - enum RendererHistogramRequester { - ASYNC_HISTOGRAMS, - SYNCHRONOUS_HISTOGRAMS - }; - - // 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. - HistogramSynchronizer(); - - // Return pointer to the singleton instance, which is allocated and - // deallocated on the main UI thread (during system startup and teardown). - static HistogramSynchronizer* CurrentSynchronizer(); - - // Contact all renderers, and get them to upload to the browser any/all - // changes to histograms. Return when all changes have been acquired, or when - // the wait time expires (whichever is sooner). This method is called on the - // main UI thread from about:histograms. - void FetchRendererHistogramsSynchronously(base::TimeDelta wait_time); - - // Contact all renderers, and get them to upload to the browser any/all - // changes to histograms. When all changes have been acquired, or when the - // wait time expires (whichever is sooner), post the callback to the - // specified message loop. Note the callback is posted exactly once. - static void FetchRendererHistogramsAsynchronously( - MessageLoop* callback_thread, - const base::Closure& callback, - base::TimeDelta wait_time); - - // This method is called on the IO thread. Deserializes the histograms and - // records that we have received histograms from a renderer process. - static void DeserializeHistogramList( - int sequence_number, const std::vector<std::string>& histograms); - - private: - friend class base::RefCountedThreadSafe<HistogramSynchronizer>; - - ~HistogramSynchronizer(); - - // Establish a new sequence_number_, and use it to notify all the renderers of - // the need to supply, to the browser, any changes in their histograms. - // The argument indicates whether this will set async_sequence_number_ or - // synchronous_sequence_number_. - // Return the sequence number that was used. - int NotifyAllRenderers(RendererHistogramRequester requester); - - // Records that we are waiting for one less histogram from a renderer for the - // given sequence number. If we have received a response from all renderers, - // either signal the waiting process or call the callback function. - void DecrementPendingRenderers(int sequence_number); - - // Set the callback_thread_ and callback_ members. If these members already - // had values, then as a side effect, post the old callback_ to the old - // callaback_thread_. This side effect should not generally happen, but is in - // place to assure correctness (that any tasks that were set, are eventually - // called, and never merely discarded). - void SetCallbackTaskAndThread(MessageLoop* callback_thread, - const base::Closure& callback); - - void ForceHistogramSynchronizationDoneCallback(int sequence_number); - - // Gets a new sequence number to be sent to renderers from browser process and - // set the number of pending responses for the given type to renderer_count. - int GetNextAvailableSequenceNumber(RendererHistogramRequester requster, - int renderer_count); - - // Internal helper function, to post task, and record callback stats. - void InternalPostTask(MessageLoop* thread, - const base::Closure& callback, - int unresponsive_renderers, - const base::TimeTicks& started); - - // This lock_ protects access to all members. - base::Lock lock_; - - // This condition variable is used to block caller of the synchronous request - // to update histograms, and to signal that thread when updates are completed. - base::ConditionVariable received_all_renderer_histograms_; - - // When a request is made to asynchronously update the histograms, we store - // the task and thread we use to post a completion notification in - // callback_ and callback_thread_. - base::Closure callback_; - MessageLoop* callback_thread_; - - // We don't track the actual renderers that are contacted for an update, only - // the count of the number of renderers, and we can sometimes time-out and - // give up on a "slow to respond" renderer. We use a sequence_number to be - // sure a response from a renderer is associated with the current round of - // requests (and not merely a VERY belated prior response). - // All sequence numbers used are non-negative. - // last_used_sequence_number_ is the most recently used number (used to avoid - // reuse for a long time). - int last_used_sequence_number_; - - // The sequence number used by the most recent asynchronous update request to - // contact all renderers. - int async_sequence_number_; - - // The number of renderers that have not yet responded to requests (as part of - // an asynchronous update). - int async_renderers_pending_; - - // The time when we were told to start the fetch histograms asynchronously - // from renderers. - base::TimeTicks async_callback_start_time_; - - // The sequence number used by the most recent synchronous update request to - // contact all renderers. - int synchronous_sequence_number_; - - // The number of renderers that have not yet responded to requests (as part of - // a synchronous update). - int synchronous_renderers_pending_; - - // This singleton instance should be started during the single threaded - // 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 (for UMA uploads), or for about:histograms. - static HistogramSynchronizer* histogram_synchronizer_; - - DISALLOW_COPY_AND_ASSIGN(HistogramSynchronizer); -}; - -#endif // CHROME_BROWSER_METRICS_HISTOGRAM_SYNCHRONIZER_H_ diff --git a/chrome/browser/metrics/metrics_service.cc b/chrome/browser/metrics/metrics_service.cc index 985e512..d2e5a84 100644 --- a/chrome/browser/metrics/metrics_service.cc +++ b/chrome/browser/metrics/metrics_service.cc @@ -167,7 +167,6 @@ #include "chrome/browser/extensions/process_map.h" #include "chrome/browser/io_thread.h" #include "chrome/browser/memory_details.h" -#include "chrome/browser/metrics/histogram_synchronizer.h" #include "chrome/browser/metrics/metrics_log.h" #include "chrome/browser/metrics/metrics_log_serializer.h" #include "chrome/browser/metrics/metrics_reporting_scheduler.h" @@ -188,6 +187,7 @@ #include "chrome/common/pref_names.h" #include "chrome/common/render_messages.h" #include "content/public/browser/child_process_data.h" +#include "content/public/browser/histogram_fetcher.h" #include "content/public/browser/load_notification_details.h" #include "content/public/browser/notification_service.h" #include "content/public/browser/plugin_service.h" @@ -1210,9 +1210,9 @@ void MetricsService::OnMemoryDetailCollectionDone() { base::StatisticsRecorder::CollectHistogramStats("Browser"); // Set up the callback to task to call after we receive histograms from all - // renderer processes. Wait time specifies how long to wait before absolutely + // child processes. Wait time specifies how long to wait before absolutely // calling us back on the task. - HistogramSynchronizer::FetchRendererHistogramsAsynchronously( + content::FetchHistogramsAsynchronously( MessageLoop::current(), callback, base::TimeDelta::FromMilliseconds(kMaxHistogramGatheringWaitDuration)); } diff --git a/chrome/browser/metrics/tracking_synchronizer.cc b/chrome/browser/metrics/tracking_synchronizer.cc index dbfaea0..75d7c0e 100644 --- a/chrome/browser/metrics/tracking_synchronizer.cc +++ b/chrome/browser/metrics/tracking_synchronizer.cc @@ -86,7 +86,6 @@ class TrackingSynchronizer::RequestContext { RequestContext::Unregister(sequence_number_); } - // Register |callback_object| in |outstanding_requests_| map for the given // |sequence_number|. static RequestContext* Register( @@ -116,7 +115,7 @@ class TrackingSynchronizer::RequestContext { return request; } - // Delete the entry for the given sequence_number| from + // 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) { @@ -144,7 +143,6 @@ class TrackingSynchronizer::RequestContext { unresponsive_processes); } - // Delete all the entries in |outstanding_requests_| map. static void OnShutdown() { // Just in case we have any pending tasks, clear them out. @@ -171,13 +169,14 @@ class TrackingSynchronizer::RequestContext { // Map of all outstanding RequestContexts, from sequence_number_ to // RequestContext. - static base::LazyInstance<RequestContextMap> outstanding_requests_; + static base::LazyInstance<RequestContextMap>::Leaky outstanding_requests_; }; // static -base::LazyInstance<TrackingSynchronizer::RequestContext::RequestContextMap> - TrackingSynchronizer::RequestContext::outstanding_requests_ = - LAZY_INSTANCE_INITIALIZER; +base::LazyInstance + <TrackingSynchronizer::RequestContext::RequestContextMap>::Leaky + TrackingSynchronizer::RequestContext::outstanding_requests_ = + LAZY_INSTANCE_INITIALIZER; // TrackingSynchronizer methods and members. diff --git a/chrome/browser/renderer_host/chrome_render_message_filter.cc b/chrome/browser/renderer_host/chrome_render_message_filter.cc index 6ca69d6..321825c 100644 --- a/chrome/browser/renderer_host/chrome_render_message_filter.cc +++ b/chrome/browser/renderer_host/chrome_render_message_filter.cc @@ -19,7 +19,6 @@ #include "chrome/browser/extensions/extension_process_manager.h" #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/extensions/extension_system.h" -#include "chrome/browser/metrics/histogram_synchronizer.h" #include "chrome/browser/nacl_host/nacl_process_host.h" #include "chrome/browser/net/chrome_url_request_context.h" #include "chrome/browser/net/predictor.h" @@ -76,8 +75,6 @@ bool ChromeRenderMessageFilter::OnMessageReceived(const IPC::Message& message, IPC_MESSAGE_HANDLER_DELAY_REPLY(ChromeViewHostMsg_LaunchNaCl, OnLaunchNaCl) #endif IPC_MESSAGE_HANDLER(ChromeViewHostMsg_DnsPrefetch, OnDnsPrefetch) - IPC_MESSAGE_HANDLER(ChromeViewHostMsg_RendererHistograms, - OnRendererHistograms) IPC_MESSAGE_HANDLER(ChromeViewHostMsg_ResourceTypeStats, OnResourceTypeStats) IPC_MESSAGE_HANDLER(ChromeViewHostMsg_UpdatedCacheStats, @@ -180,12 +177,6 @@ void ChromeRenderMessageFilter::OnDnsPrefetch( profile_->GetNetworkPredictor()->DnsPrefetchList(hostnames); } -void ChromeRenderMessageFilter::OnRendererHistograms( - int sequence_number, - const std::vector<std::string>& histograms) { - HistogramSynchronizer::DeserializeHistogramList(sequence_number, histograms); -} - void ChromeRenderMessageFilter::OnResourceTypeStats( const WebCache::ResourceTypeStats& stats) { HISTOGRAM_COUNTS("WebCoreCache.ImagesSizeKB", diff --git a/chrome/browser/renderer_host/chrome_render_message_filter.h b/chrome/browser/renderer_host/chrome_render_message_filter.h index 9440848..71898ad 100644 --- a/chrome/browser/renderer_host/chrome_render_message_filter.h +++ b/chrome/browser/renderer_host/chrome_render_message_filter.h @@ -78,8 +78,6 @@ class ChromeRenderMessageFilter : public content::BrowserMessageFilter { IPC::Message* reply_msg); #endif void OnDnsPrefetch(const std::vector<std::string>& hostnames); - void OnRendererHistograms(int sequence_number, - const std::vector<std::string>& histogram_info); void OnResourceTypeStats(const WebKit::WebCache::ResourceTypeStats& stats); void OnUpdatedCacheStats(const WebKit::WebCache::UsageStats& stats); void OnFPS(int routing_id, float fps); diff --git a/chrome/browser/ui/webui/about_ui.cc b/chrome/browser/ui/webui/about_ui.cc index 856aca4..e441804 100644 --- a/chrome/browser/ui/webui/about_ui.cc +++ b/chrome/browser/ui/webui/about_ui.cc @@ -18,7 +18,6 @@ #include "base/json/json_writer.h" #include "base/memory/ref_counted_memory.h" #include "base/memory/singleton.h" -#include "base/metrics/histogram.h" #include "base/metrics/stats_table.h" #include "base/path_service.h" #include "base/string_number_conversions.h" @@ -33,7 +32,6 @@ #include "chrome/browser/browser_process.h" #include "chrome/browser/defaults.h" #include "chrome/browser/memory_details.h" -#include "chrome/browser/metrics/histogram_synchronizer.h" #include "chrome/browser/net/predictor.h" #include "chrome/browser/net/url_fixer_upper.h" #include "chrome/browser/plugin_prefs.h" @@ -800,34 +798,6 @@ class AboutDnsHandler : public base::RefCountedThreadSafe<AboutDnsHandler> { DISALLOW_COPY_AND_ASSIGN(AboutDnsHandler); }; -std::string AboutHistograms(const std::string& query) { - TimeDelta wait_time = TimeDelta::FromMilliseconds(10000); - -#ifndef NDEBUG - base::StatisticsRecorder::CollectHistogramStats("Browser"); -#endif - - HistogramSynchronizer* current_synchronizer = - HistogramSynchronizer::CurrentSynchronizer(); - DCHECK(current_synchronizer != NULL); - current_synchronizer->FetchRendererHistogramsSynchronously(wait_time); - - std::string unescaped_query; - std::string unescaped_title("About Histograms"); - if (!query.empty()) { - unescaped_query = net::UnescapeURLComponent(query, - net::UnescapeRule::NORMAL); - unescaped_title += " - " + unescaped_query; - } - - std::string data; - AppendHeader(&data, 0, unescaped_title); - AppendBody(&data); - base::StatisticsRecorder::WriteHTMLGraph(unescaped_query, &data); - AppendFooter(&data); - return data; -} - void FinishMemoryDataRequest(const std::string& path, AboutUIHTMLSource* source, int request_id) { @@ -1406,8 +1376,6 @@ void AboutUIHTMLSource::StartDataRequest(const std::string& path, } else if (host == chrome::kChromeUIDNSHost) { AboutDnsHandler::Start(this, request_id); return; - } else if (host == chrome::kChromeUIHistogramsHost) { - response = AboutHistograms(path); #if defined(OS_LINUX) || defined(OS_OPENBSD) } else if (host == chrome::kChromeUILinuxProxyConfigHost) { response = AboutLinuxProxyConfig(); diff --git a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc index 2d4aef0..3876837 100644 --- a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc +++ b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc @@ -329,7 +329,6 @@ WebUIFactoryFunction GetWebUIFactoryFunction(WebUI* web_ui, if (url.host() == chrome::kChromeUIChromeURLsHost || url.host() == chrome::kChromeUICreditsHost || url.host() == chrome::kChromeUIDNSHost || - url.host() == chrome::kChromeUIHistogramsHost || url.host() == chrome::kChromeUIMemoryHost || url.host() == chrome::kChromeUIMemoryRedirectHost || url.host() == chrome::kChromeUIStatsHost || diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index 4e275aa..c350214 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -1410,8 +1410,6 @@ 'browser/memory_purger.h', 'browser/metrics/field_trial_synchronizer.cc', 'browser/metrics/field_trial_synchronizer.h', - 'browser/metrics/histogram_synchronizer.cc', - 'browser/metrics/histogram_synchronizer.h', 'browser/metrics/metric_event_duration_details.h', 'browser/metrics/metrics_log.cc', 'browser/metrics/metrics_log.h', diff --git a/chrome/chrome_common.gypi b/chrome/chrome_common.gypi index 06c2130..ea8fad6 100644 --- a/chrome/chrome_common.gypi +++ b/chrome/chrome_common.gypi @@ -223,8 +223,6 @@ 'common/mac/objc_zombie.mm', 'common/metrics/experiments_helper.cc', 'common/metrics/experiments_helper.h', - 'common/metrics/histogram_sender.cc', - 'common/metrics/histogram_sender.h', 'common/metrics/metrics_log_base.cc', 'common/metrics/metrics_log_base.h', 'common/metrics/metrics_log_manager.cc', diff --git a/chrome/chrome_renderer.gypi b/chrome/chrome_renderer.gypi index e26075d..0236adf6 100644 --- a/chrome/chrome_renderer.gypi +++ b/chrome/chrome_renderer.gypi @@ -227,8 +227,6 @@ 'renderer/print_web_view_helper_linux.cc', 'renderer/print_web_view_helper_mac.mm', 'renderer/print_web_view_helper_win.cc', - 'renderer/renderer_histogram_snapshots.cc', - 'renderer/renderer_histogram_snapshots.h', 'renderer/safe_browsing/feature_extractor_clock.cc', 'renderer/safe_browsing/feature_extractor_clock.h', 'renderer/safe_browsing/features.cc', diff --git a/chrome/common/chrome_constants.cc b/chrome/common/chrome_constants.cc index c089a98..1d4a4e5 100644 --- a/chrome/common/chrome_constants.cc +++ b/chrome/common/chrome_constants.cc @@ -193,8 +193,6 @@ const FilePath::CharType kGDataCacheDirname[] = FPL("GCache"); const bool kRecordModeEnabled = true; -const int kHistogramSynchronizerReservedSequenceNumber = 0; - const char* const kUnknownLanguageCode = "und"; const int kJavascriptMessageExpectedDelay = 1000; diff --git a/chrome/common/chrome_constants.h b/chrome/common/chrome_constants.h index 1009976..12e4733 100644 --- a/chrome/common/chrome_constants.h +++ b/chrome/common/chrome_constants.h @@ -100,13 +100,6 @@ extern const FilePath::CharType kGDataCacheDirname[]; extern const bool kRecordModeEnabled; -// Most sequence numbers are used by a renderer when responding to a browser -// request for histogram data. This reserved number is used when a renderer -// sends an unprovoked update, such as after a page has been loaded. Using -// this reserved constant avoids any chance of confusion with a response having -// a browser-supplied sequence number. -extern const int kHistogramSynchronizerReservedSequenceNumber; - // The language code used when the language of a page could not be detected. // (Matches what the CLD -Compact Language Detection- library reports.) extern const char* const kUnknownLanguageCode; diff --git a/chrome/common/metrics/histogram_sender.h b/chrome/common/metrics/histogram_sender.h deleted file mode 100644 index ab597c6..0000000 --- a/chrome/common/metrics/histogram_sender.h +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_COMMON_METRICS_HISTOGRAM_SENDER_H_ -#define CHROME_COMMON_METRICS_HISTOGRAM_SENDER_H_ - -#include <map> -#include <string> - -#include "base/basictypes.h" -#include "base/memory/scoped_ptr.h" -#include "base/metrics/histogram.h" - -// HistogramSender handles the logistics of gathering up available histograms -// for transmission (such as from renderer to browser, or from browser to UMA -// upload). It has several pure virtual functions that are replaced in -// derived classes to allow the exact lower level transmission mechanism, -// or error report mechanism, to be replaced. Since histograms can sit in -// memory for an extended period of time, and are vulnerable to memory -// corruption, this class also validates as much rendundancy as it can before -// calling for the marginal change (a.k.a., delta) in a histogram to be sent -// onward. -class HistogramSender { - protected: - HistogramSender(); - virtual ~HistogramSender(); - - // Snapshot all histograms, and transmit the delta. - // The arguments allow a derived class to select only a subset for - // transmission, or to set a flag in each transmitted histogram. - void TransmitAllHistograms(base::Histogram::Flags flags_to_set, - bool send_only_uma); - - // Send the histograms onward, as defined in a derived class. - // This is only called with a delta, listing samples that have not previously - // been transmitted. - virtual void TransmitHistogramDelta( - const base::Histogram& histogram, - const base::Histogram::SampleSet& snapshot) = 0; - - // Record various errors found during attempts to send histograms. - virtual void InconsistencyDetected(int problem) = 0; - virtual void UniqueInconsistencyDetected(int problem) = 0; - virtual void SnapshotProblemResolved(int amount) = 0; - - private: - // Maintain a map of histogram names to the sample stats we've sent. - typedef std::map<std::string, base::Histogram::SampleSet> LoggedSampleMap; - // List of histograms names, and their encontered corruptions. - typedef std::map<std::string, int> ProblemMap; - - // Snapshot this histogram, and transmit the delta. - void TransmitHistogram(const base::Histogram& histogram); - - // For histograms, record what we've already transmitted (as a sample for each - // histogram) so that we can send only the delta with the next log. - LoggedSampleMap logged_samples_; - - // List of histograms found corrupt to be corrupt, and their problems. - scoped_ptr<ProblemMap> inconsistencies_; - - DISALLOW_COPY_AND_ASSIGN(HistogramSender); -}; - -#endif // CHROME_COMMON_METRICS_HISTOGRAM_SENDER_H_ diff --git a/chrome/common/metrics/metrics_service_base.cc b/chrome/common/metrics/metrics_service_base.cc index 42f84d7..a491578 100644 --- a/chrome/common/metrics/metrics_service_base.cc +++ b/chrome/common/metrics/metrics_service_base.cc @@ -10,7 +10,8 @@ using base::Histogram; -MetricsServiceBase::MetricsServiceBase() { +MetricsServiceBase::MetricsServiceBase() + : ALLOW_THIS_IN_INITIALIZER_LIST(histogram_snapshot_manager_(this)) { } MetricsServiceBase::~MetricsServiceBase() { @@ -31,10 +32,10 @@ const char MetricsServiceBase::kMimeTypeProto[] = void MetricsServiceBase::RecordCurrentHistograms() { DCHECK(log_manager_.current_log()); - TransmitAllHistograms(base::Histogram::kNoFlags, true); + histogram_snapshot_manager_.PrepareDeltas(base::Histogram::kNoFlags, true); } -void MetricsServiceBase::TransmitHistogramDelta( +void MetricsServiceBase::RecordDelta( const base::Histogram& histogram, const base::Histogram::SampleSet& snapshot) { log_manager_.current_log()->RecordHistogramDelta(histogram, snapshot); diff --git a/chrome/common/metrics/metrics_service_base.h b/chrome/common/metrics/metrics_service_base.h index 23b6a87..16fb6df 100644 --- a/chrome/common/metrics/metrics_service_base.h +++ b/chrome/common/metrics/metrics_service_base.h @@ -7,13 +7,22 @@ #include "base/basictypes.h" #include "base/metrics/histogram.h" -#include "chrome/common/metrics/histogram_sender.h" +#include "base/metrics/histogram_flattener.h" +#include "base/metrics/histogram_snapshot_manager.h" #include "chrome/common/metrics/metrics_log_manager.h" // This class provides base functionality for logging metrics data. // TODO(ananta): Factor out more common code from chrome and chrome frame // metrics service into this class. -class MetricsServiceBase : public HistogramSender { +class MetricsServiceBase : public base::HistogramFlattener { + public: + // HistogramFlattener interface (override) methods. + virtual void RecordDelta(const base::Histogram& histogram, + const base::Histogram::SampleSet& snapshot) OVERRIDE; + virtual void InconsistencyDetected(int problem) OVERRIDE; + virtual void UniqueInconsistencyDetected(int problem) OVERRIDE; + virtual void SnapshotProblemResolved(int amount) OVERRIDE; + protected: MetricsServiceBase(); virtual ~MetricsServiceBase(); @@ -34,13 +43,8 @@ class MetricsServiceBase : public HistogramSender { MetricsLogManager log_manager_; private: - // HistogramSender interface (override) methods. - virtual void TransmitHistogramDelta( - const base::Histogram& histogram, - const base::Histogram::SampleSet& snapshot) OVERRIDE; - virtual void InconsistencyDetected(int problem) OVERRIDE; - virtual void UniqueInconsistencyDetected(int problem) OVERRIDE; - virtual void SnapshotProblemResolved(int amount) OVERRIDE; + // |histogram_snapshot_manager_| prepares histogram deltas for transmission. + base::HistogramSnapshotManager histogram_snapshot_manager_; DISALLOW_COPY_AND_ASSIGN(MetricsServiceBase); }; diff --git a/chrome/common/render_messages.h b/chrome/common/render_messages.h index c4191ca..cea44c4 100644 --- a/chrome/common/render_messages.h +++ b/chrome/common/render_messages.h @@ -238,10 +238,6 @@ IPC_MESSAGE_ROUTED1(ChromeViewMsg_LoadBlockedPlugins, // resource types. IPC_MESSAGE_CONTROL0(ChromeViewMsg_GetCacheResourceStats) -// Asks the renderer to send back Histograms. -IPC_MESSAGE_CONTROL1(ChromeViewMsg_GetRendererHistograms, - int /* sequence number of Renderer Histograms. */) - // Tells the renderer to create a FieldTrial, and by using a 100% probability // for the FieldTrial, forces the FieldTrial to have assigned group name. IPC_MESSAGE_CONTROL2(ChromeViewMsg_SetFieldTrialGroup, diff --git a/chrome/common/url_constants.cc b/chrome/common/url_constants.cc index 425dc83..788e49d 100644 --- a/chrome/common/url_constants.cc +++ b/chrome/common/url_constants.cc @@ -157,7 +157,6 @@ const char kChromeUIGpuInternalsHost[] = "gpu-internals"; const char kChromeUIHangHost[] = "hang"; const char kChromeUIHelpFrameHost[] = "help-frame"; const char kChromeUIHelpHost[] = "help"; -const char kChromeUIHistogramsHost[] = "histograms"; const char kChromeUIHistoryHost[] = "history"; const char kChromeUIHistoryFrameHost[] = "history-frame"; const char kChromeUIInputWindowDialogHost[] = "input-window-dialog"; diff --git a/chrome/common/url_constants.h b/chrome/common/url_constants.h index 50dab9b..a3c7211 100644 --- a/chrome/common/url_constants.h +++ b/chrome/common/url_constants.h @@ -148,7 +148,6 @@ extern const char kChromeUIHelpHost[]; extern const char kChromeUIGpuHost[]; extern const char kChromeUIGpuInternalsHost[]; extern const char kChromeUIHangHost[]; -extern const char kChromeUIHistogramsHost[]; extern const char kChromeUIHistoryHost[]; extern const char kChromeUIHistoryFrameHost[]; extern const char kChromeUIInputWindowDialogHost[]; diff --git a/chrome/renderer/chrome_content_renderer_client.cc b/chrome/renderer/chrome_content_renderer_client.cc index 76f6020..764874a 100644 --- a/chrome/renderer/chrome_content_renderer_client.cc +++ b/chrome/renderer/chrome_content_renderer_client.cc @@ -55,7 +55,6 @@ #include "chrome/renderer/prerender/prerender_webmediaplayer.h" #include "chrome/renderer/prerender/prerenderer_client.h" #include "chrome/renderer/print_web_view_helper.h" -#include "chrome/renderer/renderer_histogram_snapshots.h" #include "chrome/renderer/safe_browsing/malware_dom_details.h" #include "chrome/renderer/safe_browsing/phishing_classifier_delegate.h" #include "chrome/renderer/search_extension.h" @@ -155,7 +154,6 @@ ChromeContentRendererClient::~ChromeContentRendererClient() { void ChromeContentRendererClient::RenderThreadStarted() { chrome_observer_.reset(new ChromeRenderProcessObserver(this)); extension_dispatcher_.reset(new ExtensionDispatcher()); - histogram_snapshots_.reset(new RendererHistogramSnapshots()); net_predictor_.reset(new RendererNetPredictor()); spellcheck_.reset(new SpellCheck()); visited_link_slave_.reset(new VisitedLinkSlave()); @@ -168,7 +166,6 @@ void ChromeContentRendererClient::RenderThreadStarted() { thread->AddObserver(chrome_observer_.get()); thread->AddObserver(extension_dispatcher_.get()); - thread->AddObserver(histogram_snapshots_.get()); #if defined(ENABLE_SAFE_BROWSING) thread->AddObserver(phishing_classifier_.get()); #endif @@ -253,7 +250,7 @@ void ChromeContentRendererClient::RenderViewCreated( chrome_observer_->content_setting_rules()); } new ExtensionHelper(render_view, extension_dispatcher_.get()); - new PageLoadHistograms(render_view, histogram_snapshots_.get()); + new PageLoadHistograms(render_view); #if defined(ENABLE_PRINTING) new PrintWebViewHelper(render_view); #endif diff --git a/chrome/renderer/chrome_content_renderer_client.h b/chrome/renderer/chrome_content_renderer_client.h index c85560a..6c4a28f 100644 --- a/chrome/renderer/chrome_content_renderer_client.h +++ b/chrome/renderer/chrome_content_renderer_client.h @@ -16,7 +16,6 @@ class ChromeRenderProcessObserver; class ExtensionDispatcher; class ExtensionSet; -class RendererHistogramSnapshots; class RendererNetPredictor; class SpellCheck; class SpellCheckProvider; @@ -159,7 +158,6 @@ class ChromeContentRendererClient : public content::ContentRendererClient { scoped_ptr<ChromeRenderProcessObserver> chrome_observer_; scoped_ptr<ExtensionDispatcher> extension_dispatcher_; - scoped_ptr<RendererHistogramSnapshots> histogram_snapshots_; scoped_ptr<RendererNetPredictor> net_predictor_; scoped_ptr<SpellCheck> spellcheck_; scoped_ptr<VisitedLinkSlave> visited_link_slave_; diff --git a/chrome/renderer/page_load_histograms.cc b/chrome/renderer/page_load_histograms.cc index ce8a529..2b7c026 100644 --- a/chrome/renderer/page_load_histograms.cc +++ b/chrome/renderer/page_load_histograms.cc @@ -8,12 +8,12 @@ #include "base/metrics/field_trial.h" #include "base/metrics/histogram.h" #include "base/time.h" -#include "chrome/common/chrome_constants.h" #include "chrome/common/extensions/url_pattern.h" #include "chrome/renderer/chrome_content_renderer_client.h" #include "chrome/renderer/prerender/prerender_helper.h" -#include "chrome/renderer/renderer_histogram_snapshots.h" +#include "content/public/common/content_constants.h" #include "content/public/renderer/document_state.h" +#include "content/public/renderer/render_thread.h" #include "content/public/renderer/render_view.h" #include "googleurl/src/gurl.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h" @@ -118,13 +118,10 @@ enum AbandonType { } // namespace -PageLoadHistograms::PageLoadHistograms( - content::RenderView* render_view, - RendererHistogramSnapshots* histogram_snapshots) +PageLoadHistograms::PageLoadHistograms(content::RenderView* render_view) : content::RenderViewObserver(render_view), cross_origin_access_count_(0), - same_origin_access_count_(0), - histogram_snapshots_(histogram_snapshots) { + same_origin_access_count_(0) { } void PageLoadHistograms::Dump(WebFrame* frame) { @@ -942,8 +939,8 @@ void PageLoadHistograms::Dump(WebFrame* frame) { // TODO(jar) BUG=33233: This needs to be moved to a PostDelayedTask, and it // should post when the onload is complete, so that it doesn't interfere with // the next load. - histogram_snapshots_->SendHistograms( - chrome::kHistogramSynchronizerReservedSequenceNumber); + content::RenderThread::Get()->UpdateHistograms( + content::kHistogramSynchronizerReservedSequenceNumber); } void PageLoadHistograms::ResetCrossFramePropertyAccess() { diff --git a/chrome/renderer/page_load_histograms.h b/chrome/renderer/page_load_histograms.h index ccf3ddb..ac0111e 100644 --- a/chrome/renderer/page_load_histograms.h +++ b/chrome/renderer/page_load_histograms.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -12,12 +12,9 @@ namespace content { class DocumentState; } -class RendererHistogramSnapshots; - class PageLoadHistograms : public content::RenderViewObserver { public: - PageLoadHistograms(content::RenderView* render_view, - RendererHistogramSnapshots* histogram_snapshots); + explicit PageLoadHistograms(content::RenderView* render_view); private: // RenderViewObserver implementation. @@ -55,8 +52,6 @@ class PageLoadHistograms : public content::RenderViewObserver { int cross_origin_access_count_; int same_origin_access_count_; - RendererHistogramSnapshots* histogram_snapshots_; - DISALLOW_COPY_AND_ASSIGN(PageLoadHistograms); }; diff --git a/chrome/renderer/renderer_histogram_snapshots.cc b/chrome/renderer/renderer_histogram_snapshots.cc deleted file mode 100644 index 297d693..0000000 --- a/chrome/renderer/renderer_histogram_snapshots.cc +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/renderer/renderer_histogram_snapshots.h" - -#include <ctype.h> - -#include "base/bind.h" -#include "base/logging.h" -#include "base/message_loop.h" -#include "base/metrics/histogram.h" -#include "chrome/common/render_messages.h" -#include "content/public/renderer/render_thread.h" - -// TODO(raman): Before renderer shuts down send final snapshot lists. - -using base::Histogram; -using base::StatisticsRecorder; -using content::RenderThread; - -RendererHistogramSnapshots::RendererHistogramSnapshots() - : ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) { -} - -RendererHistogramSnapshots::~RendererHistogramSnapshots() { -} - -// Send data quickly! -void RendererHistogramSnapshots::SendHistograms(int sequence_number) { - RenderThread::Get()->GetMessageLoop()->PostTask( - FROM_HERE, base::Bind(&RendererHistogramSnapshots::UploadAllHistrograms, - weak_factory_.GetWeakPtr(), sequence_number)); -} - -bool RendererHistogramSnapshots::OnControlMessageReceived( - const IPC::Message& message) { - bool handled = true; - IPC_BEGIN_MESSAGE_MAP(RendererHistogramSnapshots, message) - IPC_MESSAGE_HANDLER(ChromeViewMsg_GetRendererHistograms, - OnGetRendererHistograms) - IPC_MESSAGE_UNHANDLED(handled = false) - IPC_END_MESSAGE_MAP() - return handled; -} - -void RendererHistogramSnapshots::OnGetRendererHistograms(int sequence_number) { - SendHistograms(sequence_number); -} - -void RendererHistogramSnapshots::UploadAllHistrograms(int sequence_number) { - DCHECK_EQ(0u, pickled_histograms_.size()); - - StatisticsRecorder::CollectHistogramStats("Renderer"); - - // Push snapshots into our pickled_histograms_ vector. - TransmitAllHistograms(Histogram::kIPCSerializationSourceFlag, false); - - // Send the sequence number and list of pickled histograms over synchronous - // IPC, so we can clear pickled_histograms_ afterwards. - RenderThread::Get()->Send(new ChromeViewHostMsg_RendererHistograms( - sequence_number, pickled_histograms_)); - - pickled_histograms_.clear(); -} - -void RendererHistogramSnapshots::TransmitHistogramDelta( - const base::Histogram& histogram, - const base::Histogram::SampleSet& snapshot) { - DCHECK_NE(0, snapshot.TotalCount()); - snapshot.CheckSize(histogram); - - std::string histogram_info = - Histogram::SerializeHistogramInfo(histogram, snapshot); - pickled_histograms_.push_back(histogram_info); -} - -void RendererHistogramSnapshots::InconsistencyDetected(int problem) { - UMA_HISTOGRAM_ENUMERATION("Histogram.InconsistenciesRenderer", - problem, Histogram::NEVER_EXCEEDED_VALUE); -} - -void RendererHistogramSnapshots::UniqueInconsistencyDetected(int problem) { - UMA_HISTOGRAM_ENUMERATION("Histogram.InconsistenciesRendererUnique", - problem, Histogram::NEVER_EXCEEDED_VALUE); -} - -void RendererHistogramSnapshots::SnapshotProblemResolved(int amount) { - UMA_HISTOGRAM_COUNTS("Histogram.InconsistentSnapshotRenderer", - std::abs(amount)); -} - diff --git a/chrome/renderer/renderer_histogram_snapshots.h b/chrome/renderer/renderer_histogram_snapshots.h deleted file mode 100644 index 6da9bc0..0000000 --- a/chrome/renderer/renderer_histogram_snapshots.h +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_RENDERER_RENDERER_HISTOGRAM_SNAPSHOTS_H_ -#define CHROME_RENDERER_RENDERER_HISTOGRAM_SNAPSHOTS_H_ - -#include <map> -#include <string> -#include <vector> - -#include "base/basictypes.h" -#include "base/memory/weak_ptr.h" -#include "base/metrics/histogram.h" -#include "base/process.h" -#include "chrome/common/metrics/histogram_sender.h" -#include "content/public/renderer/render_process_observer.h" - -class RendererHistogramSnapshots : public HistogramSender, - public content::RenderProcessObserver { - public: - RendererHistogramSnapshots(); - virtual ~RendererHistogramSnapshots(); - - // Send the histogram data. - void SendHistograms(int sequence_number); - - private: - // RenderProcessObserver implementation. - virtual bool OnControlMessageReceived(const IPC::Message& message) OVERRIDE; - - void OnGetRendererHistograms(int sequence_number); - - // Maintain a map of histogram names to the sample stats we've sent. - typedef std::map<std::string, base::Histogram::SampleSet> LoggedSampleMap; - typedef std::vector<std::string> HistogramPickledList; - - // Extract snapshot data and then send it off the the Browser process. - // Send only a delta to what we have already sent. - void UploadAllHistrograms(int sequence_number); - - base::WeakPtrFactory<RendererHistogramSnapshots> weak_factory_; - - // HistogramSender interface (override) methods. - virtual void TransmitHistogramDelta( - const base::Histogram& histogram, - const base::Histogram::SampleSet& snapshot) OVERRIDE; - virtual void InconsistencyDetected(int problem) OVERRIDE; - virtual void UniqueInconsistencyDetected(int problem) OVERRIDE; - virtual void SnapshotProblemResolved(int amount) OVERRIDE; - - // Collection of histograms to send to the browser. - HistogramPickledList pickled_histograms_; - - DISALLOW_COPY_AND_ASSIGN(RendererHistogramSnapshots); -}; - -#endif // CHROME_RENDERER_RENDERER_HISTOGRAM_SNAPSHOTS_H_ diff --git a/content/browser/browser_child_process_host_impl.cc b/content/browser/browser_child_process_host_impl.cc index 00076d9..ffceeff 100644 --- a/content/browser/browser_child_process_host_impl.cc +++ b/content/browser/browser_child_process_host_impl.cc @@ -14,6 +14,7 @@ #include "base/process_util.h" #include "base/stl_util.h" #include "base/string_util.h" +#include "content/browser/histogram_message_filter.h" #include "content/browser/profiler_message_filter.h" #include "content/browser/renderer_host/resource_message_filter.h" #include "content/browser/trace_message_filter.h" @@ -85,6 +86,7 @@ BrowserChildProcessHostImpl::BrowserChildProcessHostImpl( child_process_host_.reset(ChildProcessHost::Create(this)); child_process_host_->AddFilter(new TraceMessageFilter); child_process_host_->AddFilter(new content::ProfilerMessageFilter(type)); + child_process_host_->AddFilter(new content::HistogramMessageFilter()); g_child_process_list.Get().push_back(this); content::GetContentClient()->browser()->BrowserChildProcessHostCreated(this); diff --git a/content/browser/histogram_controller.cc b/content/browser/histogram_controller.cc new file mode 100644 index 0000000..086e6ea --- /dev/null +++ b/content/browser/histogram_controller.cc @@ -0,0 +1,112 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/browser/histogram_controller.h" + +#include "base/bind.h" +#include "base/metrics/histogram.h" +#include "content/browser/histogram_subscriber.h" +#include "content/common/child_process_messages.h" +#include "content/public/browser/browser_child_process_host_iterator.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/child_process_data.h" +#include "content/public/browser/render_process_host.h" + +namespace content { + +HistogramController* HistogramController::GetInstance() { + return Singleton<HistogramController>::get(); +} + +HistogramController::HistogramController() : subscriber_(NULL) { +} + +HistogramController::~HistogramController() { +} + +void HistogramController::OnPendingProcesses(int sequence_number, + int pending_processes, + bool end) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + if (subscriber_) + subscriber_->OnPendingProcesses(sequence_number, pending_processes, end); +} + +void HistogramController::OnHistogramDataCollected( + int sequence_number, + const std::vector<std::string>& pickled_histograms) { + if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { + BrowserThread::PostTask( + BrowserThread::UI, FROM_HERE, + base::Bind(&HistogramController::OnHistogramDataCollected, + base::Unretained(this), + sequence_number, + pickled_histograms)); + return; + } + + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + if (subscriber_) { + subscriber_->OnHistogramDataCollected(sequence_number, + pickled_histograms); + } +} + +void HistogramController::Register(HistogramSubscriber* subscriber) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + DCHECK(!subscriber_); + subscriber_ = subscriber; +} + +void HistogramController::Unregister( + const HistogramSubscriber* subscriber) { + DCHECK_EQ(subscriber_, subscriber); + subscriber_ = NULL; +} + +void HistogramController::GetHistogramDataFromChildProcesses( + int sequence_number) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + + int pending_processes = 0; + for (BrowserChildProcessHostIterator iter; !iter.Done(); ++iter) { + ++pending_processes; + if (!iter.Send(new ChildProcessMsg_GetChildHistogramData(sequence_number))) + --pending_processes; + } + + BrowserThread::PostTask( + BrowserThread::UI, + FROM_HERE, + base::Bind( + &HistogramController::OnPendingProcesses, + base::Unretained(this), + sequence_number, + pending_processes, + true)); +} + +void HistogramController::GetHistogramData(int sequence_number) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + + int pending_processes = 0; + for (RenderProcessHost::iterator it(RenderProcessHost::AllHostsIterator()); + !it.IsAtEnd(); it.Advance()) { + ++pending_processes; + if (!it.GetCurrentValue()->Send( + new ChildProcessMsg_GetChildHistogramData(sequence_number))) { + --pending_processes; + } + } + OnPendingProcesses(sequence_number, pending_processes, false); + + BrowserThread::PostTask( + BrowserThread::IO, + FROM_HERE, + base::Bind(&HistogramController::GetHistogramDataFromChildProcesses, + base::Unretained(this), + sequence_number)); +} + +} // namespace content diff --git a/content/browser/histogram_controller.h b/content/browser/histogram_controller.h new file mode 100644 index 0000000..01892e9 --- /dev/null +++ b/content/browser/histogram_controller.h @@ -0,0 +1,70 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_BROWSER_HISTOGRAM_CONTROLLER_H_ +#define CONTENT_BROWSER_HISTOGRAM_CONTROLLER_H_ + +#include <string> +#include <vector> + +#include "base/memory/singleton.h" + +namespace content { + +class HistogramSubscriber; + +// HistogramController is used on the browser process to collect histogram data. +// Only the browser UI thread is allowed to interact with the +// HistogramController object. +class HistogramController { + public: + // Returns the HistogramController object for the current process, or NULL if + // none. + static HistogramController* GetInstance(); + + // Normally instantiated when the child process is launched. Only one instance + // should be created per process. + HistogramController(); + virtual ~HistogramController(); + + // Register the subscriber so that it will be called when for example + // OnHistogramDataCollected is returning histogram data from a child process. + // This is called on UI thread. + void Register(HistogramSubscriber* subscriber); + + // Unregister the subscriber so that it will not be called when for example + // OnHistogramDataCollected is returning histogram data from a child process. + // Safe to call even if caller is not the current subscriber. + void Unregister(const HistogramSubscriber* subscriber); + + // Contact all processes and get their histogram data. + void GetHistogramData(int sequence_number); + + // Notify the |subscriber_| that it should expect at least |pending_processes| + // additional calls to OnHistogramDataCollected(). OnPendingProcess() may be + // called repeatedly; the last call will have |end| set to true, indicating + // that there is no longer a possibility for the count of pending processes to + // increase. This is called on the UI thread. + void OnPendingProcesses(int sequence_number, int pending_processes, bool end); + + // Send the |histogram| back to the |subscriber_|. + // This can be called from any thread. + void OnHistogramDataCollected( + int sequence_number, + const std::vector<std::string>& pickled_histograms); + + private: + friend struct DefaultSingletonTraits<HistogramController>; + + // Contact child processes and get their histogram data. + void GetHistogramDataFromChildProcesses(int sequence_number); + + HistogramSubscriber* subscriber_; + + DISALLOW_COPY_AND_ASSIGN(HistogramController); +}; + +} // namespace content + +#endif // CONTENT_BROWSER_HISTOGRAM_CONTROLLER_H_ diff --git a/content/browser/histogram_internals_request_job.cc b/content/browser/histogram_internals_request_job.cc new file mode 100644 index 0000000..cb3c8fc --- /dev/null +++ b/content/browser/histogram_internals_request_job.cc @@ -0,0 +1,72 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/browser/histogram_internals_request_job.h" + +#include "base/metrics/histogram.h" +#include "content/browser/histogram_synchronizer.h" +#include "googleurl/src/gurl.h" +#include "net/base/escape.h" +#include "net/url_request/url_request.h" + +namespace content { + +HistogramInternalsRequestJob::HistogramInternalsRequestJob( + net::URLRequest* request) : net::URLRequestSimpleJob(request) { + const std::string& spec = request->url().possibly_invalid_spec(); + const url_parse::Parsed& parsed = + request->url().parsed_for_possibly_invalid_spec(); + // + 1 to skip the slash at the beginning of the path. + int offset = parsed.CountCharactersBefore(url_parse::Parsed::PATH, false) + 1; + + if (offset < static_cast<int>(spec.size())) + path_.assign(spec.substr(offset)); +} + +void AboutHistogram(std::string* data, const std::string& path) { +#ifndef NDEBUG + // We only rush the acquisition of Histogram meta-data (meta-histograms) in + // Debug mode, so that developers don't damage our data that we upload to UMA + // (in official builds). + base::StatisticsRecorder::CollectHistogramStats("Browser"); +#endif + content::HistogramSynchronizer::FetchHistograms(); + + std::string unescaped_query; + std::string unescaped_title("About Histograms"); + if (!path.empty()) { + unescaped_query = net::UnescapeURLComponent(path, + net::UnescapeRule::NORMAL); + unescaped_title += " - " + unescaped_query; + } + + data->append("<!DOCTYPE html>\n<html>\n<head>\n"); + data->append( + "<meta http-equiv=\"X-WebKit-CSP\" content=\"object-src 'none'; " + "script-src 'none' 'unsafe-eval'\">"); + data->append("<title>"); + data->append(net::EscapeForHTML(unescaped_title)); + data->append("</title>\n"); + data->append("</head><body>"); + + // Display any stats for which we sent off requests the last time. + data->append("<p>Stats as of last page load;"); + data->append("reload to get stats as of this page load.</p>\n"); + data->append("<table width=\"100%\">\n"); + + base::StatisticsRecorder::WriteHTMLGraph(unescaped_query, data); +} + +bool HistogramInternalsRequestJob::GetData(std::string* mime_type, + std::string* charset, + std::string* data) const { + mime_type->assign("text/html"); + charset->assign("UTF8"); + + data->clear(); + AboutHistogram(data, path_); + return true; +} + +} // namespace content diff --git a/content/browser/histogram_internals_request_job.h b/content/browser/histogram_internals_request_job.h new file mode 100644 index 0000000..0613af3 --- /dev/null +++ b/content/browser/histogram_internals_request_job.h @@ -0,0 +1,34 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_BROWSER_HISTOGRAM_INTERNALS_REQUEST_JOB_H_ +#define CONTENT_BROWSER_HISTOGRAM_INTERNALS_REQUEST_JOB_H_ + +#include <string> + +#include "base/basictypes.h" +#include "net/url_request/url_request_simple_job.h" + +namespace content { + +class HistogramInternalsRequestJob : public net::URLRequestSimpleJob { + public: + explicit HistogramInternalsRequestJob(net::URLRequest* request); + + virtual bool GetData(std::string* mime_type, + std::string* charset, + std::string* data) const OVERRIDE; + + private: + virtual ~HistogramInternalsRequestJob() {} + + // The string to select histograms which have |path_| as a substring. + std::string path_; + + DISALLOW_IMPLICIT_CONSTRUCTORS(HistogramInternalsRequestJob); +}; + +} // namespace content + +#endif // CONTENT_BROWSER_HISTOGRAM_INTERNALS_REQUEST_JOB_H_ diff --git a/content/browser/histogram_message_filter.cc b/content/browser/histogram_message_filter.cc new file mode 100644 index 0000000..959c280 --- /dev/null +++ b/content/browser/histogram_message_filter.cc @@ -0,0 +1,40 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/browser/histogram_message_filter.h" + +#include "base/process_util.h" +#include "content/browser/histogram_controller.h" +#include "content/browser/tcmalloc_internals_request_job.h" +#include "content/common/child_process_messages.h" + +namespace content { + +HistogramMessageFilter::HistogramMessageFilter() { +} + +void HistogramMessageFilter::OnChannelConnected(int32 peer_pid) { + BrowserMessageFilter::OnChannelConnected(peer_pid); +} + +bool HistogramMessageFilter::OnMessageReceived(const IPC::Message& message, + bool* message_was_ok) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP_EX(HistogramMessageFilter, message, *message_was_ok) + IPC_MESSAGE_HANDLER(ChildProcessHostMsg_ChildHistogramData, + OnChildHistogramData) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP_EX() + return handled; +} + +HistogramMessageFilter::~HistogramMessageFilter() {} + +void HistogramMessageFilter::OnChildHistogramData( + int sequence_number, + const std::vector<std::string>& pickled_histograms) { + HistogramController::GetInstance()->OnHistogramDataCollected( + sequence_number, pickled_histograms); +} +} diff --git a/content/browser/histogram_message_filter.h b/content/browser/histogram_message_filter.h new file mode 100644 index 0000000..b8ca89d --- /dev/null +++ b/content/browser/histogram_message_filter.h @@ -0,0 +1,42 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_BROWSER_HISTOGRAM_MESSAGE_FILTER_H_ +#define CONTENT_BROWSER_HISTOGRAM_MESSAGE_FILTER_H_ + +#include <string> +#include <vector> + +#include "content/public/browser/browser_message_filter.h" +#include "content/public/common/process_type.h" + +namespace content { + +// This class sends and receives histogram messages in the browser process. +class HistogramMessageFilter : public BrowserMessageFilter { + public: + HistogramMessageFilter(); + + // content::BrowserMessageFilter implementation. + virtual void OnChannelConnected(int32 peer_pid) OVERRIDE; + + // content::BrowserMessageFilter implementation. + virtual bool OnMessageReceived(const IPC::Message& message, + bool* message_was_ok) OVERRIDE; + + private: + virtual ~HistogramMessageFilter(); + + // Message handlers. + void OnChildHistogramData(int sequence_number, + const std::vector<std::string>& pickled_histograms); + + ProcessType process_type_; + + DISALLOW_COPY_AND_ASSIGN(HistogramMessageFilter); +}; + +} // namespace content + +#endif // CONTENT_BROWSER_HISTOGRAM_MESSAGE_FILTER_H_ diff --git a/content/browser/histogram_subscriber.h b/content/browser/histogram_subscriber.h new file mode 100644 index 0000000..993e4c9 --- /dev/null +++ b/content/browser/histogram_subscriber.h @@ -0,0 +1,33 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_BROWSER_HISTOGRAM_SUBSCRIBER_H_ +#define CONTENT_BROWSER_HISTOGRAM_SUBSCRIBER_H_ + +#include <string> +#include <vector> + +namespace content { + +// Objects interested in receiving histograms derive from HistogramSubscriber. +class HistogramSubscriber { + public: + virtual ~HistogramSubscriber() {} + + // Send number of pending processes to subscriber. |end| is set to true if it + // is the last time. This is called on the UI thread. + virtual void OnPendingProcesses(int sequence_number, + int pending_processes, + bool end) = 0; + + // Send |histogram| back to subscriber. + // This is called on the UI thread. + virtual void OnHistogramDataCollected( + int sequence_number, + const std::vector<std::string>& pickled_histograms) = 0; +}; + +} // namespace content + +#endif // CONTENT_BROWSER_HISTOGRAM_SUBSCRIBER_H_ diff --git a/content/browser/histogram_synchronizer.cc b/content/browser/histogram_synchronizer.cc new file mode 100644 index 0000000..bb90b07 --- /dev/null +++ b/content/browser/histogram_synchronizer.cc @@ -0,0 +1,346 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/browser/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 "content/browser/histogram_controller.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/histogram_fetcher.h" +#include "content/public/common/content_constants.h" + +using base::Time; +using base::TimeDelta; +using base::TimeTicks; + +namespace { + +// 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. +// We have code that handles wrapping around on an overflow into negative +// territory. +static const int kNeverUsableSequenceNumber = -2; + +} // anonymous namespace + +namespace content { + +// The "RequestContext" structure describes an individual request received from +// the UI. All methods are accessible on UI thread. +class HistogramSynchronizer::RequestContext { + public: + // A map from sequence_number_ to the actual RequestContexts. + typedef std::map<int, RequestContext*> RequestContextMap; + + RequestContext(const base::Closure& callback, int sequence_number) + : callback_(callback), + sequence_number_(sequence_number), + received_process_group_count_(0), + processes_pending_(0) { + } + ~RequestContext() {} + + void SetReceivedProcessGroupCount(bool done) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + received_process_group_count_ = done; + } + + // Methods for book keeping of 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 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_) + RequestContext::Unregister(sequence_number_); + } + + // Register |callback| in |outstanding_requests_| map for the given + // |sequence_number|. + static void Register(const base::Closure& callback, int sequence_number) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + + RequestContext* request = new RequestContext(callback, sequence_number); + outstanding_requests_.Get()[sequence_number] = 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 = it->second; + DCHECK_EQ(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_EQ(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 request; + 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()) { + 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_|. + 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 RequestContexts, from sequence_number_ to + // RequestContext. + static base::LazyInstance<RequestContextMap>::Leaky outstanding_requests_; +}; + +// static +base::LazyInstance + <HistogramSynchronizer::RequestContext::RequestContextMap>::Leaky + HistogramSynchronizer::RequestContext::outstanding_requests_ = + LAZY_INSTANCE_INITIALIZER; + +HistogramSynchronizer::HistogramSynchronizer() + : lock_(), + callback_thread_(NULL), + last_used_sequence_number_(kNeverUsableSequenceNumber), + async_sequence_number_(kNeverUsableSequenceNumber) { + content::HistogramController::GetInstance()->Register(this); +} + +HistogramSynchronizer::~HistogramSynchronizer() { + RequestContext::OnShutdown(); + + // Just in case we have any pending tasks, clear them out. + SetCallbackTaskAndThread(NULL, base::Closure()); +} + +HistogramSynchronizer* HistogramSynchronizer::GetInstance() { + return Singleton<HistogramSynchronizer, + LeakySingletonTraits<HistogramSynchronizer> >::get(); +} + +// static +void HistogramSynchronizer::FetchHistograms() { + if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { + BrowserThread::PostTask( + BrowserThread::UI, FROM_HERE, + base::Bind(&HistogramSynchronizer::FetchHistograms)); + return; + } + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + + HistogramSynchronizer* current_synchronizer = + HistogramSynchronizer::GetInstance(); + if (current_synchronizer == NULL) + return; + + current_synchronizer->RegisterAndNotifyAllProcesses( + HistogramSynchronizer::UNKNOWN, + base::TimeDelta::FromMinutes(1)); +} + +void FetchHistogramsAsynchronously(MessageLoop* callback_thread, + const base::Closure& callback, + base::TimeDelta wait_time) { + HistogramSynchronizer::FetchHistogramsAsynchronously( + callback_thread, callback, wait_time); +} + +// static +void HistogramSynchronizer::FetchHistogramsAsynchronously( + MessageLoop* callback_thread, + const base::Closure& callback, + base::TimeDelta wait_time) { + DCHECK(callback_thread != NULL); + DCHECK(!callback.is_null()); + + HistogramSynchronizer* current_synchronizer = + HistogramSynchronizer::GetInstance(); + current_synchronizer->SetCallbackTaskAndThread( + callback_thread, callback); + + current_synchronizer->RegisterAndNotifyAllProcesses( + HistogramSynchronizer::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, + base::Unretained(this), + sequence_number); + + RequestContext::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 cancel the requests for non-responsive processes. + BrowserThread::PostDelayedTask( + BrowserThread::UI, FROM_HERE, + base::Bind(&RequestContext::Unregister, sequence_number), + wait_time); +} + +void HistogramSynchronizer::OnPendingProcesses(int sequence_number, + int pending_processes, + bool end) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + + RequestContext* request = RequestContext::GetRequestContext(sequence_number); + if (!request) + return; + request->AddProcessesPending(pending_processes); + request->SetReceivedProcessGroupCount(end); + request->DeleteIfAllDone(); +} + +void HistogramSynchronizer::OnHistogramDataCollected( + int sequence_number, + const std::vector<std::string>& pickled_histograms) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + + RequestContext* request = RequestContext::GetRequestContext(sequence_number); + + for (std::vector<std::string>::const_iterator it = pickled_histograms.begin(); + it < pickled_histograms.end(); + ++it) { + base::Histogram::DeserializeHistogramInfo(*it); + } + + if (!request) + return; + + // Delete request if we have heard back from all child processes. + request->DecrementProcessesPending(); + request->DeleteIfAllDone(); +} + +void HistogramSynchronizer::SetCallbackTaskAndThread( + MessageLoop* callback_thread, + const base::Closure& callback) { + base::Closure old_callback; + MessageLoop* old_thread = NULL; + { + base::AutoLock auto_lock(lock_); + old_callback = callback_; + callback_ = callback; + old_thread = callback_thread_; + callback_thread_ = callback_thread; + // Prevent premature calling of our new callbacks. + async_sequence_number_ = kNeverUsableSequenceNumber; + } + // Just in case there was a task pending.... + InternalPostTask(old_thread, old_callback); +} + +void HistogramSynchronizer::ForceHistogramSynchronizationDoneCallback( + int sequence_number) { + base::Closure callback; + MessageLoop* thread = NULL; + { + base::AutoLock lock(lock_); + if (sequence_number != async_sequence_number_) + return; + callback = callback_; + thread = callback_thread_; + callback_.Reset(); + callback_thread_ = NULL; + } + InternalPostTask(thread, callback); +} + +void HistogramSynchronizer::InternalPostTask(MessageLoop* thread, + const base::Closure& callback) { + if (callback.is_null() || !thread) + return; + thread->PostTask(FROM_HERE, callback); +} + +int HistogramSynchronizer::GetNextAvailableSequenceNumber( + ProcessHistogramRequester requester) { + base::AutoLock auto_lock(lock_); + ++last_used_sequence_number_; + // Watch out for wrapping to a negative number. + if (last_used_sequence_number_ < 0) { + // Bypass the reserved number, which is used when a renderer spontaneously + // decides to send some histogram data. + last_used_sequence_number_ = + kHistogramSynchronizerReservedSequenceNumber + 1; + } + DCHECK_NE(last_used_sequence_number_, + kHistogramSynchronizerReservedSequenceNumber); + if (requester == ASYNC_HISTOGRAMS) + async_sequence_number_ = last_used_sequence_number_; + return last_used_sequence_number_; +} + +} // namespace content diff --git a/content/browser/histogram_synchronizer.h b/content/browser/histogram_synchronizer.h new file mode 100644 index 0000000..3e68d3c --- /dev/null +++ b/content/browser/histogram_synchronizer.h @@ -0,0 +1,151 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_BROWSER_HISTOGRAM_SYNCHRONIZER_H_ +#define CONTENT_BROWSER_HISTOGRAM_SYNCHRONIZER_H_ + +#include <string> +#include <vector> + +#include "base/basictypes.h" +#include "base/callback.h" +#include "base/memory/singleton.h" +#include "base/synchronization/lock.h" +#include "base/time.h" +#include "content/browser/histogram_subscriber.h" + +class MessageLoop; + +namespace content { + +// This class maintains state that is used to upload histogram data from the +// various child processes, into the browser process. Such transactions are +// usually instigated by the browser. In general, a child process will respond +// by gathering snapshots of all internal histograms, calculating what has +// changed since its last upload, and transmitting a pickled collection of +// deltas. +// +// There are actually two modes of update request. One is synchronous (and +// blocks the UI thread, waiting to populate an about:histograms tab) and the +// other is asynchronous, and used by the metrics services in preparation for a +// log upload. +// +// To assure that all the processes have responded, a counter is maintained to +// indicate the number of pending (not yet responsive) processes. To avoid +// confusion about a response (i.e., is the process responding to a current +// request for an update, or to an old request for an update) we tag each group +// of requests with a sequence number. When an update arrives we can ignore it +// (relative to the counter) if it does not relate to a current outstanding +// sequence number. +// +// There is one final mode of use, where a renderer spontaneously decides to +// transmit a collection of histogram data. This is designed for use when the +// renderer is terminating. Unfortunately, renders may be terminated without +// warning, and the best we can do is periodically acquire data from a tab, such +// as when a page load has completed. In this mode, the renderer uses a +// reserved sequence number, different from any sequence number that might be +// specified by a browser request. Since this sequence number can't match an +// outstanding sequence number, the pickled data is accepted into the browser, +// but there is no impact on the counters. + +class HistogramSynchronizer : public content::HistogramSubscriber { + public: + enum ProcessHistogramRequester { + UNKNOWN, + ASYNC_HISTOGRAMS, + }; + + // Return pointer to the singleton instance for the current process, or NULL + // if none. + static HistogramSynchronizer* GetInstance(); + + // Contact all processes, and get them to upload to the browser any/all + // changes to histograms. This method is called from about:histograms. + static void FetchHistograms(); + + // Contact all child processes, and get them to upload to the browser any/all + // changes to histograms. When all changes have been acquired, or when the + // wait time expires (whichever is sooner), post the callback to the + // specified message loop. Note the callback is posted exactly once. + static void FetchHistogramsAsynchronously(MessageLoop* callback_thread, + const base::Closure& callback, + base::TimeDelta wait_time); + + private: + friend struct DefaultSingletonTraits<HistogramSynchronizer>; + + class RequestContext; + + HistogramSynchronizer(); + virtual ~HistogramSynchronizer(); + + // Establish a new sequence number, and use it to notify all processes + // (renderers, plugins, GPU, etc) of the need to supply, to the browser, + // any/all changes to their histograms. |wait_time| specifies the amount of + // time to wait before cancelling the requests for non-responsive processes. + void RegisterAndNotifyAllProcesses(ProcessHistogramRequester requester, + base::TimeDelta wait_time); + + // ------------------------------------------------------- + // HistogramSubscriber 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 histogram_data back to caller and also record that we are waiting + // for one less histogram data from child process for the given sequence + // number. This method is accessible on UI thread. + virtual void OnHistogramDataCollected( + int sequence_number, + const std::vector<std::string>& pickled_histograms) OVERRIDE; + + // Set the callback_thread_ and callback_ members. If these members already + // had values, then as a side effect, post the old callback_ to the old + // callaback_thread_. This side effect should not generally happen, but is in + // place to assure correctness (that any tasks that were set, are eventually + // called, and never merely discarded). + void SetCallbackTaskAndThread(MessageLoop* callback_thread, + const base::Closure& callback); + + void ForceHistogramSynchronizationDoneCallback(int sequence_number); + + // Internal helper function, to post task, and record callback stats. + void InternalPostTask(MessageLoop* thread, const base::Closure& callback); + + // Gets a new sequence number to be sent to processes from browser process. + int GetNextAvailableSequenceNumber(ProcessHistogramRequester requster); + + // This lock_ protects access to all members. + base::Lock lock_; + + // When a request is made to asynchronously update the histograms, we store + // the task and thread we use to post a completion notification in + // callback_ and callback_thread_. + base::Closure callback_; + MessageLoop* callback_thread_; + + // 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 + // give up on a "slow to respond" process. We use a sequence_number to be + // sure a response from a process is associated with the current round of + // requests (and not merely a VERY belated prior response). + // All sequence numbers used are non-negative. + // last_used_sequence_number_ is the most recently used number (used to avoid + // reuse for a long time). + int last_used_sequence_number_; + + // The sequence number used by the most recent asynchronous update request to + // contact all processes. + int async_sequence_number_; + + DISALLOW_COPY_AND_ASSIGN(HistogramSynchronizer); +}; + +} // namespace content + +#endif // CONTENT_BROWSER_HISTOGRAM_SYNCHRONIZER_H_ diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc index bfea883..1531d1abb 100644 --- a/content/browser/renderer_host/render_process_host_impl.cc +++ b/content/browser/renderer_host/render_process_host_impl.cc @@ -54,6 +54,7 @@ #include "content/browser/geolocation/geolocation_dispatcher_host.h" #include "content/browser/gpu/gpu_data_manager_impl.h" #include "content/browser/gpu/gpu_process_host.h" +#include "content/browser/histogram_message_filter.h" #include "content/browser/in_process_webkit/indexed_db_context_impl.h" #include "content/browser/in_process_webkit/indexed_db_dispatcher_host.h" #include "content/browser/mime_registry_message_filter.h" @@ -603,6 +604,7 @@ void RenderProcessHostImpl::CreateMessageFilters() { GetContentClient()->browser()->CreateQuotaPermissionContext())); channel_->AddFilter(new GamepadBrowserMessageFilter(this)); channel_->AddFilter(new ProfilerMessageFilter(PROCESS_TYPE_RENDERER)); + channel_->AddFilter(new content::HistogramMessageFilter()); } int RenderProcessHostImpl::GetNextRoutingID() { diff --git a/content/browser/resource_context_impl.cc b/content/browser/resource_context_impl.cc index ef9b75d..2a143f1 100644 --- a/content/browser/resource_context_impl.cc +++ b/content/browser/resource_context_impl.cc @@ -8,6 +8,7 @@ #include "content/browser/appcache/chrome_appcache_service.h" #include "content/browser/fileapi/browser_file_system_helper.h" #include "content/browser/fileapi/chrome_blob_storage_context.h" +#include "content/browser/histogram_internals_request_job.h" #include "content/browser/host_zoom_map_impl.h" #include "content/browser/in_process_webkit/indexed_db_context_impl.h" #include "content/browser/net/view_blob_internals_job_factory.h" @@ -119,6 +120,12 @@ class DeveloperProtocolHandler } #endif + // Next check for chrome://histograms/, which uses its own job type. + if (request->url().SchemeIs(chrome::kChromeUIScheme) && + request->url().host() == chrome::kChromeUIHistogramHost) { + return new HistogramInternalsRequestJob(request); + } + return NULL; } diff --git a/content/common/child_histogram_message_filter.cc b/content/common/child_histogram_message_filter.cc new file mode 100644 index 0000000..5cc137c --- /dev/null +++ b/content/common/child_histogram_message_filter.cc @@ -0,0 +1,98 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/common/child_histogram_message_filter.h" + +#include <ctype.h> + +#include "base/bind.h" +#include "base/message_loop.h" +#include "content/common/child_process.h" +#include "content/common/child_process_messages.h" +#include "content/common/child_thread.h" + +namespace content { + +ChildHistogramMessageFilter::ChildHistogramMessageFilter() + : channel_(NULL), + ALLOW_THIS_IN_INITIALIZER_LIST(histogram_snapshot_manager_(this)) { +} + +ChildHistogramMessageFilter::~ChildHistogramMessageFilter() { +} + +void ChildHistogramMessageFilter::OnFilterAdded(IPC::Channel* channel) { + channel_ = channel; +} + +void ChildHistogramMessageFilter::OnFilterRemoved() { +} + +bool ChildHistogramMessageFilter::OnMessageReceived( + const IPC::Message& message) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(ChildHistogramMessageFilter, message) + IPC_MESSAGE_HANDLER(ChildProcessMsg_GetChildHistogramData, + OnGetChildHistogramData) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +void ChildHistogramMessageFilter::SendHistograms(int sequence_number) { + ChildProcess::current()->io_message_loop_proxy()->PostTask( + FROM_HERE, base::Bind(&ChildHistogramMessageFilter::UploadAllHistrograms, + this, sequence_number)); +} + +void ChildHistogramMessageFilter::OnGetChildHistogramData(int sequence_number) { + UploadAllHistrograms(sequence_number); +} + +void ChildHistogramMessageFilter::UploadAllHistrograms(int sequence_number) { + DCHECK_EQ(0u, pickled_histograms_.size()); + + base::StatisticsRecorder::CollectHistogramStats("ChildProcess"); + + // Push snapshots into our pickled_histograms_ vector. + histogram_snapshot_manager_.PrepareDeltas( + base::Histogram::kIPCSerializationSourceFlag, false); + + channel_->Send(new ChildProcessHostMsg_ChildHistogramData( + sequence_number, pickled_histograms_)); + + pickled_histograms_.clear(); + static int count = 0; + count++; + DHISTOGRAM_COUNTS("Histogram.ChildProcessHistogramSentCount", count); +} + +void ChildHistogramMessageFilter::RecordDelta( + const base::Histogram& histogram, + const base::Histogram::SampleSet& snapshot) { + DCHECK_NE(0, snapshot.TotalCount()); + snapshot.CheckSize(histogram); + + std::string histogram_info = + base::Histogram::SerializeHistogramInfo(histogram, snapshot); + + pickled_histograms_.push_back(histogram_info); +} + +void ChildHistogramMessageFilter::InconsistencyDetected(int problem) { + UMA_HISTOGRAM_ENUMERATION("Histogram.InconsistenciesChildProcess", + problem, base::Histogram::NEVER_EXCEEDED_VALUE); +} + +void ChildHistogramMessageFilter::UniqueInconsistencyDetected(int problem) { + UMA_HISTOGRAM_ENUMERATION("Histogram.InconsistenciesChildProcessUnique", + problem, base::Histogram::NEVER_EXCEEDED_VALUE); +} + +void ChildHistogramMessageFilter::SnapshotProblemResolved(int amount) { + UMA_HISTOGRAM_COUNTS("Histogram.InconsistentSnapshotChildProcess", + std::abs(amount)); +} + +} // namespace content diff --git a/content/common/child_histogram_message_filter.h b/content/common/child_histogram_message_filter.h new file mode 100644 index 0000000..ce9a348 --- /dev/null +++ b/content/common/child_histogram_message_filter.h @@ -0,0 +1,65 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_COMMOM_CHILD_HISTOGRAM_MESSAGE_FILTER_H_ +#define CONTENT_COMMOM_CHILD_HISTOGRAM_MESSAGE_FILTER_H_ + +#include <string> +#include <vector> + +#include "base/basictypes.h" +#include "base/metrics/histogram.h" +#include "base/metrics/histogram_flattener.h" +#include "base/metrics/histogram_snapshot_manager.h" +#include "ipc/ipc_channel_proxy.h" + +class MessageLoop; + +namespace content { + +class ChildHistogramMessageFilter : public base::HistogramFlattener, + public IPC::ChannelProxy::MessageFilter { + public: + ChildHistogramMessageFilter(); + + // IPC::ChannelProxy::MessageFilter implementation. + virtual void OnFilterAdded(IPC::Channel* channel) OVERRIDE; + virtual void OnFilterRemoved() OVERRIDE; + virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; + + void SendHistograms(int sequence_number); + + // HistogramFlattener interface (override) methods. + virtual void RecordDelta(const base::Histogram& histogram, + const base::Histogram::SampleSet& snapshot) OVERRIDE; + virtual void InconsistencyDetected(int problem) OVERRIDE; + virtual void UniqueInconsistencyDetected(int problem) OVERRIDE; + virtual void SnapshotProblemResolved(int amount) OVERRIDE; + + private: + typedef std::vector<std::string> HistogramPickledList; + + virtual ~ChildHistogramMessageFilter(); + + // Message handlers. + virtual void OnGetChildHistogramData(int sequence_number); + + // Extract snapshot data and then send it off the the Browser process. + // Send only a delta to what we have already sent. + void UploadAllHistrograms(int sequence_number); + + IPC::Channel* channel_; + + // Collection of histograms to send to the browser. + HistogramPickledList pickled_histograms_; + + // |histogram_snapshot_manager_| prepares histogram deltas for transmission. + base::HistogramSnapshotManager histogram_snapshot_manager_; + + DISALLOW_COPY_AND_ASSIGN(ChildHistogramMessageFilter); +}; + +} // namespace content + +#endif // CONTENT_COMMOM_CHILD_HISTOGRAM_MESSAGE_FILTER_H_ diff --git a/content/common/child_process_messages.h b/content/common/child_process_messages.h index a48067b..1403969 100644 --- a/content/common/child_process_messages.h +++ b/content/common/child_process_messages.h @@ -5,6 +5,9 @@ // Common IPC messages used for child processes. // Multiply-included message file, hence no include guard. +#include <string> +#include <vector> + #include "base/shared_memory.h" #include "base/tracked_objects.h" #include "base/values.h" @@ -87,7 +90,11 @@ IPC_MESSAGE_CONTROL1(ChildProcessMsg_SetProfilerStatus, // Send to all the child processes to send back profiler data (ThreadData in // tracked_objects). IPC_MESSAGE_CONTROL1(ChildProcessMsg_GetChildProfilerData, - int /* sequence number */) + int /* sequence_number */) + +// Send to all the child processes to send back histogram data. +IPC_MESSAGE_CONTROL1(ChildProcessMsg_GetChildHistogramData, + int /* sequence_number */) // Sent to child processes to dump their handle table. IPC_MESSAGE_CONTROL0(ChildProcessMsg_DumpHandles) @@ -122,8 +129,13 @@ IPC_MESSAGE_CONTROL1(ChildProcessHostMsg_TraceBufferPercentFullReply, // Send back profiler data (ThreadData in tracked_objects). IPC_MESSAGE_CONTROL2(ChildProcessHostMsg_ChildProfilerData, - int, /* sequence number */ - tracked_objects::ProcessDataSnapshot /* profiler data */) + int, /* sequence_number */ + tracked_objects::ProcessDataSnapshot /* profiler_data */) + +// Send back histograms as vector of pickled-histogram strings. +IPC_MESSAGE_CONTROL2(ChildProcessHostMsg_ChildHistogramData, + int, /* sequence_number */ + std::vector<std::string> /* histogram_data */) // Reply to ChildProcessMsg_DumpHandles when handle table dump is complete. IPC_MESSAGE_CONTROL0(ChildProcessHostMsg_DumpHandlesDone) diff --git a/content/common/child_thread.cc b/content/common/child_thread.cc index e313345..7dec3ec 100644 --- a/content/common/child_thread.cc +++ b/content/common/child_thread.cc @@ -10,6 +10,7 @@ #include "base/process.h" #include "base/string_util.h" #include "base/tracked_objects.h" +#include "content/common/child_histogram_message_filter.h" #include "content/common/child_process.h" #include "content/common/child_process_messages.h" #include "content/common/child_trace_message_filter.h" @@ -60,6 +61,9 @@ void ChildThread::Init() { sync_message_filter_ = new IPC::SyncMessageFilter(ChildProcess::current()->GetShutDownEvent()); + histogram_message_filter_ = new content::ChildHistogramMessageFilter(); + + channel_->AddFilter(histogram_message_filter_.get()); channel_->AddFilter(sync_message_filter_.get()); channel_->AddFilter(new ChildTraceMessageFilter()); } @@ -69,6 +73,7 @@ ChildThread::~ChildThread() { IPC::Logging::GetInstance()->SetIPCSender(NULL); #endif + channel_->RemoveFilter(histogram_message_filter_.get()); channel_->RemoveFilter(sync_message_filter_.get()); // The ChannelProxy object caches a pointer to the IPC thread, so need to diff --git a/content/common/child_thread.h b/content/common/child_thread.h index 1a583de..22cfb2c 100644 --- a/content/common/child_thread.h +++ b/content/common/child_thread.h @@ -20,6 +20,7 @@ class QuotaDispatcher; class SocketStreamDispatcher; namespace content { +class ChildHistogramMessageFilter; class ResourceDispatcher; } @@ -81,6 +82,10 @@ class CONTENT_EXPORT ChildThread : public IPC::Listener, public IPC::Sender { // lifetime is less than the main thread. IPC::SyncMessageFilter* sync_message_filter(); + content::ChildHistogramMessageFilter* child_histogram_message_filter() const { + return histogram_message_filter_.get(); + } + MessageLoop* message_loop(); // Returns the one child thread. @@ -146,6 +151,8 @@ class CONTENT_EXPORT ChildThread : public IPC::Listener, public IPC::Sender { scoped_ptr<QuotaDispatcher> quota_dispatcher_; + scoped_refptr<content::ChildHistogramMessageFilter> histogram_message_filter_; + DISALLOW_COPY_AND_ASSIGN(ChildThread); }; diff --git a/content/content_browser.gypi b/content/content_browser.gypi index 07def56..54115b9 100644 --- a/content/content_browser.gypi +++ b/content/content_browser.gypi @@ -84,6 +84,7 @@ 'public/browser/global_request_id.h', 'public/browser/gpu_data_manager.h', 'public/browser/gpu_data_manager_observer.h', + 'public/browser/histogram_fetcher.h', 'public/browser/host_zoom_map.h', 'public/browser/indexed_db_context.h', 'public/browser/interstitial_page.h', @@ -406,6 +407,15 @@ 'browser/gpu/gpu_process_host_ui_shim.h', 'browser/gpu/gpu_surface_tracker.cc', 'browser/gpu/gpu_surface_tracker.h', + 'browser/histogram_controller.cc', + 'browser/histogram_controller.h', + 'browser/histogram_internals_request_job.cc', + 'browser/histogram_internals_request_job.h', + 'browser/histogram_message_filter.cc', + 'browser/histogram_message_filter.h', + 'browser/histogram_subscriber.h', + 'browser/histogram_synchronizer.cc', + 'browser/histogram_synchronizer.h', 'browser/host_zoom_map_impl.cc', 'browser/host_zoom_map_impl.h', 'browser/in_process_webkit/browser_webkitplatformsupport_impl.cc', diff --git a/content/content_common.gypi b/content/content_common.gypi index ae14818..2dbfa9b 100644 --- a/content/content_common.gypi +++ b/content/content_common.gypi @@ -122,6 +122,8 @@ 'common/appcache/appcache_dispatcher.h', 'common/appcache_messages.h', 'common/browser_plugin_messages.h', + 'common/child_histogram_message_filter.cc', + 'common/child_histogram_message_filter.h', 'common/child_process.cc', 'common/child_process.h', 'common/child_process_host_impl.cc', diff --git a/content/public/browser/histogram_fetcher.h b/content/public/browser/histogram_fetcher.h new file mode 100644 index 0000000..73dabde --- /dev/null +++ b/content/public/browser/histogram_fetcher.h @@ -0,0 +1,29 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_PUBLIC_BROWSER_HISTOGRAM_FETCHER_H_ +#define CONTENT_PUBLIC_BROWSER_HISTOGRAM_FETCHER_H_ + +#include "base/basictypes.h" +#include "base/callback.h" +#include "base/time.h" +#include "content/common/content_export.h" + +class MessageLoop; + +namespace content { + +// Fetch histogram data asynchronously from the various child processes, into +// the browser process. This method is used by the metrics services in +// preparation for a log upload. It contacts all processes, and get them to +// upload to the browser any/all changes to histograms. When all changes have +// been acquired, or when the wait time expires (whichever is sooner), post the +// callback to the specified message loop. Note the callback is posted exactly +// once. +CONTENT_EXPORT void FetchHistogramsAsynchronously(MessageLoop* callback_thread, + const base::Closure& callback, + base::TimeDelta wait_time); +} // namespace content + +#endif // CONTENT_PUBLIC_BROWSER_HISTOGRAM_FETCHER_H_ diff --git a/content/public/common/content_constants.cc b/content/public/common/content_constants.cc index 7875162..f3b79f59f 100644 --- a/content/public/common/content_constants.cc +++ b/content/public/common/content_constants.cc @@ -30,4 +30,6 @@ const char kStatsFilename[] = "ChromiumStats2"; const int kStatsMaxThreads = 32; const int kStatsMaxCounters = 3000; +const int kHistogramSynchronizerReservedSequenceNumber = 0; + } // namespace content diff --git a/content/public/common/content_constants.h b/content/public/common/content_constants.h index e0bc5f4..3b1c091 100644 --- a/content/public/common/content_constants.h +++ b/content/public/common/content_constants.h @@ -46,6 +46,13 @@ extern const char kStatsFilename[]; extern const int kStatsMaxThreads; extern const int kStatsMaxCounters; +// Most sequence numbers are used by a renderer when responding to a browser +// request for histogram data. This reserved number is used when a renderer +// sends an unprovoked update, such as after a page has been loaded. Using +// this reserved constant avoids any chance of confusion with a response having +// a browser-supplied sequence number. +CONTENT_EXPORT extern const int kHistogramSynchronizerReservedSequenceNumber; + } // namespace content #endif // CONTENT_PUBLIC_COMMON_CONTENT_CONSTANTS_H_ diff --git a/content/public/common/url_constants.cc b/content/public/common/url_constants.cc index 85c3ead..8337146 100644 --- a/content/public/common/url_constants.cc +++ b/content/public/common/url_constants.cc @@ -35,6 +35,7 @@ const char kChromeUIBlobInternalsHost[] = "blob-internals"; const char kChromeUIBrowserCrashHost[] = "inducebrowsercrashforrealz"; const char kChromeUINetworkViewCacheHost[] = "view-http-cache"; const char kChromeUITcmallocHost[] = "tcmalloc"; +const char kChromeUIHistogramHost[] = "histograms"; const char kChromeUICrashURL[] = "chrome://crash"; const char kChromeUIGpuCleanURL[] = "chrome://gpuclean"; const char kChromeUIGpuCrashURL[] = "chrome://gpucrash"; diff --git a/content/public/common/url_constants.h b/content/public/common/url_constants.h index 919685c..7fd1150 100644 --- a/content/public/common/url_constants.h +++ b/content/public/common/url_constants.h @@ -41,6 +41,7 @@ CONTENT_EXPORT extern const char kChromeUIBlobInternalsHost[]; CONTENT_EXPORT extern const char kChromeUIBrowserCrashHost[]; CONTENT_EXPORT extern const char kChromeUINetworkViewCacheHost[]; CONTENT_EXPORT extern const char kChromeUITcmallocHost[]; +CONTENT_EXPORT extern const char kChromeUIHistogramHost[]; // Full about URLs (including schemes). CONTENT_EXPORT extern const char kChromeUICrashURL[]; diff --git a/content/public/renderer/render_thread.h b/content/public/renderer/render_thread.h index 1c10084..fd2fa36 100644 --- a/content/public/renderer/render_thread.h +++ b/content/public/renderer/render_thread.h @@ -104,6 +104,8 @@ class CONTENT_EXPORT RenderThread : public IPC::Sender { virtual void SetIdleNotificationDelayInMs( int64 idle_notification_delay_in_ms) = 0; + virtual void UpdateHistograms(int sequence_number) = 0; + #if defined(OS_WIN) // Request that the given font be loaded by the browser so it's cached by the // OS. Please see ChildProcessHost::PreCacheFont for details. diff --git a/content/public/test/mock_render_thread.h b/content/public/test/mock_render_thread.h index f7fec7b..3a68a31 100644 --- a/content/public/test/mock_render_thread.h +++ b/content/public/test/mock_render_thread.h @@ -73,6 +73,7 @@ class MockRenderThread : public RenderThread { virtual void PreCacheFont(const LOGFONT& log_font) OVERRIDE; virtual void ReleaseCachedFonts() OVERRIDE; #endif + virtual void UpdateHistograms(int sequence_number) OVERRIDE; ////////////////////////////////////////////////////////////////////////// // The following functions are called by the test itself. diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc index afbf45f..dea6cf5 100644 --- a/content/renderer/render_thread_impl.cc +++ b/content/renderer/render_thread_impl.cc @@ -25,6 +25,7 @@ #include "base/values.h" #include "base/win/scoped_com_initializer.h" #include "content/common/appcache/appcache_dispatcher.h" +#include "content/common/child_histogram_message_filter.h" #include "content/common/child_process_messages.h" #include "content/common/database_messages.h" #include "content/common/db_message_filter.h" @@ -759,6 +760,10 @@ void RenderThreadImpl::ReleaseCachedFonts() { #endif // OS_WIN +void RenderThreadImpl::UpdateHistograms(int sequence_number) { + child_histogram_message_filter()->SendHistograms(sequence_number); +} + bool RenderThreadImpl::IsWebFrameValid(WebKit::WebFrame* web_frame) { if (!web_frame) return false; // We must be shutting down. diff --git a/content/renderer/render_thread_impl.h b/content/renderer/render_thread_impl.h index 381581f..8857120 100644 --- a/content/renderer/render_thread_impl.h +++ b/content/renderer/render_thread_impl.h @@ -129,6 +129,7 @@ class CONTENT_EXPORT RenderThreadImpl : public content::RenderThread, virtual void PreCacheFont(const LOGFONT& log_font) OVERRIDE; virtual void ReleaseCachedFonts() OVERRIDE; #endif + virtual void UpdateHistograms(int sequence_number) OVERRIDE; // content::ChildThread: virtual bool IsWebFrameValid(WebKit::WebFrame* frame) OVERRIDE; diff --git a/content/test/mock_render_thread.cc b/content/test/mock_render_thread.cc index 8143718..c333b07 100644 --- a/content/test/mock_render_thread.cc +++ b/content/test/mock_render_thread.cc @@ -174,6 +174,9 @@ void MockRenderThread::ReleaseCachedFonts() { #endif // OS_WIN +void MockRenderThread::UpdateHistograms(int sequence_number) { +} + void MockRenderThread::SendCloseMessage() { ViewMsg_Close msg(routing_id_); widget_->OnMessageReceived(msg); |