Chromium Code Reviews| 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 |