Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / components / metrics / profiler / tracking_synchronizer.cc
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.
4
5 #include "components/metrics/profiler/tracking_synchronizer.h"
6
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"
15
16 using base::TimeTicks;
17 using content::BrowserThread;
18
19 namespace metrics {
20
21 namespace {
22
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;
29
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;
36
37 }  // namespace
38
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;
45
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) {
53   }
54   ~RequestContext() {}
55
56   void SetReceivedProcessGroupCount(bool done) {
57     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
58     received_process_group_count_ = done;
59   }
60
61   // Methods for book keeping of processes_pending_.
62   void IncrementProcessesPending() {
63     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
64     ++processes_pending_;
65   }
66
67   void AddProcessesPending(int processes_pending) {
68     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
69     processes_pending_ += processes_pending;
70   }
71
72   void DecrementProcessesPending() {
73     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
74     --processes_pending_;
75   }
76
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));
83
84     if (processes_pending_ <= 0 && received_process_group_count_)
85       RequestContext::Unregister(sequence_number_);
86   }
87
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));
94
95     RequestContext* request = new RequestContext(
96         callback_object, sequence_number);
97     outstanding_requests_.Get()[sequence_number] = request;
98
99     return request;
100   }
101
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));
106
107     RequestContextMap::iterator it =
108         outstanding_requests_.Get().find(sequence_number);
109     if (it == outstanding_requests_.Get().end())
110       return NULL;
111
112     RequestContext* request = it->second;
113     DCHECK_EQ(sequence_number, request->sequence_number_);
114     return request;
115   }
116
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));
122
123     RequestContextMap::iterator it =
124         outstanding_requests_.Get().find(sequence_number);
125     if (it == outstanding_requests_.Get().end())
126       return;
127
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_;
132
133     if (request->callback_object_.get())
134       request->callback_object_->FinishedReceivingProfilerData();
135
136     delete request;
137     outstanding_requests_.Get().erase(it);
138
139     UMA_HISTOGRAM_BOOLEAN("Profiling.ReceivedProcessGroupCount",
140                           received_process_group_count);
141     UMA_HISTOGRAM_COUNTS("Profiling.PendingProcessNotResponding",
142                          unresponsive_processes);
143   }
144
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);
152     }
153   }
154
155   // Requests are made to asynchronously send data to the |callback_object_|.
156   base::WeakPtr<TrackingSynchronizerObserver> callback_object_;
157
158   // The sequence number used by the most recent update request to contact all
159   // processes.
160   int sequence_number_;
161
162   // Indicates if we have received all pending processes count.
163   bool received_process_group_count_;
164
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_;
168
169   // Map of all outstanding RequestContexts, from sequence_number_ to
170   // RequestContext.
171   static base::LazyInstance<RequestContextMap>::Leaky outstanding_requests_;
172 };
173
174 // static
175 base::LazyInstance
176     <TrackingSynchronizer::RequestContext::RequestContextMap>::Leaky
177         TrackingSynchronizer::RequestContext::outstanding_requests_ =
178             LAZY_INSTANCE_INITIALIZER;
179
180 // TrackingSynchronizer methods and members.
181
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);
187 }
188
189 TrackingSynchronizer::~TrackingSynchronizer() {
190   content::ProfilerController::GetInstance()->Unregister(this);
191
192   // Just in case we have any pending tasks, clear them out.
193   RequestContext::OnShutdown();
194
195   g_tracking_synchronizer = NULL;
196 }
197
198 // static
199 void TrackingSynchronizer::FetchProfilerDataAsynchronously(
200     const base::WeakPtr<TrackingSynchronizerObserver>& callback_object) {
201   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
202
203   if (!g_tracking_synchronizer) {
204     // System teardown is happening.
205     return;
206   }
207
208   int sequence_number = g_tracking_synchronizer->RegisterAndNotifyAllProcesses(
209       callback_object);
210
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));
217 }
218
219 void TrackingSynchronizer::OnPendingProcesses(int sequence_number,
220                                               int pending_processes,
221                                               bool end) {
222   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
223
224   RequestContext* request = RequestContext::GetRequestContext(sequence_number);
225   if (!request)
226     return;
227   request->AddProcessesPending(pending_processes);
228   request->SetReceivedProcessGroupCount(end);
229   request->DeleteIfAllDone();
230 }
231
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);
239 }
240
241 int TrackingSynchronizer::RegisterAndNotifyAllProcesses(
242     const base::WeakPtr<TrackingSynchronizerObserver>& callback_object) {
243   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
244
245   int sequence_number = GetNextAvailableSequenceNumber();
246
247   RequestContext* request =
248       RequestContext::Register(sequence_number, callback_object);
249
250   // Increment pending process count for sending browser's profiler data.
251   request->IncrementProcessesPending();
252
253   // Get profiler data from renderer and browser child processes.
254   content::ProfilerController::GetInstance()->GetProfilerData(sequence_number);
255
256   // Send profiler_data from browser process.
257   tracked_objects::ProcessDataSnapshot process_data;
258   tracked_objects::ThreadData::Snapshot(false, &process_data);
259   DecrementPendingProcessesAndSendData(sequence_number, process_data,
260                                        content::PROCESS_TYPE_BROWSER);
261
262   return sequence_number;
263 }
264
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));
270
271   RequestContext* request = RequestContext::GetRequestContext(sequence_number);
272   if (!request)
273     return;
274
275   if (request->callback_object_.get()) {
276     request->callback_object_
277         ->ReceivedProfilerData(profiler_data, process_type);
278   }
279
280   // Delete request if we have heard back from all child processes.
281   request->DecrementProcessesPending();
282   request->DeleteIfAllDone();
283 }
284
285 int TrackingSynchronizer::GetNextAvailableSequenceNumber() {
286   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
287
288   ++last_used_sequence_number_;
289
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_;
294 }
295
296 }  // namespace metrics