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

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

Powered by Google App Engine
This is Rietveld 408576698