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

Side by Side Diff: base/tracked_objects.cc

Issue 8775061: Support incremental-max and sample in Profiler data (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 9 years 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"
(...skipping 15 matching lines...) Expand all
26 // that we only record after parsing the command line flag --enable-tracking. 26 // that we only record after parsing the command line flag --enable-tracking.
27 // Note that the flag may force either state, so this really controls only the 27 // Note that the flag may force either state, so this really controls only the
28 // period of time up until that flag is parsed. If there is no flag seen, then 28 // period of time up until that flag is parsed. If there is no flag seen, then
29 // this state may prevail for much or all of the process lifetime. 29 // this state may prevail for much or all of the process lifetime.
30 static const ThreadData::Status kInitialStartupState = ThreadData::ACTIVE; 30 static const ThreadData::Status kInitialStartupState = ThreadData::ACTIVE;
31 } // anonymous namespace. 31 } // anonymous namespace.
32 32
33 //------------------------------------------------------------------------------ 33 //------------------------------------------------------------------------------
34 // DeathData tallies durations when a death takes place. 34 // DeathData tallies durations when a death takes place.
35 35
36 void DeathData::RecordDeath(DurationInt queue_duration, 36 DeathData::DeathData() {
37 DurationInt run_duration) { 37 Clear();
38 ++count_;
39 queue_time_.AddDuration(queue_duration);
40 run_time_.AddDuration(run_duration);
41 } 38 }
42 39
43 DurationInt DeathData::AverageMsRunDuration() const { 40 DeathData::DeathData(int count) {
44 return run_time_.AverageMsDuration(count_); 41 Clear();
42 count_ = count;
45 } 43 }
46 44
47 DurationInt DeathData::AverageMsQueueDuration() const { 45 // TODO(jar): I need to see if this macro to optimize branching is worth it.
48 return queue_time_.AverageMsDuration(count_); 46 //
47 // This macro has no branching, so it is surely fast, and is equivalent to:
48 // if (assign_it)
49 // target = source;
50 // We use a macro rather than a template to force this to inline.
51 // Related code for calculating max is discussed on the web.
52 #define CONDITIONAL_ASSIGN(assign_it, target, source) \
53 ((target) ^= ((target) ^ (source)) & -static_cast<DurationInt>(assign_it))
54
55 void DeathData::RecordDeath(const DurationInt queue_duration,
56 const DurationInt run_duration,
57 int32 random_number) {
58 queue_duration_sum_ += queue_duration;
59 run_duration_sum_ += run_duration;
60 ++count_;
61
62 // Take a uniformly distributed sample over all durations ever supplied.
63 // The probability that we (instead) use this new sample is 1/count_. This
64 // results in a completely uniform selection of the sample.
65 // We ignore the fact that we correlated our selection of a sample of run
66 // and queue times.
67 bool take_sample = 0 == (random_number % count_);
68 CONDITIONAL_ASSIGN(take_sample, queue_duration_sample_, queue_duration);
69 CONDITIONAL_ASSIGN(take_sample, run_duration_sample_, run_duration);
70
71 CONDITIONAL_ASSIGN(queue_duration_max_ < queue_duration, queue_duration_max_,
72 queue_duration);
73 CONDITIONAL_ASSIGN(run_duration_max_ < run_duration, run_duration_max_,
74 run_duration);
75 // Ensure we got the macros right.
76 DCHECK_GE(queue_duration_max_, queue_duration);
77 DCHECK_GE(run_duration_max_, run_duration);
78 DCHECK(!take_sample || run_duration_sample_ == run_duration);
79 DCHECK(!take_sample || queue_duration_sample_ == queue_duration);
49 } 80 }
50 81
51 void DeathData::AddDeathData(const DeathData& other) { 82 int DeathData::count() const { return count_; }
52 count_ += other.count_; 83
53 queue_time_.AddData(other.queue_time_); 84 DurationInt DeathData::run_duration_sum() const { return run_duration_sum_; }
54 run_time_.AddData(other.run_time_); 85
86 DurationInt DeathData::run_duration_max() const { return run_duration_max_; }
87
88 DurationInt DeathData::run_duration_sample() const {
89 return run_duration_sample_;
55 } 90 }
56 91
92 DurationInt DeathData::queue_duration_sum() const {
93 return queue_duration_sum_;
94 }
95
96 DurationInt DeathData::queue_duration_max() const {
97 return queue_duration_max_;
98 }
99
100 DurationInt DeathData::queue_duration_sample() const {
101 return queue_duration_sample_;
102 }
103
104
57 base::DictionaryValue* DeathData::ToValue() const { 105 base::DictionaryValue* DeathData::ToValue() const {
58 base::DictionaryValue* dictionary = new base::DictionaryValue; 106 base::DictionaryValue* dictionary = new base::DictionaryValue;
59 dictionary->Set("count", base::Value::CreateIntegerValue(count_)); 107 dictionary->Set("count", base::Value::CreateIntegerValue(count_));
60 dictionary->Set("run_ms", 108 dictionary->Set("run_ms",
61 base::Value::CreateIntegerValue(run_time_.duration())); 109 base::Value::CreateIntegerValue(run_duration_sum()));
110 dictionary->Set("run_ms_max",
111 base::Value::CreateIntegerValue(run_duration_max()));
112 dictionary->Set("run_ms_sample",
113 base::Value::CreateIntegerValue(run_duration_sample()));
62 dictionary->Set("queue_ms", 114 dictionary->Set("queue_ms",
63 base::Value::CreateIntegerValue(queue_time_.duration())); 115 base::Value::CreateIntegerValue(queue_duration_sum()));
64 dictionary->Set("run_ms_max",
65 base::Value::CreateIntegerValue(run_time_.max()));
66 dictionary->Set("queue_ms_max", 116 dictionary->Set("queue_ms_max",
67 base::Value::CreateIntegerValue(queue_time_.max())); 117 base::Value::CreateIntegerValue(queue_duration_max()));
118 dictionary->Set("queue_ms_sample",
119 base::Value::CreateIntegerValue(queue_duration_sample()));
68 return dictionary; 120 return dictionary;
69 } 121 }
70 122
123 void DeathData::ResetMax() {
124 run_duration_max_ = 0;
125 queue_duration_max_ = 0;
126 }
127
71 void DeathData::Clear() { 128 void DeathData::Clear() {
72 count_ = 0; 129 count_ = 0;
73 run_time_.Clear(); 130 run_duration_sum_ = 0;
74 queue_time_.Clear(); 131 run_duration_max_ = 0;
132 run_duration_sample_ = 0;
133 queue_duration_sum_ = 0;
134 queue_duration_max_ = 0;
135 queue_duration_sample_ = 0;
75 } 136 }
76 137
77 //------------------------------------------------------------------------------ 138 //------------------------------------------------------------------------------
78
79 void DeathData::Data::AddData(const Data& other) {
80 duration_ += other.duration_;
81 if (max_ > other.max_)
82 return;
83 max_ = other.max_;
84 }
85
86 void DeathData::Data::AddDuration(DurationInt duration) {
87 duration_ += duration;
88 if (max_ > duration)
89 return;
90 max_ = duration;
91 }
92
93 DurationInt DeathData::Data::AverageMsDuration(int count) const {
94 if (duration_ == 0 || !count)
95 return 0;
96 return (duration_ + count / 2) / count;
97 }
98
99 void DeathData::Data::Clear() {
100 duration_ = 0;
101 max_ = 0;
102 }
103 //------------------------------------------------------------------------------
104 BirthOnThread::BirthOnThread(const Location& location, 139 BirthOnThread::BirthOnThread(const Location& location,
105 const ThreadData& current) 140 const ThreadData& current)
106 : location_(location), 141 : location_(location),
107 birth_thread_(&current) {} 142 birth_thread_(&current) {
143 }
144
145 const Location BirthOnThread::location() const { return location_; }
146 const ThreadData* BirthOnThread::birth_thread() const { return birth_thread_; }
108 147
109 //------------------------------------------------------------------------------ 148 //------------------------------------------------------------------------------
110 Births::Births(const Location& location, const ThreadData& current) 149 Births::Births(const Location& location, const ThreadData& current)
111 : BirthOnThread(location, current), 150 : BirthOnThread(location, current),
112 birth_count_(1) { } 151 birth_count_(1) { }
113 152
153 int Births::birth_count() const { return birth_count_; }
154
155 void Births::RecordBirth() { ++birth_count_; }
156
157 void Births::ForgetBirth() { --birth_count_; }
158
159 void Births::Clear() { birth_count_ = 0; }
160
114 //------------------------------------------------------------------------------ 161 //------------------------------------------------------------------------------
115 // ThreadData maintains the central data for all births and deaths. 162 // ThreadData maintains the central data for all births and deaths on a single
163 // thread.
116 164
117 // TODO(jar): We should pull all these static vars together, into a struct, and 165 // TODO(jar): We should pull all these static vars together, into a struct, and
118 // optimize layout so that we benefit from locality of reference during accesses 166 // optimize layout so that we benefit from locality of reference during accesses
119 // to them. 167 // to them.
120 168
121 // A TLS slot which points to the ThreadData instance for the current thread. We 169 // A TLS slot which points to the ThreadData instance for the current thread. We
122 // do a fake initialization here (zeroing out data), and then the real in-place 170 // do a fake initialization here (zeroing out data), and then the real in-place
123 // construction happens when we call tls_index_.Initialize(). 171 // construction happens when we call tls_index_.Initialize().
124 // static 172 // static
125 base::ThreadLocalStorage::Slot ThreadData::tls_index_(base::LINKER_INITIALIZED); 173 base::ThreadLocalStorage::Slot ThreadData::tls_index_(base::LINKER_INITIALIZED);
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
163 next_retired_worker_(NULL), 211 next_retired_worker_(NULL),
164 worker_thread_number_(thread_number) { 212 worker_thread_number_(thread_number) {
165 CHECK_GT(thread_number, 0); 213 CHECK_GT(thread_number, 0);
166 base::StringAppendF(&thread_name_, "WorkerThread-%d", thread_number); 214 base::StringAppendF(&thread_name_, "WorkerThread-%d", thread_number);
167 PushToHeadOfList(); // Which sets real incarnation_count_for_pool_. 215 PushToHeadOfList(); // Which sets real incarnation_count_for_pool_.
168 } 216 }
169 217
170 ThreadData::~ThreadData() {} 218 ThreadData::~ThreadData() {}
171 219
172 void ThreadData::PushToHeadOfList() { 220 void ThreadData::PushToHeadOfList() {
221 // Toss in a hint of randomness (atop the uniniitalized value).
222 random_number_ += static_cast<int32>(this - static_cast<ThreadData*>(0));
223 random_number_ ^= (Now() - TrackedTime()).InMilliseconds();
224
173 DCHECK(!next_); 225 DCHECK(!next_);
174 base::AutoLock lock(*list_lock_.Pointer()); 226 base::AutoLock lock(*list_lock_.Pointer());
175 incarnation_count_for_pool_ = incarnation_counter_; 227 incarnation_count_for_pool_ = incarnation_counter_;
176 next_ = all_thread_data_list_head_; 228 next_ = all_thread_data_list_head_;
177 all_thread_data_list_head_ = this; 229 all_thread_data_list_head_ = this;
178 } 230 }
179 231
180 // static 232 // static
233 ThreadData* ThreadData::first() {
234 base::AutoLock lock(*list_lock_.Pointer());
235 return all_thread_data_list_head_;
236 }
237
238 ThreadData* ThreadData::next() const { return next_; }
239
240 // static
181 void ThreadData::InitializeThreadContext(const std::string& suggested_name) { 241 void ThreadData::InitializeThreadContext(const std::string& suggested_name) {
182 if (!Initialize()) // Always initialize if needed. 242 if (!Initialize()) // Always initialize if needed.
183 return; 243 return;
184 ThreadData* current_thread_data = 244 ThreadData* current_thread_data =
185 reinterpret_cast<ThreadData*>(tls_index_.Get()); 245 reinterpret_cast<ThreadData*>(tls_index_.Get());
186 if (current_thread_data) 246 if (current_thread_data)
187 return; // Browser tests instigate this. 247 return; // Browser tests instigate this.
188 current_thread_data = new ThreadData(suggested_name); 248 current_thread_data = new ThreadData(suggested_name);
189 tls_index_.Set(current_thread_data); 249 tls_index_.Set(current_thread_data);
190 } 250 }
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
245 return; 305 return;
246 } 306 }
247 // We must NOT do any allocations during this callback. 307 // We must NOT do any allocations during this callback.
248 // Using the simple linked lists avoids all allocations. 308 // Using the simple linked lists avoids all allocations.
249 DCHECK_EQ(this->next_retired_worker_, reinterpret_cast<ThreadData*>(NULL)); 309 DCHECK_EQ(this->next_retired_worker_, reinterpret_cast<ThreadData*>(NULL));
250 this->next_retired_worker_ = first_retired_worker_; 310 this->next_retired_worker_ = first_retired_worker_;
251 first_retired_worker_ = this; 311 first_retired_worker_ = this;
252 } 312 }
253 313
254 // static 314 // static
255 base::DictionaryValue* ThreadData::ToValue() { 315 base::DictionaryValue* ThreadData::ToValue(bool reset_max) {
256 DataCollector collected_data; // Gather data. 316 DataCollector collected_data; // Gather data.
317 // Request multiple calls to collected_data.Append() for all threads.
318 SendAllMaps(reset_max, &collected_data);
257 collected_data.AddListOfLivingObjects(); // Add births that are still alive. 319 collected_data.AddListOfLivingObjects(); // Add births that are still alive.
258 base::ListValue* list = collected_data.ToValue(); 320 base::ListValue* list = collected_data.ToValue();
259 base::DictionaryValue* dictionary = new base::DictionaryValue(); 321 base::DictionaryValue* dictionary = new base::DictionaryValue();
260 dictionary->Set("list", list); 322 dictionary->Set("list", list);
261 return dictionary; 323 return dictionary;
262 } 324 }
263 325
264 Births* ThreadData::TallyABirth(const Location& location) { 326 Births* ThreadData::TallyABirth(const Location& location) {
265 BirthMap::iterator it = birth_map_.find(location); 327 BirthMap::iterator it = birth_map_.find(location);
266 if (it != birth_map_.end()) { 328 if (it != birth_map_.end()) {
267 it->second->RecordBirth(); 329 it->second->RecordBirth();
268 return it->second; 330 return it->second;
269 } 331 }
270 332
271 Births* tracker = new Births(location, *this); 333 Births* tracker = new Births(location, *this);
272 // Lock since the map may get relocated now, and other threads sometimes 334 // Lock since the map may get relocated now, and other threads sometimes
273 // snapshot it (but they lock before copying it). 335 // snapshot it (but they lock before copying it).
274 base::AutoLock lock(map_lock_); 336 base::AutoLock lock(map_lock_);
275 birth_map_[location] = tracker; 337 birth_map_[location] = tracker;
276 return tracker; 338 return tracker;
277 } 339 }
278 340
279 void ThreadData::TallyADeath(const Births& birth, 341 void ThreadData::TallyADeath(const Births& birth,
280 DurationInt queue_duration, 342 DurationInt queue_duration,
281 DurationInt run_duration) { 343 DurationInt run_duration) {
344 // Stir in some randomness, plus add constant in case durations are zero.
345 const DurationInt kSomePrimeNumber = 4294967279;
346 random_number_ += queue_duration + run_duration + kSomePrimeNumber;
347 // An address is going to have some randomness to it as well ;-).
348 random_number_ ^= static_cast<int32>(&birth - reinterpret_cast<Births*>(0));
349
282 DeathMap::iterator it = death_map_.find(&birth); 350 DeathMap::iterator it = death_map_.find(&birth);
283 DeathData* death_data; 351 DeathData* death_data;
284 if (it != death_map_.end()) { 352 if (it != death_map_.end()) {
285 death_data = &it->second; 353 death_data = &it->second;
286 } else { 354 } else {
287 base::AutoLock lock(map_lock_); // Lock as the map may get relocated now. 355 base::AutoLock lock(map_lock_); // Lock as the map may get relocated now.
288 death_data = &death_map_[&birth]; 356 death_data = &death_map_[&birth];
289 } // Release lock ASAP. 357 } // Release lock ASAP.
290 death_data->RecordDeath(queue_duration, run_duration); 358 death_data->RecordDeath(queue_duration, run_duration, random_number_);
291 } 359 }
292 360
293 // static 361 // static
294 Births* ThreadData::TallyABirthIfActive(const Location& location) { 362 Births* ThreadData::TallyABirthIfActive(const Location& location) {
295 if (!kTrackAllTaskObjects) 363 if (!kTrackAllTaskObjects)
296 return NULL; // Not compiled in. 364 return NULL; // Not compiled in.
297 365
298 if (!tracking_status()) 366 if (!tracking_status())
299 return NULL; 367 return NULL;
300 ThreadData* current_thread_data = Get(); 368 ThreadData* current_thread_data = Get();
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after
402 if (!current_thread_data) 470 if (!current_thread_data)
403 return; 471 return;
404 472
405 DurationInt queue_duration = 0; 473 DurationInt queue_duration = 0;
406 DurationInt run_duration = 0; 474 DurationInt run_duration = 0;
407 if (!start_of_run.is_null() && !end_of_run.is_null()) 475 if (!start_of_run.is_null() && !end_of_run.is_null())
408 run_duration = (end_of_run - start_of_run).InMilliseconds(); 476 run_duration = (end_of_run - start_of_run).InMilliseconds();
409 current_thread_data->TallyADeath(*birth, queue_duration, run_duration); 477 current_thread_data->TallyADeath(*birth, queue_duration, run_duration);
410 } 478 }
411 479
412 // static 480 const std::string ThreadData::thread_name() const { return thread_name_; }
413 ThreadData* ThreadData::first() {
414 base::AutoLock lock(*list_lock_.Pointer());
415 return all_thread_data_list_head_;
416 }
417 481
418 // This may be called from another thread. 482 // This may be called from another thread.
419 void ThreadData::SnapshotBirthMap(BirthMap *output) const { 483 void ThreadData::SnapshotMaps(bool reset_max,
484 BirthMap* birth_map,
485 DeathMap* death_map) {
420 base::AutoLock lock(map_lock_); 486 base::AutoLock lock(map_lock_);
421 for (BirthMap::const_iterator it = birth_map_.begin(); 487 for (BirthMap::const_iterator it = birth_map_.begin();
422 it != birth_map_.end(); ++it) 488 it != birth_map_.end(); ++it)
423 (*output)[it->first] = it->second; 489 (*birth_map)[it->first] = it->second;
424 } 490 for (DeathMap::iterator it = death_map_.begin();
425 491 it != death_map_.end(); ++it) {
426 // This may be called from another thread. 492 (*death_map)[it->first] = it->second;
427 void ThreadData::SnapshotDeathMap(DeathMap *output) const { 493 if (reset_max)
428 base::AutoLock lock(map_lock_); 494 it->second.ResetMax();
429 for (DeathMap::const_iterator it = death_map_.begin(); 495 }
430 it != death_map_.end(); ++it)
431 (*output)[it->first] = it->second;
432 } 496 }
433 497
434 // static 498 // static
499 void ThreadData::SendAllMaps(bool reset_max, class DataCollector* target) {
500 if (!kTrackAllTaskObjects)
501 return; // Not compiled in.
502 // Get an unchanging copy of a ThreadData list.
503 ThreadData* my_list = ThreadData::first();
504
505 // Gather data serially.
506 // This hackish approach *can* get some slighly corrupt tallies, as we are
507 // grabbing values without the protection of a lock, but it has the advantage
508 // of working even with threads that don't have message loops. If a user
509 // sees any strangeness, they can always just run their stats gathering a
510 // second time.
511 for (ThreadData* thread_data = my_list;
512 thread_data;
513 thread_data = thread_data->next()) {
514 // Get copy of data.
515 ThreadData::BirthMap birth_map;
516 ThreadData::DeathMap death_map;
517 thread_data->SnapshotMaps(reset_max, &birth_map, &death_map);
518 target->Append(*thread_data, birth_map, death_map);
519 }
520 }
521
522 // static
435 void ThreadData::ResetAllThreadData() { 523 void ThreadData::ResetAllThreadData() {
436 ThreadData* my_list = first(); 524 ThreadData* my_list = first();
437 525
438 for (ThreadData* thread_data = my_list; 526 for (ThreadData* thread_data = my_list;
439 thread_data; 527 thread_data;
440 thread_data = thread_data->next()) 528 thread_data = thread_data->next())
441 thread_data->Reset(); 529 thread_data->Reset();
442 } 530 }
443 531
444 void ThreadData::Reset() { 532 void ThreadData::Reset() {
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
536 // We must be single threaded... but be careful anyway. 624 // We must be single threaded... but be careful anyway.
537 if (!InitializeAndSetTrackingStatus(false)) 625 if (!InitializeAndSetTrackingStatus(false))
538 return; 626 return;
539 ThreadData* thread_data_list; 627 ThreadData* thread_data_list;
540 { 628 {
541 base::AutoLock lock(*list_lock_.Pointer()); 629 base::AutoLock lock(*list_lock_.Pointer());
542 thread_data_list = all_thread_data_list_head_; 630 thread_data_list = all_thread_data_list_head_;
543 all_thread_data_list_head_ = NULL; 631 all_thread_data_list_head_ = NULL;
544 ++incarnation_counter_; 632 ++incarnation_counter_;
545 // To be clean, break apart the retired worker list (though we leak them). 633 // To be clean, break apart the retired worker list (though we leak them).
546 while(first_retired_worker_) { 634 while (first_retired_worker_) {
547 ThreadData* worker = first_retired_worker_; 635 ThreadData* worker = first_retired_worker_;
548 CHECK_GT(worker->worker_thread_number_, 0); 636 CHECK_GT(worker->worker_thread_number_, 0);
549 first_retired_worker_ = worker->next_retired_worker_; 637 first_retired_worker_ = worker->next_retired_worker_;
550 worker->next_retired_worker_ = NULL; 638 worker->next_retired_worker_ = NULL;
551 } 639 }
552 } 640 }
553 641
554 // Put most global static back in pristine shape. 642 // Put most global static back in pristine shape.
555 worker_thread_data_creation_count_ = 0; 643 worker_thread_data_creation_count_ = 0;
556 cleanup_count_ = 0; 644 cleanup_count_ = 0;
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
610 base::Value::CreateStringValue(birth_->birth_thread()->thread_name())); 698 base::Value::CreateStringValue(birth_->birth_thread()->thread_name()));
611 dictionary->Set("death_thread", 699 dictionary->Set("death_thread",
612 base::Value::CreateStringValue(DeathThreadName())); 700 base::Value::CreateStringValue(DeathThreadName()));
613 dictionary->Set("location", birth_->location().ToValue()); 701 dictionary->Set("location", birth_->location().ToValue());
614 return dictionary; 702 return dictionary;
615 } 703 }
616 704
617 //------------------------------------------------------------------------------ 705 //------------------------------------------------------------------------------
618 // DataCollector 706 // DataCollector
619 707
620 DataCollector::DataCollector() { 708 DataCollector::DataCollector() {}
621 if (!kTrackAllTaskObjects)
622 return; // Not compiled in.
623
624 // Get an unchanging copy of a ThreadData list.
625 ThreadData* my_list = ThreadData::first();
626
627 // Gather data serially.
628 // This hackish approach *can* get some slighly corrupt tallies, as we are
629 // grabbing values without the protection of a lock, but it has the advantage
630 // of working even with threads that don't have message loops. If a user
631 // sees any strangeness, they can always just run their stats gathering a
632 // second time.
633 for (ThreadData* thread_data = my_list;
634 thread_data;
635 thread_data = thread_data->next()) {
636 Append(*thread_data);
637 }
638 }
639 709
640 DataCollector::~DataCollector() { 710 DataCollector::~DataCollector() {
641 } 711 }
642 712
643 void DataCollector::Append(const ThreadData& thread_data) { 713 void DataCollector::Append(const ThreadData &thread_data,
644 // Get copy of data. 714 const ThreadData::BirthMap &birth_map,
645 ThreadData::BirthMap birth_map; 715 const ThreadData::DeathMap &death_map) {
646 thread_data.SnapshotBirthMap(&birth_map);
647 ThreadData::DeathMap death_map;
648 thread_data.SnapshotDeathMap(&death_map);
649
650 for (ThreadData::DeathMap::const_iterator it = death_map.begin(); 716 for (ThreadData::DeathMap::const_iterator it = death_map.begin();
651 it != death_map.end(); ++it) { 717 it != death_map.end(); ++it) {
652 collection_.push_back(Snapshot(*it->first, thread_data, it->second)); 718 collection_.push_back(Snapshot(*it->first, thread_data, it->second));
653 global_birth_count_[it->first] -= it->first->birth_count(); 719 global_birth_count_[it->first] -= it->first->birth_count();
654 } 720 }
655 721
656 for (ThreadData::BirthMap::const_iterator it = birth_map.begin(); 722 for (ThreadData::BirthMap::const_iterator it = birth_map.begin();
657 it != birth_map.end(); ++it) { 723 it != birth_map.end(); ++it) {
658 global_birth_count_[it->second] += it->second->birth_count(); 724 global_birth_count_[it->second] += it->second->birth_count();
659 } 725 }
(...skipping 13 matching lines...) Expand all
673 739
674 base::ListValue* DataCollector::ToValue() const { 740 base::ListValue* DataCollector::ToValue() const {
675 base::ListValue* list = new base::ListValue; 741 base::ListValue* list = new base::ListValue;
676 for (size_t i = 0; i < collection_.size(); ++i) { 742 for (size_t i = 0; i < collection_.size(); ++i) {
677 list->Append(collection_[i].ToValue()); 743 list->Append(collection_[i].ToValue());
678 } 744 }
679 return list; 745 return list;
680 } 746 }
681 747
682 } // namespace tracked_objects 748 } // namespace tracked_objects
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698