Support use of third party time function for about:profiler

This uses TCMalloc to provide a time function, allowing
us to see how much memory was allocated on a single thread
during the running of a task.  The alternate time function
is put in place only when a specific environment variable
is detected during TCMalloc startup.

This change currently is activated only in Windows/Linux,
as it is based on changes TCMalloc (not used on Mac).

We also create an infrastructure for using any alternate
timer, to replace the "wall clock time," on a per-thread
basis, in the about:profiler infrastructure.  That interface
may be used on other platforms, including scenarios where
we have a per-thread-CPU-time function to replace the
wall-clock timer.  In all cases, when this alternate timer
is activated, we lose the ability to calculated queueing
time.  Queueing time is based on a time snapshot taken on
a second thread, and hence is not comparable to the
alternate timer (when the alternate timer is engaged).


r=rtenneti
BUG=103321
Review URL: https://chromiumcodereview.appspot.com/9212025

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@122180 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/base/tracked_objects.cc b/base/tracked_objects.cc
index 87af8dc..c837b9a 100644
--- a/base/tracked_objects.cc
+++ b/base/tracked_objects.cc
@@ -8,6 +8,7 @@
 
 #include "base/format_macros.h"
 #include "base/message_loop.h"
+#include "base/profiler/alternate_timer.h"
 #include "base/stringprintf.h"
 #include "base/third_party/valgrind/memcheck.h"
 #include "base/threading/thread_restrictions.h"
@@ -35,6 +36,14 @@
 const ThreadData::Status kInitialStartupState =
     ThreadData::PROFILING_CHILDREN_ACTIVE;
 
+// Control whether an alternate time source (Now() function) is supported by
+// the ThreadData class.  This compile time flag should be set to true if we
+// want other modules (such as a memory allocator, or a thread-specific CPU time
+// clock) to be able to provide a thread-specific Now() function.  Without this
+// compile-time flag, the code will only support the wall-clock time.  This flag
+// can be flipped to efficiently disable this path (if there is a performance
+// problem with its presence).
+static const bool kAllowAlternateTimeSourceHandling = true;
 }  // namespace
 
 //------------------------------------------------------------------------------
@@ -176,6 +185,9 @@
 // optimize layout so that we benefit from locality of reference during accesses
 // to them.
 
+// static
+NowFunction* ThreadData::now_function_ = NULL;
+
 // A TLS slot which points to the ThreadData instance for the current thread. We
 // do a fake initialization here (zeroing out data), and then the real in-place
 // construction happens when we call tls_index_.Initialize().
@@ -370,6 +382,12 @@
   // An address is going to have some randomness to it as well ;-).
   random_number_ ^= static_cast<int32>(&birth - reinterpret_cast<Births*>(0));
 
+  // We don't have queue durations without OS timer. OS timer is automatically
+  // used for task-post-timing, so the use of an alternate timer implies all
+  // queue times are invalid.
+  if (kAllowAlternateTimeSourceHandling && now_function_)
+    queue_duration = 0;
+
   DeathMap::iterator it = death_map_.find(&birth);
   DeathData* death_data;
   if (it != death_map_.end()) {
@@ -579,6 +597,24 @@
     it->second->Clear();
 }
 
+static void OptionallyInitializeAlternateTimer() {
+  char* alternate_selector = getenv(kAlternateProfilerTime);
+  if (!alternate_selector)
+    return;
+  switch (*alternate_selector) {
+    case '0':  // This is the default value, and uses the wall clock time.
+      break;
+    case '1':  {
+      // Use the TCMalloc allocations-on-thread as a pseudo-time.
+      ThreadData::SetAlternateTimeSource(GetAlternateTimeSource());
+      break;
+      }
+    default:
+      NOTREACHED();
+      break;
+  }
+}
+
 bool ThreadData::Initialize() {
   if (!kTrackAllTaskObjects)
     return false;  // Not compiled in.
@@ -594,6 +630,13 @@
   if (status_ >= DEACTIVATED)
     return true;  // Someone raced in here and beat us.
 
+  // Put an alternate timer in place if the environment calls for it, such as
+  // for tracking TCMalloc allocations.  This insertion is idempotent, so we
+  // don't mind if there is a race, and we'd prefer not to be in a lock while
+  // doing this work.
+  if (kAllowAlternateTimeSourceHandling)
+    OptionallyInitializeAlternateTimer();
+
   // Perform the "real" TLS initialization now, and leave it intact through
   // process termination.
   if (!tls_index_.initialized()) {  // Testing may have initialized this.
@@ -666,7 +709,16 @@
 }
 
 // static
+void ThreadData::SetAlternateTimeSource(NowFunction* now_function) {
+  DCHECK(now_function);
+  if (kAllowAlternateTimeSourceHandling)
+    now_function_ = now_function;
+}
+
+// static
 TrackedTime ThreadData::Now() {
+  if (kAllowAlternateTimeSourceHandling && now_function_)
+    return TrackedTime::FromMilliseconds((*now_function_)());
   if (kTrackAllTaskObjects && TrackingStatus())
     return TrackedTime::Now();
   return TrackedTime();  // Super fast when disabled, or not compiled.