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

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

Powered by Google App Engine
This is Rietveld 408576698