Add instrumentation to the MessagePumpMac family of classes.

This adds UMA-uploaded histograms of sampling intervals for key points of data:
* Total time spent in a CFRunLoop
* Total time waiting in CFRunLoop
* Total time servicing MessagePump::Delegate (the MessageLoop)
* The MessageLoop queue size and queueing delay before servicing

It adds 1 second sampling for 15 seconds at startup, only for the main thread
(NSApplication-based) run loops.

The data will be used to determine if adding scheduling-like behavior to the
MessagePump will result in more efficient processing of the MessageLoop work.

An unforunate side effect of this change is exposing another method on the
MessagePump::Delegate interface, but there does not appear to be a better way
to do this.

BUG=264886
R=jar@chromium.org, mark@chromium.org

Review URL: https://codereview.chromium.org/22911026

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@221427 0039d316-1c4b-4281-b951-d872f2087c98


CrOS-Libchrome-Original-Commit: 370d7cb8ebcaaac4cf1f9075981b41de92348bc7
diff --git a/base/message_loop/message_loop.cc b/base/message_loop/message_loop.cc
index 701594a..cf0b31c 100644
--- a/base/message_loop/message_loop.cc
+++ b/base/message_loop/message_loop.cc
@@ -660,6 +660,20 @@
   return false;
 }
 
+void MessageLoop::GetQueueingInformation(size_t* queue_size,
+                                         TimeDelta* queueing_delay) {
+  *queue_size = work_queue_.size();
+  if (*queue_size == 0) {
+    *queueing_delay = TimeDelta();
+    return;
+  }
+
+  const PendingTask& next_to_run = work_queue_.front();
+  tracked_objects::Duration duration =
+      tracked_objects::TrackedTime::Now() - next_to_run.EffectiveTimePosted();
+  *queueing_delay = TimeDelta::FromMilliseconds(duration.InMilliseconds());
+}
+
 void MessageLoop::DeleteSoonInternal(const tracked_objects::Location& from_here,
                                      void(*deleter)(const void*),
                                      const void* object) {
diff --git a/base/message_loop/message_loop.h b/base/message_loop/message_loop.h
index f22c904..db6aa9b 100644
--- a/base/message_loop/message_loop.h
+++ b/base/message_loop/message_loop.h
@@ -478,6 +478,8 @@
   virtual bool DoWork() OVERRIDE;
   virtual bool DoDelayedWork(TimeTicks* next_delayed_work_time) OVERRIDE;
   virtual bool DoIdleWork() OVERRIDE;
+  virtual void GetQueueingInformation(size_t* queue_size,
+                                      TimeDelta* queueing_delay) OVERRIDE;
 
   Type type_;
 
diff --git a/base/message_loop/message_pump.h b/base/message_loop/message_pump.h
index 0ebba3a..816bb3c 100644
--- a/base/message_loop/message_pump.h
+++ b/base/message_loop/message_pump.h
@@ -6,10 +6,12 @@
 #define BASE_MESSAGE_LOOP_MESSAGE_PUMP_H_
 
 #include "base/base_export.h"
+#include "base/basictypes.h"
 #include "base/threading/non_thread_safe.h"
 
 namespace base {
 
+class TimeDelta;
 class TimeTicks;
 
 class BASE_EXPORT MessagePump : public NonThreadSafe {
@@ -39,6 +41,19 @@
     // Called from within Run just before the message pump goes to sleep.
     // Returns true to indicate that idle work was done.
     virtual bool DoIdleWork() = 0;
+
+    // Via the two required out pointers, returns the length of the Delegate's
+    // work queue and the length of time that the first item in the queue has
+    // been waiting to run. If the work queue is empty, the count and delay
+    // will both be zero.
+    // Note that this only counts the tasks in the ready-to-run queue and not
+    // the incoming queue that is used by other threads to post tasks. The
+    // latter queue requires holding a lock, which is deemed too expensive for
+    // instrumentation code. Under normal conditions, the incoming queue should
+    // be small or zero, but under heavy loads it may be much larger and
+    // |queue_count| may be up to 1/4 the size of the incoming queue.
+    virtual void GetQueueingInformation(size_t* queue_count,
+                                        TimeDelta* queueing_delay) {}
   };
 
   MessagePump();