OLD | NEW |
---|---|
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 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 | 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 "chrome/browser/metrics/tracking_synchronizer.h" | 5 #include "chrome/browser/metrics/tracking_synchronizer.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/json/json_reader.h" | 8 #include "base/json/json_reader.h" |
9 #include "base/json/json_writer.h" | 9 #include "base/json/json_writer.h" |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
11 #include "base/metrics/histogram.h" | 11 #include "base/metrics/histogram.h" |
12 #include "base/threading/thread.h" | 12 #include "base/threading/thread.h" |
13 #include "base/tracked_objects.h" | 13 #include "base/tracked_objects.h" |
14 #include "chrome/browser/ui/webui/tracing_ui.h" | 14 #include "chrome/browser/ui/webui/tracing_ui.h" |
15 #include "chrome/common/chrome_constants.h" | 15 #include "chrome/common/chrome_constants.h" |
16 #include "chrome/common/render_messages.h" | 16 #include "chrome/common/render_messages.h" |
17 #include "content/browser/browser_child_process_host.h" | |
18 #include "content/browser/profiler_controller.h" | |
19 #include "content/common/child_process_info.h" | |
20 #include "content/common/child_process_messages.h" | |
17 #include "content/public/browser/browser_thread.h" | 21 #include "content/public/browser/browser_thread.h" |
18 #include "content/public/browser/render_process_host.h" | 22 #include "content/public/browser/render_process_host.h" |
19 | 23 |
20 using base::TimeTicks; | 24 using base::TimeTicks; |
21 using content::BrowserThread; | 25 using content::BrowserThread; |
22 | 26 |
23 namespace chrome_browser_metrics { | 27 namespace chrome_browser_metrics { |
24 | 28 |
25 // Negative numbers are never used as sequence numbers. We explicitly pick a | 29 // Negative numbers are never used as sequence numbers. We explicitly pick a |
26 // negative number that is "so negative" that even when we add one (as is done | 30 // negative number that is "so negative" that even when we add one (as is done |
27 // when we generated the next sequence number) that it will still be negative. | 31 // when we generated the next sequence number) that it will still be negative. |
28 // We have code that handles wrapping around on an overflow into negative | 32 // We have code that handles wrapping around on an overflow into negative |
29 // territory. | 33 // territory. |
30 static const int kNeverUsableSequenceNumber = -2; | 34 static const int kNeverUsableSequenceNumber = -2; |
31 | 35 |
32 TrackingSynchronizer::TrackingSynchronizer() | 36 TrackingSynchronizer::TrackingSynchronizer() |
33 : last_used_sequence_number_(kNeverUsableSequenceNumber) { | 37 : last_used_sequence_number_(kNeverUsableSequenceNumber) { |
34 DCHECK(tracking_synchronizer_ == NULL); | 38 DCHECK(tracking_synchronizer_ == NULL); |
35 tracking_synchronizer_ = this; | 39 tracking_synchronizer_ = this; |
40 ProfilerController::GetInstance()->RegisterSubscriber(this); | |
36 } | 41 } |
37 | 42 |
38 TrackingSynchronizer::~TrackingSynchronizer() { | 43 TrackingSynchronizer::~TrackingSynchronizer() { |
44 ProfilerController::GetInstance()->CancelSubscriber(this); | |
39 // Just in case we have any pending tasks, clear them out. | 45 // Just in case we have any pending tasks, clear them out. |
40 while (!outstanding_requests_.empty()) { | 46 while (!outstanding_requests_.empty()) { |
41 RequestContextMap::iterator it = outstanding_requests_.begin(); | 47 RequestContextMap::iterator it = outstanding_requests_.begin(); |
42 delete it->second; | 48 delete it->second; |
43 outstanding_requests_.erase(it); | 49 outstanding_requests_.erase(it); |
44 } | 50 } |
45 | 51 |
46 tracking_synchronizer_ = NULL; | 52 tracking_synchronizer_ = NULL; |
47 } | 53 } |
48 | 54 |
49 // static | 55 // static |
50 TrackingSynchronizer* TrackingSynchronizer::CurrentSynchronizer() { | 56 void TrackingSynchronizer::FetchProfilerDataAsynchronously( |
51 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
52 DCHECK(tracking_synchronizer_ != NULL); | |
53 return tracking_synchronizer_; | |
54 } | |
55 | |
56 // static | |
57 void TrackingSynchronizer::FetchTrackingDataAsynchronously( | |
58 const base::WeakPtr<ProfilerUI>& callback_object) { | 57 const base::WeakPtr<ProfilerUI>& callback_object) { |
59 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 58 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
60 | 59 |
61 TrackingSynchronizer* current_synchronizer = CurrentSynchronizer(); | 60 TrackingSynchronizer* current_synchronizer = CurrentSynchronizer(); |
62 if (current_synchronizer == NULL) { | 61 if (current_synchronizer == NULL) { |
63 // System teardown is happening. | 62 // System teardown is happening. |
64 return; | 63 return; |
65 } | 64 } |
66 | 65 |
67 int sequence_number = current_synchronizer->RegisterAndNotifyAllProcesses( | 66 int sequence_number = current_synchronizer->RegisterAndNotifyAllProcesses( |
68 callback_object); | 67 callback_object); |
69 | 68 |
70 // Post a task that would be called after waiting for wait_time. This acts | 69 // Post a task that would be called after waiting for wait_time. This acts |
71 // as a watchdog, to cancel the requests for non-responsive processes. | 70 // as a watchdog, to cancel the requests for non-responsive processes. |
72 BrowserThread::PostDelayedTask( | 71 BrowserThread::PostDelayedTask( |
73 BrowserThread::UI, FROM_HERE, | 72 BrowserThread::UI, FROM_HERE, |
74 NewRunnableMethod( | 73 NewRunnableMethod( |
75 current_synchronizer, | 74 current_synchronizer, |
76 &TrackingSynchronizer::ForceTrackingSynchronizationDoneCallback, | 75 &TrackingSynchronizer::ForceProfilerSynchronizationDoneCallback, |
77 sequence_number), | 76 sequence_number), |
78 60000); | 77 60000); |
79 } | 78 } |
80 | 79 |
81 // static | 80 // static |
82 void TrackingSynchronizer::SetTrackingStatus(bool enable) { | 81 void TrackingSynchronizer::SetProfilerStatus(bool enable) { |
83 // To iterate over all processes, or to send messages to the hosts, we need | 82 // To iterate over all processes, or to send messages to the hosts, we need |
84 // to be on the UI thread. | 83 // to be on the UI thread. |
85 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 84 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
86 | 85 |
87 for (content::RenderProcessHost::iterator it( | 86 for (content::RenderProcessHost::iterator it( |
88 content::RenderProcessHost::AllHostsIterator()); | 87 content::RenderProcessHost::AllHostsIterator()); |
89 !it.IsAtEnd(); it.Advance()) { | 88 !it.IsAtEnd(); it.Advance()) { |
90 content::RenderProcessHost* render_process_host = it.GetCurrentValue(); | 89 content::RenderProcessHost* render_process_host = it.GetCurrentValue(); |
91 DCHECK(render_process_host); | 90 DCHECK(render_process_host); |
92 // Ignore processes that don't have a connection, such as crashed tabs. | 91 // Ignore processes that don't have a connection, such as crashed tabs. |
93 if (!render_process_host->HasConnection()) | 92 if (!render_process_host->HasConnection()) |
94 continue; | 93 continue; |
95 | 94 |
96 render_process_host->Send(new ChromeViewMsg_SetTrackingStatus(enable)); | 95 render_process_host->Send(new ChromeViewMsg_SetProfilerStatus(enable)); |
97 } | 96 } |
97 | |
98 BrowserThread::PostTask( | |
99 BrowserThread::IO, FROM_HERE, | |
100 base::Bind( | |
101 &TrackingSynchronizer::SetProfilerStatusInChildProcesses, enable)); | |
98 } | 102 } |
99 | 103 |
100 // static | 104 // static |
101 void TrackingSynchronizer::IsTrackingEnabled(int process_id) { | 105 void TrackingSynchronizer::IsProfilerEnabledForRenderer( |
106 int renderer_process_id) { | |
102 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 107 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
103 // To find the process, or to send messages to the hosts, we need to be on the | 108 // To find the process, or to send messages to the hosts, we need to be on the |
104 // UI thread. | 109 // UI thread. |
105 BrowserThread::PostTask( | 110 BrowserThread::PostTask( |
106 BrowserThread::UI, FROM_HERE, | 111 BrowserThread::UI, FROM_HERE, |
107 base::Bind( | 112 base::Bind( |
108 &TrackingSynchronizer::SetTrackingStatusInProcess, process_id)); | 113 &TrackingSynchronizer::SendRendererSetProfilerStatusOnUI, |
114 renderer_process_id)); | |
109 } | 115 } |
110 | 116 |
111 // static | 117 // static |
112 void TrackingSynchronizer::SetTrackingStatusInProcess(int process_id) { | 118 void TrackingSynchronizer::OnRendererProfilerDatatCollected( |
119 int sequence_number, | |
120 const std::string& profiler_data) { | |
121 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
122 BrowserThread::PostTask( | |
123 BrowserThread::UI, FROM_HERE, | |
124 base::Bind(&TrackingSynchronizer::OnRendererProfilerDatatCollectedOnUI, | |
125 sequence_number, | |
126 profiler_data)); | |
127 } | |
128 | |
129 void TrackingSynchronizer::OnBrowserChildProfilerDataCollected( | |
130 int sequence_number, | |
131 const std::string& profiler_data) { | |
132 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
133 | |
134 base::Value* value = | |
135 base::JSONReader().JsonToValue(profiler_data, false, true); | |
136 DCHECK(value->GetType() == base::Value::TYPE_DICTIONARY); | |
137 base::DictionaryValue* dictionary_value = | |
138 static_cast<DictionaryValue*>(value); | |
139 | |
140 DecrementPendingProcessesAndSendDataOnIO(sequence_number, dictionary_value); | |
141 } | |
142 | |
143 void TrackingSynchronizer::OnIsProfilerEnabledForChildProcess( | |
144 base::ProcessId child_process_id) { | |
145 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
113 // To find the process, or to send messages to the hosts, we need to be on the | 146 // To find the process, or to send messages to the hosts, we need to be on the |
114 // UI thread. | 147 // IO thread. We post a task to set the status. |
115 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 148 BrowserThread::PostTask( |
116 | 149 BrowserThread::IO, FROM_HERE, |
117 bool enable = tracked_objects::ThreadData::tracking_status(); | 150 base::Bind( |
118 | 151 &TrackingSynchronizer::SendChildSetProfilerStatusOnIO, |
119 content::RenderProcessHost* process = | 152 child_process_id)); |
120 content::RenderProcessHost::FromID(process_id); | |
121 // Ignore processes that don't have a connection, such as crashed tabs. | |
122 if (!process || !process->HasConnection()) | |
123 return; | |
124 process->Send(new ChromeViewMsg_SetTrackingStatus(enable)); | |
125 } | 153 } |
126 | 154 |
127 // static | 155 // static |
128 void TrackingSynchronizer::DeserializeTrackingList( | 156 TrackingSynchronizer* TrackingSynchronizer::CurrentSynchronizer() { |
129 int sequence_number, | |
130 const std::string& tracking_data, | |
131 ChildProcessInfo::ProcessType process_type) { | |
132 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
133 BrowserThread::PostTask( | |
134 BrowserThread::UI, FROM_HERE, | |
135 base::Bind( | |
136 &TrackingSynchronizer::DeserializeTrackingListOnUI, | |
137 sequence_number, tracking_data, process_type)); | |
138 } | |
139 | |
140 // static | |
141 void TrackingSynchronizer::DeserializeTrackingListOnUI( | |
142 int sequence_number, | |
143 const std::string& tracking_data, | |
144 ChildProcessInfo::ProcessType process_type) { | |
145 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 157 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
146 | 158 DCHECK(tracking_synchronizer_ != NULL); |
147 TrackingSynchronizer* current_synchronizer = CurrentSynchronizer(); | 159 return tracking_synchronizer_; |
148 if (current_synchronizer == NULL) | |
149 return; | |
150 | |
151 base::Value* value = | |
152 base::JSONReader().JsonToValue(tracking_data, false, true); | |
153 DCHECK(value->GetType() == base::Value::TYPE_DICTIONARY); | |
154 base::DictionaryValue* dictionary_value = | |
155 static_cast<DictionaryValue*>(value); | |
156 dictionary_value->SetString( | |
157 "process_type", ChildProcessInfo::GetTypeNameInEnglish(process_type)); | |
158 | |
159 current_synchronizer->DecrementPendingProcessesAndSendData( | |
160 sequence_number, dictionary_value); | |
161 } | 160 } |
162 | 161 |
163 int TrackingSynchronizer::RegisterAndNotifyAllProcesses( | 162 int TrackingSynchronizer::RegisterAndNotifyAllProcesses( |
164 const base::WeakPtr<ProfilerUI>& callback_object) { | 163 const base::WeakPtr<ProfilerUI>& callback_object) { |
165 // To iterate over all processes, or to send messages to the hosts, we need | 164 // To iterate over all processes, or to send messages to the hosts, we need |
166 // to be on the UI thread. | 165 // to be on the UI thread. |
167 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 166 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
168 | 167 |
169 int sequence_number = GetNextAvailableSequenceNumber(); | 168 int sequence_number = GetNextAvailableSequenceNumber(); |
170 | 169 |
171 // Initialize processes_pending with one because we are going to send | 170 // ui_processes_pending is initialized to 1 to send browser's data. |
172 // browser's ThreadData. | 171 // io_processes_pending is initialized to 1 for browser child processes. |
172 // threads_pending is set to 2 to wait for data from UI thread (for renderer | |
173 // processes) and IO thread (for browser child processes). | |
173 RequestContext* request = new RequestContext( | 174 RequestContext* request = new RequestContext( |
174 callback_object, sequence_number, 1, TimeTicks::Now()); | 175 callback_object, sequence_number, 1, 1, 2, TimeTicks::Now()); |
175 outstanding_requests_[sequence_number] = request; | 176 outstanding_requests_[sequence_number] = request; |
176 | 177 |
177 DCHECK_GT(request->processes_pending_, 0); | 178 NotifyAllRendererProcesses(request); |
179 | |
180 BrowserThread::PostTask( | |
181 BrowserThread::IO, FROM_HERE, | |
182 base::Bind( | |
183 &TrackingSynchronizer::NotifyAllChildProcesses, | |
184 base::Unretained(this), request)); | |
185 | |
186 // Get the ThreadData for the browser process and send it back. | |
187 base::DictionaryValue* value = tracked_objects::ThreadData::ToValue(); | |
188 const std::string process_type = | |
189 ChildProcessInfo::GetTypeNameInEnglish(ChildProcessInfo::BROWSER_PROCESS); | |
190 value->SetString("process_type", process_type); | |
191 value->SetInteger("process_id", base::GetCurrentProcId()); | |
192 DCHECK_GE(request->ui_processes_pending_, 1); | |
193 DecrementPendingProcessesAndSendDataOnUI(sequence_number, value); | |
194 | |
195 return sequence_number; | |
196 } | |
197 | |
198 void TrackingSynchronizer::NotifyAllRendererProcesses(RequestContext* request) { | |
199 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
200 DCHECK_EQ(request->ui_processes_pending_, 1); | |
201 | |
202 const std::string render_process_type = | |
203 ChildProcessInfo::GetTypeNameInEnglish(ChildProcessInfo::RENDER_PROCESS); | |
204 | |
178 for (content::RenderProcessHost::iterator it( | 205 for (content::RenderProcessHost::iterator it( |
179 content::RenderProcessHost::AllHostsIterator()); | 206 content::RenderProcessHost::AllHostsIterator()); |
180 !it.IsAtEnd(); it.Advance()) { | 207 !it.IsAtEnd(); it.Advance()) { |
181 content::RenderProcessHost* render_process_host = it.GetCurrentValue(); | 208 content::RenderProcessHost* render_process_host = it.GetCurrentValue(); |
182 DCHECK(render_process_host); | 209 DCHECK(render_process_host); |
183 // Ignore processes that don't have a connection, such as crashed tabs. | 210 // Ignore processes that don't have a connection, such as crashed tabs. |
184 if (!render_process_host->HasConnection()) | 211 if (!render_process_host->HasConnection()) |
185 continue; | 212 continue; |
186 | 213 |
187 ++request->processes_pending_; | 214 ++request->ui_processes_pending_; |
188 if (!render_process_host->Send( | 215 if (!render_process_host->Send(new ChromeViewMsg_GetRendererProfilerData( |
189 new ChromeViewMsg_GetRendererTrackedData(sequence_number))) { | 216 request->sequence_number_, render_process_type))) { |
190 DecrementPendingProcesses(sequence_number); | 217 DecrementPendingProcessesAndSendDataOnUI(request->sequence_number_, NULL); |
218 } | |
219 } | |
220 DCHECK_GE(request->ui_processes_pending_, 1); | |
221 } | |
222 | |
223 void TrackingSynchronizer::NotifyAllChildProcesses(RequestContext* request) { | |
224 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
225 DCHECK_EQ(1, request->io_processes_pending_); | |
226 | |
227 // Default constr references a singleton. | |
jam
2011/11/19 23:36:25
nit: this comment, and below, seem unnecessary. i.
ramant (doing other things)
2011/11/25 23:59:48
Done.
| |
228 for (BrowserChildProcessHost::Iterator child_process_host; | |
229 !child_process_host.Done(); ++child_process_host) { | |
230 const std::string process_type = | |
231 ChildProcessInfo::GetTypeNameInEnglish(child_process_host->type()); | |
232 | |
233 ++request->io_processes_pending_; | |
234 if (!child_process_host->Send(new ChildProcessMsg_GetChildProfilerData( | |
235 request->sequence_number_, process_type))) { | |
236 DecrementPendingProcessesAndSendDataOnIO(request->sequence_number_, NULL); | |
191 } | 237 } |
192 } | 238 } |
193 | 239 |
194 // Get the ThreadData for the browser process and send it back. | 240 DCHECK_GE(request->io_processes_pending_, 1); |
195 base::DictionaryValue* value = tracked_objects::ThreadData::ToValue(); | 241 if (--request->io_processes_pending_ == 0) { |
196 const std::string process_type = | 242 // We are done because we are not waiting for any browser child processes. |
197 ChildProcessInfo::GetTypeNameInEnglish(ChildProcessInfo::BROWSER_PROCESS); | 243 BrowserThread::PostTask( |
198 value->SetString("process_type", process_type); | 244 BrowserThread::UI, FROM_HERE, |
199 value->SetInteger("process_id", base::GetCurrentProcId()); | 245 base::Bind(&TrackingSynchronizer::DeleteIfAllDone, |
200 DCHECK_GT(request->processes_pending_, 0); | 246 base::Unretained(this), request)); |
201 DecrementPendingProcessesAndSendData(sequence_number, value); | 247 } |
248 } | |
202 | 249 |
203 return sequence_number; | 250 // static |
251 void TrackingSynchronizer::OnRendererProfilerDatatCollectedOnUI( | |
252 int sequence_number, | |
253 const std::string& profiler_data) { | |
254 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
255 | |
256 TrackingSynchronizer* current_synchronizer = CurrentSynchronizer(); | |
257 if (current_synchronizer == NULL) | |
258 return; | |
259 | |
260 base::Value* value = | |
261 base::JSONReader().JsonToValue(profiler_data, false, true); | |
262 DCHECK(value->GetType() == base::Value::TYPE_DICTIONARY); | |
263 base::DictionaryValue* dictionary_value = | |
264 static_cast<DictionaryValue*>(value); | |
265 | |
266 current_synchronizer->DecrementPendingProcessesAndSendDataOnUI( | |
267 sequence_number, dictionary_value); | |
268 } | |
269 | |
270 void TrackingSynchronizer::DecrementPendingProcessesAndSendDataOnUI( | |
271 int sequence_number, | |
272 base::DictionaryValue* value) { | |
273 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
274 | |
275 DecrementProcessesCallback decrement_pending_process_cb = | |
276 base::Bind(&TrackingSynchronizer::DecrementUIProcesses, | |
277 base::Unretained(this)); | |
278 | |
279 DecrementPendingProcessesAndSendData(sequence_number, | |
280 value, | |
281 MessageLoop::current(), | |
282 decrement_pending_process_cb); | |
283 } | |
284 | |
285 void TrackingSynchronizer::DecrementPendingProcessesAndSendDataOnIO( | |
286 int sequence_number, | |
287 base::DictionaryValue* value) { | |
288 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
289 | |
290 DecrementProcessesCallback decrement_pending_process_cb = | |
291 base::Bind(&TrackingSynchronizer::DecrementIOProcesses, | |
292 base::Unretained(this)); | |
293 | |
294 BrowserThread::PostTask( | |
295 BrowserThread::UI, FROM_HERE, | |
296 base::Bind( | |
297 &TrackingSynchronizer::DecrementPendingProcessesAndSendData, | |
298 base::Unretained(this), | |
299 sequence_number, | |
300 value, | |
301 MessageLoop::current(), | |
302 decrement_pending_process_cb)); | |
204 } | 303 } |
205 | 304 |
206 void TrackingSynchronizer::DecrementPendingProcessesAndSendData( | 305 void TrackingSynchronizer::DecrementPendingProcessesAndSendData( |
207 int sequence_number, | 306 int sequence_number, |
208 base::DictionaryValue* value) { | 307 base::DictionaryValue* value, |
308 MessageLoop* callback_thread, | |
309 const DecrementProcessesCallback& decrement_pending_process_cb) { | |
209 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 310 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
210 | 311 |
211 RequestContextMap::iterator it = | 312 RequestContextMap::iterator it = |
212 outstanding_requests_.find(sequence_number); | 313 outstanding_requests_.find(sequence_number); |
213 if (it == outstanding_requests_.end()) { | 314 if (it == outstanding_requests_.end()) { |
214 delete value; | 315 delete value; |
215 return; | 316 return; |
216 } | 317 } |
217 | 318 |
218 RequestContext* request = NULL; | 319 RequestContext* request = NULL; |
219 request = it->second; | 320 request = it->second; |
220 DCHECK(sequence_number == request->sequence_number_); | 321 DCHECK(sequence_number == request->sequence_number_); |
221 | 322 |
222 if (value && request->callback_object_) { | 323 if (value && request->callback_object_) { |
223 // Transfers ownership of |value| to |callback_object_|. | 324 // Transfers ownership of |value| to |callback_object_|. |
224 request->callback_object_->ReceivedData(value); | 325 request->callback_object_->ReceivedData(value); |
225 } else { | 326 } else { |
226 delete value; | 327 delete value; |
227 } | 328 } |
228 | 329 |
229 if (--request->processes_pending_ <= 0) | 330 callback_thread->PostTask( |
230 ForceTrackingSynchronizationDoneCallback(sequence_number); | 331 FROM_HERE, |
332 base::Bind( | |
333 &TrackingSynchronizer::RunDecrementProcessesCallback, | |
334 this, decrement_pending_process_cb, request)); | |
231 } | 335 } |
232 | 336 |
233 void TrackingSynchronizer::DecrementPendingProcesses(int sequence_number) { | 337 void TrackingSynchronizer::DecrementUIProcesses(RequestContext* request) { |
234 DecrementPendingProcessesAndSendData(sequence_number, NULL); | 338 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
339 DCHECK_GT(request->ui_processes_pending_, 0); | |
340 if (--request->ui_processes_pending_ <= 0) { | |
341 DeleteIfAllDone(request); | |
342 } | |
235 } | 343 } |
236 | 344 |
237 void TrackingSynchronizer::ForceTrackingSynchronizationDoneCallback( | 345 void TrackingSynchronizer::DecrementIOProcesses(RequestContext* request) { |
346 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
347 DCHECK_GT(request->io_processes_pending_, 0); | |
348 if (--request->io_processes_pending_ <= 0) { | |
349 BrowserThread::PostTask( | |
350 BrowserThread::UI, FROM_HERE, | |
351 base::Bind(&TrackingSynchronizer::DeleteIfAllDone, | |
352 base::Unretained(this), request)); | |
353 } | |
354 } | |
355 | |
356 void TrackingSynchronizer::DeleteIfAllDone(RequestContext* request) { | |
357 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
358 DCHECK(request); | |
359 // Return if we still need to hear from other threads. | |
360 if (--request->threads_pending_) | |
361 return; | |
362 | |
363 DCHECK_EQ(0, request->ui_processes_pending_); | |
364 DCHECK_EQ(0, request->io_processes_pending_); | |
365 ForceProfilerSynchronizationDoneCallback(request->sequence_number_); | |
366 } | |
367 | |
368 void TrackingSynchronizer::ForceProfilerSynchronizationDoneCallback( | |
238 int sequence_number) { | 369 int sequence_number) { |
239 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 370 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
240 | 371 |
241 int unresponsive_processes; | |
242 RequestContextMap::iterator it = | 372 RequestContextMap::iterator it = |
243 outstanding_requests_.find(sequence_number); | 373 outstanding_requests_.find(sequence_number); |
244 if (it == outstanding_requests_.end()) | 374 if (it == outstanding_requests_.end()) |
245 return; | 375 return; |
246 | 376 |
247 RequestContext* request = it->second; | 377 RequestContext* request = it->second; |
248 | 378 |
249 DCHECK(sequence_number == request->sequence_number_); | 379 DCHECK(sequence_number == request->sequence_number_); |
250 | 380 |
251 unresponsive_processes = request->processes_pending_; | 381 int unresponsive_processes = request->ui_processes_pending_; |
252 | 382 |
253 delete it->second; | 383 delete it->second; |
254 outstanding_requests_.erase(it); | 384 outstanding_requests_.erase(it); |
255 | 385 |
256 UMA_HISTOGRAM_COUNTS("Tracking.ProcessNotRespondingAsynchronous", | 386 UMA_HISTOGRAM_COUNTS("Profiler.ProcessNotRespondingAsynchronous", |
257 unresponsive_processes); | 387 unresponsive_processes); |
258 } | 388 } |
259 | 389 |
260 int TrackingSynchronizer::GetNextAvailableSequenceNumber() { | 390 int TrackingSynchronizer::GetNextAvailableSequenceNumber() { |
261 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 391 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
262 | 392 |
263 ++last_used_sequence_number_; | 393 ++last_used_sequence_number_; |
264 | 394 |
265 // Watch out for wrapping to a negative number. | 395 // Watch out for wrapping to a negative number. |
266 if (last_used_sequence_number_ < 0) | 396 if (last_used_sequence_number_ < 0) |
267 last_used_sequence_number_ = 1; | 397 last_used_sequence_number_ = 1; |
268 return last_used_sequence_number_; | 398 return last_used_sequence_number_; |
269 } | 399 } |
270 | 400 |
401 void TrackingSynchronizer::RunDecrementProcessesCallback( | |
402 const DecrementProcessesCallback& decrement_pending_process_cb, | |
403 RequestContext* request) { | |
404 decrement_pending_process_cb.Run(request); | |
405 } | |
406 | |
407 // static | |
408 void TrackingSynchronizer::SetProfilerStatusInChildProcesses(bool enable) { | |
409 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
410 | |
411 // Default constr references a singleton. | |
412 for (BrowserChildProcessHost::Iterator child_process_host; | |
413 !child_process_host.Done(); ++child_process_host) { | |
414 child_process_host->Send(new ChildProcessMsg_SetProfilerStatus(enable)); | |
415 } | |
416 } | |
417 | |
418 // static | |
419 void TrackingSynchronizer::SendRendererSetProfilerStatusOnUI( | |
420 int renderer_process_id) { | |
421 // To find the process, or to send messages to the hosts, we need to be on the | |
422 // UI thread. | |
423 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
424 | |
425 bool enable = tracked_objects::ThreadData::tracking_status(); | |
426 | |
427 content::RenderProcessHost* process = | |
428 content::RenderProcessHost::FromID(renderer_process_id); | |
429 // Ignore processes that don't have a connection, such as crashed tabs. | |
430 if (!process || !process->HasConnection()) | |
431 return; | |
432 process->Send(new ChromeViewMsg_SetProfilerStatus(enable)); | |
433 } | |
434 | |
435 // static | |
436 void TrackingSynchronizer::SendChildSetProfilerStatusOnIO( | |
437 base::ProcessId child_process_id) { | |
438 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
439 | |
440 bool enable = tracked_objects::ThreadData::tracking_status(); | |
441 | |
442 // Default constr references a singleton. | |
443 for (BrowserChildProcessHost::Iterator child_process_host; | |
444 !child_process_host.Done(); ++child_process_host) { | |
445 if (base::GetProcId(child_process_host->handle()) == child_process_id) | |
446 child_process_host->Send(new ChildProcessMsg_SetProfilerStatus(enable)); | |
447 } | |
448 } | |
449 | |
271 // static | 450 // static |
272 TrackingSynchronizer* TrackingSynchronizer::tracking_synchronizer_ = NULL; | 451 TrackingSynchronizer* TrackingSynchronizer::tracking_synchronizer_ = NULL; |
273 | 452 |
274 } // namespace chrome_browser_metrics | 453 } // namespace chrome_browser_metrics |
OLD | NEW |