| Index: base/message_loop/message_pump_mac.mm
|
| diff --git a/base/message_loop/message_pump_mac.mm b/base/message_loop/message_pump_mac.mm
|
| index 0ab9ab7c467de5128be33444db018ce73d369f7d..914977b13d59355e1dd566a6453ea4ae4eb69c78 100644
|
| --- a/base/message_loop/message_pump_mac.mm
|
| +++ b/base/message_loop/message_pump_mac.mm
|
| @@ -8,15 +8,11 @@
|
| #import <Foundation/Foundation.h>
|
|
|
| #include <limits>
|
| -#include <stack>
|
|
|
| -#include "base/format_macros.h"
|
| #include "base/logging.h"
|
| #include "base/mac/scoped_cftyperef.h"
|
| #include "base/message_loop/timer_slack.h"
|
| -#include "base/metrics/histogram.h"
|
| #include "base/run_loop.h"
|
| -#include "base/strings/stringprintf.h"
|
| #include "base/time/time.h"
|
|
|
| #if !defined(OS_IOS)
|
| @@ -123,226 +119,6 @@ class MessagePumpScopedAutoreleasePool {
|
| DISALLOW_COPY_AND_ASSIGN(MessagePumpScopedAutoreleasePool);
|
| };
|
|
|
| -// This class is used to instrument the MessagePump to gather various timing
|
| -// data about when the underlying run loop is entered, when it is waiting, and
|
| -// when it is servicing its delegate.
|
| -//
|
| -// The metrics are gathered as UMA-tracked histograms. To gather the data over
|
| -// time, sampling is used, such that a new histogram is created for each metric
|
| -// every |sampling_interval| for |sampling_duration|. After sampling is
|
| -// complete, this class deletes itself.
|
| -class MessagePumpInstrumentation {
|
| - public:
|
| - // Creates an instrument for the MessagePump on the current thread. Every
|
| - // |sampling_interval|, a new histogram will be created to track the metrics
|
| - // over time. After |sampling_duration|, this will delete itself, causing the
|
| - // WeakPtr to go NULL.
|
| - static WeakPtr<MessagePumpInstrumentation> Create(
|
| - const TimeDelta& sampling_interval,
|
| - const TimeDelta& sampling_duration) {
|
| - MessagePumpInstrumentation* instrument =
|
| - new MessagePumpInstrumentation(sampling_interval, sampling_duration);
|
| - return instrument->weak_ptr_factory_.GetWeakPtr();
|
| - }
|
| -
|
| - // Starts the timer that runs the sampling instrumentation. Can be called
|
| - // multiple times as a noop.
|
| - void StartIfNeeded() {
|
| - if (timer_)
|
| - return;
|
| -
|
| - sampling_start_time_ = generation_start_time_ = TimeTicks::Now();
|
| -
|
| - CFRunLoopTimerContext timer_context = { .info = this };
|
| - timer_.reset(CFRunLoopTimerCreate(
|
| - NULL, // allocator
|
| - (Time::Now() + sampling_interval_).ToCFAbsoluteTime(),
|
| - sampling_interval_.InSecondsF(),
|
| - 0, // flags
|
| - 0, // order
|
| - &MessagePumpInstrumentation::TimerFired,
|
| - &timer_context));
|
| - CFRunLoopAddTimerToAllModes(CFRunLoopGetCurrent(), timer_);
|
| - }
|
| -
|
| - // Used to track kCFRunLoopEntry.
|
| - void LoopEntered() {
|
| - loop_run_times_.push(TimeTicks::Now());
|
| - }
|
| -
|
| - // Used to track kCFRunLoopExit.
|
| - void LoopExited() {
|
| - TimeDelta duration = TimeTicks::Now() - loop_run_times_.top();
|
| - loop_run_times_.pop();
|
| - GetHistogram(LOOP_CYCLE)->AddTime(duration);
|
| - }
|
| -
|
| - // Used to track kCFRunLoopBeforeWaiting.
|
| - void WaitingStarted() {
|
| - loop_wait_times_.push(TimeTicks::Now());
|
| - }
|
| -
|
| - // Used to track kCFRunLoopAfterWaiting.
|
| - void WaitingFinished() {
|
| - TimeDelta duration = TimeTicks::Now() - loop_wait_times_.top();
|
| - loop_wait_times_.pop();
|
| - GetHistogram(LOOP_WAIT)->AddTime(duration);
|
| - }
|
| -
|
| - // Used to track when the MessagePump will invoke its |delegate|.
|
| - void WorkSourceEntered(MessagePump::Delegate* delegate) {
|
| - work_source_times_.push(TimeTicks::Now());
|
| - if (delegate) {
|
| - size_t queue_size;
|
| - TimeDelta queuing_delay;
|
| - delegate->GetQueueingInformation(&queue_size, &queuing_delay);
|
| - GetHistogram(QUEUE_SIZE)->Add(queue_size);
|
| - GetHistogram(QUEUE_DELAY)->AddTime(queuing_delay);
|
| - }
|
| - }
|
| -
|
| - // Used to track the completion of servicing the MessagePump::Delegate.
|
| - void WorkSourceExited() {
|
| - TimeDelta duration = TimeTicks::Now() - work_source_times_.top();
|
| - work_source_times_.pop();
|
| - GetHistogram(WORK_SOURCE)->AddTime(duration);
|
| - }
|
| -
|
| - private:
|
| - enum HistogramEvent {
|
| - // Time-based histograms:
|
| - LOOP_CYCLE, // LoopEntered/LoopExited
|
| - LOOP_WAIT, // WaitingStarted/WaitingEnded
|
| - WORK_SOURCE, // WorkSourceExited
|
| - QUEUE_DELAY, // WorkSourceEntered
|
| -
|
| - // Value-based histograms:
|
| - // NOTE: Do not add value-based histograms before this event, only after.
|
| - QUEUE_SIZE, // WorkSourceEntered
|
| -
|
| - HISTOGRAM_EVENT_MAX,
|
| - };
|
| -
|
| - MessagePumpInstrumentation(const TimeDelta& sampling_interval,
|
| - const TimeDelta& sampling_duration)
|
| - : weak_ptr_factory_(this),
|
| - sampling_interval_(sampling_interval),
|
| - sampling_duration_(sampling_duration),
|
| - sample_generation_(0) {
|
| - // Create all the histogram objects that will be used for sampling.
|
| - const char kHistogramName[] = "MessagePumpMac.%s.SampleMs.%" PRId64;
|
| - for (TimeDelta i; i < sampling_duration_; i += sampling_interval_) {
|
| - int64 sample = i.InMilliseconds();
|
| -
|
| - // Generate the time-based histograms.
|
| - for (int j = LOOP_CYCLE; j < QUEUE_SIZE; ++j) {
|
| - std::string name = StringPrintf(kHistogramName,
|
| - NameForEnum(static_cast<HistogramEvent>(j)), sample);
|
| - histograms_[j].push_back(
|
| - Histogram::FactoryTimeGet(name, TimeDelta::FromMilliseconds(1),
|
| - sampling_interval_, 50,
|
| - HistogramBase::kUmaTargetedHistogramFlag));
|
| - }
|
| -
|
| - // Generate the value-based histograms.
|
| - for (int j = QUEUE_SIZE; j < HISTOGRAM_EVENT_MAX; ++j) {
|
| - std::string name = StringPrintf(kHistogramName,
|
| - NameForEnum(static_cast<HistogramEvent>(j)), sample);
|
| - histograms_[j].push_back(
|
| - Histogram::FactoryGet(name, 1, 10000, 50,
|
| - HistogramBase::kUmaTargetedHistogramFlag));
|
| - }
|
| - }
|
| - }
|
| -
|
| - ~MessagePumpInstrumentation() {
|
| - if (timer_)
|
| - CFRunLoopTimerInvalidate(timer_);
|
| - }
|
| -
|
| - const char* NameForEnum(HistogramEvent event) {
|
| - switch (event) {
|
| - case LOOP_CYCLE: return "LoopCycle";
|
| - case LOOP_WAIT: return "Waiting";
|
| - case WORK_SOURCE: return "WorkSource";
|
| - case QUEUE_DELAY: return "QueueingDelay";
|
| - case QUEUE_SIZE: return "QueueSize";
|
| - default:
|
| - NOTREACHED();
|
| - return NULL;
|
| - }
|
| - }
|
| -
|
| - static void TimerFired(CFRunLoopTimerRef timer, void* context) {
|
| - static_cast<MessagePumpInstrumentation*>(context)->TimerFired();
|
| - }
|
| -
|
| - // Called by the run loop when the sampling_interval_ has elapsed. Advances
|
| - // the sample_generation_, which controls into which histogram data is
|
| - // recorded, while recording and accounting for timer skew. Will delete this
|
| - // object after |sampling_duration_| has elapsed.
|
| - void TimerFired() {
|
| - TimeTicks now = TimeTicks::Now();
|
| - TimeDelta delta = now - generation_start_time_;
|
| -
|
| - // The timer fired, so advance the generation by at least one.
|
| - ++sample_generation_;
|
| -
|
| - // To account for large timer skew/drift, advance the generation by any
|
| - // more completed intervals.
|
| - for (TimeDelta skew_advance = delta - sampling_interval_;
|
| - skew_advance >= sampling_interval_;
|
| - skew_advance -= sampling_interval_) {
|
| - ++sample_generation_;
|
| - }
|
| -
|
| - generation_start_time_ = now;
|
| - if (now >= sampling_start_time_ + sampling_duration_)
|
| - delete this;
|
| - }
|
| -
|
| - HistogramBase* GetHistogram(HistogramEvent event) {
|
| - DCHECK_LT(sample_generation_, histograms_[event].size());
|
| - return histograms_[event][sample_generation_];
|
| - }
|
| -
|
| - // Vends the pointer to the Create()or.
|
| - WeakPtrFactory<MessagePumpInstrumentation> weak_ptr_factory_;
|
| -
|
| - // The interval and duration of the sampling.
|
| - TimeDelta sampling_interval_;
|
| - TimeDelta sampling_duration_;
|
| -
|
| - // The time at which sampling started.
|
| - TimeTicks sampling_start_time_;
|
| -
|
| - // The timer that advances the sample_generation_ and sets the
|
| - // generation_start_time_ for the current sample interval.
|
| - base::ScopedCFTypeRef<CFRunLoopTimerRef> timer_;
|
| -
|
| - // The two-dimensional array of histograms. The first dimension is the
|
| - // HistogramEvent type. The second is for the sampling intervals.
|
| - std::vector<HistogramBase*> histograms_[HISTOGRAM_EVENT_MAX];
|
| -
|
| - // The index in the second dimension of histograms_, which controls in which
|
| - // sampled histogram events are recorded.
|
| - size_t sample_generation_;
|
| -
|
| - // The last time at which the timer fired. This is used to track timer skew
|
| - // (i.e. it did not fire on time) and properly account for it when advancing
|
| - // samle_generation_.
|
| - TimeTicks generation_start_time_;
|
| -
|
| - // MessagePump activations can be nested. Use a stack for each of the
|
| - // possibly reentrant HistogramEvent types to properly balance and calculate
|
| - // the timing information.
|
| - std::stack<TimeTicks> loop_run_times_;
|
| - std::stack<TimeTicks> loop_wait_times_;
|
| - std::stack<TimeTicks> work_source_times_;
|
| -
|
| - DISALLOW_COPY_AND_ASSIGN(MessagePumpInstrumentation);
|
| -};
|
| -
|
| // Must be called on the run loop thread.
|
| MessagePumpCFRunLoopBase::MessagePumpCFRunLoopBase()
|
| : delegate_(NULL),
|
| @@ -393,11 +169,10 @@ MessagePumpCFRunLoopBase::MessagePumpCFRunLoopBase()
|
| CFRunLoopObserverContext observer_context = CFRunLoopObserverContext();
|
| observer_context.info = this;
|
| pre_wait_observer_ = CFRunLoopObserverCreate(NULL, // allocator
|
| - kCFRunLoopBeforeWaiting |
|
| - kCFRunLoopAfterWaiting,
|
| + kCFRunLoopBeforeWaiting,
|
| true, // repeat
|
| 0, // priority
|
| - StartOrEndWaitObserver,
|
| + PreWaitObserver,
|
| &observer_context);
|
| CFRunLoopAddObserverToAllModes(run_loop_, pre_wait_observer_);
|
|
|
| @@ -482,11 +257,6 @@ void MessagePumpCFRunLoopBase::SetDelegate(Delegate* delegate) {
|
| }
|
| }
|
|
|
| -void MessagePumpCFRunLoopBase::EnableInstrumentation() {
|
| - instrumentation_ = MessagePumpInstrumentation::Create(
|
| - TimeDelta::FromSeconds(1), TimeDelta::FromSeconds(15));
|
| -}
|
| -
|
| // May be called on any thread.
|
| void MessagePumpCFRunLoopBase::ScheduleWork() {
|
| CFRunLoopSourceSignal(work_source_);
|
| @@ -543,9 +313,6 @@ bool MessagePumpCFRunLoopBase::RunWork() {
|
| return false;
|
| }
|
|
|
| - if (instrumentation_)
|
| - instrumentation_->WorkSourceEntered(delegate_);
|
| -
|
| // The NSApplication-based run loop only drains the autorelease pool at each
|
| // UI event (NSEvent). The autorelease pool is not drained for each
|
| // CFRunLoopSource target that's run. Use a local pool for any autoreleased
|
| @@ -585,9 +352,6 @@ bool MessagePumpCFRunLoopBase::RunWork() {
|
| CFRunLoopSourceSignal(work_source_);
|
| }
|
|
|
| - if (instrumentation_)
|
| - instrumentation_->WorkSourceExited();
|
| -
|
| return resignal_work_source;
|
| }
|
|
|
| @@ -672,18 +436,11 @@ void MessagePumpCFRunLoopBase::MaybeScheduleNestingDeferredWork() {
|
|
|
| // Called from the run loop.
|
| // static
|
| -void MessagePumpCFRunLoopBase::StartOrEndWaitObserver(
|
| - CFRunLoopObserverRef observer,
|
| - CFRunLoopActivity activity,
|
| - void* info) {
|
| +void MessagePumpCFRunLoopBase::PreWaitObserver(CFRunLoopObserverRef observer,
|
| + CFRunLoopActivity activity,
|
| + void* info) {
|
| MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info);
|
|
|
| - if (activity == kCFRunLoopAfterWaiting) {
|
| - if (self->instrumentation_)
|
| - self->instrumentation_->WaitingFinished();
|
| - return;
|
| - }
|
| -
|
| // Attempt to do some idle work before going to sleep.
|
| self->RunIdleWork();
|
|
|
| @@ -692,9 +449,6 @@ void MessagePumpCFRunLoopBase::StartOrEndWaitObserver(
|
| // nesting-deferred work may have accumulated. Schedule it for processing
|
| // if appropriate.
|
| self->MaybeScheduleNestingDeferredWork();
|
| -
|
| - if (self->instrumentation_)
|
| - self->instrumentation_->WaitingStarted();
|
| }
|
|
|
| // Called from the run loop.
|
| @@ -721,9 +475,6 @@ void MessagePumpCFRunLoopBase::EnterExitObserver(CFRunLoopObserverRef observer,
|
|
|
| switch (activity) {
|
| case kCFRunLoopEntry:
|
| - if (self->instrumentation_)
|
| - self->instrumentation_->LoopEntered();
|
| -
|
| ++self->nesting_level_;
|
| if (self->nesting_level_ > self->deepest_nesting_level_) {
|
| self->deepest_nesting_level_ = self->nesting_level_;
|
| @@ -737,9 +488,9 @@ void MessagePumpCFRunLoopBase::EnterExitObserver(CFRunLoopObserverRef observer,
|
| // handling sources to exiting without any sleep. This most commonly
|
| // occurs when CFRunLoopRunInMode is passed a timeout of 0, causing it
|
| // to make a single pass through the loop and exit without sleep. Some
|
| - // native loops use CFRunLoop in this way. Because StartOrEndWaitObserver
|
| - // will not be called in these case, MaybeScheduleNestingDeferredWork
|
| - // needs to be called here, as the run loop exits.
|
| + // native loops use CFRunLoop in this way. Because PreWaitObserver will
|
| + // not be called in these case, MaybeScheduleNestingDeferredWork needs
|
| + // to be called here, as the run loop exits.
|
| //
|
| // MaybeScheduleNestingDeferredWork consults self->nesting_level_
|
| // to determine whether to schedule nesting-deferred work. It expects
|
| @@ -749,9 +500,6 @@ void MessagePumpCFRunLoopBase::EnterExitObserver(CFRunLoopObserverRef observer,
|
| // loop.
|
| self->MaybeScheduleNestingDeferredWork();
|
| --self->nesting_level_;
|
| -
|
| - if (self->instrumentation_)
|
| - self->instrumentation_->LoopExited();
|
| break;
|
|
|
| default:
|
| @@ -881,15 +629,11 @@ void MessagePumpUIApplication::Attach(Delegate* delegate) {
|
| MessagePumpNSApplication::MessagePumpNSApplication()
|
| : keep_running_(true),
|
| running_own_loop_(false) {
|
| - EnableInstrumentation();
|
| }
|
|
|
| MessagePumpNSApplication::~MessagePumpNSApplication() {}
|
|
|
| void MessagePumpNSApplication::DoRun(Delegate* delegate) {
|
| - if (instrumentation_)
|
| - instrumentation_->StartIfNeeded();
|
| -
|
| bool last_running_own_loop_ = running_own_loop_;
|
|
|
| // NSApp must be initialized by calling:
|
|
|