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