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