Chromium Code Reviews
[email protected] (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(577)

Side by Side Diff: base/tracked_objects.cc

Issue 9212025: Support use of third party time function to profiler (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Created 8 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "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/profiler/alternate_timer.h"
11 #include "base/stringprintf.h" 12 #include "base/stringprintf.h"
12 #include "base/third_party/valgrind/memcheck.h" 13 #include "base/third_party/valgrind/memcheck.h"
13 #include "base/threading/thread_restrictions.h" 14 #include "base/threading/thread_restrictions.h"
14 #include "build/build_config.h" 15 #include "build/build_config.h"
15 #include "base/port.h" 16 #include "base/port.h"
16 17
17 using base::TimeDelta; 18 using base::TimeDelta;
18 19
19 namespace tracked_objects { 20 namespace tracked_objects {
20 21
21 namespace { 22 namespace {
22 23
23 // Flag to compile out almost all of the task tracking code. 24 // Flag to compile out almost all of the task tracking code.
24 const bool kTrackAllTaskObjects = true; 25 const bool kTrackAllTaskObjects = true;
25 26
26 // Flag to compile out parent-child link recording. 27 // Flag to compile out parent-child link recording.
27 const bool kTrackParentChildLinks = false; 28 const bool kTrackParentChildLinks = false;
28 29
29 // When ThreadData is first initialized, should we start in an ACTIVE state to 30 // When ThreadData is first initialized, should we start in an ACTIVE state to
30 // record all of the startup-time tasks, or should we start up DEACTIVATED, so 31 // record all of the startup-time tasks, or should we start up DEACTIVATED, so
31 // that we only record after parsing the command line flag --enable-tracking. 32 // that we only record after parsing the command line flag --enable-tracking.
32 // Note that the flag may force either state, so this really controls only the 33 // Note that the flag may force either state, so this really controls only the
33 // period of time up until that flag is parsed. If there is no flag seen, then 34 // period of time up until that flag is parsed. If there is no flag seen, then
34 // this state may prevail for much or all of the process lifetime. 35 // this state may prevail for much or all of the process lifetime.
35 const ThreadData::Status kInitialStartupState = 36 const ThreadData::Status kInitialStartupState =
36 ThreadData::PROFILING_CHILDREN_ACTIVE; 37 ThreadData::PROFILING_CHILDREN_ACTIVE;
37 38
39 // Control whether an alternate time source (Now() function) is supported by
40 // the ThreadData class. This compile time flag should be set to try if we want
ramant (doing other things) 2012/02/15 18:33:46 nit: try -> true
jar (doing other things) 2012/02/15 20:26:32 Done. I added a lot of text to try to be even cle
41 // other modules, such as an allocator, to call with a new thread-specific
42 // Now() function to use (instead of of calling into tracked_time).
43 static const bool kAllowAlternateTimeSourceHandling = true;
44
45 // Environment variable name that is used to activate alternate timer profiling
46 // (such as using TCMalloc allocations to provide a pseudo-timer) for tasks
47 // instead of wall clock profiling.
48 static const char k_alternate_profile_timer[] = "CHROME_PROFILER_TIME";
ramant (doing other things) 2012/02/15 18:33:46 nit: should we consider commenting that "k_alterna
jar (doing other things) 2012/02/15 20:26:32 I went back and tried to move it to shared place.
49
38 } // namespace 50 } // namespace
39 51
40 //------------------------------------------------------------------------------ 52 //------------------------------------------------------------------------------
41 // DeathData tallies durations when a death takes place. 53 // DeathData tallies durations when a death takes place.
42 54
43 DeathData::DeathData() { 55 DeathData::DeathData() {
44 Clear(); 56 Clear();
45 } 57 }
46 58
47 DeathData::DeathData(int count) { 59 DeathData::DeathData(int count) {
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after
169 void Births::Clear() { birth_count_ = 0; } 181 void Births::Clear() { birth_count_ = 0; }
170 182
171 //------------------------------------------------------------------------------ 183 //------------------------------------------------------------------------------
172 // ThreadData maintains the central data for all births and deaths on a single 184 // ThreadData maintains the central data for all births and deaths on a single
173 // thread. 185 // thread.
174 186
175 // TODO(jar): We should pull all these static vars together, into a struct, and 187 // TODO(jar): We should pull all these static vars together, into a struct, and
176 // optimize layout so that we benefit from locality of reference during accesses 188 // optimize layout so that we benefit from locality of reference during accesses
177 // to them. 189 // to them.
178 190
191 // static
192 NowFunction* ThreadData::now_function_ = NULL;
193
179 // A TLS slot which points to the ThreadData instance for the current thread. We 194 // A TLS slot which points to the ThreadData instance for the current thread. We
180 // do a fake initialization here (zeroing out data), and then the real in-place 195 // do a fake initialization here (zeroing out data), and then the real in-place
181 // construction happens when we call tls_index_.Initialize(). 196 // construction happens when we call tls_index_.Initialize().
182 // static 197 // static
183 base::ThreadLocalStorage::StaticSlot ThreadData::tls_index_ = TLS_INITIALIZER; 198 base::ThreadLocalStorage::StaticSlot ThreadData::tls_index_ = TLS_INITIALIZER;
184 199
185 // static 200 // static
186 int ThreadData::worker_thread_data_creation_count_ = 0; 201 int ThreadData::worker_thread_data_creation_count_ = 0;
187 202
188 // static 203 // static
(...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after
363 378
364 void ThreadData::TallyADeath(const Births& birth, 379 void ThreadData::TallyADeath(const Births& birth,
365 DurationInt queue_duration, 380 DurationInt queue_duration,
366 DurationInt run_duration) { 381 DurationInt run_duration) {
367 // Stir in some randomness, plus add constant in case durations are zero. 382 // Stir in some randomness, plus add constant in case durations are zero.
368 const DurationInt kSomePrimeNumber = 2147483647; 383 const DurationInt kSomePrimeNumber = 2147483647;
369 random_number_ += queue_duration + run_duration + kSomePrimeNumber; 384 random_number_ += queue_duration + run_duration + kSomePrimeNumber;
370 // An address is going to have some randomness to it as well ;-). 385 // An address is going to have some randomness to it as well ;-).
371 random_number_ ^= static_cast<int32>(&birth - reinterpret_cast<Births*>(0)); 386 random_number_ ^= static_cast<int32>(&birth - reinterpret_cast<Births*>(0));
372 387
388 // We don't have queue durations without OS timer. OS timer is automatically
389 // used for task-post-timing, so the use of an alternate timer implies all
390 // queue times are invalid.
391 if (kAllowAlternateTimeSourceHandling && now_function_)
392 queue_duration = 0;
393
373 DeathMap::iterator it = death_map_.find(&birth); 394 DeathMap::iterator it = death_map_.find(&birth);
374 DeathData* death_data; 395 DeathData* death_data;
375 if (it != death_map_.end()) { 396 if (it != death_map_.end()) {
376 death_data = &it->second; 397 death_data = &it->second;
377 } else { 398 } else {
378 base::AutoLock lock(map_lock_); // Lock as the map may get relocated now. 399 base::AutoLock lock(map_lock_); // Lock as the map may get relocated now.
379 death_data = &death_map_[&birth]; 400 death_data = &death_map_[&birth];
380 } // Release lock ASAP. 401 } // Release lock ASAP.
381 death_data->RecordDeath(queue_duration, run_duration, random_number_); 402 death_data->RecordDeath(queue_duration, run_duration, random_number_);
382 403
(...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after
572 void ThreadData::Reset() { 593 void ThreadData::Reset() {
573 base::AutoLock lock(map_lock_); 594 base::AutoLock lock(map_lock_);
574 for (DeathMap::iterator it = death_map_.begin(); 595 for (DeathMap::iterator it = death_map_.begin();
575 it != death_map_.end(); ++it) 596 it != death_map_.end(); ++it)
576 it->second.Clear(); 597 it->second.Clear();
577 for (BirthMap::iterator it = birth_map_.begin(); 598 for (BirthMap::iterator it = birth_map_.begin();
578 it != birth_map_.end(); ++it) 599 it != birth_map_.end(); ++it)
579 it->second->Clear(); 600 it->second->Clear();
580 } 601 }
581 602
603 static void OptionallyInitializeAlternateTimer() {
604 char* alternate_selector = getenv(k_alternate_profile_timer);
605 if (!alternate_selector)
606 return;
607 switch (*alternate_selector) {
608 case '0': // This is the default value, and uses the wall clock time.
609 break;
610 case '1': {
611 // Use the TCMalloc allocations-on-thread as a pseudo-time.
612 NowFunction* now_function = GetAlternateTimeSource();
613 if (!now_function)
614 break;
615 ThreadData::SetAlternateTimeSource(now_function);
ramant (doing other things) 2012/02/15 18:33:46 nit: should we consider moving the following check
jar (doing other things) 2012/02/15 20:26:32 Done.
616 break;
617 }
618
619 default:
620 NOTREACHED();
621 break;
622 }
623 }
624
582 bool ThreadData::Initialize() { 625 bool ThreadData::Initialize() {
583 if (!kTrackAllTaskObjects) 626 if (!kTrackAllTaskObjects)
584 return false; // Not compiled in. 627 return false; // Not compiled in.
585 if (status_ >= DEACTIVATED) 628 if (status_ >= DEACTIVATED)
586 return true; // Someone else did the initialization. 629 return true; // Someone else did the initialization.
587 // Due to racy lazy initialization in tests, we'll need to recheck status_ 630 // Due to racy lazy initialization in tests, we'll need to recheck status_
588 // after we acquire the lock. 631 // after we acquire the lock.
589 632
590 // Ensure that we don't double initialize tls. We are called when single 633 // Ensure that we don't double initialize tls. We are called when single
591 // threaded in the product, but some tests may be racy and lazy about our 634 // threaded in the product, but some tests may be racy and lazy about our
592 // initialization. 635 // initialization.
593 base::AutoLock lock(*list_lock_.Pointer()); 636 base::AutoLock lock(*list_lock_.Pointer());
594 if (status_ >= DEACTIVATED) 637 if (status_ >= DEACTIVATED)
595 return true; // Someone raced in here and beat us. 638 return true; // Someone raced in here and beat us.
596 639
640 // Put an alternate timer in place if the environment calls for it, such as
641 // for tracking TCMalloc allocations. This insertion is idempotent, so we
642 // don't mind if there is a race, and we'd prefer not to be in a lock while
643 // doing this work.
ramant (doing other things) 2012/02/15 18:33:46 Wondered if "_heap_init" happens before ThreadData
jar (doing other things) 2012/02/15 20:26:32 heap_init is run super-duper-early, before *any* a
644 if (kAllowAlternateTimeSourceHandling)
645 OptionallyInitializeAlternateTimer();
646
597 // Perform the "real" TLS initialization now, and leave it intact through 647 // Perform the "real" TLS initialization now, and leave it intact through
598 // process termination. 648 // process termination.
599 if (!tls_index_.initialized()) { // Testing may have initialized this. 649 if (!tls_index_.initialized()) { // Testing may have initialized this.
600 DCHECK_EQ(status_, UNINITIALIZED); 650 DCHECK_EQ(status_, UNINITIALIZED);
601 tls_index_.Initialize(&ThreadData::OnThreadTermination); 651 tls_index_.Initialize(&ThreadData::OnThreadTermination);
602 if (!tls_index_.initialized()) 652 if (!tls_index_.initialized())
603 return false; 653 return false;
604 } else { 654 } else {
605 // TLS was initialzed for us earlier. 655 // TLS was initialzed for us earlier.
606 DCHECK_EQ(status_, DORMANT_DURING_TESTS); 656 DCHECK_EQ(status_, DORMANT_DURING_TESTS);
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
659 } 709 }
660 return Now(); 710 return Now();
661 } 711 }
662 712
663 // static 713 // static
664 TrackedTime ThreadData::NowForEndOfRun() { 714 TrackedTime ThreadData::NowForEndOfRun() {
665 return Now(); 715 return Now();
666 } 716 }
667 717
668 // static 718 // static
719 void ThreadData::SetAlternateTimeSource(NowFunction* now_function) {
720 if (kAllowAlternateTimeSourceHandling)
721 now_function_ = now_function;
722 }
723
724 // static
669 TrackedTime ThreadData::Now() { 725 TrackedTime ThreadData::Now() {
726 if (kAllowAlternateTimeSourceHandling && now_function_)
727 return TrackedTime::FromMilliseconds((*now_function_)());
670 if (kTrackAllTaskObjects && TrackingStatus()) 728 if (kTrackAllTaskObjects && TrackingStatus())
671 return TrackedTime::Now(); 729 return TrackedTime::Now();
672 return TrackedTime(); // Super fast when disabled, or not compiled. 730 return TrackedTime(); // Super fast when disabled, or not compiled.
673 } 731 }
674 732
675 // static 733 // static
676 void ThreadData::EnsureCleanupWasCalled(int major_threads_shutdown_count) { 734 void ThreadData::EnsureCleanupWasCalled(int major_threads_shutdown_count) {
677 base::AutoLock lock(*list_lock_.Pointer()); 735 base::AutoLock lock(*list_lock_.Pointer());
678 if (worker_thread_data_creation_count_ == 0) 736 if (worker_thread_data_creation_count_ == 0)
679 return; // We haven't really run much, and couldn't have leaked. 737 return; // We haven't really run much, and couldn't have leaked.
(...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after
830 ++it) { 888 ++it) {
831 base::DictionaryValue* parent_child = new base::DictionaryValue; 889 base::DictionaryValue* parent_child = new base::DictionaryValue;
832 it->first->ToValue("parent", parent_child); 890 it->first->ToValue("parent", parent_child);
833 it->second->ToValue("child", parent_child); 891 it->second->ToValue("child", parent_child);
834 descendants->Append(parent_child); 892 descendants->Append(parent_child);
835 } 893 }
836 dictionary->Set("descendants", descendants); 894 dictionary->Set("descendants", descendants);
837 } 895 }
838 896
839 } // namespace tracked_objects 897 } // namespace tracked_objects
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698