OLD | NEW |
---|---|
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 "components/metrics/profiler/tracking_synchronizer.h" | 5 #include "components/metrics/profiler/tracking_synchronizer.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/metrics/histogram.h" | 8 #include "base/metrics/histogram.h" |
9 #include "base/threading/thread.h" | 9 #include "base/threading/thread.h" |
10 #include "base/tracked_objects.h" | 10 #include "base/tracked_objects.h" |
(...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
173 }; | 173 }; |
174 | 174 |
175 // static | 175 // static |
176 base::LazyInstance | 176 base::LazyInstance |
177 <TrackingSynchronizer::RequestContext::RequestContextMap>::Leaky | 177 <TrackingSynchronizer::RequestContext::RequestContextMap>::Leaky |
178 TrackingSynchronizer::RequestContext::outstanding_requests_ = | 178 TrackingSynchronizer::RequestContext::outstanding_requests_ = |
179 LAZY_INSTANCE_INITIALIZER; | 179 LAZY_INSTANCE_INITIALIZER; |
180 | 180 |
181 // TrackingSynchronizer methods and members. | 181 // TrackingSynchronizer methods and members. |
182 | 182 |
183 TrackingSynchronizer::TrackingSynchronizer(base::TimeTicks now) | 183 TrackingSynchronizer::TrackingSynchronizer(scoped_ptr<base::TickClock> clock) |
184 : last_used_sequence_number_(kNeverUsableSequenceNumber), start_time_(now) { | 184 : last_used_sequence_number_(kNeverUsableSequenceNumber), |
185 clock_(clock.Pass()) { | |
185 DCHECK(!g_tracking_synchronizer); | 186 DCHECK(!g_tracking_synchronizer); |
186 g_tracking_synchronizer = this; | 187 g_tracking_synchronizer = this; |
187 phase_start_times_.push_back(now); | 188 phase_start_times_.push_back(clock_->NowTicks()); |
188 | 189 |
189 #if !defined(OS_IOS) | 190 #if !defined(OS_IOS) |
190 // TODO: This ifdef and other ifdefs for OS_IOS in this file are only | 191 // TODO: This ifdef and other ifdefs for OS_IOS in this file are only |
191 // short-term hacks to make this compile on iOS, and the proper solution is to | 192 // short-term hacks to make this compile on iOS, and the proper solution is to |
192 // refactor to remove content dependencies from shared code. | 193 // refactor to remove content dependencies from shared code. |
193 // See crbug/472210. | 194 // See crbug/472210. |
194 content::ProfilerController::GetInstance()->Register(this); | 195 content::ProfilerController::GetInstance()->Register(this); |
195 #endif | 196 #endif |
196 } | 197 } |
197 | 198 |
(...skipping 22 matching lines...) Expand all Loading... | |
220 callback_object); | 221 callback_object); |
221 | 222 |
222 // Post a task that would be called after waiting for wait_time. This acts | 223 // Post a task that would be called after waiting for wait_time. This acts |
223 // as a watchdog, to cancel the requests for non-responsive processes. | 224 // as a watchdog, to cancel the requests for non-responsive processes. |
224 BrowserThread::PostDelayedTask( | 225 BrowserThread::PostDelayedTask( |
225 BrowserThread::UI, FROM_HERE, | 226 BrowserThread::UI, FROM_HERE, |
226 base::Bind(&RequestContext::Unregister, sequence_number), | 227 base::Bind(&RequestContext::Unregister, sequence_number), |
227 base::TimeDelta::FromMinutes(1)); | 228 base::TimeDelta::FromMinutes(1)); |
228 } | 229 } |
229 | 230 |
231 // static | |
232 void TrackingSynchronizer::OnProfilingPhaseCompleted( | |
233 ProfilerEventProto::ProfilerEvent profiling_event) { | |
234 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
235 | |
236 if (!g_tracking_synchronizer) { | |
237 // System teardown is happening. | |
238 return; | |
239 } | |
240 | |
241 g_tracking_synchronizer->NotifyAllProcessesOfProfilingPhaseCompletion( | |
242 profiling_event); | |
243 } | |
244 | |
230 void TrackingSynchronizer::OnPendingProcesses(int sequence_number, | 245 void TrackingSynchronizer::OnPendingProcesses(int sequence_number, |
231 int pending_processes, | 246 int pending_processes, |
232 bool end) { | 247 bool end) { |
233 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 248 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
234 | 249 |
235 RequestContext* request = RequestContext::GetRequestContext(sequence_number); | 250 RequestContext* request = RequestContext::GetRequestContext(sequence_number); |
236 if (!request) | 251 if (!request) |
237 return; | 252 return; |
238 request->AddProcessesPending(pending_processes); | 253 request->AddProcessesPending(pending_processes); |
239 request->SetReceivedProcessGroupCount(end); | 254 request->SetReceivedProcessGroupCount(end); |
(...skipping 14 matching lines...) Expand all Loading... | |
254 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 269 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
255 | 270 |
256 int sequence_number = GetNextAvailableSequenceNumber(); | 271 int sequence_number = GetNextAvailableSequenceNumber(); |
257 | 272 |
258 RequestContext* request = | 273 RequestContext* request = |
259 RequestContext::Register(sequence_number, callback_object); | 274 RequestContext::Register(sequence_number, callback_object); |
260 | 275 |
261 // Increment pending process count for sending browser's profiler data. | 276 // Increment pending process count for sending browser's profiler data. |
262 request->IncrementProcessesPending(); | 277 request->IncrementProcessesPending(); |
263 | 278 |
279 const int current_profiling_phase = phase_completion_events_sequence_.size(); | |
280 | |
264 #if !defined(OS_IOS) | 281 #if !defined(OS_IOS) |
265 // Get profiler data from renderer and browser child processes. | 282 // Get profiler data from renderer and browser child processes. |
266 content::ProfilerController::GetInstance()->GetProfilerData(sequence_number); | 283 content::ProfilerController::GetInstance()->GetProfilerData( |
284 sequence_number, current_profiling_phase); | |
267 #endif | 285 #endif |
268 | 286 |
269 // Send process data snapshot from browser process. | 287 // Send process data snapshot from browser process. |
270 tracked_objects::ProcessDataSnapshot process_data_snapshot; | 288 tracked_objects::ProcessDataSnapshot process_data_snapshot; |
271 tracked_objects::ThreadData::Snapshot(&process_data_snapshot); | 289 tracked_objects::ThreadData::Snapshot(current_profiling_phase, |
290 &process_data_snapshot); | |
291 | |
272 DecrementPendingProcessesAndSendData(sequence_number, process_data_snapshot, | 292 DecrementPendingProcessesAndSendData(sequence_number, process_data_snapshot, |
273 content::PROCESS_TYPE_BROWSER); | 293 content::PROCESS_TYPE_BROWSER); |
274 | 294 |
275 return sequence_number; | 295 return sequence_number; |
276 } | 296 } |
277 | 297 |
298 void TrackingSynchronizer::RegisterPhaseCompletion( | |
299 ProfilerEventProto::ProfilerEvent profiling_event) { | |
300 phase_completion_events_sequence_.push_back(profiling_event); | |
301 phase_start_times_.push_back(clock_->NowTicks()); | |
302 } | |
303 | |
304 void TrackingSynchronizer::NotifyAllProcessesOfProfilingPhaseCompletion( | |
305 ProfilerEventProto::ProfilerEvent profiling_event) { | |
306 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
307 | |
308 if (variations::GetVariationParamValue("UMALogPhasedProfiling", | |
309 "send_split_profiles") == "false") { | |
310 return; | |
311 } | |
312 | |
313 int profiling_phase = phase_completion_events_sequence_.size(); | |
314 | |
315 // If you hit this check, stop and think. You just added a new profiling | |
316 // phase. Each profiling phase takes additional memory in DeathData's list of | |
317 // snapshots. We cannot grow it indefinitely. Consider collapsing older phases | |
318 // after they were sent to UMA server, or other ways to save memory. | |
319 DCHECK(profiling_phase < 1); | |
Alexei Svitkine (slow)
2015/04/15 19:22:50
DCHECK_LT?
vadimt
2015/04/15 19:52:15
Done.
| |
320 | |
321 RegisterPhaseCompletion(profiling_event); | |
322 | |
323 #if !defined(OS_IOS) | |
324 // Notify renderer and browser child processes. | |
325 content::ProfilerController::GetInstance()->OnProfilingPhaseCompleted( | |
326 profiling_phase); | |
327 #endif | |
328 | |
329 // Notify browser process. | |
330 tracked_objects::ThreadData::OnProfilingPhaseCompleted(profiling_phase); | |
331 } | |
332 | |
278 void TrackingSynchronizer::SendData( | 333 void TrackingSynchronizer::SendData( |
279 const tracked_objects::ProcessDataSnapshot& profiler_data, | 334 const tracked_objects::ProcessDataSnapshot& profiler_data, |
280 content::ProcessType process_type, | 335 content::ProcessType process_type, |
281 base::TimeTicks now, | |
282 TrackingSynchronizerObserver* observer) const { | 336 TrackingSynchronizerObserver* observer) const { |
283 // We are going to loop though past profiling phases and notify the request | 337 // We are going to loop though past profiling phases and notify the request |
284 // about each phase that is contained in profiler_data. past_events | 338 // about each phase that is contained in profiler_data. past_events |
285 // will track the set of past profiling events as we go. | 339 // will track the set of past profiling events as we go. |
286 ProfilerEvents past_events; | 340 ProfilerEvents past_events; |
287 | 341 |
288 // Go through all completed phases, and through the current one. The current | 342 // Go through all completed phases, and through the current one. The current |
289 // one is not in phase_completion_events_sequence_, but note the <= | 343 // one is not in phase_completion_events_sequence_, but note the <= |
290 // comparison. | 344 // comparison. |
291 for (size_t phase = 0; phase <= phase_completion_events_sequence_.size(); | 345 for (size_t phase = 0; phase <= phase_completion_events_sequence_.size(); |
292 ++phase) { | 346 ++phase) { |
293 auto it = profiler_data.phased_process_data_snapshots.find(phase); | 347 auto it = profiler_data.phased_snapshots.find(phase); |
294 | 348 |
295 if (it != profiler_data.phased_process_data_snapshots.end()) { | 349 if (it != profiler_data.phased_snapshots.end()) { |
296 // If the phase is contained in the received snapshot, notify the | 350 // If the phase is contained in the received snapshot, notify the |
297 // request. | 351 // request. |
298 const base::TimeDelta phase_start = | 352 const base::TimeTicks phase_start = phase_start_times_[phase]; |
299 phase_start_times_[phase] - start_time_; | 353 const base::TimeTicks phase_finish = phase + 1 < phase_start_times_.size() |
300 const base::TimeDelta phase_finish = | 354 ? phase_start_times_[phase + 1] |
301 (phase + 1 < phase_start_times_.size() ? phase_start_times_[phase + 1] | 355 : clock_->NowTicks(); |
302 : now) - | 356 observer->ReceivedProfilerData( |
303 start_time_; | 357 ProfilerDataAttributes(phase, profiler_data.process_id, process_type, |
304 observer->ReceivedProfilerData(it->second, profiler_data.process_id, | 358 phase_start, phase_finish), |
305 process_type, phase, phase_start, | 359 it->second, past_events); |
306 phase_finish, past_events); | |
307 } | 360 } |
308 | 361 |
309 if (phase < phase_completion_events_sequence_.size()) { | 362 if (phase < phase_completion_events_sequence_.size()) { |
310 past_events.push_back(phase_completion_events_sequence_[phase]); | 363 past_events.push_back(phase_completion_events_sequence_[phase]); |
311 } | 364 } |
312 } | 365 } |
313 } | 366 } |
314 | 367 |
315 void TrackingSynchronizer::DecrementPendingProcessesAndSendData( | 368 void TrackingSynchronizer::DecrementPendingProcessesAndSendData( |
316 int sequence_number, | 369 int sequence_number, |
317 const tracked_objects::ProcessDataSnapshot& profiler_data, | 370 const tracked_objects::ProcessDataSnapshot& profiler_data, |
318 content::ProcessType process_type) { | 371 content::ProcessType process_type) { |
319 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 372 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
320 | 373 |
321 RequestContext* request = RequestContext::GetRequestContext(sequence_number); | 374 RequestContext* request = RequestContext::GetRequestContext(sequence_number); |
322 if (!request) | 375 if (!request) |
323 return; | 376 return; |
324 | 377 |
325 TrackingSynchronizerObserver* observer = request->callback_object_.get(); | 378 TrackingSynchronizerObserver* observer = request->callback_object_.get(); |
326 if (observer) | 379 if (observer) |
327 SendData(profiler_data, process_type, base::TimeTicks::Now(), observer); | 380 SendData(profiler_data, process_type, observer); |
328 | 381 |
329 // Delete request if we have heard back from all child processes. | 382 // Delete request if we have heard back from all child processes. |
330 request->DecrementProcessesPending(); | 383 request->DecrementProcessesPending(); |
331 request->DeleteIfAllDone(); | 384 request->DeleteIfAllDone(); |
332 } | 385 } |
333 | 386 |
334 int TrackingSynchronizer::GetNextAvailableSequenceNumber() { | 387 int TrackingSynchronizer::GetNextAvailableSequenceNumber() { |
335 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 388 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
336 | 389 |
337 ++last_used_sequence_number_; | 390 ++last_used_sequence_number_; |
338 | 391 |
339 // Watch out for wrapping to a negative number. | 392 // Watch out for wrapping to a negative number. |
340 if (last_used_sequence_number_ < 0) | 393 if (last_used_sequence_number_ < 0) |
341 last_used_sequence_number_ = 1; | 394 last_used_sequence_number_ = 1; |
342 return last_used_sequence_number_; | 395 return last_used_sequence_number_; |
343 } | 396 } |
344 | 397 |
345 } // namespace metrics | 398 } // namespace metrics |
OLD | NEW |