Roll src/third_party/skia de7665a:76033be
[chromium-blink-merge.git] / components / metrics / profiler / tracking_synchronizer.cc
blob8d53bd2a7ec19f42df2336cd968f5dcf49eb89b2
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 "content/public/browser/browser_thread.h"
13 #include "content/public/browser/profiler_controller.h"
14 #include "content/public/common/process_type.h"
16 using base::TimeTicks;
17 using content::BrowserThread;
19 namespace metrics {
21 namespace {
23 // Negative numbers are never used as sequence numbers. We explicitly pick a
24 // negative number that is "so negative" that even when we add one (as is done
25 // when we generated the next sequence number) that it will still be negative.
26 // We have code that handles wrapping around on an overflow into negative
27 // territory.
28 const int kNeverUsableSequenceNumber = -2;
30 // This singleton instance should be started during the single threaded
31 // portion of main(). It initializes globals to provide support for all future
32 // calls. This object is created on the UI thread, and it is destroyed after
33 // all the other threads have gone away. As a result, it is ok to call it
34 // from the UI thread, or for about:profiler.
35 static TrackingSynchronizer* g_tracking_synchronizer = NULL;
37 } // namespace
39 // The "RequestContext" structure describes an individual request received
40 // from the UI. All methods are accessible on UI thread.
41 class TrackingSynchronizer::RequestContext {
42 public:
43 // A map from sequence_number_ to the actual RequestContexts.
44 typedef std::map<int, RequestContext*> RequestContextMap;
46 RequestContext(
47 const base::WeakPtr<TrackingSynchronizerObserver>& callback_object,
48 int sequence_number)
49 : callback_object_(callback_object),
50 sequence_number_(sequence_number),
51 received_process_group_count_(0),
52 processes_pending_(0) {
54 ~RequestContext() {}
56 void SetReceivedProcessGroupCount(bool done) {
57 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
58 received_process_group_count_ = done;
61 // Methods for book keeping of processes_pending_.
62 void IncrementProcessesPending() {
63 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
64 ++processes_pending_;
67 void AddProcessesPending(int processes_pending) {
68 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
69 processes_pending_ += processes_pending;
72 void DecrementProcessesPending() {
73 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
74 --processes_pending_;
77 // Records that we are waiting for one less tracking data from a process for
78 // the given sequence number. If |received_process_group_count_| and
79 // |processes_pending_| are zero, then delete the current object by calling
80 // Unregister.
81 void DeleteIfAllDone() {
82 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
84 if (processes_pending_ <= 0 && received_process_group_count_)
85 RequestContext::Unregister(sequence_number_);
88 // Register |callback_object| in |outstanding_requests_| map for the given
89 // |sequence_number|.
90 static RequestContext* Register(
91 int sequence_number,
92 const base::WeakPtr<TrackingSynchronizerObserver>& callback_object) {
93 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
95 RequestContext* request = new RequestContext(
96 callback_object, sequence_number);
97 outstanding_requests_.Get()[sequence_number] = request;
99 return request;
102 // Find the |RequestContext| in |outstanding_requests_| map for the given
103 // |sequence_number|.
104 static RequestContext* GetRequestContext(int sequence_number) {
105 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
107 RequestContextMap::iterator it =
108 outstanding_requests_.Get().find(sequence_number);
109 if (it == outstanding_requests_.Get().end())
110 return NULL;
112 RequestContext* request = it->second;
113 DCHECK_EQ(sequence_number, request->sequence_number_);
114 return request;
117 // Delete the entry for the given |sequence_number| from
118 // |outstanding_requests_| map. This method is called when all changes have
119 // been acquired, or when the wait time expires (whichever is sooner).
120 static void Unregister(int sequence_number) {
121 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
123 RequestContextMap::iterator it =
124 outstanding_requests_.Get().find(sequence_number);
125 if (it == outstanding_requests_.Get().end())
126 return;
128 RequestContext* request = it->second;
129 DCHECK_EQ(sequence_number, request->sequence_number_);
130 bool received_process_group_count = request->received_process_group_count_;
131 int unresponsive_processes = request->processes_pending_;
133 if (request->callback_object_.get())
134 request->callback_object_->FinishedReceivingProfilerData();
136 delete request;
137 outstanding_requests_.Get().erase(it);
139 UMA_HISTOGRAM_BOOLEAN("Profiling.ReceivedProcessGroupCount",
140 received_process_group_count);
141 UMA_HISTOGRAM_COUNTS("Profiling.PendingProcessNotResponding",
142 unresponsive_processes);
145 // Delete all the entries in |outstanding_requests_| map.
146 static void OnShutdown() {
147 // Just in case we have any pending tasks, clear them out.
148 while (!outstanding_requests_.Get().empty()) {
149 RequestContextMap::iterator it = outstanding_requests_.Get().begin();
150 delete it->second;
151 outstanding_requests_.Get().erase(it);
155 // Requests are made to asynchronously send data to the |callback_object_|.
156 base::WeakPtr<TrackingSynchronizerObserver> callback_object_;
158 // The sequence number used by the most recent update request to contact all
159 // processes.
160 int sequence_number_;
162 // Indicates if we have received all pending processes count.
163 bool received_process_group_count_;
165 // The number of pending processes (browser, all renderer processes and
166 // browser child processes) that have not yet responded to requests.
167 int processes_pending_;
169 // Map of all outstanding RequestContexts, from sequence_number_ to
170 // RequestContext.
171 static base::LazyInstance<RequestContextMap>::Leaky outstanding_requests_;
174 // static
175 base::LazyInstance
176 <TrackingSynchronizer::RequestContext::RequestContextMap>::Leaky
177 TrackingSynchronizer::RequestContext::outstanding_requests_ =
178 LAZY_INSTANCE_INITIALIZER;
180 // TrackingSynchronizer methods and members.
182 TrackingSynchronizer::TrackingSynchronizer()
183 : last_used_sequence_number_(kNeverUsableSequenceNumber) {
184 DCHECK(!g_tracking_synchronizer);
185 g_tracking_synchronizer = this;
186 content::ProfilerController::GetInstance()->Register(this);
189 TrackingSynchronizer::~TrackingSynchronizer() {
190 content::ProfilerController::GetInstance()->Unregister(this);
192 // Just in case we have any pending tasks, clear them out.
193 RequestContext::OnShutdown();
195 g_tracking_synchronizer = NULL;
198 // static
199 void TrackingSynchronizer::FetchProfilerDataAsynchronously(
200 const base::WeakPtr<TrackingSynchronizerObserver>& callback_object) {
201 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
203 if (!g_tracking_synchronizer) {
204 // System teardown is happening.
205 return;
208 int sequence_number = g_tracking_synchronizer->RegisterAndNotifyAllProcesses(
209 callback_object);
211 // Post a task that would be called after waiting for wait_time. This acts
212 // as a watchdog, to cancel the requests for non-responsive processes.
213 BrowserThread::PostDelayedTask(
214 BrowserThread::UI, FROM_HERE,
215 base::Bind(&RequestContext::Unregister, sequence_number),
216 base::TimeDelta::FromMinutes(1));
219 void TrackingSynchronizer::OnPendingProcesses(int sequence_number,
220 int pending_processes,
221 bool end) {
222 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
224 RequestContext* request = RequestContext::GetRequestContext(sequence_number);
225 if (!request)
226 return;
227 request->AddProcessesPending(pending_processes);
228 request->SetReceivedProcessGroupCount(end);
229 request->DeleteIfAllDone();
232 void TrackingSynchronizer::OnProfilerDataCollected(
233 int sequence_number,
234 const tracked_objects::ProcessDataSnapshot& profiler_data,
235 int process_type) {
236 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
237 DecrementPendingProcessesAndSendData(sequence_number, profiler_data,
238 process_type);
241 int TrackingSynchronizer::RegisterAndNotifyAllProcesses(
242 const base::WeakPtr<TrackingSynchronizerObserver>& callback_object) {
243 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
245 int sequence_number = GetNextAvailableSequenceNumber();
247 RequestContext* request =
248 RequestContext::Register(sequence_number, callback_object);
250 // Increment pending process count for sending browser's profiler data.
251 request->IncrementProcessesPending();
253 // Get profiler data from renderer and browser child processes.
254 content::ProfilerController::GetInstance()->GetProfilerData(sequence_number);
256 // Send profiler_data from browser process.
257 tracked_objects::ProcessDataSnapshot process_data;
258 tracked_objects::ThreadData::Snapshot(&process_data);
259 DecrementPendingProcessesAndSendData(sequence_number, process_data,
260 content::PROCESS_TYPE_BROWSER);
262 return sequence_number;
265 void TrackingSynchronizer::DecrementPendingProcessesAndSendData(
266 int sequence_number,
267 const tracked_objects::ProcessDataSnapshot& profiler_data,
268 int process_type) {
269 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
271 RequestContext* request = RequestContext::GetRequestContext(sequence_number);
272 if (!request)
273 return;
275 if (request->callback_object_.get()) {
276 request->callback_object_
277 ->ReceivedProfilerData(profiler_data, process_type);
280 // Delete request if we have heard back from all child processes.
281 request->DecrementProcessesPending();
282 request->DeleteIfAllDone();
285 int TrackingSynchronizer::GetNextAvailableSequenceNumber() {
286 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
288 ++last_used_sequence_number_;
290 // Watch out for wrapping to a negative number.
291 if (last_used_sequence_number_ < 0)
292 last_used_sequence_number_ = 1;
293 return last_used_sequence_number_;
296 } // namespace metrics