Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1135)

Side by Side Diff: content/browser/histogram_synchronizer_impl.cc

Issue 10454086: Histograms - Support histograms for Plugins, GPU (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Created 8 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/metrics/histogram_synchronizer.h" 5 #include "content/browser/histogram_synchronizer_impl.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/lazy_instance.h"
8 #include "base/logging.h" 9 #include "base/logging.h"
9 #include "base/metrics/histogram.h" 10 #include "base/metrics/histogram.h"
10 #include "base/threading/thread.h" 11 #include "base/threading/thread.h"
11 #include "base/threading/thread_restrictions.h" 12 #include "base/threading/thread_restrictions.h"
12 #include "chrome/common/chrome_constants.h" 13 #include "content/browser/histogram_controller.h"
13 #include "chrome/common/render_messages.h"
14 #include "content/public/browser/browser_thread.h" 14 #include "content/public/browser/browser_thread.h"
15 #include "content/public/browser/render_process_host.h" 15 #include "content/public/common/content_constants.h"
16 16
17 using base::Time; 17 using base::Time;
18 using base::TimeDelta; 18 using base::TimeDelta;
19 using base::TimeTicks; 19 using base::TimeTicks;
20 using content::BrowserThread; 20 using content::BrowserThread;
21 21
22 namespace {
23
22 // Negative numbers are never used as sequence numbers. We explicitly pick a 24 // 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 25 // 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. 26 // 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 27 // We have code that handles wrapping around on an overflow into negative
26 // territory. 28 // territory.
27 static const int kNeverUsableSequenceNumber = -2; 29 static const int kNeverUsableSequenceNumber = -2;
28 30
29 HistogramSynchronizer::HistogramSynchronizer() 31 // This singleton instance should be started during the single threaded
30 : lock_(), 32 // portion of main(). It initializes globals to provide support for all future
31 received_all_renderer_histograms_(&lock_), 33 // calls. This object is created on the UI thread, and it is destroyed after
32 callback_thread_(NULL), 34 // all the other threads have gone away. As a result, it is ok to call it
jam 2012/06/07 03:34:33 who destroys this?
ramant (doing other things) 2012/06/07 23:39:25 Used singleton and deleted g_histogram_synchronize
33 last_used_sequence_number_(kNeverUsableSequenceNumber), 35 // from the UI thread (for UMA uploads), or for about:histograms.
34 async_sequence_number_(kNeverUsableSequenceNumber), 36 static content::HistogramSynchronizerImpl* g_histogram_synchronizer = NULL;
35 async_renderers_pending_(0), 37
36 synchronous_sequence_number_(kNeverUsableSequenceNumber), 38 } // anonymous namespace
37 synchronous_renderers_pending_(0) { 39
38 DCHECK(histogram_synchronizer_ == NULL); 40 namespace content {
39 histogram_synchronizer_ = this; 41
40 } 42 // The "RequestContext" structure describes an individual request received from
41 43 // the UI. All methods are accessible on UI thread.
42 HistogramSynchronizer::~HistogramSynchronizer() { 44 class HistogramSynchronizerImpl::RequestContext {
45 public:
46 // A map from sequence_number_ to the actual RequestContexts.
47 typedef std::map<int, RequestContext*> RequestContextMap;
48
49 RequestContext(const base::Closure& callback, int sequence_number)
50 : callback_(callback),
51 sequence_number_(sequence_number),
52 received_process_group_count_(0),
53 processes_pending_(0) {
54 }
55 ~RequestContext() {}
56
57 void SetReceivedProcessGroupCount(bool done) {
58 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
59 received_process_group_count_ = done;
60 }
61
62 // Methods for book keeping of processes_pending_.
63 void AddProcessesPending(int processes_pending) {
64 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
65 processes_pending_ += processes_pending;
66 }
67
68 void DecrementProcessesPending() {
69 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
70 --processes_pending_;
71 }
72
73 // Records that we are waiting for one less histogram data from a process for
74 // the given sequence number. If |received_process_group_count_| and
75 // |processes_pending_| are zero, then delete the current object by calling
76 // Unregister.
77 void DeleteIfAllDone() {
78 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
79
80 if (processes_pending_ <= 0 && received_process_group_count_)
81 RequestContext::Unregister(sequence_number_);
82 }
83
84 // Register |callback| in |outstanding_requests_| map for the given
85 // |sequence_number|.
86 static void Register(const base::Closure& callback, int sequence_number) {
87 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
88
89 RequestContext* request = new RequestContext(callback, sequence_number);
90 outstanding_requests_.Get()[sequence_number] = request;
91 }
92
93 // Find the |RequestContext| in |outstanding_requests_| map for the given
94 // |sequence_number|.
95 static RequestContext* GetRequestContext(int sequence_number) {
96 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
97
98 RequestContextMap::iterator it =
99 outstanding_requests_.Get().find(sequence_number);
100 if (it == outstanding_requests_.Get().end())
101 return NULL;
102
103 RequestContext* request = it->second;
104 DCHECK_EQ(sequence_number, request->sequence_number_);
105 return request;
106 }
107
108 // Delete the entry for the given |sequence_number| from
109 // |outstanding_requests_| map. This method is called when all changes have
110 // been acquired, or when the wait time expires (whichever is sooner).
111 static void Unregister(int sequence_number) {
112 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
113
114 RequestContextMap::iterator it =
115 outstanding_requests_.Get().find(sequence_number);
116 if (it == outstanding_requests_.Get().end())
117 return;
118
119 RequestContext* request = it->second;
120 DCHECK_EQ(sequence_number, request->sequence_number_);
121 bool received_process_group_count = request->received_process_group_count_;
122 int unresponsive_processes = request->processes_pending_;
123
124 request->callback_.Run();
125
126 delete request;
127 outstanding_requests_.Get().erase(it);
128
129 UMA_HISTOGRAM_BOOLEAN("Histogram.ReceivedProcessGroupCount",
130 received_process_group_count);
131 UMA_HISTOGRAM_COUNTS("Histogram.PendingProcessNotResponding",
132 unresponsive_processes);
133 }
134
135 // Delete all the entries in |outstanding_requests_| map.
136 static void OnShutdown() {
137 // Just in case we have any pending tasks, clear them out.
138 while (!outstanding_requests_.Get().empty()) {
139 RequestContextMap::iterator it = outstanding_requests_.Get().begin();
140 delete it->second;
141 outstanding_requests_.Get().erase(it);
142 }
143 }
144
145 // Requests are made to asynchronously send data to the |callback_|.
146 base::Closure callback_;
147
148 // The sequence number used by the most recent update request to contact all
149 // processes.
150 int sequence_number_;
151
152 // Indicates if we have received all pending processes count.
153 bool received_process_group_count_;
154
155 // The number of pending processes (all renderer processes and browser child
156 // processes) that have not yet responded to requests.
157 int processes_pending_;
158
159 // Map of all outstanding RequestContexts, from sequence_number_ to
160 // RequestContext.
161 static base::LazyInstance<RequestContextMap>::Leaky outstanding_requests_;
162 };
163
164 HistogramSynchronizerImpl::HistogramSynchronizerImpl()
165 : lock_(),
166 callback_thread_(NULL),
167 last_used_sequence_number_(kNeverUsableSequenceNumber),
168 async_sequence_number_(kNeverUsableSequenceNumber) {
169 DCHECK(g_histogram_synchronizer == NULL);
170 g_histogram_synchronizer = this;
171 content::HistogramController::GetInstance()->Register(this);
172 }
173
174 HistogramSynchronizerImpl::~HistogramSynchronizerImpl() {
175 RequestContext::OnShutdown();
176
43 // Just in case we have any pending tasks, clear them out. 177 // Just in case we have any pending tasks, clear them out.
44 SetCallbackTaskAndThread(NULL, base::Closure()); 178 SetCallbackTaskAndThread(NULL, base::Closure());
45 histogram_synchronizer_ = NULL; 179 g_histogram_synchronizer = NULL;
180 }
181
182 content::HistogramSynchronizer* content::HistogramSynchronizer::GetInstance() {
183 return new HistogramSynchronizerImpl();
46 } 184 }
47 185
48 // static 186 // static
49 HistogramSynchronizer* HistogramSynchronizer::CurrentSynchronizer() { 187 HistogramSynchronizerImpl* HistogramSynchronizerImpl::CurrentSynchronizer() {
50 DCHECK(histogram_synchronizer_ != NULL); 188 DCHECK(g_histogram_synchronizer != NULL);
51 return histogram_synchronizer_; 189 return g_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 } 190 }
78 191
79 // static 192 // static
80 void HistogramSynchronizer::FetchRendererHistogramsAsynchronously( 193 void HistogramSynchronizer::FetchHistograms() {
194 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
195 BrowserThread::PostTask(
196 BrowserThread::UI, FROM_HERE,
197 base::Bind(&HistogramSynchronizer::FetchHistograms));
198 return;
199 }
200 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
201
202 HistogramSynchronizerImpl* current_synchronizer =
203 HistogramSynchronizerImpl::CurrentSynchronizer();
204 if (current_synchronizer == NULL)
205 return;
206
207 current_synchronizer->RegisterAndNotifyAllProcesses(
208 HistogramSynchronizerImpl::UNKNOWN,
209 base::TimeDelta::FromMinutes(1));
210 }
211
212 // static
213 void HistogramSynchronizer::FetchHistogramsAsynchronously(
81 MessageLoop* callback_thread, 214 MessageLoop* callback_thread,
82 const base::Closure& callback, 215 const base::Closure& callback,
83 base::TimeDelta wait_time) { 216 base::TimeDelta wait_time) {
84 DCHECK(callback_thread != NULL); 217 DCHECK(callback_thread != NULL);
85 DCHECK(!callback.is_null()); 218 DCHECK(!callback.is_null());
86 219
87 HistogramSynchronizer* current_synchronizer = CurrentSynchronizer(); 220 HistogramSynchronizerImpl* current_synchronizer =
88 221 HistogramSynchronizerImpl::CurrentSynchronizer();
89 if (current_synchronizer == NULL) { 222 if (current_synchronizer == NULL) {
90 // System teardown is happening. 223 // System teardown is happening.
91 callback_thread->PostTask(FROM_HERE, callback); 224 callback_thread->PostTask(FROM_HERE, callback);
92 return; 225 return;
93 } 226 }
94 227
95 current_synchronizer->SetCallbackTaskAndThread(callback_thread, 228 current_synchronizer->SetCallbackTaskAndThread(
96 callback); 229 callback_thread, callback);
97 230
98 int sequence_number = 231 current_synchronizer->RegisterAndNotifyAllProcesses(
99 current_synchronizer->NotifyAllRenderers(ASYNC_HISTOGRAMS); 232 HistogramSynchronizerImpl::ASYNC_HISTOGRAMS, wait_time);
233 }
234
235 void HistogramSynchronizerImpl::RegisterAndNotifyAllProcesses(
236 ProcessHistogramRequester requester,
237 base::TimeDelta wait_time) {
238 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
239
240 int sequence_number = GetNextAvailableSequenceNumber(requester);
241
242 base::Closure callback =
243 base::Bind(
244 &HistogramSynchronizerImpl::ForceHistogramSynchronizationDoneCallback,
245 this,
246 sequence_number);
247
248 RequestContext::Register(callback, sequence_number);
249
250 // Get histogram data from renderer and browser child processes.
251 content::HistogramController::GetInstance()->GetHistogramData(
252 sequence_number);
100 253
101 // Post a task that would be called after waiting for wait_time. This acts 254 // 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 255 // as a watchdog, to cancel the requests for non-responsive processes.
103 // making the callback.
104 BrowserThread::PostDelayedTask( 256 BrowserThread::PostDelayedTask(
105 BrowserThread::UI, FROM_HERE, 257 BrowserThread::UI, FROM_HERE,
106 base::Bind( 258 base::Bind(&RequestContext::Unregister, sequence_number),
107 &HistogramSynchronizer::ForceHistogramSynchronizationDoneCallback,
108 current_synchronizer,
109 sequence_number),
110 wait_time); 259 wait_time);
111 } 260 }
112 261
113 // static 262 void HistogramSynchronizerImpl::OnPendingProcesses(int sequence_number,
114 void HistogramSynchronizer::DeserializeHistogramList( 263 int pending_processes,
264 bool end) {
265 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
266
267 RequestContext* request = RequestContext::GetRequestContext(sequence_number);
268 if (!request)
269 return;
270 request->AddProcessesPending(pending_processes);
271 request->SetReceivedProcessGroupCount(end);
272 request->DeleteIfAllDone();
273 }
274
275 void HistogramSynchronizerImpl::OnHistogramDataCollected(
276 int sequence_number,
277 const std::vector<std::string>& histogram_data) {
278 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
279 DecrementPendingProcessesAndSendData(sequence_number, histogram_data);
280 }
281
282 void HistogramSynchronizerImpl::DecrementPendingProcessesAndSendData(
115 int sequence_number, 283 int sequence_number,
116 const std::vector<std::string>& histograms) { 284 const std::vector<std::string>& histograms) {
117 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 285 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
286
287 RequestContext* request = RequestContext::GetRequestContext(sequence_number);
288
118 for (std::vector<std::string>::const_iterator it = histograms.begin(); 289 for (std::vector<std::string>::const_iterator it = histograms.begin();
119 it < histograms.end(); 290 it < histograms.end();
120 ++it) { 291 ++it) {
121 base::Histogram::DeserializeHistogramInfo(*it); 292 base::Histogram::DeserializeHistogramInfo(*it);
122 } 293 }
123 294
124 HistogramSynchronizer* current_synchronizer = CurrentSynchronizer(); 295 if (!request)
125 if (current_synchronizer == NULL) 296 return;
126 return; 297
127 298 // Delete request if we have heard back from all child processes.
128 // Record that we have received a histogram from renderer process. 299 request->DecrementProcessesPending();
129 current_synchronizer->DecrementPendingRenderers(sequence_number); 300 request->DeleteIfAllDone();
130 } 301 }
131 302
132 int HistogramSynchronizer::NotifyAllRenderers( 303 void HistogramSynchronizerImpl::SetCallbackTaskAndThread(
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, 304 MessageLoop* callback_thread,
180 const base::Closure& callback) { 305 const base::Closure& callback) {
181 base::Closure old_callback; 306 base::Closure old_callback;
182 MessageLoop* old_thread = NULL; 307 MessageLoop* old_thread = NULL;
183 TimeTicks old_start_time;
184 int unresponsive_renderers;
185 const TimeTicks now = TimeTicks::Now();
186 { 308 {
187 base::AutoLock auto_lock(lock_); 309 base::AutoLock auto_lock(lock_);
188 old_callback = callback_; 310 old_callback = callback_;
189 callback_ = callback; 311 callback_ = callback;
190 old_thread = callback_thread_; 312 old_thread = callback_thread_;
191 callback_thread_ = callback_thread; 313 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. 314 // Prevent premature calling of our new callbacks.
196 async_sequence_number_ = kNeverUsableSequenceNumber; 315 async_sequence_number_ = kNeverUsableSequenceNumber;
197 } 316 }
198 // Just in case there was a task pending.... 317 // Just in case there was a task pending....
199 InternalPostTask(old_thread, old_callback, unresponsive_renderers, 318 InternalPostTask(old_thread, old_callback);
200 old_start_time); 319 }
201 } 320
202 321 void HistogramSynchronizerImpl::ForceHistogramSynchronizationDoneCallback(
203 void HistogramSynchronizer::ForceHistogramSynchronizationDoneCallback(
204 int sequence_number) { 322 int sequence_number) {
205 base::Closure callback; 323 base::Closure callback;
206 MessageLoop* thread = NULL; 324 MessageLoop* thread = NULL;
207 TimeTicks started;
208 int unresponsive_renderers;
209 { 325 {
210 base::AutoLock lock(lock_); 326 base::AutoLock lock(lock_);
211 if (sequence_number != async_sequence_number_) 327 if (sequence_number != async_sequence_number_)
212 return; 328 return;
213 callback = callback_; 329 callback = callback_;
214 thread = callback_thread_; 330 thread = callback_thread_;
215 callback_.Reset(); 331 callback_.Reset();
216 callback_thread_ = NULL; 332 callback_thread_ = NULL;
217 started = async_callback_start_time_;
218 unresponsive_renderers = async_renderers_pending_;
219 } 333 }
220 InternalPostTask(thread, callback, unresponsive_renderers, started); 334 InternalPostTask(thread, callback);
221 } 335 }
222 336
223 void HistogramSynchronizer::InternalPostTask(MessageLoop* thread, 337 void HistogramSynchronizerImpl::InternalPostTask(
224 const base::Closure& callback, 338 MessageLoop* thread,
225 int unresponsive_renderers, 339 const base::Closure& callback) {
226 const base::TimeTicks& started) {
227 if (callback.is_null() || !thread) 340 if (callback.is_null() || !thread)
228 return; 341 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); 342 thread->PostTask(FROM_HERE, callback);
237 } 343 }
238 344
239 int HistogramSynchronizer::GetNextAvailableSequenceNumber( 345 int HistogramSynchronizerImpl::GetNextAvailableSequenceNumber(
240 RendererHistogramRequester requester, 346 ProcessHistogramRequester requester) {
241 int renderer_count) {
242 base::AutoLock auto_lock(lock_); 347 base::AutoLock auto_lock(lock_);
243 ++last_used_sequence_number_; 348 ++last_used_sequence_number_;
244 // Watch out for wrapping to a negative number. 349 // Watch out for wrapping to a negative number.
245 if (last_used_sequence_number_ < 0) { 350 if (last_used_sequence_number_ < 0) {
246 // Bypass the reserved number, which is used when a renderer spontaneously 351 // Bypass the reserved number, which is used when a renderer spontaneously
247 // decides to send some histogram data. 352 // decides to send some histogram data.
248 last_used_sequence_number_ = 353 last_used_sequence_number_ =
249 chrome::kHistogramSynchronizerReservedSequenceNumber + 1; 354 kHistogramSynchronizerReservedSequenceNumber + 1;
250 } 355 }
251 DCHECK_NE(last_used_sequence_number_, 356 DCHECK_NE(last_used_sequence_number_,
252 chrome::kHistogramSynchronizerReservedSequenceNumber); 357 kHistogramSynchronizerReservedSequenceNumber);
253 if (requester == ASYNC_HISTOGRAMS) { 358 if (requester == ASYNC_HISTOGRAMS)
254 async_sequence_number_ = last_used_sequence_number_; 359 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_; 360 return last_used_sequence_number_;
261 } 361 }
262 362
263 // static 363 // static
264 HistogramSynchronizer* HistogramSynchronizer::histogram_synchronizer_ = NULL; 364 base::LazyInstance
365 <HistogramSynchronizerImpl::RequestContext::RequestContextMap>::Leaky
366 HistogramSynchronizerImpl::RequestContext::outstanding_requests_ =
367 LAZY_INSTANCE_INITIALIZER;
368
369 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698