1 // Copyright (c) 2011 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 #ifndef CHROME_BROWSER_METRICS_HISTOGRAM_SYNCHRONIZER_H_ 6 #define CHROME_BROWSER_METRICS_HISTOGRAM_SYNCHRONIZER_H_ 7 #pragma once 8 9 #include <string> 10 #include <vector> 11 12 #include "base/basictypes.h" 13 #include "base/memory/ref_counted.h" 14 #include "base/synchronization/condition_variable.h" 15 #include "base/synchronization/lock.h" 16 #include "base/time.h" 17 18 class MessageLoop; 19 class Task; 20 21 // This class maintains state that is used to upload histogram data from the 22 // various renderer processes, into the browser process. Such transactions are 23 // usually instigated by the browser. In general, a renderer process will 24 // respond by gathering snapshots of all internal histograms, calculating what 25 // has changed since its last upload, and transmitting a pickled collection of 26 // deltas. 27 // 28 // There are actually two modes of update request. One is synchronous (and 29 // blocks the UI thread, waiting to populate an about:histograms tab) and the 30 // other is asynchronous, and used by the metrics services in preparation for a 31 // log upload. 32 // 33 // To assure that all the renderers have responded, a counter is maintained (for 34 // each mode) to indicate the number of pending (not yet responsive) renderers. 35 // To avoid confusion about a response (i.e., is the renderer responding to a 36 // current request for an update, or to an old request for an update) we tag 37 // each group of requests with a sequence number. When an update arrives we can 38 // ignore it (relative to the counter) if it does not relate to a current 39 // outstanding sequence number. 40 // 41 // There is one final mode of use, where a renderer spontaneously decides to 42 // transmit a collection of histogram data. This is designed for use when the 43 // renderer is terminating. Unfortunately, renders may be terminated without 44 // warning, and the best we can do is periodically acquire data from a tab, such 45 // as when a page load has completed. In this mode, the renderer uses a 46 // reserved sequence number, different from any sequence number that might be 47 // specified by a browser request. Since this sequence number can't match an 48 // outstanding sequence number, the pickled data is accepted into the browser, 49 // but there is no impact on the counters. 50 51 class HistogramSynchronizer : public 52 base::RefCountedThreadSafe<HistogramSynchronizer> { 53 public: 54 55 enum RendererHistogramRequester { 56 ASYNC_HISTOGRAMS, 57 SYNCHRONOUS_HISTOGRAMS 58 }; 59 60 // Construction also sets up the global singleton instance. This instance is 61 // used to communicate between the IO and UI thread, and is destroyed only 62 // as the main thread (browser_main) terminates, which means the IO thread has 63 // already completed, and will not need this instance any further. 64 HistogramSynchronizer(); 65 66 ~HistogramSynchronizer(); 67 68 // Return pointer to the singleton instance, which is allocated and 69 // deallocated on the main UI thread (during system startup and teardown). 70 static HistogramSynchronizer* CurrentSynchronizer(); 71 72 // Contact all renderers, and get them to upload to the browser any/all 73 // changes to histograms. Return when all changes have been acquired, or when 74 // the wait time expires (whichever is sooner). This method is called on the 75 // main UI thread from about:histograms. 76 void FetchRendererHistogramsSynchronously(base::TimeDelta wait_time); 77 78 // Contact all renderers, and get them to upload to the browser any/all 79 // changes to histograms. When all changes have been acquired, or when the 80 // wait time expires (whichever is sooner), post the callback_task to the 81 // specified thread. Note the callback_task is posted exactly once. 82 static void FetchRendererHistogramsAsynchronously( 83 MessageLoop* callback_thread, Task* callback_task, int wait_time); 84 85 // This method is called on the IO thread. Deserializes the histograms and 86 // records that we have received histograms from a renderer process. 87 static void DeserializeHistogramList( 88 int sequence_number, const std::vector<std::string>& histograms); 89 90 private: 91 // Establish a new sequence_number_, and use it to notify all the renderers of 92 // the need to supply, to the browser, any changes in their histograms. 93 // The argument indicates whether this will set async_sequence_number_ or 94 // synchronous_sequence_number_. 95 // Return the sequence number that was used. 96 int NotifyAllRenderers(RendererHistogramRequester requester); 97 98 // Records that we are waiting for one less histogram from a renderer for the 99 // given sequence number. If we have received a response from all renderers, 100 // either signal the waiting process or call the callback function. 101 void DecrementPendingRenderers(int sequence_number); 102 103 // Set the callback_thread_ and callback_task_ members. If these members 104 // already had values, then as a side effect, post the old callback_task_ to 105 // the old callaback_thread_. This side effect should not generally happen, 106 // but is in place to assure correctness (that any tasks that were set, are 107 // eventually called, and never merely discarded). 108 void SetCallbackTaskAndThread(MessageLoop* callback_thread, 109 Task* callback_task); 110 111 void ForceHistogramSynchronizationDoneCallback(int sequence_number); 112 113 // Gets a new sequence number to be sent to renderers from browser process and 114 // set the number of pending responses for the given type to renderer_count. 115 int GetNextAvailableSequenceNumber(RendererHistogramRequester requster, 116 int renderer_count); 117 118 // Internal helper function, to post task, and record callback stats. 119 void InternalPostTask(MessageLoop* thread, Task* task, 120 int unresponsive_renderers, const base::TimeTicks& started); 121 122 // This lock_ protects access to all members. 123 base::Lock lock_; 124 125 // This condition variable is used to block caller of the synchronous request 126 // to update histograms, and to signal that thread when updates are completed. 127 base::ConditionVariable received_all_renderer_histograms_; 128 129 // When a request is made to asynchronously update the histograms, we store 130 // the task and thread we use to post a completion notification in 131 // callback_task_ and callback_thread_. 132 Task* callback_task_; 133 MessageLoop* callback_thread_; 134 135 // We don't track the actual renderers that are contacted for an update, only 136 // the count of the number of renderers, and we can sometimes time-out and 137 // give up on a "slow to respond" renderer. We use a sequence_number to be 138 // sure a response from a renderer is associated with the current round of 139 // requests (and not merely a VERY belated prior response). 140 // All sequence numbers used are non-negative. 141 // last_used_sequence_number_ is the most recently used number (used to avoid 142 // reuse for a long time). 143 int last_used_sequence_number_; 144 145 // The sequence number used by the most recent asynchronous update request to 146 // contact all renderers. 147 int async_sequence_number_; 148 149 // The number of renderers that have not yet responded to requests (as part of 150 // an asynchronous update). 151 int async_renderers_pending_; 152 153 // The time when we were told to start the fetch histograms asynchronously 154 // from renderers. 155 base::TimeTicks async_callback_start_time_; 156 157 // The sequence number used by the most recent synchronous update request to 158 // contact all renderers. 159 int synchronous_sequence_number_; 160 161 // The number of renderers that have not yet responded to requests (as part of 162 // a synchronous update). 163 int synchronous_renderers_pending_; 164 165 // This singleton instance should be started during the single threaded 166 // portion of main(). It initializes globals to provide support for all future 167 // calls. This object is created on the UI thread, and it is destroyed after 168 // all the other threads have gone away. As a result, it is ok to call it 169 // from the UI thread (for UMA uploads), or for about:histograms. 170 static HistogramSynchronizer* histogram_synchronizer_; 171 172 DISALLOW_COPY_AND_ASSIGN(HistogramSynchronizer); 173 }; 174 175 #endif // CHROME_BROWSER_METRICS_HISTOGRAM_SYNCHRONIZER_H_ 176