Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(186)

Side by Side Diff: chrome/browser/metrics/tracking_synchronizer.cc

Issue 8413009: Changes to upload tracked_objects data from all renderer (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 9 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
Property Changes:
Added: svn:executable
+ *
OLDNEW
(Empty)
1 // Copyright (c) 2011 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 "chrome/browser/metrics/tracking_synchronizer.h"
6
7 #include "base/json/json_reader.h"
8 #include "base/json/json_writer.h"
9 #include "base/logging.h"
10 #include "base/metrics/histogram.h"
11 #include "base/threading/thread.h"
12 #include "base/tracked_objects.h"
13 #include "chrome/common/chrome_constants.h"
14 #include "chrome/common/render_messages.h"
15 #include "content/browser/renderer_host/render_process_host.h"
16 #include "content/public/browser/browser_thread.h"
17
18 using base::TimeTicks;
19
20 namespace chrome_browser_metrics {
21
22 // Negative numbers are never used as sequence numbers. We explicitly pick a
23 // negative number that is "so negative" that even when we add one (as is done
24 // when we generated the next sequence number) that it will still be negative.
25 // We have code that handles wrapping around on an overflow into negative
26 // territory.
27 static const int kNeverUsableSequenceNumber = -2;
28
29 TrackingSynchronizer::TrackingSynchronizer()
30 : last_used_sequence_number_(kNeverUsableSequenceNumber) {
jar (doing other things) 2011/11/03 06:23:15 nit: Indent the colon for an initializer list 4 sp
ramant (doing other things) 2011/11/03 21:51:39 Done.
31 DCHECK(tracking_synchronizer_ == NULL);
32 tracking_synchronizer_ = this;
33 }
34
35 TrackingSynchronizer::~TrackingSynchronizer() {
36 // Just in case we have any pending tasks, clear them out.
37 while (!outstanding_requests_.empty()) {
38 RequestContextMap::iterator it = outstanding_requests_.begin();
39 delete it->second;
40 outstanding_requests_.erase(it);
41 }
42
43 tracking_synchronizer_ = NULL;
44 }
45
46 // static
47 TrackingSynchronizer* TrackingSynchronizer::CurrentSynchronizer() {
48 DCHECK(tracking_synchronizer_ != NULL);
49 return tracking_synchronizer_;
jar (doing other things) 2011/11/03 06:23:15 You might want to DCHECK() that we're on the UI th
ramant (doing other things) 2011/11/03 21:51:39 Done.
50 }
51
52 // static
53 // Used for testing purposes only.
54 // TODO(rtenneti): DELETE it.
55 void TrackingSynchronizer::FetchTrackingDataSynchronously(std::string* output) {
56 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
57
58 TrackingSynchronizer* current_synchronizer = CurrentSynchronizer();
59 if (!current_synchronizer)
60 return;
61
62 scoped_refptr<CallbackObject> callback_object(new CallbackObject);
63
64 // Set the tracking status for testing purposes.
65 bool enable = tracked_objects::ThreadData::tracking_status();
66 SetTrackingStatus(enable);
67
68 // Get the data for testing purposes.
69 FetchTrackingDataAsynchronously(callback_object);
70
71 if (!callback_object->GetValue())
72 return;
73
74 // Send whatever data we have for testing purposes.
75 base::JSONWriter::Write(callback_object->GetValue(), false, output);
76 }
77
78 // static
79 void TrackingSynchronizer::FetchTrackingDataAsynchronously(
80 scoped_refptr<CallbackObject> callback_object) {
81 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
82 DCHECK(callback_object != NULL);
83
84 TrackingSynchronizer* current_synchronizer = CurrentSynchronizer();
85
86 if (current_synchronizer == NULL) {
87 // System teardown is happening.
88 return;
89 }
90
91 int sequence_number = current_synchronizer->RegisterAndNotifyAllProcesses(
92 callback_object);
93
94 // Post a task that would be called after waiting for wait_time. This acts
95 // as a watchdog, to cancel the requests for non-responsive processes.
96 BrowserThread::PostDelayedTask(
97 BrowserThread::UI, FROM_HERE,
98 NewRunnableMethod(
99 current_synchronizer,
100 &TrackingSynchronizer::ForceTrackingSynchronizationDoneCallback,
101 sequence_number),
102 60000);
103 }
104
105 // static
106 void TrackingSynchronizer::SetTrackingStatus(bool enable) {
107 // To iterate over all processes, or to send messages to the hosts, we need
108 // to be on the UI thread.
109 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
110
111 for (RenderProcessHost::iterator it(RenderProcessHost::AllHostsIterator());
112 !it.IsAtEnd(); it.Advance()) {
113 RenderProcessHost* render_process_host = it.GetCurrentValue();
114 DCHECK(render_process_host);
115 // Ignore processes that don't have a connection, such as crashed tabs.
116 if (!render_process_host->HasConnection())
117 continue;
118
119 render_process_host->Send(new ChromeViewMsg_SetTrackingStatus(enable));
120 }
121 }
122
123 // static
124 void TrackingSynchronizer::IsTrackingEnabled(int process_id) {
125 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
126 // To find the process, or to send messages to the hosts, we need to be on the
127 // UI thread.
128 BrowserThread::PostTask(
129 BrowserThread::UI, FROM_HERE,
130 NewRunnableFunction(
131 &TrackingSynchronizer::SetTrackingStatusInProcess, process_id));
132 }
133
134 // static
135 void TrackingSynchronizer::SetTrackingStatusInProcess(int process_id) {
136 // To find the process, or to send messages to the hosts, we need to be on the
137 // UI thread.
138 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
139
140 bool enable = tracked_objects::ThreadData::tracking_status();
141
142 RenderProcessHost* process = RenderProcessHost::FromID(process_id);
143 // Ignore processes that don't have a connection, such as crashed tabs.
144 if (!process || !process->HasConnection())
145 return;
146 process->Send(new ChromeViewMsg_SetTrackingStatus(enable));
147 }
148
149 // static
150 void TrackingSynchronizer::DeserializeTrackingList(
151 int sequence_number,
152 const std::string& tracking_data,
153 ChildProcessInfo::ProcessType process_type) {
154 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
155
156 TrackingSynchronizer* current_synchronizer = CurrentSynchronizer();
jar (doing other things) 2011/11/03 06:23:15 I think we need to bounce over to the UI thread be
ramant (doing other things) 2011/11/03 21:51:39 Done.
157 if (current_synchronizer == NULL)
158 return;
159
160 base::Value* value =
161 base::JSONReader().JsonToValue(tracking_data, false, true);
162 DCHECK(value->GetType() == base::Value::TYPE_DICTIONARY);
163 base::DictionaryValue* dictionary_value =
164 static_cast<DictionaryValue*>(value);
165 dictionary_value->SetString(
166 "process_type", ChildProcessInfo::GetTypeNameInEnglish(process_type));
167
168 // Send back the tracking data we have received from a process.
169 BrowserThread::PostTask(
170 BrowserThread::UI, FROM_HERE,
171 NewRunnableMethod(
172 current_synchronizer,
173 &TrackingSynchronizer::DecrementPendingProcessesAndSendData,
174 sequence_number,
175 dictionary_value));
176 }
177
178 int TrackingSynchronizer::RegisterAndNotifyAllProcesses(
179 scoped_refptr<CallbackObject> callback_object) {
180 // To iterate over all processes, or to send messages to the hosts, we need
181 // to be on the UI thread.
182 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
183
184 int sequence_number = GetNextAvailableSequenceNumber();
185
186 // Initialize processes_pending with one because we are going to send
187 // browser's ThreadData.
188 RequestContext* request = new RequestContext(
189 callback_object, sequence_number, 1, TimeTicks::Now());
190 outstanding_requests_[sequence_number] = request;
191
192 DCHECK_GT(request->processes_pending_, 0);
193 for (RenderProcessHost::iterator it(RenderProcessHost::AllHostsIterator());
194 !it.IsAtEnd(); it.Advance()) {
195 RenderProcessHost* render_process_host = it.GetCurrentValue();
196 DCHECK(render_process_host);
197 // Ignore processes that don't have a connection, such as crashed tabs.
198 if (!render_process_host->HasConnection())
199 continue;
200
201 ++request->processes_pending_;
202 if (!render_process_host->Send(
203 new ChromeViewMsg_GetRendererTrackedData(sequence_number))) {
204 DecrementPendingProcesses(sequence_number);
205 }
206 }
207
208 // Get the ThreadData for the browser process and send it back.
209 base::DictionaryValue* value = tracked_objects::ThreadData::ToValue();
210 const std::string process_type =
211 ChildProcessInfo::GetTypeNameInEnglish(ChildProcessInfo::BROWSER_PROCESS);
212 value->SetString("process_type", process_type);
213 value->SetInteger("process_id", base::GetCurrentProcId());
214 DCHECK_GT(request->processes_pending_, 0);
215 DecrementPendingProcessesAndSendData(sequence_number, value);
216
217 return sequence_number;
218 }
219
220 void TrackingSynchronizer::DecrementPendingProcessesAndSendData(
221 int sequence_number,
222 base::DictionaryValue* value) {
223 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
224
225 RequestContext* request = NULL;
226 bool completed = false;
227
228 RequestContextMap::iterator it =
229 outstanding_requests_.find(sequence_number);
230 if (it == outstanding_requests_.end())
231 return;
jar (doing other things) 2011/11/03 06:23:15 This will probably leak value. Probably delete it
ramant (doing other things) 2011/11/03 21:51:39 Done.
232
233 request = it->second;
jar (doing other things) 2011/11/03 06:23:15 nit: Move declarations on lines 225 down to here (
ramant (doing other things) 2011/11/03 21:51:39 Done.
234
235 DCHECK(sequence_number == request->sequence_number_);
236 if (--request->processes_pending_ <= 0)
237 completed = true;
238
239 if (value) {
240 // Transfers ownership of |value| to |callback_object_|.
241 request->callback_object_->SendData(value);
242 }
jar (doing other things) 2011/11/03 06:23:15 probably: else { delete value; }
ramant (doing other things) 2011/11/03 21:51:39 Done.
243
244 if (completed)
245 ForceTrackingSynchronizationDoneCallback(sequence_number);
246 }
247
248 void TrackingSynchronizer::DecrementPendingProcesses(int sequence_number) {
249 DecrementPendingProcessesAndSendData(sequence_number, NULL);
250 }
251
252 void TrackingSynchronizer::ForceTrackingSynchronizationDoneCallback(
253 int sequence_number) {
254 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
255
256 TimeTicks started;
257 int unresponsive_processes;
258 RequestContextMap::iterator it =
259 outstanding_requests_.find(sequence_number);
260 if (it == outstanding_requests_.end())
261 return;
262
263 RequestContext* request = it->second;
264
265 DCHECK(sequence_number == request->sequence_number_);
266
267 started = request->request_start_time_;
jar (doing other things) 2011/11/03 06:23:15 Do we need this anymore? Probably delete declarat
ramant (doing other things) 2011/11/03 21:51:39 Done.
268 unresponsive_processes = request->processes_pending_;
269
270 delete it->second;
271 outstanding_requests_.erase(it);
272
273 UMA_HISTOGRAM_COUNTS("Tracking.ProcessNotRespondingAsynchronous",
274 unresponsive_processes);
275 }
276
277 int TrackingSynchronizer::GetNextAvailableSequenceNumber() {
278 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
279
280 ++last_used_sequence_number_;
281
282 static const int kReservedSequenceNumber = 0;
jar (doing other things) 2011/11/03 06:23:15 Do you anticipate a need for this?
ramant (doing other things) 2011/11/03 21:51:39 Done.
283
284 // Watch out for wrapping to a negative number.
285 if (last_used_sequence_number_ < 0) {
286 // Bypass the reserved number, which is used when a process spontaneously
287 // decides to send some tracking data.
288 last_used_sequence_number_ = kReservedSequenceNumber + 1;
289 }
290 DCHECK_NE(last_used_sequence_number_, kReservedSequenceNumber);
291 return last_used_sequence_number_;
292 }
293
294 // static
295 TrackingSynchronizer* TrackingSynchronizer::tracking_synchronizer_ = NULL;
296
297 } // namespace chrome_browser_metrics
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698