diff options
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); |