Revert of High resolution timer fix for Windows (https://codereview.chromium.org/395913006/)

Reason for revert:
This patch seems to make following browser_tests flakey

PPAPINaClNewlibTest.Graphics2D_FlushOffscreenUpdate
NetInternalsTest.netInternalsHSTSViewAddOverwrite
NetInternalsTest.netInternalsHSTSViewAddDelete
NetInternalsTest.netInternalsHSTSViewAddTwice

http://build.chromium.org/p/chromium.win/builders/XP%20Tests%20%282%29/builds/34734
http://build.chromium.org/p/chromium.win/builders/XP%20Tests%20%281%29/builds/32086
http://build.chromium.org/p/chromium.win/builders/Vista%20Tests%20%281%29/builds/47545


Original issue's description:
> This is jamesr@ code I am landing.
> 
> On Windows the message pump code tried to manage the systemwide timer resolution to fire delayed tasks with better than 15ms resolution but it was buggy:
> 
> 1- A short task that was not followed by any other task will leave the systemwide timer pegged to 1ms
> 
> 2- After we decided to crank up the timer we would 'lease' the timer for 1 second, for no good reason.
> 
> Both issues are detrimental to battery power.
> 
> The source of both problems is that we tried to decide with incomplete information. This patch solves that by having 1 bit for each pending task that requires a high resolution timer and a sum of the number of tasks that require high res timers.
> 
> BUG=153139
> TEST=included here, also see the bug for manual testing.
> 
> Committed: https://src.chromium.org/viewvc/chrome?view=rev&revision=284625

TBR=jamesr@chromium.org,darin@chromium.org,cpu@chromium.org
NOTREECHECKS=true
NOTRY=true
BUG=153139

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

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@284664 0039d316-1c4b-4281-b951-d872f2087c98
parent 74c10312
...@@ -8,14 +8,12 @@ ...@@ -8,14 +8,12 @@
#include "base/location.h" #include "base/location.h"
#include "base/message_loop/message_loop.h" #include "base/message_loop/message_loop.h"
#include "base/synchronization/waitable_event.h" #include "base/synchronization/waitable_event.h"
#include "base/time/time.h"
namespace base { namespace base {
namespace internal { namespace internal {
IncomingTaskQueue::IncomingTaskQueue(MessageLoop* message_loop) IncomingTaskQueue::IncomingTaskQueue(MessageLoop* message_loop)
: high_res_task_count_(0), : message_loop_(message_loop),
message_loop_(message_loop),
next_sequence_num_(0) { next_sequence_num_(0) {
} }
...@@ -27,23 +25,15 @@ bool IncomingTaskQueue::AddToIncomingQueue( ...@@ -27,23 +25,15 @@ bool IncomingTaskQueue::AddToIncomingQueue(
AutoLock locked(incoming_queue_lock_); AutoLock locked(incoming_queue_lock_);
PendingTask pending_task( PendingTask pending_task(
from_here, task, CalculateDelayedRuntime(delay), nestable); from_here, task, CalculateDelayedRuntime(delay), nestable);
#if defined(OS_WIN)
// We consider the task needs a high resolution timer if the delay is
// more than 0 and less than 32ms. This caps the relative error to
// less than 50% : a 33ms wait can wake at 48ms since the default
// resolution on Windows is between 10 and 15ms.
if (delay > TimeDelta() &&
delay.InMilliseconds() < (2 * Time::kMinLowResolutionThresholdMs)) {
++high_res_task_count_;
pending_task.is_high_res = true;
}
#endif
return PostPendingTask(&pending_task); return PostPendingTask(&pending_task);
} }
bool IncomingTaskQueue::HasHighResolutionTasks() { bool IncomingTaskQueue::IsHighResolutionTimerEnabledForTesting() {
AutoLock lock(incoming_queue_lock_); #if defined(OS_WIN)
return high_res_task_count_ > 0; return !high_resolution_timer_expiration_.is_null();
#else
return true;
#endif
} }
bool IncomingTaskQueue::IsIdleForTesting() { bool IncomingTaskQueue::IsIdleForTesting() {
...@@ -51,22 +41,29 @@ bool IncomingTaskQueue::IsIdleForTesting() { ...@@ -51,22 +41,29 @@ bool IncomingTaskQueue::IsIdleForTesting() {
return incoming_queue_.empty(); return incoming_queue_.empty();
} }
int IncomingTaskQueue::ReloadWorkQueue(TaskQueue* work_queue) { void IncomingTaskQueue::ReloadWorkQueue(TaskQueue* work_queue) {
// Make sure no tasks are lost. // Make sure no tasks are lost.
DCHECK(work_queue->empty()); DCHECK(work_queue->empty());
// Acquire all we can from the inter-thread queue with one lock acquisition. // Acquire all we can from the inter-thread queue with one lock acquisition.
AutoLock lock(incoming_queue_lock_); AutoLock lock(incoming_queue_lock_);
if (!incoming_queue_.empty()) if (!incoming_queue_.empty())
incoming_queue_.Swap(work_queue); incoming_queue_.Swap(work_queue); // Constant time
// Reset the count of high resolution tasks since our queue is now empty. DCHECK(incoming_queue_.empty());
int high_res_tasks = high_res_task_count_;
high_res_task_count_ = 0;
return high_res_tasks;
} }
void IncomingTaskQueue::WillDestroyCurrentMessageLoop() { void IncomingTaskQueue::WillDestroyCurrentMessageLoop() {
#if defined(OS_WIN)
// If we left the high-resolution timer activated, deactivate it now.
// Doing this is not-critical, it is mainly to make sure we track
// the high resolution timer activations properly in our unit tests.
if (!high_resolution_timer_expiration_.is_null()) {
Time::ActivateHighResolutionTimer(false);
high_resolution_timer_expiration_ = TimeTicks();
}
#endif
AutoLock lock(incoming_queue_lock_); AutoLock lock(incoming_queue_lock_);
message_loop_ = NULL; message_loop_ = NULL;
} }
...@@ -78,10 +75,40 @@ IncomingTaskQueue::~IncomingTaskQueue() { ...@@ -78,10 +75,40 @@ IncomingTaskQueue::~IncomingTaskQueue() {
TimeTicks IncomingTaskQueue::CalculateDelayedRuntime(TimeDelta delay) { TimeTicks IncomingTaskQueue::CalculateDelayedRuntime(TimeDelta delay) {
TimeTicks delayed_run_time; TimeTicks delayed_run_time;
if (delay > TimeDelta()) if (delay > TimeDelta()) {
delayed_run_time = TimeTicks::Now() + delay; delayed_run_time = TimeTicks::Now() + delay;
else
#if defined(OS_WIN)
if (high_resolution_timer_expiration_.is_null()) {
// Windows timers are granular to 15.6ms. If we only set high-res
// timers for those under 15.6ms, then a 18ms timer ticks at ~32ms,
// which as a percentage is pretty inaccurate. So enable high
// res timers for any timer which is within 2x of the granularity.
// This is a tradeoff between accuracy and power management.
bool needs_high_res_timers = delay.InMilliseconds() <
(2 * Time::kMinLowResolutionThresholdMs);
if (needs_high_res_timers) {
if (Time::ActivateHighResolutionTimer(true)) {
high_resolution_timer_expiration_ = TimeTicks::Now() +
TimeDelta::FromMilliseconds(
MessageLoop::kHighResolutionTimerModeLeaseTimeMs);
}
}
}
#endif
} else {
DCHECK_EQ(delay.InMilliseconds(), 0) << "delay should not be negative"; DCHECK_EQ(delay.InMilliseconds(), 0) << "delay should not be negative";
}
#if defined(OS_WIN)
if (!high_resolution_timer_expiration_.is_null()) {
if (TimeTicks::Now() > high_resolution_timer_expiration_) {
Time::ActivateHighResolutionTimer(false);
high_resolution_timer_expiration_ = TimeTicks();
}
}
#endif
return delayed_run_time; return delayed_run_time;
} }
......
...@@ -38,17 +38,16 @@ class BASE_EXPORT IncomingTaskQueue ...@@ -38,17 +38,16 @@ class BASE_EXPORT IncomingTaskQueue
TimeDelta delay, TimeDelta delay,
bool nestable); bool nestable);
// Returns true if the queue contains tasks that require higher than default // Returns true if the message loop has high resolution timers enabled.
// timer resolution. Currently only needed for Windows. // Provided for testing.
bool HasHighResolutionTasks(); bool IsHighResolutionTimerEnabledForTesting();
// Returns true if the message loop is "idle". Provided for testing. // Returns true if the message loop is "idle". Provided for testing.
bool IsIdleForTesting(); bool IsIdleForTesting();
// Loads tasks from the |incoming_queue_| into |*work_queue|. Must be called // Loads tasks from the |incoming_queue_| into |*work_queue|. Must be called
// from the thread that is running the loop. Returns the number of tasks that // from the thread that is running the loop.
// require high resolution timers. void ReloadWorkQueue(TaskQueue* work_queue);
int ReloadWorkQueue(TaskQueue* work_queue);
// Disconnects |this| from the parent message loop. // Disconnects |this| from the parent message loop.
void WillDestroyCurrentMessageLoop(); void WillDestroyCurrentMessageLoop();
...@@ -66,11 +65,12 @@ class BASE_EXPORT IncomingTaskQueue ...@@ -66,11 +65,12 @@ class BASE_EXPORT IncomingTaskQueue
// does not retain |pending_task->task| beyond this function call. // does not retain |pending_task->task| beyond this function call.
bool PostPendingTask(PendingTask* pending_task); bool PostPendingTask(PendingTask* pending_task);
// Number of tasks that require high resolution timing. This value is kept #if defined(OS_WIN)
// so that ReloadWorkQueue() completes in constant time. TimeTicks high_resolution_timer_expiration_;
int high_res_task_count_; #endif
// The lock that protects access to the members of this class. // The lock that protects access to |incoming_queue_|, |message_loop_| and
// |next_sequence_num_|.
base::Lock incoming_queue_lock_; base::Lock incoming_queue_lock_;
// An incoming queue of tasks that are acquired under a mutex for processing // An incoming queue of tasks that are acquired under a mutex for processing
......
...@@ -127,8 +127,6 @@ MessageLoop::DestructionObserver::~DestructionObserver() { ...@@ -127,8 +127,6 @@ MessageLoop::DestructionObserver::~DestructionObserver() {
MessageLoop::MessageLoop(Type type) MessageLoop::MessageLoop(Type type)
: type_(type), : type_(type),
pending_high_res_tasks_(0),
in_high_res_mode_(false),
nestable_tasks_allowed_(true), nestable_tasks_allowed_(true),
#if defined(OS_WIN) #if defined(OS_WIN)
os_modal_loop_(false), os_modal_loop_(false),
...@@ -143,8 +141,6 @@ MessageLoop::MessageLoop(Type type) ...@@ -143,8 +141,6 @@ MessageLoop::MessageLoop(Type type)
MessageLoop::MessageLoop(scoped_ptr<MessagePump> pump) MessageLoop::MessageLoop(scoped_ptr<MessagePump> pump)
: pump_(pump.Pass()), : pump_(pump.Pass()),
type_(TYPE_CUSTOM), type_(TYPE_CUSTOM),
pending_high_res_tasks_(0),
in_high_res_mode_(false),
nestable_tasks_allowed_(true), nestable_tasks_allowed_(true),
#if defined(OS_WIN) #if defined(OS_WIN)
os_modal_loop_(false), os_modal_loop_(false),
...@@ -157,11 +153,8 @@ MessageLoop::MessageLoop(scoped_ptr<MessagePump> pump) ...@@ -157,11 +153,8 @@ MessageLoop::MessageLoop(scoped_ptr<MessagePump> pump)
MessageLoop::~MessageLoop() { MessageLoop::~MessageLoop() {
DCHECK_EQ(this, current()); DCHECK_EQ(this, current());
DCHECK(!run_loop_); DCHECK(!run_loop_);
#if defined(OS_WIN)
if (in_high_res_mode_)
Time::ActivateHighResolutionTimer(false);
#endif
// Clean up any unprocessed tasks, but take care: deleting a task could // Clean up any unprocessed tasks, but take care: deleting a task could
// result in the addition of more tasks (e.g., via DeleteSoon). We set a // result in the addition of more tasks (e.g., via DeleteSoon). We set a
...@@ -376,8 +369,8 @@ bool MessageLoop::is_running() const { ...@@ -376,8 +369,8 @@ bool MessageLoop::is_running() const {
return run_loop_ != NULL; return run_loop_ != NULL;
} }
bool MessageLoop::HasHighResolutionTasks() { bool MessageLoop::IsHighResolutionTimerEnabledForTesting() {
return incoming_task_queue_->HasHighResolutionTasks(); return incoming_task_queue_->IsHighResolutionTimerEnabledForTesting();
} }
bool MessageLoop::IsIdleForTesting() { bool MessageLoop::IsIdleForTesting() {
...@@ -445,11 +438,6 @@ void MessageLoop::RunTask(const PendingTask& pending_task) { ...@@ -445,11 +438,6 @@ void MessageLoop::RunTask(const PendingTask& pending_task) {
"src_file", pending_task.posted_from.file_name(), "src_file", pending_task.posted_from.file_name(),
"src_func", pending_task.posted_from.function_name()); "src_func", pending_task.posted_from.function_name());
if (pending_task.is_high_res) {
pending_high_res_tasks_--;
CHECK(pending_high_res_tasks_ >= 0);
}
DCHECK(nestable_tasks_allowed_); DCHECK(nestable_tasks_allowed_);
// Execute the task and assume the worst: It is probably not reentrant. // Execute the task and assume the worst: It is probably not reentrant.
nestable_tasks_allowed_ = false; nestable_tasks_allowed_ = false;
...@@ -535,10 +523,8 @@ void MessageLoop::ReloadWorkQueue() { ...@@ -535,10 +523,8 @@ void MessageLoop::ReloadWorkQueue() {
// |*work_queue| by waiting until the last minute (|*work_queue| is empty) to // |*work_queue| by waiting until the last minute (|*work_queue| is empty) to
// load. That reduces the number of locks-per-task significantly when our // load. That reduces the number of locks-per-task significantly when our
// queues get large. // queues get large.
if (work_queue_.empty()) { if (work_queue_.empty())
pending_high_res_tasks_ +=
incoming_task_queue_->ReloadWorkQueue(&work_queue_); incoming_task_queue_->ReloadWorkQueue(&work_queue_);
}
} }
void MessageLoop::ScheduleWork(bool was_empty) { void MessageLoop::ScheduleWork(bool was_empty) {
...@@ -643,14 +629,6 @@ bool MessageLoop::DoIdleWork() { ...@@ -643,14 +629,6 @@ bool MessageLoop::DoIdleWork() {
if (run_loop_->quit_when_idle_received_) if (run_loop_->quit_when_idle_received_)
pump_->Quit(); pump_->Quit();
// We will now do a kernel wait for more tasks.
#if defined(OS_WIN)
// The Windows scheduler has by default ~15ms resolution. If we have high
// resolution tasks pending we need to temporarity increase the systemwide
// timer resolution to 1ms, and if we don't we need to go back to 15ms.
in_high_res_mode_ = pending_high_res_tasks_ > 0;
Time::ActivateHighResolutionTimer(in_high_res_mode_);
#endif
return false; return false;
} }
......
...@@ -371,6 +371,10 @@ class BASE_EXPORT MessageLoop : public MessagePump::Delegate { ...@@ -371,6 +371,10 @@ class BASE_EXPORT MessageLoop : public MessagePump::Delegate {
void AddTaskObserver(TaskObserver* task_observer); void AddTaskObserver(TaskObserver* task_observer);
void RemoveTaskObserver(TaskObserver* task_observer); void RemoveTaskObserver(TaskObserver* task_observer);
// When we go into high resolution timer mode, we will stay in hi-res mode
// for at least 1s.
static const int kHighResolutionTimerModeLeaseTimeMs = 1000;
#if defined(OS_WIN) #if defined(OS_WIN)
void set_os_modal_loop(bool os_modal_loop) { void set_os_modal_loop(bool os_modal_loop) {
os_modal_loop_ = os_modal_loop; os_modal_loop_ = os_modal_loop;
...@@ -386,7 +390,7 @@ class BASE_EXPORT MessageLoop : public MessagePump::Delegate { ...@@ -386,7 +390,7 @@ class BASE_EXPORT MessageLoop : public MessagePump::Delegate {
// Returns true if the message loop has high resolution timers enabled. // Returns true if the message loop has high resolution timers enabled.
// Provided for testing. // Provided for testing.
bool HasHighResolutionTasks(); bool IsHighResolutionTimerEnabledForTesting();
// Returns true if the message loop is "idle". Provided for testing. // Returns true if the message loop is "idle". Provided for testing.
bool IsIdleForTesting(); bool IsIdleForTesting();
...@@ -456,14 +460,6 @@ class BASE_EXPORT MessageLoop : public MessagePump::Delegate { ...@@ -456,14 +460,6 @@ class BASE_EXPORT MessageLoop : public MessagePump::Delegate {
// this queue is only accessed (push/pop) by our current thread. // this queue is only accessed (push/pop) by our current thread.
TaskQueue work_queue_; TaskQueue work_queue_;
// How many high resolution tasks are in the pending task queue. This value
// increases by N every time we call ReloadWorkQueue() and decreases by 1
// every time we call RunTask() if the task needs a high resolution timer.
int pending_high_res_tasks_;
// Tracks if we have requested high resolution timers. Its only use is to
// turn off the high resolution timer upon loop destruction.
bool in_high_res_mode_;
// Contains delayed tasks, sorted by their 'delayed_run_time' property. // Contains delayed tasks, sorted by their 'delayed_run_time' property.
DelayedTaskQueue delayed_work_queue_; DelayedTaskQueue delayed_work_queue_;
......
...@@ -730,20 +730,30 @@ TEST(MessageLoopTest, HighResolutionTimer) { ...@@ -730,20 +730,30 @@ TEST(MessageLoopTest, HighResolutionTimer) {
const TimeDelta kFastTimer = TimeDelta::FromMilliseconds(5); const TimeDelta kFastTimer = TimeDelta::FromMilliseconds(5);
const TimeDelta kSlowTimer = TimeDelta::FromMilliseconds(100); const TimeDelta kSlowTimer = TimeDelta::FromMilliseconds(100);
EXPECT_FALSE(loop.HasHighResolutionTasks()); EXPECT_FALSE(loop.IsHighResolutionTimerEnabledForTesting());
// Post a fast task to enable the high resolution timers. // Post a fast task to enable the high resolution timers.
loop.PostDelayedTask(FROM_HERE, Bind(&PostNTasksThenQuit, 1), loop.PostDelayedTask(FROM_HERE, Bind(&PostNTasksThenQuit, 1),
kFastTimer); kFastTimer);
EXPECT_TRUE(loop.HasHighResolutionTasks());
loop.Run(); loop.Run();
EXPECT_FALSE(loop.HasHighResolutionTasks()); EXPECT_TRUE(loop.IsHighResolutionTimerEnabledForTesting());
EXPECT_FALSE(Time::IsHighResolutionTimerInUse());
// Check that a slow task does not trigger the high resolution logic. // Post a slow task and verify high resolution timers
// are still enabled.
loop.PostDelayedTask(FROM_HERE, Bind(&PostNTasksThenQuit, 1),
kSlowTimer);
loop.Run();
EXPECT_TRUE(loop.IsHighResolutionTimerEnabledForTesting());
// Wait for a while so that high-resolution mode elapses.
PlatformThread::Sleep(TimeDelta::FromMilliseconds(
MessageLoop::kHighResolutionTimerModeLeaseTimeMs));
// Post a slow task to disable the high resolution timers.
loop.PostDelayedTask(FROM_HERE, Bind(&PostNTasksThenQuit, 1), loop.PostDelayedTask(FROM_HERE, Bind(&PostNTasksThenQuit, 1),
kSlowTimer); kSlowTimer);
EXPECT_FALSE(loop.HasHighResolutionTasks());
loop.Run(); loop.Run();
EXPECT_FALSE(loop.HasHighResolutionTasks()); EXPECT_FALSE(loop.IsHighResolutionTimerEnabledForTesting());
} }
#endif // defined(OS_WIN) #endif // defined(OS_WIN)
......
...@@ -39,8 +39,7 @@ class BASE_EXPORT MessagePump : public NonThreadSafe { ...@@ -39,8 +39,7 @@ class BASE_EXPORT MessagePump : public NonThreadSafe {
virtual bool DoDelayedWork(TimeTicks* next_delayed_work_time) = 0; virtual bool DoDelayedWork(TimeTicks* next_delayed_work_time) = 0;
// Called from within Run just before the message pump goes to sleep. // Called from within Run just before the message pump goes to sleep.
// Returns true to indicate that idle work was done. Returning false means // Returns true to indicate that idle work was done.
// the pump will now wait.
virtual bool DoIdleWork() = 0; virtual bool DoIdleWork() = 0;
}; };
......
...@@ -8,14 +8,19 @@ ...@@ -8,14 +8,19 @@
namespace base { namespace base {
#if _MSC_VER >= 1700
// This a temporary fix for compiling on VS2012. http://crbug.com/154744
PendingTask::PendingTask() : sequence_num(-1), nestable(false) {
}
#endif
PendingTask::PendingTask(const tracked_objects::Location& posted_from, PendingTask::PendingTask(const tracked_objects::Location& posted_from,
const base::Closure& task) const base::Closure& task)
: base::TrackingInfo(posted_from, TimeTicks()), : base::TrackingInfo(posted_from, TimeTicks()),
task(task), task(task),
posted_from(posted_from), posted_from(posted_from),
sequence_num(0), sequence_num(0),
nestable(true), nestable(true) {
is_high_res(false) {
} }
PendingTask::PendingTask(const tracked_objects::Location& posted_from, PendingTask::PendingTask(const tracked_objects::Location& posted_from,
...@@ -26,8 +31,7 @@ PendingTask::PendingTask(const tracked_objects::Location& posted_from, ...@@ -26,8 +31,7 @@ PendingTask::PendingTask(const tracked_objects::Location& posted_from,
task(task), task(task),
posted_from(posted_from), posted_from(posted_from),
sequence_num(0), sequence_num(0),
nestable(nestable), nestable(nestable) {
is_high_res(false) {
} }
PendingTask::~PendingTask() { PendingTask::~PendingTask() {
......
...@@ -18,6 +18,9 @@ namespace base { ...@@ -18,6 +18,9 @@ namespace base {
// Contains data about a pending task. Stored in TaskQueue and DelayedTaskQueue // Contains data about a pending task. Stored in TaskQueue and DelayedTaskQueue
// for use by classes that queue and execute tasks. // for use by classes that queue and execute tasks.
struct BASE_EXPORT PendingTask : public TrackingInfo { struct BASE_EXPORT PendingTask : public TrackingInfo {
#if _MSC_VER >= 1700
PendingTask();
#endif
PendingTask(const tracked_objects::Location& posted_from, PendingTask(const tracked_objects::Location& posted_from,
const Closure& task); const Closure& task);
PendingTask(const tracked_objects::Location& posted_from, PendingTask(const tracked_objects::Location& posted_from,
...@@ -40,9 +43,6 @@ struct BASE_EXPORT PendingTask : public TrackingInfo { ...@@ -40,9 +43,6 @@ struct BASE_EXPORT PendingTask : public TrackingInfo {
// OK to dispatch from a nested loop. // OK to dispatch from a nested loop.
bool nestable; bool nestable;
// Needs high resolution timers.
bool is_high_res;
}; };
// Wrapper around std::queue specialized for PendingTask which adds a Swap // Wrapper around std::queue specialized for PendingTask which adds a Swap
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment