| OLD | NEW |
| 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/stringprintf.h" | 11 #include "base/stringprintf.h" |
| 12 #include "base/third_party/valgrind/memcheck.h" | 12 #include "base/third_party/valgrind/memcheck.h" |
| 13 #include "base/threading/thread_restrictions.h" | 13 #include "base/threading/thread_restrictions.h" |
| 14 #include "build/build_config.h" | 14 #include "build/build_config.h" |
| 15 #include "base/port.h" | 15 #include "base/port.h" |
| 16 | 16 |
| 17 using base::TimeDelta; | 17 using base::TimeDelta; |
| 18 | 18 |
| 19 namespace tracked_objects { | 19 namespace tracked_objects { |
| 20 | 20 |
| 21 namespace { | 21 namespace { |
| 22 // Flag to compile out almost all of the task tracking code. | 22 // Flag to compile out almost all of the task tracking code. |
| 23 static const bool kTrackAllTaskObjects = true; | 23 static const bool kTrackAllTaskObjects = true; |
| 24 | 24 |
| 25 // Flag to compile out parent-child link recording. |
| 26 static const bool kTrackParentChildLinks = false; |
| 27 |
| 25 // When ThreadData is first initialized, should we start in an ACTIVE state to | 28 // When ThreadData is first initialized, should we start in an ACTIVE state to |
| 26 // record all of the startup-time tasks, or should we start up DEACTIVATED, so | 29 // record all of the startup-time tasks, or should we start up DEACTIVATED, so |
| 27 // that we only record after parsing the command line flag --enable-tracking. | 30 // that we only record after parsing the command line flag --enable-tracking. |
| 28 // Note that the flag may force either state, so this really controls only the | 31 // Note that the flag may force either state, so this really controls only the |
| 29 // period of time up until that flag is parsed. If there is no flag seen, then | 32 // period of time up until that flag is parsed. If there is no flag seen, then |
| 30 // this state may prevail for much or all of the process lifetime. | 33 // this state may prevail for much or all of the process lifetime. |
| 31 static const ThreadData::Status kInitialStartupState = ThreadData::ACTIVE; | 34 static const ThreadData::Status kInitialStartupState = |
| 32 } // anonymous namespace. | 35 ThreadData::PROFILING_CHILDREN_ACTIVE; |
| 36 } // namespace |
| 33 | 37 |
| 34 //------------------------------------------------------------------------------ | 38 //------------------------------------------------------------------------------ |
| 35 // DeathData tallies durations when a death takes place. | 39 // DeathData tallies durations when a death takes place. |
| 36 | 40 |
| 37 DeathData::DeathData() { | 41 DeathData::DeathData() { |
| 38 Clear(); | 42 Clear(); |
| 39 } | 43 } |
| 40 | 44 |
| 41 DeathData::DeathData(int count) { | 45 DeathData::DeathData(int count) { |
| 42 Clear(); | 46 Clear(); |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 135 //------------------------------------------------------------------------------ | 139 //------------------------------------------------------------------------------ |
| 136 BirthOnThread::BirthOnThread(const Location& location, | 140 BirthOnThread::BirthOnThread(const Location& location, |
| 137 const ThreadData& current) | 141 const ThreadData& current) |
| 138 : location_(location), | 142 : location_(location), |
| 139 birth_thread_(¤t) { | 143 birth_thread_(¤t) { |
| 140 } | 144 } |
| 141 | 145 |
| 142 const Location BirthOnThread::location() const { return location_; } | 146 const Location BirthOnThread::location() const { return location_; } |
| 143 const ThreadData* BirthOnThread::birth_thread() const { return birth_thread_; } | 147 const ThreadData* BirthOnThread::birth_thread() const { return birth_thread_; } |
| 144 | 148 |
| 149 void BirthOnThread::ToValue(const std::string& prefix, |
| 150 base::DictionaryValue* dictionary) const { |
| 151 dictionary->Set(prefix + "_location", location_.ToValue()); |
| 152 dictionary->Set(prefix + "_thread", |
| 153 base::Value::CreateStringValue(birth_thread_->thread_name())); |
| 154 } |
| 155 |
| 145 //------------------------------------------------------------------------------ | 156 //------------------------------------------------------------------------------ |
| 146 Births::Births(const Location& location, const ThreadData& current) | 157 Births::Births(const Location& location, const ThreadData& current) |
| 147 : BirthOnThread(location, current), | 158 : BirthOnThread(location, current), |
| 148 birth_count_(1) { } | 159 birth_count_(1) { } |
| 149 | 160 |
| 150 int Births::birth_count() const { return birth_count_; } | 161 int Births::birth_count() const { return birth_count_; } |
| 151 | 162 |
| 152 void Births::RecordBirth() { ++birth_count_; } | 163 void Births::RecordBirth() { ++birth_count_; } |
| 153 | 164 |
| 154 void Births::ForgetBirth() { --birth_count_; } | 165 void Births::ForgetBirth() { --birth_count_; } |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 186 | 197 |
| 187 // static | 198 // static |
| 188 base::LazyInstance<base::Lock, | 199 base::LazyInstance<base::Lock, |
| 189 base::LeakyLazyInstanceTraits<base::Lock> > | 200 base::LeakyLazyInstanceTraits<base::Lock> > |
| 190 ThreadData::list_lock_ = LAZY_INSTANCE_INITIALIZER; | 201 ThreadData::list_lock_ = LAZY_INSTANCE_INITIALIZER; |
| 191 | 202 |
| 192 // static | 203 // static |
| 193 ThreadData::Status ThreadData::status_ = ThreadData::UNINITIALIZED; | 204 ThreadData::Status ThreadData::status_ = ThreadData::UNINITIALIZED; |
| 194 | 205 |
| 195 ThreadData::ThreadData(const std::string& suggested_name) | 206 ThreadData::ThreadData(const std::string& suggested_name) |
| 196 : incarnation_count_for_pool_(-1), | 207 : next_(NULL), |
| 197 next_(NULL), | |
| 198 next_retired_worker_(NULL), | 208 next_retired_worker_(NULL), |
| 199 worker_thread_number_(0) { | 209 worker_thread_number_(0), |
| 210 incarnation_count_for_pool_(-1) { |
| 200 DCHECK_GE(suggested_name.size(), 0u); | 211 DCHECK_GE(suggested_name.size(), 0u); |
| 201 thread_name_ = suggested_name; | 212 thread_name_ = suggested_name; |
| 202 PushToHeadOfList(); // Which sets real incarnation_count_for_pool_. | 213 PushToHeadOfList(); // Which sets real incarnation_count_for_pool_. |
| 203 } | 214 } |
| 204 | 215 |
| 205 ThreadData::ThreadData(int thread_number) | 216 ThreadData::ThreadData(int thread_number) |
| 206 : incarnation_count_for_pool_(-1), | 217 : next_(NULL), |
| 207 next_(NULL), | |
| 208 next_retired_worker_(NULL), | 218 next_retired_worker_(NULL), |
| 209 worker_thread_number_(thread_number) { | 219 worker_thread_number_(thread_number), |
| 220 incarnation_count_for_pool_(-1) { |
| 210 CHECK_GT(thread_number, 0); | 221 CHECK_GT(thread_number, 0); |
| 211 base::StringAppendF(&thread_name_, "WorkerThread-%d", thread_number); | 222 base::StringAppendF(&thread_name_, "WorkerThread-%d", thread_number); |
| 212 PushToHeadOfList(); // Which sets real incarnation_count_for_pool_. | 223 PushToHeadOfList(); // Which sets real incarnation_count_for_pool_. |
| 213 } | 224 } |
| 214 | 225 |
| 215 ThreadData::~ThreadData() {} | 226 ThreadData::~ThreadData() {} |
| 216 | 227 |
| 217 void ThreadData::PushToHeadOfList() { | 228 void ThreadData::PushToHeadOfList() { |
| 218 // Toss in a hint of randomness (atop the uniniitalized value). | 229 // Toss in a hint of randomness (atop the uniniitalized value). |
| 219 (void)VALGRIND_MAKE_MEM_DEFINED_IF_ADDRESSABLE(&random_number_, | 230 (void)VALGRIND_MAKE_MEM_DEFINED_IF_ADDRESSABLE(&random_number_, |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 276 worker_thread_data = new ThreadData(worker_thread_number); | 287 worker_thread_data = new ThreadData(worker_thread_number); |
| 277 } | 288 } |
| 278 DCHECK_GT(worker_thread_data->worker_thread_number_, 0); | 289 DCHECK_GT(worker_thread_data->worker_thread_number_, 0); |
| 279 | 290 |
| 280 tls_index_.Set(worker_thread_data); | 291 tls_index_.Set(worker_thread_data); |
| 281 return worker_thread_data; | 292 return worker_thread_data; |
| 282 } | 293 } |
| 283 | 294 |
| 284 // static | 295 // static |
| 285 void ThreadData::OnThreadTermination(void* thread_data) { | 296 void ThreadData::OnThreadTermination(void* thread_data) { |
| 297 DCHECK(thread_data); // TLS should *never* call us with a NULL. |
| 286 // We must NOT do any allocations during this callback. There is a chance | 298 // We must NOT do any allocations during this callback. There is a chance |
| 287 // that the allocator is no longer active on this thread. | 299 // that the allocator is no longer active on this thread. |
| 288 if (!kTrackAllTaskObjects) | 300 if (!kTrackAllTaskObjects) |
| 289 return; // Not compiled in. | 301 return; // Not compiled in. |
| 290 if (!thread_data) | |
| 291 return; | |
| 292 reinterpret_cast<ThreadData*>(thread_data)->OnThreadTerminationCleanup(); | 302 reinterpret_cast<ThreadData*>(thread_data)->OnThreadTerminationCleanup(); |
| 293 } | 303 } |
| 294 | 304 |
| 295 void ThreadData::OnThreadTerminationCleanup() { | 305 void ThreadData::OnThreadTerminationCleanup() { |
| 296 // The list_lock_ was created when we registered the callback, so it won't be | 306 // The list_lock_ was created when we registered the callback, so it won't be |
| 297 // allocated here despite the lazy reference. | 307 // allocated here despite the lazy reference. |
| 298 base::AutoLock lock(*list_lock_.Pointer()); | 308 base::AutoLock lock(*list_lock_.Pointer()); |
| 299 if (incarnation_counter_ != incarnation_count_for_pool_) | 309 if (incarnation_counter_ != incarnation_count_for_pool_) |
| 300 return; // ThreadData was constructed in an earlier unit test. | 310 return; // ThreadData was constructed in an earlier unit test. |
| 301 ++cleanup_count_; | 311 ++cleanup_count_; |
| 302 // Only worker threads need to be retired and reused. | 312 // Only worker threads need to be retired and reused. |
| 303 if (!worker_thread_number_) { | 313 if (!worker_thread_number_) { |
| 304 return; | 314 return; |
| 305 } | 315 } |
| 306 // We must NOT do any allocations during this callback. | 316 // We must NOT do any allocations during this callback. |
| 307 // Using the simple linked lists avoids all allocations. | 317 // Using the simple linked lists avoids all allocations. |
| 308 DCHECK_EQ(this->next_retired_worker_, reinterpret_cast<ThreadData*>(NULL)); | 318 DCHECK_EQ(this->next_retired_worker_, reinterpret_cast<ThreadData*>(NULL)); |
| 309 this->next_retired_worker_ = first_retired_worker_; | 319 this->next_retired_worker_ = first_retired_worker_; |
| 310 first_retired_worker_ = this; | 320 first_retired_worker_ = this; |
| 311 } | 321 } |
| 312 | 322 |
| 313 // static | 323 // static |
| 314 base::DictionaryValue* ThreadData::ToValue(bool reset_max) { | 324 base::DictionaryValue* ThreadData::ToValue(bool reset_max) { |
| 315 DataCollector collected_data; // Gather data. | 325 DataCollector collected_data; // Gather data. |
| 316 // Request multiple calls to collected_data.Append() for all threads. | 326 // Request multiple calls to collected_data.Append() for all threads. |
| 317 SendAllMaps(reset_max, &collected_data); | 327 SendAllMaps(reset_max, &collected_data); |
| 318 collected_data.AddListOfLivingObjects(); // Add births that are still alive. | 328 collected_data.AddListOfLivingObjects(); // Add births that are still alive. |
| 319 base::ListValue* list = collected_data.ToValue(); | |
| 320 base::DictionaryValue* dictionary = new base::DictionaryValue(); | 329 base::DictionaryValue* dictionary = new base::DictionaryValue(); |
| 321 dictionary->Set("list", list); | 330 collected_data.ToValue(dictionary); |
| 322 return dictionary; | 331 return dictionary; |
| 323 } | 332 } |
| 324 | 333 |
| 325 Births* ThreadData::TallyABirth(const Location& location) { | 334 Births* ThreadData::TallyABirth(const Location& location) { |
| 326 BirthMap::iterator it = birth_map_.find(location); | 335 BirthMap::iterator it = birth_map_.find(location); |
| 336 Births* child; |
| 327 if (it != birth_map_.end()) { | 337 if (it != birth_map_.end()) { |
| 328 it->second->RecordBirth(); | 338 child = it->second; |
| 329 return it->second; | 339 child->RecordBirth(); |
| 340 } else { |
| 341 child = new Births(location, *this); // Leak this. |
| 342 // Lock since the map may get relocated now, and other threads sometimes |
| 343 // snapshot it (but they lock before copying it). |
| 344 base::AutoLock lock(map_lock_); |
| 345 birth_map_[location] = child; |
| 330 } | 346 } |
| 331 | 347 |
| 332 Births* tracker = new Births(location, *this); | 348 if (kTrackParentChildLinks && status_ > PROFILING_ACTIVE && |
| 333 // Lock since the map may get relocated now, and other threads sometimes | 349 !parent_stack_.empty()) { |
| 334 // snapshot it (but they lock before copying it). | 350 const Births* parent = parent_stack_.top(); |
| 335 base::AutoLock lock(map_lock_); | 351 ParentChildPair pair(parent, child); |
| 336 birth_map_[location] = tracker; | 352 if (parent_child_set_.find(pair) == parent_child_set_.end()) { |
| 337 return tracker; | 353 // Lock since the map may get relocated now, and other threads sometimes |
| 354 // snapshot it (but they lock before copying it). |
| 355 base::AutoLock lock(map_lock_); |
| 356 parent_child_set_.insert(pair); |
| 357 } |
| 358 } |
| 359 |
| 360 return child; |
| 338 } | 361 } |
| 339 | 362 |
| 340 void ThreadData::TallyADeath(const Births& birth, | 363 void ThreadData::TallyADeath(const Births& birth, |
| 341 DurationInt queue_duration, | 364 DurationInt queue_duration, |
| 342 DurationInt run_duration) { | 365 DurationInt run_duration) { |
| 343 // Stir in some randomness, plus add constant in case durations are zero. | 366 // Stir in some randomness, plus add constant in case durations are zero. |
| 344 const DurationInt kSomePrimeNumber = 5939; // To big is 4294967279; | 367 const DurationInt kSomePrimeNumber = 2147483647; |
| 345 random_number_ += queue_duration + run_duration + kSomePrimeNumber; | 368 random_number_ += queue_duration + run_duration + kSomePrimeNumber; |
| 346 // An address is going to have some randomness to it as well ;-). | 369 // An address is going to have some randomness to it as well ;-). |
| 347 random_number_ ^= static_cast<int32>(&birth - reinterpret_cast<Births*>(0)); | 370 random_number_ ^= static_cast<int32>(&birth - reinterpret_cast<Births*>(0)); |
| 348 | 371 |
| 349 DeathMap::iterator it = death_map_.find(&birth); | 372 DeathMap::iterator it = death_map_.find(&birth); |
| 350 DeathData* death_data; | 373 DeathData* death_data; |
| 351 if (it != death_map_.end()) { | 374 if (it != death_map_.end()) { |
| 352 death_data = &it->second; | 375 death_data = &it->second; |
| 353 } else { | 376 } else { |
| 354 base::AutoLock lock(map_lock_); // Lock as the map may get relocated now. | 377 base::AutoLock lock(map_lock_); // Lock as the map may get relocated now. |
| 355 death_data = &death_map_[&birth]; | 378 death_data = &death_map_[&birth]; |
| 356 } // Release lock ASAP. | 379 } // Release lock ASAP. |
| 357 death_data->RecordDeath(queue_duration, run_duration, random_number_); | 380 death_data->RecordDeath(queue_duration, run_duration, random_number_); |
| 381 |
| 382 if (!kTrackParentChildLinks) |
| 383 return; |
| 384 if (!parent_stack_.empty()) { // We might get turned off. |
| 385 DCHECK_EQ(parent_stack_.top(), &birth); |
| 386 parent_stack_.pop(); |
| 387 } |
| 358 } | 388 } |
| 359 | 389 |
| 360 // static | 390 // static |
| 361 Births* ThreadData::TallyABirthIfActive(const Location& location) { | 391 Births* ThreadData::TallyABirthIfActive(const Location& location) { |
| 362 if (!kTrackAllTaskObjects) | 392 if (!kTrackAllTaskObjects) |
| 363 return NULL; // Not compiled in. | 393 return NULL; // Not compiled in. |
| 364 | 394 |
| 365 if (!tracking_status()) | 395 if (!tracking_status()) |
| 366 return NULL; | 396 return NULL; |
| 367 ThreadData* current_thread_data = Get(); | 397 ThreadData* current_thread_data = Get(); |
| (...skipping 24 matching lines...) Expand all Loading... |
| 392 // we identify such tasks, and replace their post_time with the time they | 422 // we identify such tasks, and replace their post_time with the time they |
| 393 // were scheduled (requested?) to emerge from the delayed task queue. This | 423 // were scheduled (requested?) to emerge from the delayed task queue. This |
| 394 // means that queueing delay for such tasks will show how long they went | 424 // means that queueing delay for such tasks will show how long they went |
| 395 // unserviced, after they *could* be serviced. This is the same stat as we | 425 // unserviced, after they *could* be serviced. This is the same stat as we |
| 396 // have for non-delayed tasks, and we consistently call it queueing delay. | 426 // have for non-delayed tasks, and we consistently call it queueing delay. |
| 397 TrackedTime effective_post_time = completed_task.delayed_run_time.is_null() | 427 TrackedTime effective_post_time = completed_task.delayed_run_time.is_null() |
| 398 ? tracked_objects::TrackedTime(completed_task.time_posted) | 428 ? tracked_objects::TrackedTime(completed_task.time_posted) |
| 399 : tracked_objects::TrackedTime(completed_task.delayed_run_time); | 429 : tracked_objects::TrackedTime(completed_task.delayed_run_time); |
| 400 | 430 |
| 401 // Watch out for a race where status_ is changing, and hence one or both | 431 // Watch out for a race where status_ is changing, and hence one or both |
| 402 // of start_of_run or end_of_run is zero. IN that case, we didn't bother to | 432 // of start_of_run or end_of_run is zero. In that case, we didn't bother to |
| 403 // get a time value since we "weren't tracking" and we were trying to be | 433 // get a time value since we "weren't tracking" and we were trying to be |
| 404 // efficient by not calling for a genuine time value. For simplicity, we'll | 434 // efficient by not calling for a genuine time value. For simplicity, we'll |
| 405 // use a default zero duration when we can't calculate a true value. | 435 // use a default zero duration when we can't calculate a true value. |
| 406 DurationInt queue_duration = 0; | 436 DurationInt queue_duration = 0; |
| 407 DurationInt run_duration = 0; | 437 DurationInt run_duration = 0; |
| 408 if (!start_of_run.is_null()) { | 438 if (!start_of_run.is_null()) { |
| 409 queue_duration = (start_of_run - effective_post_time).InMilliseconds(); | 439 queue_duration = (start_of_run - effective_post_time).InMilliseconds(); |
| 410 if (!end_of_run.is_null()) | 440 if (!end_of_run.is_null()) |
| 411 run_duration = (end_of_run - start_of_run).InMilliseconds(); | 441 run_duration = (end_of_run - start_of_run).InMilliseconds(); |
| 412 } | 442 } |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 474 if (!start_of_run.is_null() && !end_of_run.is_null()) | 504 if (!start_of_run.is_null() && !end_of_run.is_null()) |
| 475 run_duration = (end_of_run - start_of_run).InMilliseconds(); | 505 run_duration = (end_of_run - start_of_run).InMilliseconds(); |
| 476 current_thread_data->TallyADeath(*birth, queue_duration, run_duration); | 506 current_thread_data->TallyADeath(*birth, queue_duration, run_duration); |
| 477 } | 507 } |
| 478 | 508 |
| 479 const std::string ThreadData::thread_name() const { return thread_name_; } | 509 const std::string ThreadData::thread_name() const { return thread_name_; } |
| 480 | 510 |
| 481 // This may be called from another thread. | 511 // This may be called from another thread. |
| 482 void ThreadData::SnapshotMaps(bool reset_max, | 512 void ThreadData::SnapshotMaps(bool reset_max, |
| 483 BirthMap* birth_map, | 513 BirthMap* birth_map, |
| 484 DeathMap* death_map) { | 514 DeathMap* death_map, |
| 515 ParentChildSet* parent_child_set) { |
| 485 base::AutoLock lock(map_lock_); | 516 base::AutoLock lock(map_lock_); |
| 486 for (BirthMap::const_iterator it = birth_map_.begin(); | 517 for (BirthMap::const_iterator it = birth_map_.begin(); |
| 487 it != birth_map_.end(); ++it) | 518 it != birth_map_.end(); ++it) |
| 488 (*birth_map)[it->first] = it->second; | 519 (*birth_map)[it->first] = it->second; |
| 489 for (DeathMap::iterator it = death_map_.begin(); | 520 for (DeathMap::iterator it = death_map_.begin(); |
| 490 it != death_map_.end(); ++it) { | 521 it != death_map_.end(); ++it) { |
| 491 (*death_map)[it->first] = it->second; | 522 (*death_map)[it->first] = it->second; |
| 492 if (reset_max) | 523 if (reset_max) |
| 493 it->second.ResetMax(); | 524 it->second.ResetMax(); |
| 494 } | 525 } |
| 526 |
| 527 if (!kTrackParentChildLinks) |
| 528 return; |
| 529 |
| 530 for (ParentChildSet::iterator it = parent_child_set_.begin(); |
| 531 it != parent_child_set_.end(); ++it) |
| 532 parent_child_set->insert(*it); |
| 495 } | 533 } |
| 496 | 534 |
| 497 // static | 535 // static |
| 498 void ThreadData::SendAllMaps(bool reset_max, class DataCollector* target) { | 536 void ThreadData::SendAllMaps(bool reset_max, class DataCollector* target) { |
| 499 if (!kTrackAllTaskObjects) | 537 if (!kTrackAllTaskObjects) |
| 500 return; // Not compiled in. | 538 return; // Not compiled in. |
| 501 // Get an unchanging copy of a ThreadData list. | 539 // Get an unchanging copy of a ThreadData list. |
| 502 ThreadData* my_list = ThreadData::first(); | 540 ThreadData* my_list = ThreadData::first(); |
| 503 | 541 |
| 504 // Gather data serially. | 542 // Gather data serially. |
| 505 // This hackish approach *can* get some slighly corrupt tallies, as we are | 543 // This hackish approach *can* get some slighly corrupt tallies, as we are |
| 506 // grabbing values without the protection of a lock, but it has the advantage | 544 // grabbing values without the protection of a lock, but it has the advantage |
| 507 // of working even with threads that don't have message loops. If a user | 545 // of working even with threads that don't have message loops. If a user |
| 508 // sees any strangeness, they can always just run their stats gathering a | 546 // sees any strangeness, they can always just run their stats gathering a |
| 509 // second time. | 547 // second time. |
| 510 for (ThreadData* thread_data = my_list; | 548 for (ThreadData* thread_data = my_list; |
| 511 thread_data; | 549 thread_data; |
| 512 thread_data = thread_data->next()) { | 550 thread_data = thread_data->next()) { |
| 513 // Get copy of data. | 551 // Get copy of data. |
| 514 ThreadData::BirthMap birth_map; | 552 ThreadData::BirthMap birth_map; |
| 515 ThreadData::DeathMap death_map; | 553 ThreadData::DeathMap death_map; |
| 516 thread_data->SnapshotMaps(reset_max, &birth_map, &death_map); | 554 ThreadData::ParentChildSet parent_child_set; |
| 517 target->Append(*thread_data, birth_map, death_map); | 555 thread_data->SnapshotMaps(reset_max, &birth_map, &death_map, |
| 556 &parent_child_set); |
| 557 target->Append(*thread_data, birth_map, death_map, parent_child_set); |
| 518 } | 558 } |
| 519 } | 559 } |
| 520 | 560 |
| 521 // static | 561 // static |
| 522 void ThreadData::ResetAllThreadData() { | 562 void ThreadData::ResetAllThreadData() { |
| 523 ThreadData* my_list = first(); | 563 ThreadData* my_list = first(); |
| 524 | 564 |
| 525 for (ThreadData* thread_data = my_list; | 565 for (ThreadData* thread_data = my_list; |
| 526 thread_data; | 566 thread_data; |
| 527 thread_data = thread_data->next()) | 567 thread_data = thread_data->next()) |
| 528 thread_data->Reset(); | 568 thread_data->Reset(); |
| 529 } | 569 } |
| 530 | 570 |
| 531 void ThreadData::Reset() { | 571 void ThreadData::Reset() { |
| 532 base::AutoLock lock(map_lock_); | 572 base::AutoLock lock(map_lock_); |
| 533 for (DeathMap::iterator it = death_map_.begin(); | 573 for (DeathMap::iterator it = death_map_.begin(); |
| 534 it != death_map_.end(); ++it) | 574 it != death_map_.end(); ++it) |
| 535 it->second.Clear(); | 575 it->second.Clear(); |
| 536 for (BirthMap::iterator it = birth_map_.begin(); | 576 for (BirthMap::iterator it = birth_map_.begin(); |
| 537 it != birth_map_.end(); ++it) | 577 it != birth_map_.end(); ++it) |
| 538 it->second->Clear(); | 578 it->second->Clear(); |
| 539 } | 579 } |
| 540 | 580 |
| 541 bool ThreadData::Initialize() { | 581 bool ThreadData::Initialize() { |
| 542 if (!kTrackAllTaskObjects) | 582 if (!kTrackAllTaskObjects) |
| 543 return false; // Not compiled in. | 583 return false; // Not compiled in. |
| 544 if (status_ != UNINITIALIZED) | 584 if (status_ >= DEACTIVATED) |
| 545 return true; // Someone else did the initialization. | 585 return true; // Someone else did the initialization. |
| 546 // Due to racy lazy initialization in tests, we'll need to recheck status_ | 586 // Due to racy lazy initialization in tests, we'll need to recheck status_ |
| 547 // after we acquire the lock. | 587 // after we acquire the lock. |
| 548 | 588 |
| 549 // Ensure that we don't double initialize tls. We are called when single | 589 // Ensure that we don't double initialize tls. We are called when single |
| 550 // threaded in the product, but some tests may be racy and lazy about our | 590 // threaded in the product, but some tests may be racy and lazy about our |
| 551 // initialization. | 591 // initialization. |
| 552 base::AutoLock lock(*list_lock_.Pointer()); | 592 base::AutoLock lock(*list_lock_.Pointer()); |
| 553 if (status_ != UNINITIALIZED) | 593 if (status_ >= DEACTIVATED) |
| 554 return true; // Someone raced in here and beat us. | 594 return true; // Someone raced in here and beat us. |
| 555 | 595 |
| 556 // Perform the "real" TLS initialization now, and leave it intact through | 596 // Perform the "real" TLS initialization now, and leave it intact through |
| 557 // process termination. | 597 // process termination. |
| 558 if (!tls_index_.initialized()) { // Testing may have initialized this. | 598 if (!tls_index_.initialized()) { // Testing may have initialized this. |
| 599 DCHECK_EQ(status_, UNINITIALIZED); |
| 559 tls_index_.Initialize(&ThreadData::OnThreadTermination); | 600 tls_index_.Initialize(&ThreadData::OnThreadTermination); |
| 560 if (!tls_index_.initialized()) | 601 if (!tls_index_.initialized()) |
| 561 return false; | 602 return false; |
| 603 } else { |
| 604 // TLS was initialzed for us earlier. |
| 605 DCHECK_EQ(status_, DORMANT_DURING_TESTS); |
| 562 } | 606 } |
| 563 | 607 |
| 564 // Incarnation counter is only significant to testing, as it otherwise will | 608 // Incarnation counter is only significant to testing, as it otherwise will |
| 565 // never again change in this process. | 609 // never again change in this process. |
| 566 ++incarnation_counter_; | 610 ++incarnation_counter_; |
| 567 | 611 |
| 568 // The lock is not critical for setting status_, but it doesn't hurt. It also | 612 // The lock is not critical for setting status_, but it doesn't hurt. It also |
| 569 // ensures that if we have a racy initialization, that we'll bail as soon as | 613 // ensures that if we have a racy initialization, that we'll bail as soon as |
| 570 // we get the lock earlier in this method. | 614 // we get the lock earlier in this method. |
| 571 status_ = kInitialStartupState; | 615 status_ = kInitialStartupState; |
| 616 if (!kTrackParentChildLinks && |
| 617 kInitialStartupState == PROFILING_CHILDREN_ACTIVE) |
| 618 status_ = PROFILING_ACTIVE; |
| 572 DCHECK(status_ != UNINITIALIZED); | 619 DCHECK(status_ != UNINITIALIZED); |
| 573 return true; | 620 return true; |
| 574 } | 621 } |
| 575 | 622 |
| 576 // static | 623 // static |
| 577 bool ThreadData::InitializeAndSetTrackingStatus(bool status) { | 624 bool ThreadData::InitializeAndSetTrackingStatus(bool status) { |
| 578 if (!Initialize()) // No-op if already initialized. | 625 if (!Initialize()) // No-op if already initialized. |
| 579 return false; // Not compiled in. | 626 return false; // Not compiled in. |
| 580 | 627 |
| 581 status_ = status ? ACTIVE : DEACTIVATED; | 628 if (!status) { |
| 629 status_ = DEACTIVATED; |
| 630 } else { |
| 631 if (kTrackParentChildLinks) |
| 632 status_ = PROFILING_CHILDREN_ACTIVE; |
| 633 else |
| 634 status_ = PROFILING_ACTIVE; |
| 635 } |
| 582 return true; | 636 return true; |
| 583 } | 637 } |
| 584 | 638 |
| 585 // static | 639 // static |
| 586 bool ThreadData::tracking_status() { | 640 bool ThreadData::tracking_status() { |
| 587 return status_ == ACTIVE; | 641 return status_ > DEACTIVATED; |
| 588 } | 642 } |
| 589 | 643 |
| 590 // static | 644 // static |
| 591 TrackedTime ThreadData::NowForStartOfRun() { | 645 bool ThreadData::tracking_parent_child_status() { |
| 646 return status_ >= PROFILING_CHILDREN_ACTIVE; |
| 647 } |
| 648 |
| 649 // static |
| 650 TrackedTime ThreadData::NowForStartOfRun(const Births* parent) { |
| 651 if (kTrackParentChildLinks && parent && status_ > PROFILING_ACTIVE) { |
| 652 ThreadData* current_thread_data = Get(); |
| 653 if (current_thread_data) |
| 654 current_thread_data->parent_stack_.push(parent); |
| 655 } |
| 592 return Now(); | 656 return Now(); |
| 593 } | 657 } |
| 594 | 658 |
| 595 // static | 659 // static |
| 596 TrackedTime ThreadData::NowForEndOfRun() { | 660 TrackedTime ThreadData::NowForEndOfRun() { |
| 597 return Now(); | 661 return Now(); |
| 598 } | 662 } |
| 599 | 663 |
| 600 // static | 664 // static |
| 601 TrackedTime ThreadData::Now() { | 665 TrackedTime ThreadData::Now() { |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 635 CHECK_GT(worker->worker_thread_number_, 0); | 699 CHECK_GT(worker->worker_thread_number_, 0); |
| 636 first_retired_worker_ = worker->next_retired_worker_; | 700 first_retired_worker_ = worker->next_retired_worker_; |
| 637 worker->next_retired_worker_ = NULL; | 701 worker->next_retired_worker_ = NULL; |
| 638 } | 702 } |
| 639 } | 703 } |
| 640 | 704 |
| 641 // Put most global static back in pristine shape. | 705 // Put most global static back in pristine shape. |
| 642 worker_thread_data_creation_count_ = 0; | 706 worker_thread_data_creation_count_ = 0; |
| 643 cleanup_count_ = 0; | 707 cleanup_count_ = 0; |
| 644 tls_index_.Set(NULL); | 708 tls_index_.Set(NULL); |
| 645 status_ = UNINITIALIZED; | 709 status_ = DORMANT_DURING_TESTS; // Almost UNINITIALIZED. |
| 646 | 710 |
| 647 // To avoid any chance of racing in unit tests, which is the only place we | 711 // To avoid any chance of racing in unit tests, which is the only place we |
| 648 // call this function, we may sometimes leak all the data structures we | 712 // call this function, we may sometimes leak all the data structures we |
| 649 // recovered, as they may still be in use on threads from prior tests! | 713 // recovered, as they may still be in use on threads from prior tests! |
| 650 if (leak) | 714 if (leak) |
| 651 return; | 715 return; |
| 652 | 716 |
| 653 // When we want to cleanup (on a single thread), here is what we do. | 717 // When we want to cleanup (on a single thread), here is what we do. |
| 654 | 718 |
| 655 // Do actual recursive delete in all ThreadData instances. | 719 // Do actual recursive delete in all ThreadData instances. |
| 656 while (thread_data_list) { | 720 while (thread_data_list) { |
| 657 ThreadData* next_thread_data = thread_data_list; | 721 ThreadData* next_thread_data = thread_data_list; |
| 658 thread_data_list = thread_data_list->next(); | 722 thread_data_list = thread_data_list->next(); |
| 659 | 723 |
| 660 for (BirthMap::iterator it = next_thread_data->birth_map_.begin(); | 724 for (BirthMap::iterator it = next_thread_data->birth_map_.begin(); |
| 661 next_thread_data->birth_map_.end() != it; ++it) | 725 next_thread_data->birth_map_.end() != it; ++it) |
| 662 delete it->second; // Delete the Birth Records. | 726 delete it->second; // Delete the Birth Records. |
| 663 next_thread_data->birth_map_.clear(); | |
| 664 next_thread_data->death_map_.clear(); | |
| 665 delete next_thread_data; // Includes all Death Records. | 727 delete next_thread_data; // Includes all Death Records. |
| 666 } | 728 } |
| 667 } | 729 } |
| 668 | 730 |
| 669 //------------------------------------------------------------------------------ | 731 //------------------------------------------------------------------------------ |
| 670 // Individual 3-tuple of birth (place and thread) along with death thread, and | 732 // Individual 3-tuple of birth (place and thread) along with death thread, and |
| 671 // the accumulated stats for instances (DeathData). | 733 // the accumulated stats for instances (DeathData). |
| 672 | 734 |
| 673 Snapshot::Snapshot(const BirthOnThread& birth_on_thread, | 735 Snapshot::Snapshot(const BirthOnThread& birth_on_thread, |
| 674 const ThreadData& death_thread, | 736 const ThreadData& death_thread, |
| (...skipping 10 matching lines...) Expand all Loading... |
| 685 } | 747 } |
| 686 | 748 |
| 687 const std::string Snapshot::DeathThreadName() const { | 749 const std::string Snapshot::DeathThreadName() const { |
| 688 if (death_thread_) | 750 if (death_thread_) |
| 689 return death_thread_->thread_name(); | 751 return death_thread_->thread_name(); |
| 690 return "Still_Alive"; | 752 return "Still_Alive"; |
| 691 } | 753 } |
| 692 | 754 |
| 693 base::DictionaryValue* Snapshot::ToValue() const { | 755 base::DictionaryValue* Snapshot::ToValue() const { |
| 694 base::DictionaryValue* dictionary = new base::DictionaryValue; | 756 base::DictionaryValue* dictionary = new base::DictionaryValue; |
| 695 dictionary->Set("death_data", death_data_.ToValue()); | 757 // TODO(jar): Switch the next two lines to: |
| 758 // birth_->ToValue("birth", dictionary); |
| 759 // ...but that will require fixing unit tests, and JS to take |
| 760 // "birth_location" rather than "location" |
| 696 dictionary->Set("birth_thread", | 761 dictionary->Set("birth_thread", |
| 697 base::Value::CreateStringValue(birth_->birth_thread()->thread_name())); | 762 base::Value::CreateStringValue(birth_->birth_thread()->thread_name())); |
| 763 dictionary->Set("location", birth_->location().ToValue()); |
| 764 |
| 765 dictionary->Set("death_data", death_data_.ToValue()); |
| 698 dictionary->Set("death_thread", | 766 dictionary->Set("death_thread", |
| 699 base::Value::CreateStringValue(DeathThreadName())); | 767 base::Value::CreateStringValue(DeathThreadName())); |
| 700 dictionary->Set("location", birth_->location().ToValue()); | |
| 701 return dictionary; | 768 return dictionary; |
| 702 } | 769 } |
| 703 | 770 |
| 704 //------------------------------------------------------------------------------ | 771 //------------------------------------------------------------------------------ |
| 705 // DataCollector | 772 // DataCollector |
| 706 | 773 |
| 707 DataCollector::DataCollector() {} | 774 DataCollector::DataCollector() {} |
| 708 | 775 |
| 709 DataCollector::~DataCollector() { | 776 DataCollector::~DataCollector() { |
| 710 } | 777 } |
| 711 | 778 |
| 712 void DataCollector::Append(const ThreadData &thread_data, | 779 void DataCollector::Append(const ThreadData& thread_data, |
| 713 const ThreadData::BirthMap &birth_map, | 780 const ThreadData::BirthMap& birth_map, |
| 714 const ThreadData::DeathMap &death_map) { | 781 const ThreadData::DeathMap& death_map, |
| 782 const ThreadData::ParentChildSet& parent_child_set) { |
| 715 for (ThreadData::DeathMap::const_iterator it = death_map.begin(); | 783 for (ThreadData::DeathMap::const_iterator it = death_map.begin(); |
| 716 it != death_map.end(); ++it) { | 784 it != death_map.end(); ++it) { |
| 717 collection_.push_back(Snapshot(*it->first, thread_data, it->second)); | 785 collection_.push_back(Snapshot(*it->first, thread_data, it->second)); |
| 718 global_birth_count_[it->first] -= it->first->birth_count(); | 786 global_birth_count_[it->first] -= it->first->birth_count(); |
| 719 } | 787 } |
| 720 | 788 |
| 721 for (ThreadData::BirthMap::const_iterator it = birth_map.begin(); | 789 for (ThreadData::BirthMap::const_iterator it = birth_map.begin(); |
| 722 it != birth_map.end(); ++it) { | 790 it != birth_map.end(); ++it) { |
| 723 global_birth_count_[it->second] += it->second->birth_count(); | 791 global_birth_count_[it->second] += it->second->birth_count(); |
| 724 } | 792 } |
| 793 |
| 794 if (!kTrackParentChildLinks) |
| 795 return; |
| 796 |
| 797 for (ThreadData::ParentChildSet::const_iterator it = parent_child_set.begin(); |
| 798 it != parent_child_set.end(); ++it) { |
| 799 parent_child_set_.insert(*it); |
| 800 } |
| 725 } | 801 } |
| 726 | 802 |
| 727 DataCollector::Collection* DataCollector::collection() { | 803 DataCollector::Collection* DataCollector::collection() { |
| 728 return &collection_; | 804 return &collection_; |
| 729 } | 805 } |
| 730 | 806 |
| 731 void DataCollector::AddListOfLivingObjects() { | 807 void DataCollector::AddListOfLivingObjects() { |
| 732 for (BirthCount::iterator it = global_birth_count_.begin(); | 808 for (BirthCount::iterator it = global_birth_count_.begin(); |
| 733 it != global_birth_count_.end(); ++it) { | 809 it != global_birth_count_.end(); ++it) { |
| 734 if (it->second > 0) | 810 if (it->second > 0) |
| 735 collection_.push_back(Snapshot(*it->first, it->second)); | 811 collection_.push_back(Snapshot(*it->first, it->second)); |
| 736 } | 812 } |
| 737 } | 813 } |
| 738 | 814 |
| 739 base::ListValue* DataCollector::ToValue() const { | 815 void DataCollector::ToValue(base::DictionaryValue* dictionary) const { |
| 740 base::ListValue* list = new base::ListValue; | 816 base::ListValue* list = new base::ListValue; |
| 741 for (size_t i = 0; i < collection_.size(); ++i) { | 817 for (size_t i = 0; i < collection_.size(); ++i) { |
| 742 list->Append(collection_[i].ToValue()); | 818 list->Append(collection_[i].ToValue()); |
| 743 } | 819 } |
| 744 return list; | 820 dictionary->Set("list", list); |
| 821 |
| 822 base::ListValue* descendants = new base::ListValue; |
| 823 for (ThreadData::ParentChildSet::const_iterator it = |
| 824 parent_child_set_.begin(); |
| 825 it != parent_child_set_.end(); |
| 826 ++it) { |
| 827 base::DictionaryValue* parent_child = new base::DictionaryValue; |
| 828 it->first->ToValue("parent", parent_child); |
| 829 it->second->ToValue("child", parent_child); |
| 830 descendants->Append(parent_child); |
| 831 } |
| 832 dictionary->Set("descendants", descendants); |
| 745 } | 833 } |
| 746 | 834 |
| 747 } // namespace tracked_objects | 835 } // namespace tracked_objects |
| OLD | NEW |