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

Side by Side Diff: base/tracked_objects.cc

Issue 445413003: Creating a framework for suppressing pollution of the profiler data (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: (presumably) last round of jar@'s comments Created 6 years, 3 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
« no previous file with comments | « base/tracked_objects.h ('k') | base/tracked_objects_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "base/tracked_objects.h" 5 #include "base/tracked_objects.h"
6 6
7 #include <limits.h> 7 #include <limits.h>
8 #include <stdlib.h> 8 #include <stdlib.h>
9 9
10 #include "base/atomicops.h" 10 #include "base/atomicops.h"
(...skipping 219 matching lines...) Expand 10 before | Expand all | Expand 10 after
230 // ThreadData maintains the central data for all births and deaths on a single 230 // ThreadData maintains the central data for all births and deaths on a single
231 // thread. 231 // thread.
232 232
233 // TODO(jar): We should pull all these static vars together, into a struct, and 233 // TODO(jar): We should pull all these static vars together, into a struct, and
234 // optimize layout so that we benefit from locality of reference during accesses 234 // optimize layout so that we benefit from locality of reference during accesses
235 // to them. 235 // to them.
236 236
237 // static 237 // static
238 NowFunction* ThreadData::now_function_ = NULL; 238 NowFunction* ThreadData::now_function_ = NULL;
239 239
240 // static
241 bool ThreadData::now_function_is_time_ = false;
242
240 // A TLS slot which points to the ThreadData instance for the current thread. We 243 // A TLS slot which points to the ThreadData instance for the current thread. We
241 // do a fake initialization here (zeroing out data), and then the real in-place 244 // do a fake initialization here (zeroing out data), and then the real in-place
242 // construction happens when we call tls_index_.Initialize(). 245 // construction happens when we call tls_index_.Initialize().
243 // static 246 // static
244 base::ThreadLocalStorage::StaticSlot ThreadData::tls_index_ = TLS_INITIALIZER; 247 base::ThreadLocalStorage::StaticSlot ThreadData::tls_index_ = TLS_INITIALIZER;
245 248
246 // static 249 // static
247 int ThreadData::worker_thread_data_creation_count_ = 0; 250 int ThreadData::worker_thread_data_creation_count_ = 0;
248 251
249 // static 252 // static
(...skipping 12 matching lines...) Expand all
262 base::LazyInstance<base::Lock>::Leaky 265 base::LazyInstance<base::Lock>::Leaky
263 ThreadData::list_lock_ = LAZY_INSTANCE_INITIALIZER; 266 ThreadData::list_lock_ = LAZY_INSTANCE_INITIALIZER;
264 267
265 // static 268 // static
266 ThreadData::Status ThreadData::status_ = ThreadData::UNINITIALIZED; 269 ThreadData::Status ThreadData::status_ = ThreadData::UNINITIALIZED;
267 270
268 ThreadData::ThreadData(const std::string& suggested_name) 271 ThreadData::ThreadData(const std::string& suggested_name)
269 : next_(NULL), 272 : next_(NULL),
270 next_retired_worker_(NULL), 273 next_retired_worker_(NULL),
271 worker_thread_number_(0), 274 worker_thread_number_(0),
272 incarnation_count_for_pool_(-1) { 275 incarnation_count_for_pool_(-1),
276 current_stopwatch_(NULL) {
273 DCHECK_GE(suggested_name.size(), 0u); 277 DCHECK_GE(suggested_name.size(), 0u);
274 thread_name_ = suggested_name; 278 thread_name_ = suggested_name;
275 PushToHeadOfList(); // Which sets real incarnation_count_for_pool_. 279 PushToHeadOfList(); // Which sets real incarnation_count_for_pool_.
276 } 280 }
277 281
278 ThreadData::ThreadData(int thread_number) 282 ThreadData::ThreadData(int thread_number)
279 : next_(NULL), 283 : next_(NULL),
280 next_retired_worker_(NULL), 284 next_retired_worker_(NULL),
281 worker_thread_number_(thread_number), 285 worker_thread_number_(thread_number),
282 incarnation_count_for_pool_(-1) { 286 incarnation_count_for_pool_(-1),
287 current_stopwatch_(NULL) {
283 CHECK_GT(thread_number, 0); 288 CHECK_GT(thread_number, 0);
284 base::StringAppendF(&thread_name_, "WorkerThread-%d", thread_number); 289 base::StringAppendF(&thread_name_, "WorkerThread-%d", thread_number);
285 PushToHeadOfList(); // Which sets real incarnation_count_for_pool_. 290 PushToHeadOfList(); // Which sets real incarnation_count_for_pool_.
286 } 291 }
287 292
288 ThreadData::~ThreadData() {} 293 ThreadData::~ThreadData() {}
289 294
290 void ThreadData::PushToHeadOfList() { 295 void ThreadData::PushToHeadOfList() {
291 // Toss in a hint of randomness (atop the uniniitalized value). 296 // Toss in a hint of randomness (atop the uniniitalized value).
292 (void)VALGRIND_MAKE_MEM_DEFINED_IF_ADDRESSABLE(&random_number_, 297 (void)VALGRIND_MAKE_MEM_DEFINED_IF_ADDRESSABLE(&random_number_,
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after
427 base::AutoLock lock(map_lock_); 432 base::AutoLock lock(map_lock_);
428 parent_child_set_.insert(pair); 433 parent_child_set_.insert(pair);
429 } 434 }
430 } 435 }
431 436
432 return child; 437 return child;
433 } 438 }
434 439
435 void ThreadData::TallyADeath(const Births& birth, 440 void ThreadData::TallyADeath(const Births& birth,
436 int32 queue_duration, 441 int32 queue_duration,
437 int32 run_duration) { 442 const TaskStopwatch& stopwatch) {
443 int32 run_duration = stopwatch.RunDurationMs();
444
438 // Stir in some randomness, plus add constant in case durations are zero. 445 // Stir in some randomness, plus add constant in case durations are zero.
439 const int32 kSomePrimeNumber = 2147483647; 446 const int32 kSomePrimeNumber = 2147483647;
440 random_number_ += queue_duration + run_duration + kSomePrimeNumber; 447 random_number_ += queue_duration + run_duration + kSomePrimeNumber;
441 // An address is going to have some randomness to it as well ;-). 448 // An address is going to have some randomness to it as well ;-).
442 random_number_ ^= static_cast<int32>(&birth - reinterpret_cast<Births*>(0)); 449 random_number_ ^= static_cast<int32>(&birth - reinterpret_cast<Births*>(0));
443 450
444 // We don't have queue durations without OS timer. OS timer is automatically 451 // We don't have queue durations without OS timer. OS timer is automatically
445 // used for task-post-timing, so the use of an alternate timer implies all 452 // used for task-post-timing, so the use of an alternate timer implies all
446 // queue times are invalid. 453 // queue times are invalid, unless it was explicitly said that we can trust
447 if (kAllowAlternateTimeSourceHandling && now_function_) 454 // the alternate timer.
455 if (kAllowAlternateTimeSourceHandling &&
456 now_function_ &&
457 !now_function_is_time_) {
448 queue_duration = 0; 458 queue_duration = 0;
459 }
449 460
450 DeathMap::iterator it = death_map_.find(&birth); 461 DeathMap::iterator it = death_map_.find(&birth);
451 DeathData* death_data; 462 DeathData* death_data;
452 if (it != death_map_.end()) { 463 if (it != death_map_.end()) {
453 death_data = &it->second; 464 death_data = &it->second;
454 } else { 465 } else {
455 base::AutoLock lock(map_lock_); // Lock as the map may get relocated now. 466 base::AutoLock lock(map_lock_); // Lock as the map may get relocated now.
456 death_data = &death_map_[&birth]; 467 death_data = &death_map_[&birth];
457 } // Release lock ASAP. 468 } // Release lock ASAP.
458 death_data->RecordDeath(queue_duration, run_duration, random_number_); 469 death_data->RecordDeath(queue_duration, run_duration, random_number_);
(...skipping 15 matching lines...) Expand all
474 return NULL; 485 return NULL;
475 ThreadData* current_thread_data = Get(); 486 ThreadData* current_thread_data = Get();
476 if (!current_thread_data) 487 if (!current_thread_data)
477 return NULL; 488 return NULL;
478 return current_thread_data->TallyABirth(location); 489 return current_thread_data->TallyABirth(location);
479 } 490 }
480 491
481 // static 492 // static
482 void ThreadData::TallyRunOnNamedThreadIfTracking( 493 void ThreadData::TallyRunOnNamedThreadIfTracking(
483 const base::TrackingInfo& completed_task, 494 const base::TrackingInfo& completed_task,
484 const TrackedTime& start_of_run, 495 const TaskStopwatch& stopwatch) {
485 const TrackedTime& end_of_run) {
486 if (!kTrackAllTaskObjects) 496 if (!kTrackAllTaskObjects)
487 return; // Not compiled in. 497 return; // Not compiled in.
488 498
489 // Even if we have been DEACTIVATED, we will process any pending births so 499 // Even if we have been DEACTIVATED, we will process any pending births so
490 // that our data structures (which counted the outstanding births) remain 500 // that our data structures (which counted the outstanding births) remain
491 // consistent. 501 // consistent.
492 const Births* birth = completed_task.birth_tally; 502 const Births* birth = completed_task.birth_tally;
493 if (!birth) 503 if (!birth)
494 return; 504 return;
495 ThreadData* current_thread_data = Get(); 505 ThreadData* current_thread_data = stopwatch.GetThreadData();
496 if (!current_thread_data) 506 if (!current_thread_data)
497 return; 507 return;
498 508
499 // Watch out for a race where status_ is changing, and hence one or both 509 // Watch out for a race where status_ is changing, and hence one or both
500 // of start_of_run or end_of_run is zero. In that case, we didn't bother to 510 // of start_of_run or end_of_run is zero. In that case, we didn't bother to
501 // get a time value since we "weren't tracking" and we were trying to be 511 // get a time value since we "weren't tracking" and we were trying to be
502 // efficient by not calling for a genuine time value. For simplicity, we'll 512 // efficient by not calling for a genuine time value. For simplicity, we'll
503 // use a default zero duration when we can't calculate a true value. 513 // use a default zero duration when we can't calculate a true value.
514 TrackedTime start_of_run = stopwatch.StartTime();
504 int32 queue_duration = 0; 515 int32 queue_duration = 0;
505 int32 run_duration = 0;
506 if (!start_of_run.is_null()) { 516 if (!start_of_run.is_null()) {
507 queue_duration = (start_of_run - completed_task.EffectiveTimePosted()) 517 queue_duration = (start_of_run - completed_task.EffectiveTimePosted())
508 .InMilliseconds(); 518 .InMilliseconds();
509 if (!end_of_run.is_null())
510 run_duration = (end_of_run - start_of_run).InMilliseconds();
511 } 519 }
512 current_thread_data->TallyADeath(*birth, queue_duration, run_duration); 520 current_thread_data->TallyADeath(*birth, queue_duration, stopwatch);
513 } 521 }
514 522
515 // static 523 // static
516 void ThreadData::TallyRunOnWorkerThreadIfTracking( 524 void ThreadData::TallyRunOnWorkerThreadIfTracking(
517 const Births* birth, 525 const Births* birth,
518 const TrackedTime& time_posted, 526 const TrackedTime& time_posted,
519 const TrackedTime& start_of_run, 527 const TaskStopwatch& stopwatch) {
520 const TrackedTime& end_of_run) {
521 if (!kTrackAllTaskObjects) 528 if (!kTrackAllTaskObjects)
522 return; // Not compiled in. 529 return; // Not compiled in.
523 530
524 // Even if we have been DEACTIVATED, we will process any pending births so 531 // Even if we have been DEACTIVATED, we will process any pending births so
525 // that our data structures (which counted the outstanding births) remain 532 // that our data structures (which counted the outstanding births) remain
526 // consistent. 533 // consistent.
527 if (!birth) 534 if (!birth)
528 return; 535 return;
529 536
530 // TODO(jar): Support the option to coalesce all worker-thread activity under 537 // TODO(jar): Support the option to coalesce all worker-thread activity under
531 // one ThreadData instance that uses locks to protect *all* access. This will 538 // one ThreadData instance that uses locks to protect *all* access. This will
532 // reduce memory (making it provably bounded), but run incrementally slower 539 // reduce memory (making it provably bounded), but run incrementally slower
533 // (since we'll use locks on TallyABirth and TallyADeath). The good news is 540 // (since we'll use locks on TallyABirth and TallyADeath). The good news is
534 // that the locks on TallyADeath will be *after* the worker thread has run, 541 // that the locks on TallyADeath will be *after* the worker thread has run,
535 // and hence nothing will be waiting for the completion (... besides some 542 // and hence nothing will be waiting for the completion (... besides some
536 // other thread that might like to run). Also, the worker threads tasks are 543 // other thread that might like to run). Also, the worker threads tasks are
537 // generally longer, and hence the cost of the lock may perchance be amortized 544 // generally longer, and hence the cost of the lock may perchance be amortized
538 // over the long task's lifetime. 545 // over the long task's lifetime.
539 ThreadData* current_thread_data = Get(); 546 ThreadData* current_thread_data = stopwatch.GetThreadData();
540 if (!current_thread_data) 547 if (!current_thread_data)
541 return; 548 return;
542 549
550 TrackedTime start_of_run = stopwatch.StartTime();
543 int32 queue_duration = 0; 551 int32 queue_duration = 0;
544 int32 run_duration = 0;
545 if (!start_of_run.is_null()) { 552 if (!start_of_run.is_null()) {
546 queue_duration = (start_of_run - time_posted).InMilliseconds(); 553 queue_duration = (start_of_run - time_posted).InMilliseconds();
547 if (!end_of_run.is_null())
548 run_duration = (end_of_run - start_of_run).InMilliseconds();
549 } 554 }
550 current_thread_data->TallyADeath(*birth, queue_duration, run_duration); 555 current_thread_data->TallyADeath(*birth, queue_duration, stopwatch);
551 } 556 }
552 557
553 // static 558 // static
554 void ThreadData::TallyRunInAScopedRegionIfTracking( 559 void ThreadData::TallyRunInAScopedRegionIfTracking(
555 const Births* birth, 560 const Births* birth,
556 const TrackedTime& start_of_run, 561 const TaskStopwatch& stopwatch) {
557 const TrackedTime& end_of_run) {
558 if (!kTrackAllTaskObjects) 562 if (!kTrackAllTaskObjects)
559 return; // Not compiled in. 563 return; // Not compiled in.
560 564
561 // Even if we have been DEACTIVATED, we will process any pending births so 565 // Even if we have been DEACTIVATED, we will process any pending births so
562 // that our data structures (which counted the outstanding births) remain 566 // that our data structures (which counted the outstanding births) remain
563 // consistent. 567 // consistent.
564 if (!birth) 568 if (!birth)
565 return; 569 return;
566 570
567 ThreadData* current_thread_data = Get(); 571 ThreadData* current_thread_data = stopwatch.GetThreadData();
568 if (!current_thread_data) 572 if (!current_thread_data)
569 return; 573 return;
570 574
571 int32 queue_duration = 0; 575 int32 queue_duration = 0;
572 int32 run_duration = 0; 576 current_thread_data->TallyADeath(*birth, queue_duration, stopwatch);
573 if (!start_of_run.is_null() && !end_of_run.is_null())
574 run_duration = (end_of_run - start_of_run).InMilliseconds();
575 current_thread_data->TallyADeath(*birth, queue_duration, run_duration);
576 } 577 }
577 578
578 // static 579 // static
579 void ThreadData::SnapshotAllExecutedTasks(bool reset_max, 580 void ThreadData::SnapshotAllExecutedTasks(bool reset_max,
580 ProcessDataSnapshot* process_data, 581 ProcessDataSnapshot* process_data,
581 BirthCountMap* birth_counts) { 582 BirthCountMap* birth_counts) {
582 if (!kTrackAllTaskObjects) 583 if (!kTrackAllTaskObjects)
583 return; // Not compiled in. 584 return; // Not compiled in.
584 585
585 // Get an unchanging copy of a ThreadData list. 586 // Get an unchanging copy of a ThreadData list.
(...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after
751 bool ThreadData::TrackingStatus() { 752 bool ThreadData::TrackingStatus() {
752 return status_ > DEACTIVATED; 753 return status_ > DEACTIVATED;
753 } 754 }
754 755
755 // static 756 // static
756 bool ThreadData::TrackingParentChildStatus() { 757 bool ThreadData::TrackingParentChildStatus() {
757 return status_ >= PROFILING_CHILDREN_ACTIVE; 758 return status_ >= PROFILING_CHILDREN_ACTIVE;
758 } 759 }
759 760
760 // static 761 // static
761 TrackedTime ThreadData::NowForStartOfRun(const Births* parent) { 762 void ThreadData::PrepareForStartOfRun(const Births* parent) {
762 if (kTrackParentChildLinks && parent && status_ > PROFILING_ACTIVE) { 763 if (kTrackParentChildLinks && parent && status_ > PROFILING_ACTIVE) {
763 ThreadData* current_thread_data = Get(); 764 ThreadData* current_thread_data = Get();
764 if (current_thread_data) 765 if (current_thread_data)
765 current_thread_data->parent_stack_.push(parent); 766 current_thread_data->parent_stack_.push(parent);
766 } 767 }
767 return Now();
768 } 768 }
769 769
770 // static 770 // static
771 TrackedTime ThreadData::NowForEndOfRun() {
772 return Now();
773 }
774
775 // static
776 void ThreadData::SetAlternateTimeSource(NowFunction* now_function) { 771 void ThreadData::SetAlternateTimeSource(NowFunction* now_function) {
777 DCHECK(now_function); 772 DCHECK(now_function);
778 if (kAllowAlternateTimeSourceHandling) 773 if (kAllowAlternateTimeSourceHandling)
779 now_function_ = now_function; 774 now_function_ = now_function;
780 } 775 }
781 776
782 // static 777 // static
783 TrackedTime ThreadData::Now() { 778 TrackedTime ThreadData::Now() {
784 if (kAllowAlternateTimeSourceHandling && now_function_) 779 if (kAllowAlternateTimeSourceHandling && now_function_)
785 return TrackedTime::FromMilliseconds((*now_function_)()); 780 return TrackedTime::FromMilliseconds((*now_function_)());
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
851 thread_data_list = thread_data_list->next(); 846 thread_data_list = thread_data_list->next();
852 847
853 for (BirthMap::iterator it = next_thread_data->birth_map_.begin(); 848 for (BirthMap::iterator it = next_thread_data->birth_map_.begin();
854 next_thread_data->birth_map_.end() != it; ++it) 849 next_thread_data->birth_map_.end() != it; ++it)
855 delete it->second; // Delete the Birth Records. 850 delete it->second; // Delete the Birth Records.
856 delete next_thread_data; // Includes all Death Records. 851 delete next_thread_data; // Includes all Death Records.
857 } 852 }
858 } 853 }
859 854
860 //------------------------------------------------------------------------------ 855 //------------------------------------------------------------------------------
856 TaskStopwatch::TaskStopwatch()
857 : start_time_(ThreadData::Now()),
858 current_thread_data_(ThreadData::Get()),
859 excluded_duration_ms_(0),
860 parent_(NULL) {
861 #ifndef NDEBUG
Ken Russell (switch to Gerrit) 2014/09/10 20:47:50 You should guard these with #if DCHECK_IS_ON inste
vadimt 2014/09/10 21:24:50 Done.
862 state_ = RUNNING;
863 child_ = NULL;
864 #endif
865
866 wallclock_duration_ms_ = 0;
867 if (!current_thread_data_)
868 return;
869
870 parent_ = current_thread_data_->current_stopwatch_;
871 #ifndef NDEBUG
872 if (parent_) {
873 DCHECK(parent_->state_ == RUNNING);
874 DCHECK(parent_->child_ == NULL);
875 parent_->child_ = this;
876 }
877 #endif
878 current_thread_data_->current_stopwatch_ = this;
879 }
880
881 TaskStopwatch::~TaskStopwatch() {
882 #ifndef NDEBUG
Ken Russell (switch to Gerrit) 2014/09/10 20:47:50 Remove NDEBUG; not necessary with above if-guard f
vadimt 2014/09/10 21:24:50 I still need #if because DCHECK, even in 'OFF' mod
883 DCHECK(state_ != RUNNING);
884 DCHECK(child_ == NULL);
885 #endif
886 }
887
888 void TaskStopwatch::Stop() {
889 const TrackedTime end_time = ThreadData::Now();
890 #ifndef NDEBUG
891 DCHECK(state_ == RUNNING);
892 state_ = STOPPED;
893 DCHECK(child_ == NULL);
894 #endif
895
896 if (!start_time_.is_null() && !end_time.is_null()) {
897 wallclock_duration_ms_ = (end_time - start_time_).InMilliseconds();
898 }
899
900 if (!current_thread_data_)
901 return;
902
903 DCHECK(current_thread_data_->current_stopwatch_ == this);
904 current_thread_data_->current_stopwatch_ = parent_;
905 if (!parent_)
906 return;
907
908 #ifndef NDEBUG
909 DCHECK(parent_->state_ == RUNNING);
910 DCHECK(parent_->child_ == this);
911 parent_->child_ = NULL;
912 #endif
913 parent_->excluded_duration_ms_ +=
914 wallclock_duration_ms_;
915 parent_ = NULL;
916 }
917
918 TrackedTime TaskStopwatch::StartTime() const {
919 return start_time_;
920 }
921
922 int32 TaskStopwatch::RunDurationMs() const {
923 #ifndef NDEBUG
924 DCHECK(state_ == STOPPED);
925 #endif
926
927 return wallclock_duration_ms_ - excluded_duration_ms_;
928 }
929
930 ThreadData* TaskStopwatch::GetThreadData() const {
931 return current_thread_data_;
932 }
933
934 //------------------------------------------------------------------------------
861 TaskSnapshot::TaskSnapshot() { 935 TaskSnapshot::TaskSnapshot() {
862 } 936 }
863 937
864 TaskSnapshot::TaskSnapshot(const BirthOnThread& birth, 938 TaskSnapshot::TaskSnapshot(const BirthOnThread& birth,
865 const DeathData& death_data, 939 const DeathData& death_data,
866 const std::string& death_thread_name) 940 const std::string& death_thread_name)
867 : birth(birth), 941 : birth(birth),
868 death_data(death_data), 942 death_data(death_data),
869 death_thread_name(death_thread_name) { 943 death_thread_name(death_thread_name) {
870 } 944 }
(...skipping 24 matching lines...) Expand all
895 : process_id(base::GetCurrentProcId()) { 969 : process_id(base::GetCurrentProcId()) {
896 #else 970 #else
897 : process_id(0) { 971 : process_id(0) {
898 #endif 972 #endif
899 } 973 }
900 974
901 ProcessDataSnapshot::~ProcessDataSnapshot() { 975 ProcessDataSnapshot::~ProcessDataSnapshot() {
902 } 976 }
903 977
904 } // namespace tracked_objects 978 } // namespace tracked_objects
OLDNEW
« no previous file with comments | « base/tracked_objects.h ('k') | base/tracked_objects_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698