Home | History | Annotate | Download | only in metrics
      1 // Copyright (c) 2010 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/metrics/histogram_synchronizer.h"
      6 
      7 #include "base/metrics/histogram.h"
      8 #include "base/logging.h"
      9 #include "base/threading/thread.h"
     10 #include "chrome/common/chrome_constants.h"
     11 #include "chrome/common/render_messages.h"
     12 #include "content/browser/browser_thread.h"
     13 #include "content/browser/renderer_host/render_process_host.h"
     14 
     15 using base::Time;
     16 using base::TimeDelta;
     17 using base::TimeTicks;
     18 
     19 // Negative numbers are never used as sequence numbers.  We explicitly pick a
     20 // negative number that is "so negative" that even when we add one (as is done
     21 // when we generated the next sequence number) that it will still be negative.
     22 // We have code that handles wrapping around on an overflow into negative
     23 // territory.
     24 static const int kNeverUsableSequenceNumber = -2;
     25 
     26 HistogramSynchronizer::HistogramSynchronizer()
     27   : lock_(),
     28     received_all_renderer_histograms_(&lock_),
     29     callback_task_(NULL),
     30     callback_thread_(NULL),
     31     last_used_sequence_number_(kNeverUsableSequenceNumber),
     32     async_sequence_number_(kNeverUsableSequenceNumber),
     33     async_renderers_pending_(0),
     34     synchronous_sequence_number_(kNeverUsableSequenceNumber),
     35     synchronous_renderers_pending_(0) {
     36   DCHECK(histogram_synchronizer_ == NULL);
     37   histogram_synchronizer_ = this;
     38 }
     39 
     40 HistogramSynchronizer::~HistogramSynchronizer() {
     41   // Just in case we have any pending tasks, clear them out.
     42   SetCallbackTaskAndThread(NULL, NULL);
     43   histogram_synchronizer_ = NULL;
     44 }
     45 
     46 // static
     47 HistogramSynchronizer* HistogramSynchronizer::CurrentSynchronizer() {
     48   DCHECK(histogram_synchronizer_ != NULL);
     49   return histogram_synchronizer_;
     50 }
     51 
     52 void HistogramSynchronizer::FetchRendererHistogramsSynchronously(
     53     TimeDelta wait_time) {
     54   NotifyAllRenderers(SYNCHRONOUS_HISTOGRAMS);
     55 
     56   TimeTicks start = TimeTicks::Now();
     57   TimeTicks end_time = start + wait_time;
     58   int unresponsive_renderer_count;
     59   {
     60     base::AutoLock auto_lock(lock_);
     61     while (synchronous_renderers_pending_ > 0 && TimeTicks::Now() < end_time) {
     62       wait_time = end_time - TimeTicks::Now();
     63       received_all_renderer_histograms_.TimedWait(wait_time);
     64     }
     65     unresponsive_renderer_count = synchronous_renderers_pending_;
     66     synchronous_renderers_pending_ = 0;
     67     synchronous_sequence_number_ = kNeverUsableSequenceNumber;
     68   }
     69   UMA_HISTOGRAM_COUNTS("Histogram.RendersNotRespondingSynchronous",
     70                        unresponsive_renderer_count);
     71   if (!unresponsive_renderer_count)
     72     UMA_HISTOGRAM_TIMES("Histogram.FetchRendererHistogramsSynchronously",
     73                         TimeTicks::Now() - start);
     74 }
     75 
     76 // static
     77 void HistogramSynchronizer::FetchRendererHistogramsAsynchronously(
     78     MessageLoop* callback_thread,
     79     Task* callback_task,
     80     int wait_time) {
     81   DCHECK(callback_thread != NULL);
     82   DCHECK(callback_task != NULL);
     83 
     84   HistogramSynchronizer* current_synchronizer = CurrentSynchronizer();
     85 
     86   if (current_synchronizer == NULL) {
     87     // System teardown is happening.
     88     callback_thread->PostTask(FROM_HERE, callback_task);
     89     return;
     90   }
     91 
     92   current_synchronizer->SetCallbackTaskAndThread(callback_thread,
     93                                                  callback_task);
     94 
     95   int sequence_number =
     96       current_synchronizer->NotifyAllRenderers(ASYNC_HISTOGRAMS);
     97 
     98   // Post a task that would be called after waiting for wait_time.  This acts
     99   // as a watchdog, to ensure that a non-responsive renderer won't block us from
    100   // making the callback.
    101   BrowserThread::PostDelayedTask(
    102       BrowserThread::UI, FROM_HERE,
    103       NewRunnableMethod(
    104           current_synchronizer,
    105           &HistogramSynchronizer::ForceHistogramSynchronizationDoneCallback,
    106           sequence_number),
    107       wait_time);
    108 }
    109 
    110 // static
    111 void HistogramSynchronizer::DeserializeHistogramList(
    112     int sequence_number,
    113     const std::vector<std::string>& histograms) {
    114   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    115   for (std::vector<std::string>::const_iterator it = histograms.begin();
    116        it < histograms.end();
    117        ++it) {
    118     base::Histogram::DeserializeHistogramInfo(*it);
    119   }
    120 
    121   HistogramSynchronizer* current_synchronizer = CurrentSynchronizer();
    122   if (current_synchronizer == NULL)
    123     return;
    124 
    125   // Record that we have received a histogram from renderer process.
    126   current_synchronizer->DecrementPendingRenderers(sequence_number);
    127 }
    128 
    129 int HistogramSynchronizer::NotifyAllRenderers(
    130     RendererHistogramRequester requester) {
    131   // To iterate over RenderProcessHosts, or to send messages to the hosts, we
    132   // need to be on the UI thread.
    133   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    134 
    135   int notification_count = 0;
    136   for (RenderProcessHost::iterator it(RenderProcessHost::AllHostsIterator());
    137        !it.IsAtEnd(); it.Advance())
    138      ++notification_count;
    139 
    140   int sequence_number = GetNextAvailableSequenceNumber(requester,
    141                                                        notification_count);
    142   for (RenderProcessHost::iterator it(RenderProcessHost::AllHostsIterator());
    143        !it.IsAtEnd(); it.Advance()) {
    144     if (!it.GetCurrentValue()->Send(
    145         new ViewMsg_GetRendererHistograms(sequence_number)))
    146       DecrementPendingRenderers(sequence_number);
    147   }
    148 
    149   return sequence_number;
    150 }
    151 
    152 void HistogramSynchronizer::DecrementPendingRenderers(int sequence_number) {
    153   bool synchronous_completed = false;
    154   bool asynchronous_completed = false;
    155 
    156   {
    157     base::AutoLock auto_lock(lock_);
    158     if (sequence_number == async_sequence_number_) {
    159       if (--async_renderers_pending_ <= 0)
    160         asynchronous_completed = true;
    161     } else if (sequence_number == synchronous_sequence_number_) {
    162       if (--synchronous_renderers_pending_ <= 0)
    163         synchronous_completed = true;
    164     }
    165   }
    166 
    167   if (asynchronous_completed)
    168     ForceHistogramSynchronizationDoneCallback(sequence_number);
    169   else if (synchronous_completed)
    170     received_all_renderer_histograms_.Signal();
    171 }
    172 
    173 void HistogramSynchronizer::SetCallbackTaskAndThread(
    174     MessageLoop* callback_thread,
    175     Task* callback_task) {
    176   Task* old_task = NULL;
    177   MessageLoop* old_thread = NULL;
    178   TimeTicks old_start_time;
    179   int unresponsive_renderers;
    180   const TimeTicks now = TimeTicks::Now();
    181   {
    182     base::AutoLock auto_lock(lock_);
    183     old_task = callback_task_;
    184     callback_task_ = callback_task;
    185     old_thread = callback_thread_;
    186     callback_thread_ = callback_thread;
    187     unresponsive_renderers = async_renderers_pending_;
    188     old_start_time = async_callback_start_time_;
    189     async_callback_start_time_ = now;
    190     // Prevent premature calling of our new callbacks.
    191     async_sequence_number_ = kNeverUsableSequenceNumber;
    192   }
    193   // Just in case there was a task pending....
    194   InternalPostTask(old_thread, old_task, unresponsive_renderers,
    195                    old_start_time);
    196 }
    197 
    198 void HistogramSynchronizer::ForceHistogramSynchronizationDoneCallback(
    199     int sequence_number) {
    200   Task* task = NULL;
    201   MessageLoop* thread = NULL;
    202   TimeTicks started;
    203   int unresponsive_renderers;
    204   {
    205     base::AutoLock lock(lock_);
    206     if (sequence_number != async_sequence_number_)
    207       return;
    208     task = callback_task_;
    209     thread = callback_thread_;
    210     callback_task_ = NULL;
    211     callback_thread_ = NULL;
    212     started = async_callback_start_time_;
    213     unresponsive_renderers = async_renderers_pending_;
    214   }
    215   InternalPostTask(thread, task, unresponsive_renderers, started);
    216 }
    217 
    218 void HistogramSynchronizer::InternalPostTask(MessageLoop* thread, Task* task,
    219                                              int unresponsive_renderers,
    220                                              const base::TimeTicks& started) {
    221   if (!task || !thread)
    222     return;
    223   UMA_HISTOGRAM_COUNTS("Histogram.RendersNotRespondingAsynchronous",
    224                        unresponsive_renderers);
    225   if (!unresponsive_renderers) {
    226     UMA_HISTOGRAM_TIMES("Histogram.FetchRendererHistogramsAsynchronously",
    227                         TimeTicks::Now() - started);
    228   }
    229 
    230   thread->PostTask(FROM_HERE, task);
    231 }
    232 
    233 int HistogramSynchronizer::GetNextAvailableSequenceNumber(
    234     RendererHistogramRequester requester,
    235     int renderer_count) {
    236   base::AutoLock auto_lock(lock_);
    237   ++last_used_sequence_number_;
    238   // Watch out for wrapping to a negative number.
    239   if (last_used_sequence_number_ < 0) {
    240     // Bypass the reserved number, which is used when a renderer spontaneously
    241     // decides to send some histogram data.
    242     last_used_sequence_number_ =
    243         chrome::kHistogramSynchronizerReservedSequenceNumber + 1;
    244   }
    245   DCHECK_NE(last_used_sequence_number_,
    246             chrome::kHistogramSynchronizerReservedSequenceNumber);
    247   if (requester == ASYNC_HISTOGRAMS) {
    248     async_sequence_number_ = last_used_sequence_number_;
    249     async_renderers_pending_ = renderer_count;
    250   } else if (requester == SYNCHRONOUS_HISTOGRAMS) {
    251     synchronous_sequence_number_ = last_used_sequence_number_;
    252     synchronous_renderers_pending_ = renderer_count;
    253   }
    254   return last_used_sequence_number_;
    255 }
    256 
    257 // static
    258 HistogramSynchronizer* HistogramSynchronizer::histogram_synchronizer_ = NULL;
    259