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

Side by Side Diff: base/tracked_objects.cc

Issue 8313013: Support JSON encoding of data for about:tracking information (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 9 years, 2 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) 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 "base/tracked_objects.h" 5 #include "base/tracked_objects.h"
6 6
7 #include <math.h> 7 #include <math.h>
8 8
9 #include "base/format_macros.h" 9 #include "base/format_macros.h"
10 #include "base/message_loop.h" 10 #include "base/message_loop.h"
11 #include "base/string_util.h" 11 #include "base/string_util.h"
12 #include "base/stringprintf.h" 12 #include "base/stringprintf.h"
13 #include "base/threading/thread_restrictions.h" 13 #include "base/threading/thread_restrictions.h"
14 14
15 using base::TimeDelta; 15 using base::TimeDelta;
16 16
17 namespace tracked_objects { 17 namespace tracked_objects {
18 18
19 // A TLS slot to the TrackRegistry for the current thread. 19
20 #if defined(TRACK_ALL_TASK_OBJECTS)
21 static const bool kTrackAllTaskObjects = true;
22 #else
23 static const bool kTrackAllTaskObjects = false;
24 #endif
25
26 // Can we count on thread termination to call for thread cleanup? If not, then
27 // we can't risk putting references to ThreadData in TLS, as it will leak on
28 // worker thread termination.
29 static const bool kWorkerThreadCleanupSupported = true;
30
31 // A TLS slot to the TrackRegistry for the current thread. We do a fake
32 // initializatio here (zeroing out data), and then the real construction takes
33 // place when we call tls_index_.Initialize().
20 // static 34 // static
21 base::ThreadLocalStorage::Slot ThreadData::tls_index_(base::LINKER_INITIALIZED); 35 base::ThreadLocalStorage::Slot ThreadData::tls_index_(base::LINKER_INITIALIZED);
22 36
23 // A global state variable to prevent repeated initialization during tests. 37 // A global state variable to prevent repeated initialization during tests.
24 // static 38 // static
25 AutoTracking::State AutoTracking::state_ = AutoTracking::kNeverBeenRun; 39 AutoTracking::State AutoTracking::state_ = AutoTracking::kNeverBeenRun;
26 40
27 // A locked protected counter to assign sequence number to threads. 41 // A locked protected counter to assign sequence number to threads.
28 // static 42 // static
29 int ThreadData::thread_number_counter = 0; 43 int ThreadData::thread_number_counter = 0;
ramant (doing other things) 2011/10/24 18:03:49 nit: g_thread_number_counter
jar (doing other things) 2011/10/24 18:43:27 Done.
30 44
31 //------------------------------------------------------------------------------ 45 //------------------------------------------------------------------------------
32 // Death data tallies durations when a death takes place. 46 // Death data tallies durations when a death takes place.
33 47
34 void DeathData::RecordDeath(const TimeDelta& queue_duration, 48 void DeathData::RecordDeath(const TimeDelta& queue_duration,
35 const TimeDelta& run_duration) { 49 const TimeDelta& run_duration) {
36 ++count_; 50 ++count_;
37 queue_duration_ += queue_duration; 51 queue_duration_ += queue_duration;
38 run_duration_ += run_duration; 52 run_duration_ += run_duration;
39 } 53 }
40 54
41 int DeathData::AverageMsRunDuration() const { 55 int DeathData::AverageMsRunDuration() const {
56 if (run_duration_ == base::TimeDelta())
57 return 0;
42 return static_cast<int>(run_duration_.InMilliseconds() / count_); 58 return static_cast<int>(run_duration_.InMilliseconds() / count_);
43 } 59 }
44 60
45 int DeathData::AverageMsQueueDuration() const { 61 int DeathData::AverageMsQueueDuration() const {
62 if (queue_duration_ == base::TimeDelta())
63 return 0;
46 return static_cast<int>(queue_duration_.InMilliseconds() / count_); 64 return static_cast<int>(queue_duration_.InMilliseconds() / count_);
47 } 65 }
48 66
49 void DeathData::AddDeathData(const DeathData& other) { 67 void DeathData::AddDeathData(const DeathData& other) {
50 count_ += other.count_; 68 count_ += other.count_;
51 queue_duration_ += other.queue_duration_; 69 queue_duration_ += other.queue_duration_;
52 run_duration_ += other.run_duration_; 70 run_duration_ += other.run_duration_;
53 } 71 }
54 72
55 void DeathData::Write(std::string* output) const { 73 void DeathData::WriteHTML(std::string* output) const {
56 if (!count_) 74 if (!count_)
57 return; 75 return;
58 base::StringAppendF(output, "%s:%d, ", 76 base::StringAppendF(output, "%s:%d, ",
59 (count_ == 1) ? "Life" : "Lives", count_); 77 (count_ == 1) ? "Life" : "Lives", count_);
60 base::StringAppendF(output, "Run:%"PRId64"ms(%dms/life) ", 78 base::StringAppendF(output, "Run:%"PRId64"ms(%dms/life) ",
61 run_duration_.InMilliseconds(), 79 run_duration_.InMilliseconds(),
62 AverageMsRunDuration()); 80 AverageMsRunDuration());
63 base::StringAppendF(output, "Queue:%"PRId64"ms(%dms/life) ", 81 base::StringAppendF(output, "Queue:%"PRId64"ms(%dms/life) ",
64 queue_duration_.InMilliseconds(), 82 queue_duration_.InMilliseconds(),
65 AverageMsQueueDuration()); 83 AverageMsQueueDuration());
66 } 84 }
67 85
86 base::DictionaryValue* DeathData::ToValue() const {
87 base::DictionaryValue* dictionary = new base::DictionaryValue;
88 dictionary->Set("count", base::Value::CreateIntegerValue(count_));
89 dictionary->Set("run_ms",
90 base::Value::CreateIntegerValue(run_duration_.InMilliseconds()));
91 dictionary->Set("queue_ms",
92 base::Value::CreateIntegerValue(queue_duration_.InMilliseconds()));
93 return dictionary;
94 }
95
68 void DeathData::Clear() { 96 void DeathData::Clear() {
69 count_ = 0; 97 count_ = 0;
70 queue_duration_ = TimeDelta(); 98 queue_duration_ = TimeDelta();
71 run_duration_ = TimeDelta(); 99 run_duration_ = TimeDelta();
72 } 100 }
73 101
74 //------------------------------------------------------------------------------ 102 //------------------------------------------------------------------------------
75 BirthOnThread::BirthOnThread(const Location& location) 103 BirthOnThread::BirthOnThread(const Location& location,
104 const ThreadData& current)
76 : location_(location), 105 : location_(location),
77 birth_thread_(ThreadData::Get()) { } 106 birth_thread_(&current) {}
78 107
79 //------------------------------------------------------------------------------ 108 //------------------------------------------------------------------------------
80 Births::Births(const Location& location) 109 Births::Births(const Location& location, const ThreadData& current)
81 : BirthOnThread(location), 110 : BirthOnThread(location, current),
82 birth_count_(1) { } 111 birth_count_(1) { }
83 112
84 //------------------------------------------------------------------------------ 113 //------------------------------------------------------------------------------
85 // ThreadData maintains the central data for all births and death. 114 // ThreadData maintains the central data for all births and deaths.
86 115
87 // static 116 // static
88 ThreadData* ThreadData::first_ = NULL; 117 ThreadData* ThreadData::all_thread_data_list_head_ = NULL;
118
119 // static
120 ThreadData::ThreadDataPool* ThreadData::unregistered_thread_data_pool_ = NULL;
121
89 // static 122 // static
90 base::Lock ThreadData::list_lock_; 123 base::Lock ThreadData::list_lock_;
91 124
92 // static 125 // static
93 ThreadData::Status ThreadData::status_ = ThreadData::UNINITIALIZED; 126 ThreadData::Status ThreadData::status_ = ThreadData::UNINITIALIZED;
94 127
95 ThreadData::ThreadData(const std::string& suggested_name) : next_(NULL) { 128 ThreadData::ThreadData(const std::string& suggested_name)
129 : next_(NULL),
130 is_a_worker_thread_(false) {
96 DCHECK_GE(suggested_name.size(), 0u); 131 DCHECK_GE(suggested_name.size(), 0u);
97 thread_name_ = suggested_name; 132 thread_name_ = suggested_name;
133 PushToHeadOfList();
98 } 134 }
99 135
100 ThreadData::ThreadData() : next_(NULL) { 136 ThreadData::ThreadData() : next_(NULL), is_a_worker_thread_(true) {
101 int thread_number; 137 int thread_number;
102 { 138 {
103 base::AutoLock lock(list_lock_); 139 base::AutoLock lock(list_lock_);
104 thread_number = ++thread_number_counter; 140 thread_number = ++thread_number_counter;
105 } 141 }
106 base::StringAppendF(&thread_name_, "WorkerThread-%d", thread_number); 142 base::StringAppendF(&thread_name_, "WorkerThread-%d", thread_number);
143 PushToHeadOfList();
107 } 144 }
108 145
109 ThreadData::~ThreadData() {} 146 ThreadData::~ThreadData() {}
110 147
148 void ThreadData::PushToHeadOfList() {
149 DCHECK(!next_);
150 base::AutoLock lock(list_lock_);
151 next_ = all_thread_data_list_head_;
152 all_thread_data_list_head_ = this;
153 }
154
111 // static 155 // static
112 void ThreadData::InitializeThreadContext(const std::string& suggested_name) { 156 void ThreadData::InitializeThreadContext(const std::string& suggested_name) {
113 if (!tls_index_.initialized()) 157 if (!tls_index_.initialized())
114 return; // For unittests only. 158 return; // For unittests only.
115 RegisterCurrentContext(new ThreadData(suggested_name)); 159 DCHECK_EQ(tls_index_.Get(), reinterpret_cast<void*>(NULL));
160 ThreadData* current_thread_data = new ThreadData(suggested_name);
161 tls_index_.Set(current_thread_data);
116 } 162 }
117 163
118 // static 164 // static
119 ThreadData* ThreadData::Get() { 165 ThreadData* ThreadData::Get() {
120 if (!tls_index_.initialized()) 166 if (!tls_index_.initialized())
121 return NULL; // For unittests only. 167 return NULL; // For unittests only.
122 ThreadData* registered = static_cast<ThreadData*>(tls_index_.Get()); 168 ThreadData* registered = reinterpret_cast<ThreadData*>(tls_index_.Get());
123 if (!registered) { 169 if (registered)
124 // We have to create a new registry entry for this ThreadData. 170 return registered;
125 // TODO(jar): Host all unamed (Worker) threads in *one* ThreadData instance, 171
126 // (with locking protection on that instance) or else recycle and re-use 172 // We must be a worker thread, since we didn't pre-register.
127 // worker thread ThreadData when the worker thread terminates. 173 ThreadData* worker_thread_data = NULL;
128 registered = RegisterCurrentContext(new ThreadData()); 174 {
175 base::AutoLock lock(list_lock_);
176 if (!unregistered_thread_data_pool_->empty()) {
177 worker_thread_data =
178 const_cast<ThreadData*>(unregistered_thread_data_pool_->top());
179 unregistered_thread_data_pool_->pop();
180 }
129 } 181 }
130 return registered; 182
183 // If we can't find a previously used instance, then we have to create one.
184 if (!worker_thread_data)
185 worker_thread_data = new ThreadData();
186
187 tls_index_.Set(worker_thread_data);
188 return worker_thread_data;
131 } 189 }
132 190
133 // static 191 // static
134 ThreadData* ThreadData::RegisterCurrentContext(ThreadData* unregistered) { 192 void ThreadData::OnThreadTermination(void* thread_data) {
135 DCHECK_EQ(tls_index_.Get(), static_cast<void*>(0)); 193 if (!kTrackAllTaskObjects)
136 bool too_late_to_register = false; 194 return; // Not compiled in.
137 { 195 DCHECK(tls_index_.initialized());
138 base::AutoLock lock(list_lock_); 196 if (!thread_data)
139 // Use lock to insure we have most recent status. 197 return;
140 if (!IsActive()) { 198 reinterpret_cast<ThreadData*>(thread_data)->OnThreadTerminationCleanup();
141 too_late_to_register = true; 199 DCHECK_EQ(tls_index_.Get(), reinterpret_cast<ThreadData*>(NULL));
142 } else { 200 }
143 // Use list_lock_ to insert as new head of list. 201
144 unregistered->next_ = first_; 202 void ThreadData::OnThreadTerminationCleanup() const {
145 first_ = unregistered; 203 tls_index_.Set(NULL);
146 } 204 if (!is_a_worker_thread_)
147 } // Release lock. 205 return;
148 if (too_late_to_register) { 206 base::AutoLock lock(list_lock_);
149 delete unregistered; 207 unregistered_thread_data_pool_->push(this);
150 unregistered = NULL;
151 } else {
152 tls_index_.Set(unregistered);
153 }
154 return unregistered;
155 } 208 }
156 209
157 // static 210 // static
158 void ThreadData::WriteHTML(const std::string& query, std::string* output) { 211 void ThreadData::WriteHTML(const std::string& query, std::string* output) {
159 if (!ThreadData::IsActive()) 212 if (!ThreadData::IsActive())
160 return; // Not yet initialized. 213 return; // Not yet initialized.
161 214
162 DataCollector collected_data; // Gather data. 215 DataCollector collected_data; // Gather data.
163 collected_data.AddListOfLivingObjects(); // Add births that are still alive. 216 collected_data.AddListOfLivingObjects(); // Add births that are still alive.
164 217
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
219 "If you wish to monitor Renderer events, be sure to run in --single-process" 272 "If you wish to monitor Renderer events, be sure to run in --single-process"
220 " mode."; 273 " mode.";
221 output->append(help_string); 274 output->append(help_string);
222 } 275 }
223 276
224 // static 277 // static
225 void ThreadData::WriteHTMLTotalAndSubtotals( 278 void ThreadData::WriteHTMLTotalAndSubtotals(
226 const DataCollector::Collection& match_array, 279 const DataCollector::Collection& match_array,
227 const Comparator& comparator, 280 const Comparator& comparator,
228 std::string* output) { 281 std::string* output) {
229 if (!match_array.size()) { 282 if (match_array.empty()) {
230 output->append("There were no tracked matches."); 283 output->append("There were no tracked matches.");
231 } else { 284 return;
232 // Aggregate during printing 285 }
233 Aggregation totals; 286 // Aggregate during printing
234 for (size_t i = 0; i < match_array.size(); ++i) { 287 Aggregation totals;
235 totals.AddDeathSnapshot(match_array[i]); 288 for (size_t i = 0; i < match_array.size(); ++i) {
289 totals.AddDeathSnapshot(match_array[i]);
290 }
291 output->append("Aggregate Stats: ");
292 totals.WriteHTML(output);
293 output->append("<hr><hr>");
294
295 Aggregation subtotals;
296 for (size_t i = 0; i < match_array.size(); ++i) {
297 if (0 == i || !comparator.Equivalent(match_array[i - 1],
298 match_array[i])) {
299 // Print group's defining characteristics.
300 comparator.WriteSortGrouping(match_array[i], output);
301 output->append("<br><br>");
236 } 302 }
237 output->append("Aggregate Stats: "); 303 comparator.WriteSnapshotHTML(match_array[i], output);
238 totals.Write(output); 304 output->append("<br>");
239 output->append("<hr><hr>"); 305 subtotals.AddDeathSnapshot(match_array[i]);
240 306 if (i + 1 >= match_array.size() ||
241 Aggregation subtotals; 307 !comparator.Equivalent(match_array[i],
242 for (size_t i = 0; i < match_array.size(); ++i) { 308 match_array[i + 1])) {
243 if (0 == i || !comparator.Equivalent(match_array[i - 1], 309 // Print aggregate stats for the group.
244 match_array[i])) {
245 // Print group's defining characteristics.
246 comparator.WriteSortGrouping(match_array[i], output);
247 output->append("<br><br>");
248 }
249 comparator.WriteSnapshot(match_array[i], output);
250 output->append("<br>"); 310 output->append("<br>");
251 subtotals.AddDeathSnapshot(match_array[i]); 311 subtotals.WriteHTML(output);
252 if (i + 1 >= match_array.size() || 312 output->append("<br><hr><br>");
253 !comparator.Equivalent(match_array[i], 313 subtotals.Clear();
254 match_array[i + 1])) {
255 // Print aggregate stats for the group.
256 output->append("<br>");
257 subtotals.Write(output);
258 output->append("<br><hr><br>");
259 subtotals.Clear();
260 }
261 } 314 }
262 } 315 }
263 } 316 }
264 317
318 // static
319 base::Value* ThreadData::ToValue(int process_type) {
320 DataCollector collected_data; // Gather data.
321 collected_data.AddListOfLivingObjects(); // Add births that are still alive.
322 base::ListValue* list = collected_data.ToValue();
323 base::DictionaryValue* dictionary = new base::DictionaryValue();
324 dictionary->Set("list", list);
325 dictionary->SetInteger("process", process_type);
326 return dictionary;
327 }
328
265 Births* ThreadData::TallyABirth(const Location& location) { 329 Births* ThreadData::TallyABirth(const Location& location) {
266 BirthMap::iterator it = birth_map_.find(location); 330 BirthMap::iterator it = birth_map_.find(location);
267 if (it != birth_map_.end()) { 331 if (it != birth_map_.end()) {
268 it->second->RecordBirth(); 332 it->second->RecordBirth();
269 return it->second; 333 return it->second;
270 } 334 }
271 335
272 Births* tracker = new Births(location); 336 Births* tracker = new Births(location, *this);
273 // Lock since the map may get relocated now, and other threads sometimes 337 // Lock since the map may get relocated now, and other threads sometimes
274 // snapshot it (but they lock before copying it). 338 // snapshot it (but they lock before copying it).
275 base::AutoLock lock(lock_); 339 base::AutoLock lock(lock_);
276 birth_map_[location] = tracker; 340 birth_map_[location] = tracker;
277 return tracker; 341 return tracker;
278 } 342 }
279 343
280 void ThreadData::TallyADeath(const Births& the_birth, 344 void ThreadData::TallyADeath(const Births& birth,
281 const TimeDelta& queue_duration, 345 const TimeDelta& queue_duration,
282 const TimeDelta& run_duration) { 346 const TimeDelta& run_duration) {
283 DeathMap::iterator it = death_map_.find(&the_birth); 347 DeathMap::iterator it = death_map_.find(&birth);
348 DeathData* death_data;
284 if (it != death_map_.end()) { 349 if (it != death_map_.end()) {
285 it->second.RecordDeath(queue_duration, run_duration); 350 death_data = &it->second;
286 return; 351 } else {
287 } 352 base::AutoLock lock(lock_); // Lock since the map may get relocated now.
288 353 death_data = &death_map_[&birth];
289 base::AutoLock lock(lock_); // Lock since the map may get relocated now. 354 } // Release lock ASAP.
290 death_map_[&the_birth].RecordDeath(queue_duration, run_duration); 355 death_data->RecordDeath(queue_duration, run_duration);
291 } 356 }
292 357
293 // static 358 // static
294 Births* ThreadData::TallyABirthIfActive(const Location& location) { 359 Births* ThreadData::TallyABirthIfActive(const Location& location) {
295 #if !defined(TRACK_ALL_TASK_OBJECTS) 360 if (!kTrackAllTaskObjects)
296 return NULL; // Not compiled in. 361 return NULL; // Not compiled in.
297 #else 362
298 if (!IsActive()) 363 if (!IsActive())
299 return NULL; 364 return NULL;
300 ThreadData* current_thread_data = Get(); 365 ThreadData* current_thread_data = Get();
301 if (!current_thread_data) 366 if (!current_thread_data)
302 return NULL; 367 return NULL;
303 return current_thread_data->TallyABirth(location); 368 return current_thread_data->TallyABirth(location);
304 #endif
305 } 369 }
306 370
307 // static 371 // static
308 void ThreadData::TallyADeathIfActive(const Births* the_birth, 372 void ThreadData::TallyADeathIfActive(const Births* birth,
309 const base::TimeTicks& time_posted, 373 const base::TimeTicks& time_posted,
310 const base::TimeTicks& delayed_start_time, 374 const base::TimeTicks& delayed_start_time,
311 const base::TimeTicks& start_of_run) { 375 const base::TimeTicks& start_of_run,
312 #if !defined(TRACK_ALL_TASK_OBJECTS) 376 const base::TimeTicks& end_of_run) {
313 return; // Not compiled in. 377 if (!kTrackAllTaskObjects)
314 #else 378 return; // Not compiled in.
315 if (!IsActive() || !the_birth) 379
380 if (!IsActive() || !birth)
316 return; 381 return;
382
317 ThreadData* current_thread_data = Get(); 383 ThreadData* current_thread_data = Get();
318 if (!current_thread_data) 384 if (!current_thread_data)
319 return; 385 return;
320 386
321 // To avoid conflating our stats with the delay duration in a PostDelayedTask, 387 // To avoid conflating our stats with the delay duration in a PostDelayedTask,
322 // we identify such tasks, and replace their post_time with the time they 388 // we identify such tasks, and replace their post_time with the time they
323 // were sechudled (requested?) to emerge from the delayed task queue. This 389 // were sechudled (requested?) to emerge from the delayed task queue. This
324 // means that queueing delay for such tasks will show how long they went 390 // means that queueing delay for such tasks will show how long they went
325 // unserviced, after they *could* be serviced. This is the same stat as we 391 // unserviced, after they *could* be serviced. This is the same stat as we
326 // have for non-delayed tasks, and we consistently call it queueing delay. 392 // have for non-delayed tasks, and we consistently call it queueing delay.
327 base::TimeTicks effective_post_time = 393 base::TimeTicks effective_post_time =
328 (delayed_start_time.is_null()) ? time_posted : delayed_start_time; 394 (delayed_start_time.is_null()) ? time_posted : delayed_start_time;
329 base::TimeDelta queue_duration = start_of_run - effective_post_time; 395 base::TimeDelta queue_duration = start_of_run - effective_post_time;
330 base::TimeDelta run_duration = Now() - start_of_run; 396 base::TimeDelta run_duration = end_of_run - start_of_run;
331 current_thread_data->TallyADeath(*the_birth, queue_duration, run_duration); 397 current_thread_data->TallyADeath(*birth, queue_duration, run_duration);
332 #endif
333 } 398 }
334 399
335 // static 400 // static
336 ThreadData* ThreadData::first() { 401 ThreadData* ThreadData::first() {
337 base::AutoLock lock(list_lock_); 402 base::AutoLock lock(list_lock_);
338 return first_; 403 return all_thread_data_list_head_;
339 } 404 }
340 405
341 // This may be called from another thread. 406 // This may be called from another thread.
342 void ThreadData::SnapshotBirthMap(BirthMap *output) const { 407 void ThreadData::SnapshotBirthMap(BirthMap *output) const {
343 base::AutoLock lock(lock_); 408 base::AutoLock lock(lock_);
344 for (BirthMap::const_iterator it = birth_map_.begin(); 409 for (BirthMap::const_iterator it = birth_map_.begin();
345 it != birth_map_.end(); ++it) 410 it != birth_map_.end(); ++it)
346 (*output)[it->first] = it->second; 411 (*output)[it->first] = it->second;
347 } 412 }
348 413
349 // This may be called from another thread. 414 // This may be called from another thread.
350 void ThreadData::SnapshotDeathMap(DeathMap *output) const { 415 void ThreadData::SnapshotDeathMap(DeathMap *output) const {
351 base::AutoLock lock(lock_); 416 base::AutoLock lock(lock_);
352 for (DeathMap::const_iterator it = death_map_.begin(); 417 for (DeathMap::const_iterator it = death_map_.begin();
353 it != death_map_.end(); ++it) 418 it != death_map_.end(); ++it)
354 (*output)[it->first] = it->second; 419 (*output)[it->first] = it->second;
355 } 420 }
356 421
357 // static 422 // static
358 void ThreadData::ResetAllThreadData() { 423 void ThreadData::ResetAllThreadData() {
359 ThreadData* my_list = Get()->first(); 424 ThreadData* my_list = first();
360 425
361 for (ThreadData* thread_data = my_list; 426 for (ThreadData* thread_data = my_list;
362 thread_data; 427 thread_data;
363 thread_data = thread_data->next()) 428 thread_data = thread_data->next())
364 thread_data->Reset(); 429 thread_data->Reset();
365 } 430 }
366 431
367 void ThreadData::Reset() { 432 void ThreadData::Reset() {
368 base::AutoLock lock(lock_); 433 base::AutoLock lock(lock_);
369 for (DeathMap::iterator it = death_map_.begin(); 434 for (DeathMap::iterator it = death_map_.begin();
370 it != death_map_.end(); ++it) 435 it != death_map_.end(); ++it)
371 it->second.Clear(); 436 it->second.Clear();
372 for (BirthMap::iterator it = birth_map_.begin(); 437 for (BirthMap::iterator it = birth_map_.begin();
373 it != birth_map_.end(); ++it) 438 it != birth_map_.end(); ++it)
374 it->second->Clear(); 439 it->second->Clear();
375 } 440 }
376 441
377 // static 442 // static
378 bool ThreadData::StartTracking(bool status) { 443 bool ThreadData::StartTracking(bool status) {
379 #if !defined(TRACK_ALL_TASK_OBJECTS) 444 if (!kTrackAllTaskObjects)
380 return false; // Not compiled in. 445 return false; // Not compiled in.
381 #else 446
447 // Do a bit of class initialization.
448 if (!unregistered_thread_data_pool_) {
449 ThreadDataPool* initial_pool = new ThreadDataPool;
450 {
451 base::AutoLock lock(list_lock_);
452 if (!unregistered_thread_data_pool_) {
453 unregistered_thread_data_pool_ = initial_pool;
454 initial_pool = NULL;
455 }
456 }
457 delete initial_pool; // In case it was not used.
458 }
459
460 // Perform the "real" initialization now, and leave it intact through
461 // process termination.
462 if (!tls_index_.initialized())
463 tls_index_.Initialize(&ThreadData::OnThreadTermination);
464 DCHECK(tls_index_.initialized());
465
382 if (!status) { 466 if (!status) {
383 base::AutoLock lock(list_lock_); 467 base::AutoLock lock(list_lock_);
384 DCHECK(status_ == ACTIVE || status_ == SHUTDOWN); 468 DCHECK(status_ == ACTIVE || status_ == SHUTDOWN);
385 status_ = SHUTDOWN; 469 status_ = SHUTDOWN;
386 return true; 470 return true;
387 } 471 }
388 base::AutoLock lock(list_lock_); 472 base::AutoLock lock(list_lock_);
389 DCHECK_EQ(UNINITIALIZED, status_); 473 DCHECK_EQ(UNINITIALIZED, status_);
390 CHECK(tls_index_.Initialize(NULL));
391 status_ = ACTIVE; 474 status_ = ACTIVE;
392 return true; 475 return true;
393 #endif
394 } 476 }
395 477
396 // static 478 // static
397 bool ThreadData::IsActive() { 479 bool ThreadData::IsActive() {
398 return status_ == ACTIVE; 480 return status_ == ACTIVE;
399 } 481 }
400 482
401 // static 483 // static
402 base::TimeTicks ThreadData::Now() { 484 base::TimeTicks ThreadData::Now() {
403 #if defined(TRACK_ALL_TASK_OBJECTS) 485 if (kTrackAllTaskObjects && status_ == ACTIVE)
404 if (status_ == ACTIVE)
405 return base::TimeTicks::Now(); 486 return base::TimeTicks::Now();
406 #endif
407 return base::TimeTicks(); // Super fast when disabled, or not compiled in. 487 return base::TimeTicks(); // Super fast when disabled, or not compiled in.
408 } 488 }
409 489
410 // static 490 // static
411 void ThreadData::ShutdownSingleThreadedCleanup() { 491 void ThreadData::ShutdownSingleThreadedCleanup() {
492 // This is only called from test code, where we need to cleanup so that
493 // additional tests can be run.
412 // We must be single threaded... but be careful anyway. 494 // We must be single threaded... but be careful anyway.
413 if (!StartTracking(false)) 495 if (!StartTracking(false))
414 return; 496 return;
415 ThreadData* thread_data_list; 497 ThreadData* thread_data_list;
498 ThreadDataPool* final_pool;
416 { 499 {
417 base::AutoLock lock(list_lock_); 500 base::AutoLock lock(list_lock_);
418 thread_data_list = first_; 501 thread_data_list = all_thread_data_list_head_;
419 first_ = NULL; 502 all_thread_data_list_head_ = NULL;
503 final_pool = unregistered_thread_data_pool_;
504 unregistered_thread_data_pool_ = NULL;
420 } 505 }
421 506
507 if (final_pool) {
508 // The thread_data_list contains *all* the instances, and we'll use it to
509 // delete them. This pool has pointers to some instances, and we just
510 // have to drop those pointers (and not do the deletes here).
511 while (!final_pool->empty())
512 final_pool->pop();
513 delete final_pool;
514 }
515
516 // Do actual recursive delete in all ThreadData instances.
422 while (thread_data_list) { 517 while (thread_data_list) {
423 ThreadData* next_thread_data = thread_data_list; 518 ThreadData* next_thread_data = thread_data_list;
424 thread_data_list = thread_data_list->next(); 519 thread_data_list = thread_data_list->next();
425 520
426 for (BirthMap::iterator it = next_thread_data->birth_map_.begin(); 521 for (BirthMap::iterator it = next_thread_data->birth_map_.begin();
427 next_thread_data->birth_map_.end() != it; ++it) 522 next_thread_data->birth_map_.end() != it; ++it)
428 delete it->second; // Delete the Birth Records. 523 delete it->second; // Delete the Birth Records.
429 next_thread_data->birth_map_.clear(); 524 next_thread_data->birth_map_.clear();
430 next_thread_data->death_map_.clear(); 525 next_thread_data->death_map_.clear();
431 delete next_thread_data; // Includes all Death Records. 526 delete next_thread_data; // Includes all Death Records.
432 } 527 }
433 528 // Put most global static back in pristine shape.
434 CHECK(tls_index_.initialized()); 529 thread_number_counter = 0;
435 tls_index_.Free(); 530 tls_index_.Set(NULL);
436 DCHECK(!tls_index_.initialized());
437 status_ = UNINITIALIZED; 531 status_ = UNINITIALIZED;
438 } 532 }
439 533
440 //------------------------------------------------------------------------------ 534 //------------------------------------------------------------------------------
441 // Individual 3-tuple of birth (place and thread) along with death thread, and 535 // Individual 3-tuple of birth (place and thread) along with death thread, and
442 // the accumulated stats for instances (DeathData). 536 // the accumulated stats for instances (DeathData).
443 537
444 Snapshot::Snapshot(const BirthOnThread& birth_on_thread, 538 Snapshot::Snapshot(const BirthOnThread& birth_on_thread,
445 const ThreadData& death_thread, 539 const ThreadData& death_thread,
446 const DeathData& death_data) 540 const DeathData& death_data)
447 : birth_(&birth_on_thread), 541 : birth_(&birth_on_thread),
448 death_thread_(&death_thread), 542 death_thread_(&death_thread),
449 death_data_(death_data) { 543 death_data_(death_data) {
450 } 544 }
451 545
452 Snapshot::Snapshot(const BirthOnThread& birth_on_thread, int count) 546 Snapshot::Snapshot(const BirthOnThread& birth_on_thread, int count)
453 : birth_(&birth_on_thread), 547 : birth_(&birth_on_thread),
454 death_thread_(NULL), 548 death_thread_(NULL),
455 death_data_(DeathData(count)) { 549 death_data_(DeathData(count)) {
456 } 550 }
457 551
458 const std::string Snapshot::DeathThreadName() const { 552 const std::string Snapshot::DeathThreadName() const {
459 if (death_thread_) 553 if (death_thread_)
460 return death_thread_->thread_name(); 554 return death_thread_->thread_name();
461 return "Still_Alive"; 555 return "Still_Alive";
462 } 556 }
463 557
464 void Snapshot::Write(std::string* output) const { 558 void Snapshot::WriteHTML(std::string* output) const {
465 death_data_.Write(output); 559 death_data_.WriteHTML(output);
466 base::StringAppendF(output, "%s->%s ", 560 base::StringAppendF(output, "%s->%s ",
467 birth_->birth_thread()->thread_name().c_str(), 561 birth_->birth_thread()->thread_name().c_str(),
468 death_thread_->thread_name().c_str()); 562 DeathThreadName().c_str());
469 birth_->location().Write(true, true, output); 563 birth_->location().Write(true, true, output);
470 } 564 }
471 565
566 base::DictionaryValue* Snapshot::ToValue() const {
567 base::DictionaryValue* dictionary = new base::DictionaryValue;
568 dictionary->Set("death_data", death_data_.ToValue());
569 dictionary->Set("birth_thread",
570 base::Value::CreateStringValue(birth_->birth_thread()->thread_name()));
571 dictionary->Set("death_thread",
572 base::Value::CreateStringValue(DeathThreadName()));
573 dictionary->Set("location", birth_->location().ToValue());
574 return dictionary;
575 }
576
472 void Snapshot::Add(const Snapshot& other) { 577 void Snapshot::Add(const Snapshot& other) {
473 death_data_.AddDeathData(other.death_data_); 578 death_data_.AddDeathData(other.death_data_);
474 } 579 }
475 580
476 //------------------------------------------------------------------------------ 581 //------------------------------------------------------------------------------
477 // DataCollector 582 // DataCollector
478 583
479 DataCollector::DataCollector() { 584 DataCollector::DataCollector() {
480 DCHECK(ThreadData::IsActive()); 585 if (!ThreadData::IsActive())
586 return;
481 587
482 // Get an unchanging copy of a ThreadData list. 588 // Get an unchanging copy of a ThreadData list.
483 ThreadData* my_list = ThreadData::Get()->first(); 589 ThreadData* my_list = ThreadData::first();
484 590
485 // Gather data serially. 591 // Gather data serially.
486 // This hackish approach *can* get some slighly corrupt tallies, as we are 592 // This hackish approach *can* get some slighly corrupt tallies, as we are
487 // grabbing values without the protection of a lock, but it has the advantage 593 // grabbing values without the protection of a lock, but it has the advantage
488 // of working even with threads that don't have message loops. If a user 594 // of working even with threads that don't have message loops. If a user
489 // sees any strangeness, they can always just run their stats gathering a 595 // sees any strangeness, they can always just run their stats gathering a
490 // second time. 596 // second time.
491 for (ThreadData* thread_data = my_list; 597 for (ThreadData* thread_data = my_list;
492 thread_data; 598 thread_data;
493 thread_data = thread_data->next()) { 599 thread_data = thread_data->next()) {
(...skipping 28 matching lines...) Expand all
522 } 628 }
523 629
524 void DataCollector::AddListOfLivingObjects() { 630 void DataCollector::AddListOfLivingObjects() {
525 for (BirthCount::iterator it = global_birth_count_.begin(); 631 for (BirthCount::iterator it = global_birth_count_.begin();
526 it != global_birth_count_.end(); ++it) { 632 it != global_birth_count_.end(); ++it) {
527 if (it->second > 0) 633 if (it->second > 0)
528 collection_.push_back(Snapshot(*it->first, it->second)); 634 collection_.push_back(Snapshot(*it->first, it->second));
529 } 635 }
530 } 636 }
531 637
638 base::ListValue* DataCollector::ToValue() const {
639 base::ListValue* list = new base::ListValue;
640 for (size_t i = 0; i < collection_.size(); ++i) {
641 list->Append(collection_[i].ToValue());
642 }
643 return list;
644 }
645
532 //------------------------------------------------------------------------------ 646 //------------------------------------------------------------------------------
533 // Aggregation 647 // Aggregation
534 648
535 Aggregation::Aggregation() 649 Aggregation::Aggregation()
536 : birth_count_(0) { 650 : birth_count_(0) {
537 } 651 }
538 652
539 Aggregation::~Aggregation() { 653 Aggregation::~Aggregation() {
540 } 654 }
541 655
(...skipping 10 matching lines...) Expand all
552 void Aggregation::AddBirth(const BirthOnThread& birth) { 666 void Aggregation::AddBirth(const BirthOnThread& birth) {
553 AddBirthPlace(birth.location()); 667 AddBirthPlace(birth.location());
554 birth_threads_[birth.birth_thread()]++; 668 birth_threads_[birth.birth_thread()]++;
555 } 669 }
556 670
557 void Aggregation::AddBirthPlace(const Location& location) { 671 void Aggregation::AddBirthPlace(const Location& location) {
558 locations_[location]++; 672 locations_[location]++;
559 birth_files_[location.file_name()]++; 673 birth_files_[location.file_name()]++;
560 } 674 }
561 675
562 void Aggregation::Write(std::string* output) const { 676 void Aggregation::WriteHTML(std::string* output) const {
563 if (locations_.size() == 1) { 677 if (locations_.size() == 1) {
564 locations_.begin()->first.Write(true, true, output); 678 locations_.begin()->first.Write(true, true, output);
565 } else { 679 } else {
566 base::StringAppendF(output, "%" PRIuS " Locations. ", locations_.size()); 680 base::StringAppendF(output, "%" PRIuS " Locations. ", locations_.size());
567 if (birth_files_.size() > 1) { 681 if (birth_files_.size() > 1) {
568 base::StringAppendF(output, "%" PRIuS " Files. ", birth_files_.size()); 682 base::StringAppendF(output, "%" PRIuS " Files. ", birth_files_.size());
569 } else { 683 } else {
570 base::StringAppendF(output, "All born in %s. ", 684 base::StringAppendF(output, "All born in %s. ",
571 birth_files_.begin()->first.c_str()); 685 birth_files_.begin()->first.c_str());
572 } 686 }
(...skipping 15 matching lines...) Expand all
588 base::StringAppendF(output, "All deleted on %s. ", 702 base::StringAppendF(output, "All deleted on %s. ",
589 death_threads_.begin()->first->thread_name().c_str()); 703 death_threads_.begin()->first->thread_name().c_str());
590 } else { 704 } else {
591 output->append("All these objects are still alive."); 705 output->append("All these objects are still alive.");
592 } 706 }
593 } 707 }
594 708
595 if (birth_count_ > 1) 709 if (birth_count_ > 1)
596 base::StringAppendF(output, "Births=%d ", birth_count_); 710 base::StringAppendF(output, "Births=%d ", birth_count_);
597 711
598 DeathData::Write(output); 712 DeathData::WriteHTML(output);
599 } 713 }
600 714
601 void Aggregation::Clear() { 715 void Aggregation::Clear() {
602 birth_count_ = 0; 716 birth_count_ = 0;
603 birth_files_.clear(); 717 birth_files_.clear();
604 locations_.clear(); 718 locations_.clear();
605 birth_threads_.clear(); 719 birth_threads_.clear();
606 DeathData::Clear(); 720 DeathData::Clear();
607 death_threads_.clear(); 721 death_threads_.clear();
608 } 722 }
(...skipping 329 matching lines...) Expand 10 before | Expand all | Expand 10 after
938 1052
939 default: 1053 default:
940 break; 1054 break;
941 } 1055 }
942 if (tiebreaker_ && !use_tiebreaker_for_sort_only_) { 1056 if (tiebreaker_ && !use_tiebreaker_for_sort_only_) {
943 wrote_data |= tiebreaker_->WriteSortGrouping(sample, output); 1057 wrote_data |= tiebreaker_->WriteSortGrouping(sample, output);
944 } 1058 }
945 return wrote_data; 1059 return wrote_data;
946 } 1060 }
947 1061
948 void Comparator::WriteSnapshot(const Snapshot& sample, 1062 void Comparator::WriteSnapshotHTML(const Snapshot& sample,
949 std::string* output) const { 1063 std::string* output) const {
950 sample.death_data().Write(output); 1064 sample.death_data().WriteHTML(output);
951 if (!(combined_selectors_ & BIRTH_THREAD) || 1065 if (!(combined_selectors_ & BIRTH_THREAD) ||
952 !(combined_selectors_ & DEATH_THREAD)) 1066 !(combined_selectors_ & DEATH_THREAD))
953 base::StringAppendF(output, "%s->%s ", 1067 base::StringAppendF(output, "%s->%s ",
954 (combined_selectors_ & BIRTH_THREAD) ? "*" : 1068 (combined_selectors_ & BIRTH_THREAD) ? "*" :
955 sample.birth().birth_thread()->thread_name().c_str(), 1069 sample.birth().birth_thread()->thread_name().c_str(),
956 (combined_selectors_ & DEATH_THREAD) ? "*" : 1070 (combined_selectors_ & DEATH_THREAD) ? "*" :
957 sample.DeathThreadName().c_str()); 1071 sample.DeathThreadName().c_str());
958 sample.birth().location().Write(!(combined_selectors_ & BIRTH_FILE), 1072 sample.birth().location().Write(!(combined_selectors_ & BIRTH_FILE),
959 !(combined_selectors_ & BIRTH_FUNCTION), 1073 !(combined_selectors_ & BIRTH_FUNCTION),
960 output); 1074 output);
961 } 1075 }
962 1076
963 } // namespace tracked_objects 1077 } // namespace tracked_objects
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698