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

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

Issue 9702014: [UMA] Use proper C++ objects to serialize tracked_objects across process boundaries. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix yet another IWYU for chromeos/ (take 4) Created 8 years, 8 months 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
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 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/metrics/histogram.h" 8 #include "base/metrics/histogram.h"
9 #include "base/process_util.h" 9 #include "base/process_util.h"
10 #include "base/threading/thread.h" 10 #include "base/threading/thread.h"
11 #include "base/tracked_objects.h" 11 #include "base/tracked_objects.h"
12 #include "chrome/browser/metrics/tracking_synchronizer_observer.h"
12 #include "content/public/browser/browser_thread.h" 13 #include "content/public/browser/browser_thread.h"
13 #include "content/public/browser/profiler_controller.h" 14 #include "content/public/browser/profiler_controller.h"
14 #include "content/public/common/process_type.h"
15 15
16 using base::TimeTicks; 16 using base::TimeTicks;
17 using content::BrowserThread; 17 using content::BrowserThread;
18 18
19 namespace {
20
21 // Negative numbers are never used as sequence numbers. We explicitly pick a
22 // negative number that is "so negative" that even when we add one (as is done
23 // when we generated the next sequence number) that it will still be negative.
24 // We have code that handles wrapping around on an overflow into negative
25 // territory.
26 const int kNeverUsableSequenceNumber = -2;
27
28 // This singleton instance should be started during the single threaded
29 // portion of main(). It initializes globals to provide support for all future
30 // calls. This object is created on the UI thread, and it is destroyed after
31 // all the other threads have gone away. As a result, it is ok to call it
32 // from the UI thread, or for about:profiler.
33 static chrome_browser_metrics::TrackingSynchronizer* g_tracking_synchronizer =
34 NULL;
35
36 } // anonymous namespace
37
19 namespace chrome_browser_metrics { 38 namespace chrome_browser_metrics {
20 39
21 // The "RequestContext" structure describes an individual request received 40 // The "RequestContext" structure describes an individual request received
22 // from the UI. All methods are accessible on UI thread. 41 // from the UI. All methods are accessible on UI thread.
23 class RequestContext { 42 class TrackingSynchronizer::RequestContext {
24 public: 43 public:
25 // A map from sequence_number_ to the actual RequestContexts. 44 // A map from sequence_number_ to the actual RequestContexts.
26 typedef std::map<int, RequestContext*> RequestContextMap; 45 typedef std::map<int, RequestContext*> RequestContextMap;
27 46
28 ~RequestContext() {} 47 RequestContext(
29 48 const base::WeakPtr<TrackingSynchronizerObserver>& callback_object,
30 RequestContext(const base::WeakPtr<ProfilerUI>& callback_object, 49 int sequence_number)
31 int sequence_number)
32 : callback_object_(callback_object), 50 : callback_object_(callback_object),
33 sequence_number_(sequence_number), 51 sequence_number_(sequence_number),
34 received_process_group_count_(0), 52 received_process_group_count_(0),
35 processes_pending_(0) { 53 processes_pending_(0) {
36 } 54 }
55 ~RequestContext() {}
37 56
38 void SetReceivedProcessGroupCount(bool done) { 57 void SetReceivedProcessGroupCount(bool done) {
39 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 58 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
40 received_process_group_count_ = done; 59 received_process_group_count_ = done;
41 } 60 }
42 61
43 // Methods for book keeping of processes_pending_. 62 // Methods for book keeping of processes_pending_.
44 void IncrementProcessesPending() { 63 void IncrementProcessesPending() {
45 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 64 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
46 ++processes_pending_; 65 ++processes_pending_;
47 } 66 }
48 67
49 void AddProcessesPending(int processes_pending) { 68 void AddProcessesPending(int processes_pending) {
50 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 69 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
51 processes_pending_ += processes_pending; 70 processes_pending_ += processes_pending;
52 } 71 }
53 72
54 void DecrementProcessesPending() { 73 void DecrementProcessesPending() {
55 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 74 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
56 --processes_pending_; 75 --processes_pending_;
57 } 76 }
58 77
59 // Records that we are waiting for one less tracking data from a process for 78 // Records that we are waiting for one less tracking data from a process for
60 // the given sequence number. If |received_process_group_count_| and 79 // the given sequence number. If |received_process_group_count_| and
61 // |processes_pending_| are zero, then delete the current object by calling 80 // |processes_pending_| are zero, then delete the current object by calling
62 // Unregister. 81 // Unregister.
63 void DeleteIfAllDone() { 82 void DeleteIfAllDone() {
64 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 83 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
65 84
66 if (processes_pending_ <= 0 && received_process_group_count_) { 85 if (processes_pending_ <= 0 && received_process_group_count_)
67 RequestContext::Unregister(sequence_number_); 86 RequestContext::Unregister(sequence_number_);
68 }
69 } 87 }
70 88
71 89
72 // Register |callback_object| in |outstanding_requests_| map for the given 90 // Register |callback_object| in |outstanding_requests_| map for the given
73 // |sequence_number|. 91 // |sequence_number|.
74 static RequestContext* Register( 92 static RequestContext* Register(
75 int sequence_number, 93 int sequence_number,
76 const base::WeakPtr<ProfilerUI>& callback_object) { 94 const base::WeakPtr<TrackingSynchronizerObserver>& callback_object) {
77 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 95 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
78 96
79 RequestContext* request = new RequestContext( 97 RequestContext* request = new RequestContext(
80 callback_object, sequence_number); 98 callback_object, sequence_number);
81 outstanding_requests_.Get()[sequence_number] = request; 99 outstanding_requests_.Get()[sequence_number] = request;
82 100
83 return request; 101 return request;
84 } 102 }
85 103
86 // Find the |RequestContext| in |outstanding_requests_| map for the given 104 // Find the |RequestContext| in |outstanding_requests_| map for the given
87 // |sequence_number|. 105 // |sequence_number|.
88 static RequestContext* GetRequestContext(int sequence_number) { 106 static RequestContext* GetRequestContext(int sequence_number) {
89 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 107 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
90 108
91 RequestContextMap::iterator it = 109 RequestContextMap::iterator it =
92 outstanding_requests_.Get().find(sequence_number); 110 outstanding_requests_.Get().find(sequence_number);
93 if (it == outstanding_requests_.Get().end()) 111 if (it == outstanding_requests_.Get().end())
94 return NULL; 112 return NULL;
95 113
96 RequestContext* request = NULL; 114 RequestContext* request = it->second;
97 request = it->second; 115 DCHECK_EQ(sequence_number, request->sequence_number_);
98 DCHECK(sequence_number == request->sequence_number_);
99 return request; 116 return request;
100 } 117 }
101 118
102 // Delete the entry for the given sequence_number| from 119 // Delete the entry for the given sequence_number| from
103 // |outstanding_requests_| map. This method is called when all changes have 120 // |outstanding_requests_| map. This method is called when all changes have
104 // been acquired, or when the wait time expires (whichever is sooner). 121 // been acquired, or when the wait time expires (whichever is sooner).
105 static void Unregister(int sequence_number) { 122 static void Unregister(int sequence_number) {
106 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 123 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
107 124
108 RequestContextMap::iterator it = 125 RequestContextMap::iterator it =
109 outstanding_requests_.Get().find(sequence_number); 126 outstanding_requests_.Get().find(sequence_number);
110 if (it == outstanding_requests_.Get().end()) 127 if (it == outstanding_requests_.Get().end())
111 return; 128 return;
112 129
113 RequestContext* request = it->second; 130 RequestContext* request = it->second;
114 DCHECK(sequence_number == request->sequence_number_); 131 DCHECK_EQ(sequence_number, request->sequence_number_);
115 bool received_process_group_count = request->received_process_group_count_; 132 bool received_process_group_count = request->received_process_group_count_;
116 int unresponsive_processes = request->processes_pending_; 133 int unresponsive_processes = request->processes_pending_;
117 134
118 delete it->second; 135 request->callback_object_->FinishedReceivingProfilerData();
136
137 delete request;
119 outstanding_requests_.Get().erase(it); 138 outstanding_requests_.Get().erase(it);
120 139
121 UMA_HISTOGRAM_BOOLEAN("Profiling.ReceivedProcessGroupCount", 140 UMA_HISTOGRAM_BOOLEAN("Profiling.ReceivedProcessGroupCount",
122 received_process_group_count); 141 received_process_group_count);
123 UMA_HISTOGRAM_COUNTS("Profiling.PendingProcessNotResponding", 142 UMA_HISTOGRAM_COUNTS("Profiling.PendingProcessNotResponding",
124 unresponsive_processes); 143 unresponsive_processes);
125 } 144 }
126 145
127 146
128 // Delete all the entries in |outstanding_requests_| map. 147 // Delete all the entries in |outstanding_requests_| map.
129 static void OnShutdown() { 148 static void OnShutdown() {
130 // Just in case we have any pending tasks, clear them out. 149 // Just in case we have any pending tasks, clear them out.
131 while (!outstanding_requests_.Get().empty()) { 150 while (!outstanding_requests_.Get().empty()) {
132 RequestContextMap::iterator it = outstanding_requests_.Get().begin(); 151 RequestContextMap::iterator it = outstanding_requests_.Get().begin();
133 delete it->second; 152 delete it->second;
134 outstanding_requests_.Get().erase(it); 153 outstanding_requests_.Get().erase(it);
135 } 154 }
136 } 155 }
137 156
138 // Requests are made to asynchronously send data to the |callback_object_|. 157 // Requests are made to asynchronously send data to the |callback_object_|.
139 base::WeakPtr<ProfilerUI> callback_object_; 158 base::WeakPtr<TrackingSynchronizerObserver> callback_object_;
140 159
141 // The sequence number used by the most recent update request to contact all 160 // The sequence number used by the most recent update request to contact all
142 // processes. 161 // processes.
143 int sequence_number_; 162 int sequence_number_;
144 163
145 // Indicates if we have received all pending processes count. 164 // Indicates if we have received all pending processes count.
146 bool received_process_group_count_; 165 bool received_process_group_count_;
147 166
148 // The number of pending processes (browser, all renderer processes and 167 // The number of pending processes (browser, all renderer processes and
149 // browser child processes) that have not yet responded to requests. 168 // browser child processes) that have not yet responded to requests.
150 int processes_pending_; 169 int processes_pending_;
151 170
152 // Map of all outstanding RequestContexts, from sequence_number_ to 171 // Map of all outstanding RequestContexts, from sequence_number_ to
153 // RequestContext. 172 // RequestContext.
154 static base::LazyInstance<RequestContextMap> outstanding_requests_; 173 static base::LazyInstance<RequestContextMap> outstanding_requests_;
155 }; 174 };
156 175
157 // Negative numbers are never used as sequence numbers. We explicitly pick a 176 // static
158 // negative number that is "so negative" that even when we add one (as is done 177 base::LazyInstance<TrackingSynchronizer::RequestContext::RequestContextMap>
159 // when we generated the next sequence number) that it will still be negative. 178 TrackingSynchronizer::RequestContext::outstanding_requests_ =
160 // We have code that handles wrapping around on an overflow into negative 179 LAZY_INSTANCE_INITIALIZER;
161 // territory.
162 static const int kNeverUsableSequenceNumber = -2;
163 180
164 // TrackingSynchronizer methods and members. 181 // TrackingSynchronizer methods and members.
165 //
166 // static
167 TrackingSynchronizer* TrackingSynchronizer::tracking_synchronizer_ = NULL;
168 182
169 TrackingSynchronizer::TrackingSynchronizer() 183 TrackingSynchronizer::TrackingSynchronizer()
170 : last_used_sequence_number_(kNeverUsableSequenceNumber) { 184 : last_used_sequence_number_(kNeverUsableSequenceNumber) {
171 DCHECK(tracking_synchronizer_ == NULL); 185 DCHECK(!g_tracking_synchronizer);
172 tracking_synchronizer_ = this; 186 g_tracking_synchronizer = this;
173 content::ProfilerController::GetInstance()->Register(this); 187 content::ProfilerController::GetInstance()->Register(this);
174 } 188 }
175 189
176 TrackingSynchronizer::~TrackingSynchronizer() { 190 TrackingSynchronizer::~TrackingSynchronizer() {
177 content::ProfilerController::GetInstance()->Unregister(this); 191 content::ProfilerController::GetInstance()->Unregister(this);
178 192
179 // Just in case we have any pending tasks, clear them out. 193 // Just in case we have any pending tasks, clear them out.
180 RequestContext::OnShutdown(); 194 RequestContext::OnShutdown();
181 195
182 tracking_synchronizer_ = NULL; 196 g_tracking_synchronizer = NULL;
183 } 197 }
184 198
185 // static 199 // static
186 void TrackingSynchronizer::FetchProfilerDataAsynchronously( 200 void TrackingSynchronizer::FetchProfilerDataAsynchronously(
187 const base::WeakPtr<ProfilerUI>& callback_object) { 201 const base::WeakPtr<TrackingSynchronizerObserver>& callback_object) {
188 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 202 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
189 203
190 TrackingSynchronizer* current_synchronizer = CurrentSynchronizer(); 204 if (!g_tracking_synchronizer) {
191 if (current_synchronizer == NULL) {
192 // System teardown is happening. 205 // System teardown is happening.
193 return; 206 return;
194 } 207 }
195 208
196 int sequence_number = current_synchronizer->RegisterAndNotifyAllProcesses( 209 int sequence_number = g_tracking_synchronizer->RegisterAndNotifyAllProcesses(
197 callback_object); 210 callback_object);
198 211
199 // Post a task that would be called after waiting for wait_time. This acts 212 // Post a task that would be called after waiting for wait_time. This acts
200 // as a watchdog, to cancel the requests for non-responsive processes. 213 // as a watchdog, to cancel the requests for non-responsive processes.
201 BrowserThread::PostDelayedTask( 214 BrowserThread::PostDelayedTask(
202 BrowserThread::UI, FROM_HERE, 215 BrowserThread::UI, FROM_HERE,
203 base::Bind(&RequestContext::Unregister, sequence_number), 216 base::Bind(&RequestContext::Unregister, sequence_number),
204 base::TimeDelta::FromMinutes(1)); 217 base::TimeDelta::FromMinutes(1));
205 } 218 }
206 219
207 void TrackingSynchronizer::OnPendingProcesses(int sequence_number, 220 void TrackingSynchronizer::OnPendingProcesses(int sequence_number,
208 int pending_processes, 221 int pending_processes,
209 bool end) { 222 bool end) {
210 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 223 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
211 224
212 RequestContext* request = RequestContext::GetRequestContext(sequence_number); 225 RequestContext* request = RequestContext::GetRequestContext(sequence_number);
213 if (!request) 226 if (!request)
214 return; 227 return;
215 request->AddProcessesPending(pending_processes); 228 request->AddProcessesPending(pending_processes);
216 request->SetReceivedProcessGroupCount(end); 229 request->SetReceivedProcessGroupCount(end);
217 request->DeleteIfAllDone(); 230 request->DeleteIfAllDone();
218 } 231 }
219 232
220 void TrackingSynchronizer::OnProfilerDataCollected( 233 void TrackingSynchronizer::OnProfilerDataCollected(
221 int sequence_number, 234 int sequence_number,
222 base::DictionaryValue* profiler_data) { 235 const tracked_objects::ProcessDataSnapshot& profiler_data,
236 content::ProcessType process_type) {
223 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 237 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
224 238 DecrementPendingProcessesAndSendData(sequence_number, profiler_data,
225 RequestContext* request = RequestContext::GetRequestContext(sequence_number); 239 process_type);
226 if (!request)
227 return;
228
229 DecrementPendingProcessesAndSendData(sequence_number, profiler_data);
230 } 240 }
231 241
232 int TrackingSynchronizer::RegisterAndNotifyAllProcesses( 242 int TrackingSynchronizer::RegisterAndNotifyAllProcesses(
233 const base::WeakPtr<ProfilerUI>& callback_object) { 243 const base::WeakPtr<TrackingSynchronizerObserver>& callback_object) {
234 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 244 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
235 245
236 int sequence_number = GetNextAvailableSequenceNumber(); 246 int sequence_number = GetNextAvailableSequenceNumber();
237 247
238 RequestContext* request = 248 RequestContext* request =
239 RequestContext::Register(sequence_number, callback_object); 249 RequestContext::Register(sequence_number, callback_object);
240 250
241 // Increment pending process count for sending browser's profiler data. 251 // Increment pending process count for sending browser's profiler data.
242 request->IncrementProcessesPending(); 252 request->IncrementProcessesPending();
243 253
244 // Get profiler data from renderer and browser child processes. 254 // Get profiler data from renderer and browser child processes.
245 content::ProfilerController::GetInstance()->GetProfilerData(sequence_number); 255 content::ProfilerController::GetInstance()->GetProfilerData(sequence_number);
246 256
247 // Send profiler_data from browser process. 257 // Send profiler_data from browser process.
248 base::DictionaryValue* value = tracked_objects::ThreadData::ToValue(false); 258 tracked_objects::ProcessDataSnapshot process_data;
249 const std::string process_type = 259 tracked_objects::ThreadData::Snapshot(false, &process_data);
250 content::GetProcessTypeNameInEnglish(content::PROCESS_TYPE_BROWSER); 260 DecrementPendingProcessesAndSendData(sequence_number, process_data,
251 value->SetString("process_type", process_type); 261 content::PROCESS_TYPE_BROWSER);
252 value->SetInteger("process_id", base::GetCurrentProcId());
253 DecrementPendingProcessesAndSendData(sequence_number, value);
254 262
255 return sequence_number; 263 return sequence_number;
256 } 264 }
257 265
258 void TrackingSynchronizer::DecrementPendingProcessesAndSendData( 266 void TrackingSynchronizer::DecrementPendingProcessesAndSendData(
259 int sequence_number, 267 int sequence_number,
260 base::DictionaryValue* value) { 268 const tracked_objects::ProcessDataSnapshot& profiler_data,
269 content::ProcessType process_type) {
261 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 270 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
262 271
263 RequestContext* request = RequestContext::GetRequestContext(sequence_number); 272 RequestContext* request = RequestContext::GetRequestContext(sequence_number);
264 if (!request) { 273 if (!request)
265 delete value;
266 return; 274 return;
267 }
268 275
269 if (value && request->callback_object_) { 276 if (request->callback_object_) {
270 // Transfers ownership of |value| to |callback_object_|. 277 request->callback_object_->ReceivedProfilerData(profiler_data,
271 request->callback_object_->ReceivedData(value); 278 process_type);
272 } else {
273 delete value;
274 } 279 }
275 280
276 // Delete request if we have heard back from all child processes. 281 // Delete request if we have heard back from all child processes.
277 request->DecrementProcessesPending(); 282 request->DecrementProcessesPending();
278 request->DeleteIfAllDone(); 283 request->DeleteIfAllDone();
279 } 284 }
280 285
281 int TrackingSynchronizer::GetNextAvailableSequenceNumber() { 286 int TrackingSynchronizer::GetNextAvailableSequenceNumber() {
282 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 287 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
283 288
284 ++last_used_sequence_number_; 289 ++last_used_sequence_number_;
285 290
286 // Watch out for wrapping to a negative number. 291 // Watch out for wrapping to a negative number.
287 if (last_used_sequence_number_ < 0) 292 if (last_used_sequence_number_ < 0)
288 last_used_sequence_number_ = 1; 293 last_used_sequence_number_ = 1;
289 return last_used_sequence_number_; 294 return last_used_sequence_number_;
290 } 295 }
291 296
292 // static
293 TrackingSynchronizer* TrackingSynchronizer::CurrentSynchronizer() {
294 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
295 DCHECK(tracking_synchronizer_ != NULL);
296 return tracking_synchronizer_;
297 }
298
299 // static
300 base::LazyInstance<RequestContext::RequestContextMap>
301 RequestContext::outstanding_requests_ = LAZY_INSTANCE_INITIALIZER;
302
303 } // namespace chrome_browser_metrics 297 } // namespace chrome_browser_metrics
OLDNEW
« no previous file with comments | « chrome/browser/metrics/tracking_synchronizer.h ('k') | chrome/browser/metrics/tracking_synchronizer_observer.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698