Update V8 to version 4.6.62.
[chromium-blink-merge.git] / components / metrics / profiler / tracking_synchronizer.cc
blobb0f63b515d6f8ccb99af888ba5ec0161e749c999
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.
5 #include "components/metrics/profiler/tracking_synchronizer.h"
7 #include "base/bind.h"
8 #include "base/metrics/histogram.h"
9 #include "base/threading/thread.h"
10 #include "base/tracked_objects.h"
11 #include "components/metrics/profiler/tracking_synchronizer_observer.h"
12 #include "components/variations/variations_associated_data.h"
13 #include "content/public/browser/browser_thread.h"
14 #include "content/public/browser/profiler_controller.h"
15 #include "content/public/common/process_type.h"
17 using base::TimeTicks;
18 using content::BrowserThread;
20 namespace metrics {
22 namespace {
24 // Negative numbers are never used as sequence numbers. We explicitly pick a
25 // negative number that is "so negative" that even when we add one (as is done
26 // when we generated the next sequence number) that it will still be negative.
27 // We have code that handles wrapping around on an overflow into negative
28 // territory.
29 const int kNeverUsableSequenceNumber = -2;
31 // This singleton instance should be started during the single threaded
32 // portion of main(). It initializes globals to provide support for all future
33 // calls. This object is created on the UI thread, and it is destroyed after
34 // all the other threads have gone away. As a result, it is ok to call it
35 // from the UI thread, or for about:profiler.
36 static TrackingSynchronizer* g_tracking_synchronizer = NULL;
38 } // namespace
40 // The "RequestContext" structure describes an individual request received
41 // from the UI. All methods are accessible on UI thread.
42 class TrackingSynchronizer::RequestContext {
43 public:
44 // A map from sequence_number_ to the actual RequestContexts.
45 typedef std::map<int, RequestContext*> RequestContextMap;
47 RequestContext(
48 const base::WeakPtr<TrackingSynchronizerObserver>& callback_object,
49 int sequence_number)
50 : callback_object_(callback_object),
51 sequence_number_(sequence_number),
52 received_process_group_count_(0),
53 processes_pending_(0) {
55 ~RequestContext() {}
57 void SetReceivedProcessGroupCount(bool done) {
58 DCHECK_CURRENTLY_ON(BrowserThread::UI);
59 received_process_group_count_ = done;
62 // Methods for book keeping of processes_pending_.
63 void IncrementProcessesPending() {
64 DCHECK_CURRENTLY_ON(BrowserThread::UI);
65 ++processes_pending_;
68 void AddProcessesPending(int processes_pending) {
69 DCHECK_CURRENTLY_ON(BrowserThread::UI);
70 processes_pending_ += processes_pending;
73 void DecrementProcessesPending() {
74 DCHECK_CURRENTLY_ON(BrowserThread::UI);
75 --processes_pending_;
78 // Records that we are waiting for one less tracking data from a process for
79 // the given sequence number. If |received_process_group_count_| and
80 // |processes_pending_| are zero, then delete the current object by calling
81 // Unregister.
82 void DeleteIfAllDone() {
83 DCHECK_CURRENTLY_ON(BrowserThread::UI);
85 if (processes_pending_ <= 0 && received_process_group_count_)
86 RequestContext::Unregister(sequence_number_);
89 // Register |callback_object| in |outstanding_requests_| map for the given
90 // |sequence_number|.
91 static RequestContext* Register(
92 int sequence_number,
93 const base::WeakPtr<TrackingSynchronizerObserver>& callback_object) {
94 DCHECK_CURRENTLY_ON(BrowserThread::UI);
96 RequestContext* request = new RequestContext(
97 callback_object, sequence_number);
98 outstanding_requests_.Get()[sequence_number] = request;
100 return request;
103 // Find the |RequestContext| in |outstanding_requests_| map for the given
104 // |sequence_number|.
105 static RequestContext* GetRequestContext(int sequence_number) {
106 DCHECK_CURRENTLY_ON(BrowserThread::UI);
108 RequestContextMap::iterator it =
109 outstanding_requests_.Get().find(sequence_number);
110 if (it == outstanding_requests_.Get().end())
111 return NULL;
113 RequestContext* request = it->second;
114 DCHECK_EQ(sequence_number, request->sequence_number_);
115 return request;
118 // Delete the entry for the given |sequence_number| from
119 // |outstanding_requests_| map. This method is called when all changes have
120 // been acquired, or when the wait time expires (whichever is sooner).
121 static void Unregister(int sequence_number) {
122 DCHECK_CURRENTLY_ON(BrowserThread::UI);
124 RequestContextMap::iterator it =
125 outstanding_requests_.Get().find(sequence_number);
126 if (it == outstanding_requests_.Get().end())
127 return;
129 RequestContext* request = it->second;
130 DCHECK_EQ(sequence_number, request->sequence_number_);
131 bool received_process_group_count = request->received_process_group_count_;
132 int unresponsive_processes = request->processes_pending_;
134 if (request->callback_object_.get())
135 request->callback_object_->FinishedReceivingProfilerData();
137 delete request;
138 outstanding_requests_.Get().erase(it);
140 UMA_HISTOGRAM_BOOLEAN("Profiling.ReceivedProcessGroupCount",
141 received_process_group_count);
142 UMA_HISTOGRAM_COUNTS("Profiling.PendingProcessNotResponding",
143 unresponsive_processes);
146 // Delete all the entries in |outstanding_requests_| map.
147 static void OnShutdown() {
148 // Just in case we have any pending tasks, clear them out.
149 while (!outstanding_requests_.Get().empty()) {
150 RequestContextMap::iterator it = outstanding_requests_.Get().begin();
151 delete it->second;
152 outstanding_requests_.Get().erase(it);
156 // Requests are made to asynchronously send data to the |callback_object_|.
157 base::WeakPtr<TrackingSynchronizerObserver> callback_object_;
159 // The sequence number used by the most recent update request to contact all
160 // processes.
161 int sequence_number_;
163 // Indicates if we have received all pending processes count.
164 bool received_process_group_count_;
166 // The number of pending processes (browser, all renderer processes and
167 // browser child processes) that have not yet responded to requests.
168 int processes_pending_;
170 // Map of all outstanding RequestContexts, from sequence_number_ to
171 // RequestContext.
172 static base::LazyInstance<RequestContextMap>::Leaky outstanding_requests_;
175 // static
176 base::LazyInstance
177 <TrackingSynchronizer::RequestContext::RequestContextMap>::Leaky
178 TrackingSynchronizer::RequestContext::outstanding_requests_ =
179 LAZY_INSTANCE_INITIALIZER;
181 // TrackingSynchronizer methods and members.
183 TrackingSynchronizer::TrackingSynchronizer(scoped_ptr<base::TickClock> clock)
184 : last_used_sequence_number_(kNeverUsableSequenceNumber),
185 clock_(clock.Pass()) {
186 DCHECK(!g_tracking_synchronizer);
187 g_tracking_synchronizer = this;
188 phase_start_times_.push_back(clock_->NowTicks());
190 #if !defined(OS_IOS)
191 // TODO: This ifdef and other ifdefs for OS_IOS in this file are only
192 // short-term hacks to make this compile on iOS, and the proper solution is to
193 // refactor to remove content dependencies from shared code.
194 // See crbug/472210.
195 content::ProfilerController::GetInstance()->Register(this);
196 #endif
199 TrackingSynchronizer::~TrackingSynchronizer() {
200 #if !defined(OS_IOS)
201 content::ProfilerController::GetInstance()->Unregister(this);
202 #endif
204 // Just in case we have any pending tasks, clear them out.
205 RequestContext::OnShutdown();
207 g_tracking_synchronizer = NULL;
210 // static
211 void TrackingSynchronizer::FetchProfilerDataAsynchronously(
212 const base::WeakPtr<TrackingSynchronizerObserver>& callback_object) {
213 DCHECK_CURRENTLY_ON(BrowserThread::UI);
215 if (!g_tracking_synchronizer) {
216 // System teardown is happening.
217 return;
220 int sequence_number = g_tracking_synchronizer->RegisterAndNotifyAllProcesses(
221 callback_object);
223 // Post a task that would be called after waiting for wait_time. This acts
224 // as a watchdog, to cancel the requests for non-responsive processes.
225 BrowserThread::PostDelayedTask(
226 BrowserThread::UI, FROM_HERE,
227 base::Bind(&RequestContext::Unregister, sequence_number),
228 base::TimeDelta::FromMinutes(1));
231 // static
232 void TrackingSynchronizer::OnProfilingPhaseCompleted(
233 ProfilerEventProto::ProfilerEvent profiling_event) {
234 DCHECK_CURRENTLY_ON(BrowserThread::UI);
236 if (!g_tracking_synchronizer) {
237 // System teardown is happening.
238 return;
241 g_tracking_synchronizer->NotifyAllProcessesOfProfilingPhaseCompletion(
242 profiling_event);
245 void TrackingSynchronizer::OnPendingProcesses(int sequence_number,
246 int pending_processes,
247 bool end) {
248 DCHECK_CURRENTLY_ON(BrowserThread::UI);
250 RequestContext* request = RequestContext::GetRequestContext(sequence_number);
251 if (!request)
252 return;
253 request->AddProcessesPending(pending_processes);
254 request->SetReceivedProcessGroupCount(end);
255 request->DeleteIfAllDone();
258 void TrackingSynchronizer::OnProfilerDataCollected(
259 int sequence_number,
260 const tracked_objects::ProcessDataSnapshot& profiler_data,
261 content::ProcessType process_type) {
262 DCHECK_CURRENTLY_ON(BrowserThread::UI);
263 DecrementPendingProcessesAndSendData(sequence_number, profiler_data,
264 process_type);
267 int TrackingSynchronizer::RegisterAndNotifyAllProcesses(
268 const base::WeakPtr<TrackingSynchronizerObserver>& callback_object) {
269 DCHECK_CURRENTLY_ON(BrowserThread::UI);
271 int sequence_number = GetNextAvailableSequenceNumber();
273 RequestContext* request =
274 RequestContext::Register(sequence_number, callback_object);
276 // Increment pending process count for sending browser's profiler data.
277 request->IncrementProcessesPending();
279 const int current_profiling_phase = phase_completion_events_sequence_.size();
281 #if !defined(OS_IOS)
282 // Get profiler data from renderer and browser child processes.
283 content::ProfilerController::GetInstance()->GetProfilerData(
284 sequence_number, current_profiling_phase);
285 #else
286 // On non-iOS platforms, |OnPendingProcesses()| is called from
287 // |content::ProfilerController|. On iOS, manually call the method to indicate
288 // that there is no need to wait for data from child processes. On iOS, there
289 // is only the main browser process.
290 OnPendingProcesses(sequence_number, 0, true);
291 #endif // !defined(OS_IOS)
293 // Send process data snapshot from browser process.
294 tracked_objects::ProcessDataSnapshot process_data_snapshot;
295 tracked_objects::ThreadData::Snapshot(current_profiling_phase,
296 &process_data_snapshot);
298 DecrementPendingProcessesAndSendData(sequence_number, process_data_snapshot,
299 content::PROCESS_TYPE_BROWSER);
301 return sequence_number;
304 void TrackingSynchronizer::RegisterPhaseCompletion(
305 ProfilerEventProto::ProfilerEvent profiling_event) {
306 phase_completion_events_sequence_.push_back(profiling_event);
307 phase_start_times_.push_back(clock_->NowTicks());
310 void TrackingSynchronizer::NotifyAllProcessesOfProfilingPhaseCompletion(
311 ProfilerEventProto::ProfilerEvent profiling_event) {
312 DCHECK_CURRENTLY_ON(BrowserThread::UI);
314 if (variations::GetVariationParamValue("UMALogPhasedProfiling",
315 "send_split_profiles") == "false") {
316 return;
319 int profiling_phase = phase_completion_events_sequence_.size();
321 // If you hit this check, stop and think. You just added a new profiling
322 // phase. Each profiling phase takes additional memory in DeathData's list of
323 // snapshots. We cannot grow it indefinitely. Consider collapsing older phases
324 // after they were sent to UMA server, or other ways to save memory.
325 DCHECK_LT(profiling_phase, 1);
327 RegisterPhaseCompletion(profiling_event);
329 #if !defined(OS_IOS)
330 // Notify renderer and browser child processes.
331 content::ProfilerController::GetInstance()->OnProfilingPhaseCompleted(
332 profiling_phase);
333 #endif
335 // Notify browser process.
336 tracked_objects::ThreadData::OnProfilingPhaseCompleted(profiling_phase);
339 void TrackingSynchronizer::SendData(
340 const tracked_objects::ProcessDataSnapshot& profiler_data,
341 content::ProcessType process_type,
342 TrackingSynchronizerObserver* observer) const {
343 // We are going to loop though past profiling phases and notify the request
344 // about each phase that is contained in profiler_data. past_events
345 // will track the set of past profiling events as we go.
346 ProfilerEvents past_events;
348 // Go through all completed phases, and through the current one. The current
349 // one is not in phase_completion_events_sequence_, but note the <=
350 // comparison.
351 for (size_t phase = 0; phase <= phase_completion_events_sequence_.size();
352 ++phase) {
353 auto it = profiler_data.phased_snapshots.find(phase);
355 if (it != profiler_data.phased_snapshots.end()) {
356 // If the phase is contained in the received snapshot, notify the
357 // request.
358 const base::TimeTicks phase_start = phase_start_times_[phase];
359 const base::TimeTicks phase_finish = phase + 1 < phase_start_times_.size()
360 ? phase_start_times_[phase + 1]
361 : clock_->NowTicks();
362 observer->ReceivedProfilerData(
363 ProfilerDataAttributes(phase, profiler_data.process_id, process_type,
364 phase_start, phase_finish),
365 it->second, past_events);
368 if (phase < phase_completion_events_sequence_.size()) {
369 past_events.push_back(phase_completion_events_sequence_[phase]);
374 void TrackingSynchronizer::DecrementPendingProcessesAndSendData(
375 int sequence_number,
376 const tracked_objects::ProcessDataSnapshot& profiler_data,
377 content::ProcessType process_type) {
378 DCHECK_CURRENTLY_ON(BrowserThread::UI);
380 RequestContext* request = RequestContext::GetRequestContext(sequence_number);
381 if (!request)
382 return;
384 TrackingSynchronizerObserver* observer = request->callback_object_.get();
385 if (observer)
386 SendData(profiler_data, process_type, observer);
388 // Delete request if we have heard back from all child processes.
389 request->DecrementProcessesPending();
390 request->DeleteIfAllDone();
393 int TrackingSynchronizer::GetNextAvailableSequenceNumber() {
394 DCHECK_CURRENTLY_ON(BrowserThread::UI);
396 ++last_used_sequence_number_;
398 // Watch out for wrapping to a negative number.
399 if (last_used_sequence_number_ < 0)
400 last_used_sequence_number_ = 1;
401 return last_used_sequence_number_;
404 } // namespace metrics