Commit 606087eb authored by Alex Clarke's avatar Alex Clarke Committed by Commit Bot

SequenceManager to perform periodic housekeeping (sweep canceled tasks)

Long delay canceled tasks can really pile up if we don't activly remove
them. We already do that in the renderer but we need to bring this
technology to other SequenceMangers.

Bug: 863341
Change-Id: Ie16674043028090f94c184c02acbef6efcf3471b
Reviewed-on: https://chromium-review.googlesource.com/c/1483076
Commit-Queue: Alex Clarke <alexclarke@chromium.org>
Reviewed-by: default avatarSami Kyöstilä <skyostil@chromium.org>
Reviewed-by: default avatarAlexander Timin <altimin@chromium.org>
Reviewed-by: default avatarAlex Clarke <alexclarke@chromium.org>
Cr-Commit-Position: refs/heads/master@{#635497}
parent 1b99d751
...@@ -28,6 +28,8 @@ class BASE_EXPORT LazyNow { ...@@ -28,6 +28,8 @@ class BASE_EXPORT LazyNow {
// Result will not be updated on any subsesequent calls. // Result will not be updated on any subsesequent calls.
TimeTicks Now(); TimeTicks Now();
bool has_value() const { return !!now_; }
private: private:
const TickClock* tick_clock_; // Not owned. const TickClock* tick_clock_; // Not owned.
Optional<TimeTicks> now_; Optional<TimeTicks> now_;
......
...@@ -62,8 +62,8 @@ namespace internal { ...@@ -62,8 +62,8 @@ namespace internal {
namespace { namespace {
constexpr base::TimeDelta kLongTaskTraceEventThreshold = constexpr TimeDelta kLongTaskTraceEventThreshold =
base::TimeDelta::FromMilliseconds(50); TimeDelta::FromMilliseconds(50);
// Proportion of tasks which will record thread time for metrics. // Proportion of tasks which will record thread time for metrics.
const double kTaskSamplingRateForRecordingCPUTime = 0.01; const double kTaskSamplingRateForRecordingCPUTime = 0.01;
// Proprortion of SequenceManagers which will record thread time for each task, // Proprortion of SequenceManagers which will record thread time for each task,
...@@ -80,6 +80,8 @@ void ReclaimMemoryFromQueue(internal::TaskQueueImpl* queue, ...@@ -80,6 +80,8 @@ void ReclaimMemoryFromQueue(internal::TaskQueueImpl* queue,
if (time_domain_now->find(time_domain) == time_domain_now->end()) if (time_domain_now->find(time_domain) == time_domain_now->end())
time_domain_now->insert(std::make_pair(time_domain, time_domain->Now())); time_domain_now->insert(std::make_pair(time_domain, time_domain->Now()));
queue->ReclaimMemory(time_domain_now->at(time_domain)); queue->ReclaimMemory(time_domain_now->at(time_domain));
queue->delayed_work_queue()->RemoveAllCanceledTasksFromFront();
queue->immediate_work_queue()->RemoveAllCanceledTasksFromFront();
} }
SequenceManager::MetricRecordingSettings InitializeMetricRecordingSettings( SequenceManager::MetricRecordingSettings InitializeMetricRecordingSettings(
...@@ -112,6 +114,9 @@ SequenceManagerImpl::SequenceManagerImpl( ...@@ -112,6 +114,9 @@ SequenceManagerImpl::SequenceManagerImpl(
TRACE_DISABLED_BY_DEFAULT("sequence_manager"), "SequenceManager", this); TRACE_DISABLED_BY_DEFAULT("sequence_manager"), "SequenceManager", this);
main_thread_only().selector.SetTaskQueueSelectorObserver(this); main_thread_only().selector.SetTaskQueueSelectorObserver(this);
main_thread_only().next_time_to_reclaim_memory =
settings.clock->NowTicks() + kReclaimMemoryInterval;
RegisterTimeDomain(main_thread_only().real_time_domain.get()); RegisterTimeDomain(main_thread_only().real_time_domain.get());
controller_->SetSequencedTaskSource(this); controller_->SetSequencedTaskSource(this);
...@@ -385,6 +390,13 @@ Optional<PendingTask> SequenceManagerImpl::TakeTaskImpl() { ...@@ -385,6 +390,13 @@ Optional<PendingTask> SequenceManagerImpl::TakeTaskImpl() {
LazyNow lazy_now(controller_->GetClock()); LazyNow lazy_now(controller_->GetClock());
WakeUpReadyDelayedQueues(&lazy_now); WakeUpReadyDelayedQueues(&lazy_now);
// If we sampled now, check if it's time to reclaim memory next time we go
// idle.
if (lazy_now.has_value() &&
lazy_now.Now() >= main_thread_only().next_time_to_reclaim_memory) {
main_thread_only().memory_reclaim_scheduled = true;
}
while (true) { while (true) {
internal::WorkQueue* work_queue = internal::WorkQueue* work_queue =
main_thread_only().selector.SelectWorkQueueToService(); main_thread_only().selector.SelectWorkQueueToService();
...@@ -486,6 +498,8 @@ bool SequenceManagerImpl::OnSystemIdle() { ...@@ -486,6 +498,8 @@ bool SequenceManagerImpl::OnSystemIdle() {
have_work_to_do = true; have_work_to_do = true;
} }
} }
if (!have_work_to_do)
MaybeReclaimMemory();
return have_work_to_do; return have_work_to_do;
} }
...@@ -708,6 +722,19 @@ void SequenceManagerImpl::OnTaskQueueEnabled(internal::TaskQueueImpl* queue) { ...@@ -708,6 +722,19 @@ void SequenceManagerImpl::OnTaskQueueEnabled(internal::TaskQueueImpl* queue) {
ScheduleWork(); ScheduleWork();
} }
void SequenceManagerImpl::MaybeReclaimMemory() {
if (!main_thread_only().memory_reclaim_scheduled)
return;
TRACE_EVENT0("sequence_manager", "SequenceManagerImpl::MaybeReclaimMemory");
ReclaimMemory();
// To avoid performance regressions we only want to do this every so often.
main_thread_only().next_time_to_reclaim_memory =
NowTicks() + kReclaimMemoryInterval;
main_thread_only().memory_reclaim_scheduled = false;
}
void SequenceManagerImpl::ReclaimMemory() { void SequenceManagerImpl::ReclaimMemory() {
std::map<TimeDomain*, TimeTicks> time_domain_now; std::map<TimeDomain*, TimeTicks> time_domain_now;
for (auto* const queue : main_thread_only().active_queues) for (auto* const queue : main_thread_only().active_queues)
...@@ -906,6 +933,8 @@ internal::TaskQueueImpl* SequenceManagerImpl::currently_executing_task_queue() ...@@ -906,6 +933,8 @@ internal::TaskQueueImpl* SequenceManagerImpl::currently_executing_task_queue()
return main_thread_only().task_execution_stack.rbegin()->task_queue; return main_thread_only().task_execution_stack.rbegin()->task_queue;
} }
constexpr TimeDelta SequenceManagerImpl::kReclaimMemoryInterval;
} // namespace internal } // namespace internal
} // namespace sequence_manager } // namespace sequence_manager
} // namespace base } // namespace base
...@@ -188,6 +188,10 @@ class BASE_EXPORT SequenceManagerImpl ...@@ -188,6 +188,10 @@ class BASE_EXPORT SequenceManagerImpl
WeakPtr<SequenceManagerImpl> GetWeakPtr(); WeakPtr<SequenceManagerImpl> GetWeakPtr();
// How frequently to perform housekeeping tasks (sweeping canceled tasks etc).
static constexpr TimeDelta kReclaimMemoryInterval =
TimeDelta::FromSeconds(30);
protected: protected:
// Create a task queue manager where |controller| controls the thread // Create a task queue manager where |controller| controls the thread
// on which the tasks are eventually run. // on which the tasks are eventually run.
...@@ -251,6 +255,12 @@ class BASE_EXPORT SequenceManagerImpl ...@@ -251,6 +255,12 @@ class BASE_EXPORT SequenceManagerImpl
std::set<TimeDomain*> time_domains; std::set<TimeDomain*> time_domains;
std::unique_ptr<internal::RealTimeDomain> real_time_domain; std::unique_ptr<internal::RealTimeDomain> real_time_domain;
// If true MaybeReclaimMemory will attempt to reclaim memory.
bool memory_reclaim_scheduled = false;
// Used to ensure we don't perform expensive housekeeping too frequently.
TimeTicks next_time_to_reclaim_memory;
// List of task queues managed by this SequenceManager. // List of task queues managed by this SequenceManager.
// - active_queues contains queues that are still running tasks. // - active_queues contains queues that are still running tasks.
// Most often they are owned by relevant TaskQueues, but // Most often they are owned by relevant TaskQueues, but
...@@ -319,6 +329,10 @@ class BASE_EXPORT SequenceManagerImpl ...@@ -319,6 +329,10 @@ class BASE_EXPORT SequenceManagerImpl
std::unique_ptr<internal::TaskQueueImpl> CreateTaskQueueImpl( std::unique_ptr<internal::TaskQueueImpl> CreateTaskQueueImpl(
const TaskQueue::Spec& spec) override; const TaskQueue::Spec& spec) override;
// Periodically reclaims memory by sweeping away canceled tasks and shrinking
// buffers.
void MaybeReclaimMemory();
// Deletes queues marked for deletion and empty queues marked for shutdown. // Deletes queues marked for deletion and empty queues marked for shutdown.
void CleanUpQueues(); void CleanUpQueues();
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include "base/auto_reset.h" #include "base/auto_reset.h"
#include "base/bind.h" #include "base/bind.h"
#include "base/callback.h" #include "base/callback.h"
#include "base/callback_helpers.h"
#include "base/location.h" #include "base/location.h"
#include "base/memory/ref_counted_memory.h" #include "base/memory/ref_counted_memory.h"
#include "base/message_loop/message_loop.h" #include "base/message_loop/message_loop.h"
...@@ -128,6 +129,8 @@ class CallCountingTickClock : public TickClock { ...@@ -128,6 +129,8 @@ class CallCountingTickClock : public TickClock {
return now_callback_.Run(); return now_callback_.Run();
} }
void Reset() { now_call_count_.store(0); }
int now_call_count() const { return now_call_count_; } int now_call_count() const { return now_call_count_; }
private: private:
...@@ -146,9 +149,15 @@ class FixtureWithMockTaskRunner final : public Fixture { ...@@ -146,9 +149,15 @@ class FixtureWithMockTaskRunner final : public Fixture {
nullptr, nullptr,
ThreadTaskRunnerHandle::Get(), ThreadTaskRunnerHandle::Get(),
mock_tick_clock(), mock_tick_clock(),
SequenceManager::Settings{.randomised_sampling_enabled = false})) { SequenceManager::Settings{.randomised_sampling_enabled = false,
.clock = mock_tick_clock()})) {
// A null clock triggers some assertions. // A null clock triggers some assertions.
AdvanceMockTickClock(TimeDelta::FromMilliseconds(1)); AdvanceMockTickClock(TimeDelta::FromMilliseconds(1));
// The SequenceManager constructor calls Now() once for setting up
// housekeeping.
EXPECT_EQ(1, GetNowTicksCallCount());
call_counting_clock_.Reset();
} }
void AdvanceMockTickClock(TimeDelta delta) override { void AdvanceMockTickClock(TimeDelta delta) override {
...@@ -211,8 +220,14 @@ class FixtureWithMockMessagePump : public Fixture { ...@@ -211,8 +220,14 @@ class FixtureWithMockMessagePump : public Fixture {
sequence_manager_ = SequenceManagerForTest::Create( sequence_manager_ = SequenceManagerForTest::Create(
std::make_unique<ThreadControllerWithMessagePumpImpl>( std::make_unique<ThreadControllerWithMessagePumpImpl>(
std::move(pump), mock_tick_clock()), std::move(pump), mock_tick_clock()),
SequenceManager::Settings{.randomised_sampling_enabled = false}); SequenceManager::Settings{.randomised_sampling_enabled = false,
.clock = mock_tick_clock()});
sequence_manager_->SetDefaultTaskRunner(MakeRefCounted<NullTaskRunner>()); sequence_manager_->SetDefaultTaskRunner(MakeRefCounted<NullTaskRunner>());
// The SequenceManager constructor calls Now() once for setting up
// housekeeping.
EXPECT_EQ(1, GetNowTicksCallCount());
call_counting_clock_.Reset();
} }
void AdvanceMockTickClock(TimeDelta delta) override { void AdvanceMockTickClock(TimeDelta delta) override {
...@@ -287,7 +302,14 @@ class FixtureWithMessageLoop : public Fixture { ...@@ -287,7 +302,14 @@ class FixtureWithMessageLoop : public Fixture {
sequence_manager_ = SequenceManagerForTest::Create( sequence_manager_ = SequenceManagerForTest::Create(
message_loop_->GetMessageLoopBase(), ThreadTaskRunnerHandle::Get(), message_loop_->GetMessageLoopBase(), ThreadTaskRunnerHandle::Get(),
mock_tick_clock(), mock_tick_clock(),
SequenceManager::Settings{.randomised_sampling_enabled = false}); SequenceManager::Settings{.randomised_sampling_enabled = false,
.clock = mock_tick_clock()});
// The SequenceManager constructor calls Now() once for setting up
// housekeeping. The MessageLoop also contains a SequenceManager so two
// calls are expected.
EXPECT_EQ(2, GetNowTicksCallCount());
call_counting_clock_.Reset();
} }
void AdvanceMockTickClock(TimeDelta delta) override { void AdvanceMockTickClock(TimeDelta delta) override {
...@@ -4471,6 +4493,77 @@ TEST_P(SequenceManagerTest, TaskPriortyInterleaving) { ...@@ -4471,6 +4493,77 @@ TEST_P(SequenceManagerTest, TaskPriortyInterleaving) {
"555555555555555555555555555555555555555555555555555555555555"); "555555555555555555555555555555555555555555555555555555555555");
} }
class CancelableTaskWithDestructionObserver {
public:
CancelableTaskWithDestructionObserver() : weak_factory_(this) {}
void Task(std::unique_ptr<ScopedClosureRunner> destruction_observer) {
destruction_observer_ = std::move(destruction_observer);
}
std::unique_ptr<ScopedClosureRunner> destruction_observer_;
WeakPtrFactory<CancelableTaskWithDestructionObserver> weak_factory_;
};
TEST_P(SequenceManagerTest, PeriodicHousekeeping) {
auto queue = CreateTaskQueue();
// Post a task that will trigger housekeeping.
queue->task_runner()->PostDelayedTask(
FROM_HERE, BindOnce(&NopTask),
SequenceManagerImpl::kReclaimMemoryInterval);
// Posts some tasks set to run long in the future and then cancel some of
// them.
bool task1_deleted = false;
bool task2_deleted = false;
bool task3_deleted = false;
CancelableTaskWithDestructionObserver task1;
CancelableTaskWithDestructionObserver task2;
CancelableTaskWithDestructionObserver task3;
queue->task_runner()->PostDelayedTask(
FROM_HERE,
BindOnce(&CancelableTaskWithDestructionObserver::Task,
task1.weak_factory_.GetWeakPtr(),
std::make_unique<ScopedClosureRunner>(
BindLambdaForTesting([&]() { task1_deleted = true; }))),
TimeDelta::FromHours(1));
queue->task_runner()->PostDelayedTask(
FROM_HERE,
BindOnce(&CancelableTaskWithDestructionObserver::Task,
task2.weak_factory_.GetWeakPtr(),
std::make_unique<ScopedClosureRunner>(
BindLambdaForTesting([&]() { task2_deleted = true; }))),
TimeDelta::FromHours(2));
queue->task_runner()->PostDelayedTask(
FROM_HERE,
BindOnce(&CancelableTaskWithDestructionObserver::Task,
task3.weak_factory_.GetWeakPtr(),
std::make_unique<ScopedClosureRunner>(
BindLambdaForTesting([&]() { task3_deleted = true; }))),
TimeDelta::FromHours(3));
task2.weak_factory_.InvalidateWeakPtrs();
task3.weak_factory_.InvalidateWeakPtrs();
EXPECT_FALSE(task1_deleted);
EXPECT_FALSE(task2_deleted);
EXPECT_FALSE(task3_deleted);
// This should trigger housekeeping which will sweep away the canceled tasks.
FastForwardBy(SequenceManagerImpl::kReclaimMemoryInterval);
EXPECT_FALSE(task1_deleted);
EXPECT_TRUE(task2_deleted);
EXPECT_TRUE(task3_deleted);
// Tidy up.
FastForwardUntilNoTasksRemain();
}
} // namespace sequence_manager_impl_unittest } // namespace sequence_manager_impl_unittest
} // namespace internal } // namespace internal
} // namespace sequence_manager } // namespace sequence_manager
......
...@@ -160,5 +160,9 @@ bool TimeDomain::HasPendingHighResolutionTasks() const { ...@@ -160,5 +160,9 @@ bool TimeDomain::HasPendingHighResolutionTasks() const {
return pending_high_res_wake_up_count_; return pending_high_res_wake_up_count_;
} }
bool TimeDomain::Empty() const {
return delayed_wake_up_queue_.empty();
}
} // namespace sequence_manager } // namespace sequence_manager
} // namespace base } // namespace base
...@@ -59,6 +59,9 @@ class BASE_EXPORT TimeDomain { ...@@ -59,6 +59,9 @@ class BASE_EXPORT TimeDomain {
void AsValueInto(trace_event::TracedValue* state) const; void AsValueInto(trace_event::TracedValue* state) const;
bool HasPendingHighResolutionTasks() const; bool HasPendingHighResolutionTasks() const;
// Returns true if there are no pending delayed tasks.
bool Empty() const;
// This is the signal that virtual time should step forward. If // This is the signal that virtual time should step forward. If
// RunLoop::QuitWhenIdle has been called then |quit_when_idle_requested| will // RunLoop::QuitWhenIdle has been called then |quit_when_idle_requested| will
// be true. Returns true if time advanced and there is now a task to run. // be true. Returns true if time advanced and there is now a task to run.
......
...@@ -99,12 +99,14 @@ class TimeDomainTest : public testing::Test { ...@@ -99,12 +99,14 @@ class TimeDomainTest : public testing::Test {
TEST_F(TimeDomainTest, ScheduleWakeUpForQueue) { TEST_F(TimeDomainTest, ScheduleWakeUpForQueue) {
TimeDelta delay = TimeDelta::FromMilliseconds(10); TimeDelta delay = TimeDelta::FromMilliseconds(10);
TimeTicks delayed_runtime = time_domain_->Now() + delay; TimeTicks delayed_runtime = time_domain_->Now() + delay;
EXPECT_TRUE(time_domain_->Empty());
EXPECT_CALL(*time_domain_.get(), SetNextDelayedDoWork(_, delayed_runtime)); EXPECT_CALL(*time_domain_.get(), SetNextDelayedDoWork(_, delayed_runtime));
TimeTicks now = time_domain_->Now(); TimeTicks now = time_domain_->Now();
LazyNow lazy_now(now); LazyNow lazy_now(now);
task_queue_->SetDelayedWakeUpForTesting( task_queue_->SetDelayedWakeUpForTesting(
internal::DelayedWakeUp{now + delay, 0}); internal::DelayedWakeUp{now + delay, 0});
EXPECT_FALSE(time_domain_->Empty());
EXPECT_EQ(delayed_runtime, time_domain_->NextScheduledRunTime()); EXPECT_EQ(delayed_runtime, time_domain_->NextScheduledRunTime());
EXPECT_EQ(task_queue_.get(), time_domain_->NextScheduledTaskQueue()); EXPECT_EQ(task_queue_.get(), time_domain_->NextScheduledTaskQueue());
...@@ -195,6 +197,7 @@ TEST_F(TimeDomainTest, UnregisterQueue) { ...@@ -195,6 +197,7 @@ TEST_F(TimeDomainTest, UnregisterQueue) {
std::unique_ptr<TaskQueueImplForTest> task_queue2 = std::unique_ptr<TaskQueueImplForTest> task_queue2 =
std::make_unique<TaskQueueImplForTest>(nullptr, time_domain_.get(), std::make_unique<TaskQueueImplForTest>(nullptr, time_domain_.get(),
TaskQueue::Spec("test")); TaskQueue::Spec("test"));
EXPECT_TRUE(time_domain_->Empty());
TimeTicks now = time_domain_->Now(); TimeTicks now = time_domain_->Now();
LazyNow lazy_now(now); LazyNow lazy_now(now);
...@@ -203,6 +206,7 @@ TEST_F(TimeDomainTest, UnregisterQueue) { ...@@ -203,6 +206,7 @@ TEST_F(TimeDomainTest, UnregisterQueue) {
task_queue_->SetDelayedWakeUpForTesting(internal::DelayedWakeUp{wake_up1, 0}); task_queue_->SetDelayedWakeUpForTesting(internal::DelayedWakeUp{wake_up1, 0});
TimeTicks wake_up2 = now + TimeDelta::FromMilliseconds(100); TimeTicks wake_up2 = now + TimeDelta::FromMilliseconds(100);
task_queue2->SetDelayedWakeUpForTesting(internal::DelayedWakeUp{wake_up2, 0}); task_queue2->SetDelayedWakeUpForTesting(internal::DelayedWakeUp{wake_up2, 0});
EXPECT_FALSE(time_domain_->Empty());
EXPECT_EQ(task_queue_.get(), time_domain_->NextScheduledTaskQueue()); EXPECT_EQ(task_queue_.get(), time_domain_->NextScheduledTaskQueue());
...@@ -216,6 +220,7 @@ TEST_F(TimeDomainTest, UnregisterQueue) { ...@@ -216,6 +220,7 @@ TEST_F(TimeDomainTest, UnregisterQueue) {
task_queue_->UnregisterTaskQueue(); task_queue_->UnregisterTaskQueue();
task_queue_ = nullptr; task_queue_ = nullptr;
EXPECT_FALSE(time_domain_->Empty());
testing::Mock::VerifyAndClearExpectations(time_domain_.get()); testing::Mock::VerifyAndClearExpectations(time_domain_.get());
EXPECT_CALL(*time_domain_.get(), SetNextDelayedDoWork(_, TimeTicks::Max())) EXPECT_CALL(*time_domain_.get(), SetNextDelayedDoWork(_, TimeTicks::Max()))
...@@ -226,6 +231,7 @@ TEST_F(TimeDomainTest, UnregisterQueue) { ...@@ -226,6 +231,7 @@ TEST_F(TimeDomainTest, UnregisterQueue) {
task_queue2->UnregisterTaskQueue(); task_queue2->UnregisterTaskQueue();
task_queue2 = nullptr; task_queue2 = nullptr;
EXPECT_TRUE(time_domain_->Empty());
} }
TEST_F(TimeDomainTest, WakeUpReadyDelayedQueues) { TEST_F(TimeDomainTest, WakeUpReadyDelayedQueues) {
......
...@@ -154,7 +154,8 @@ Task WorkQueue::TakeTaskFromWorkQueue() { ...@@ -154,7 +154,8 @@ Task WorkQueue::TakeTaskFromWorkQueue() {
} }
bool WorkQueue::RemoveAllCanceledTasksFromFront() { bool WorkQueue::RemoveAllCanceledTasksFromFront() {
DCHECK(work_queue_sets_); if (!work_queue_sets_)
return false;
bool task_removed = false; bool task_removed = false;
while (!tasks_.empty() && while (!tasks_.empty() &&
(!tasks_.front().task || tasks_.front().task.IsCancelled())) { (!tasks_.front().task || tasks_.front().task.IsCancelled())) {
......
...@@ -17,8 +17,6 @@ blink_platform_sources("scheduler") { ...@@ -17,8 +17,6 @@ blink_platform_sources("scheduler") {
"common/frame_or_worker_scheduler.cc", "common/frame_or_worker_scheduler.cc",
"common/idle_helper.cc", "common/idle_helper.cc",
"common/idle_helper.h", "common/idle_helper.h",
"common/idle_memory_reclaimer.cc",
"common/idle_memory_reclaimer.h",
"common/metrics_helper.cc", "common/metrics_helper.cc",
"common/metrics_helper.h", "common/metrics_helper.h",
"common/pollable_thread_safe_flag.cc", "common/pollable_thread_safe_flag.cc",
...@@ -185,7 +183,6 @@ jumbo_source_set("unit_tests") { ...@@ -185,7 +183,6 @@ jumbo_source_set("unit_tests") {
sources = [ sources = [
"common/cooperative_scheduling_manager_unittest.cc", "common/cooperative_scheduling_manager_unittest.cc",
"common/idle_helper_unittest.cc", "common/idle_helper_unittest.cc",
"common/idle_memory_reclaimer_unittest.cc",
"common/metrics_helper_unittest.cc", "common/metrics_helper_unittest.cc",
"common/post_cancellable_task_unittest.cc", "common/post_cancellable_task_unittest.cc",
"common/scheduler_helper_unittest.cc", "common/scheduler_helper_unittest.cc",
......
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "third_party/blink/renderer/platform/scheduler/common/idle_memory_reclaimer.h"
#include "base/bind.h"
namespace blink {
namespace scheduler {
namespace {
constexpr const int kReclaimMemoryIntervalSeconds = 30;
}
IdleMemoryReclaimer::IdleMemoryReclaimer(
SchedulerHelper* scheduler_helper,
scoped_refptr<SingleThreadIdleTaskRunner> idle_task_runner)
: scheduler_helper_(scheduler_helper),
idle_task_runner_(idle_task_runner),
weak_factory_(this) {
PostIdleTask();
}
void IdleMemoryReclaimer::PostIdleTask() {
idle_task_runner_->PostDelayedIdleTask(
FROM_HERE, base::TimeDelta::FromSeconds(kReclaimMemoryIntervalSeconds),
base::BindOnce(&IdleMemoryReclaimer::IdleTask,
weak_factory_.GetWeakPtr()));
}
void IdleMemoryReclaimer::IdleTask(base::TimeTicks deadline) {
TRACE_EVENT0("renderer.scheduler", "IdleMemoryReclaimer::IdleTask");
scheduler_helper_->ReclaimMemory();
PostIdleTask();
}
} // namespace scheduler
} // namespace blink
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_COMMON_IDLE_MEMORY_RECLAIMER_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_COMMON_IDLE_MEMORY_RECLAIMER_H_
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "third_party/blink/renderer/platform/scheduler/common/scheduler_helper.h"
#include "third_party/blink/renderer/platform/scheduler/common/single_thread_idle_task_runner.h"
namespace blink {
namespace scheduler {
// This class periodically sweeps away canceled delayed tasks and considers
// resizing to fit all internal queues, which helps reduce memory consumption.
class PLATFORM_EXPORT IdleMemoryReclaimer {
public:
IdleMemoryReclaimer(
SchedulerHelper* scheduler_helper,
scoped_refptr<SingleThreadIdleTaskRunner> idle_task_runner);
private:
void PostIdleTask();
void IdleTask(base::TimeTicks deadline);
SchedulerHelper* scheduler_helper_; // NOT OWNED
scoped_refptr<SingleThreadIdleTaskRunner> idle_task_runner_;
base::WeakPtrFactory<IdleMemoryReclaimer> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(IdleMemoryReclaimer);
};
} // namespace scheduler
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_COMMON_IDLE_MEMORY_RECLAIMER_H_
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "third_party/blink/renderer/platform/scheduler/common/idle_memory_reclaimer.h"
#include "base/bind.h"
#include "base/task/sequence_manager/lazy_now.h"
#include "base/task/sequence_manager/task_queue.h"
#include "base/task/sequence_manager/test/sequence_manager_for_test.h"
#include "base/test/scoped_task_environment.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/renderer/platform/scheduler/common/idle_helper.h"
#include "third_party/blink/renderer/platform/scheduler/common/scheduler_helper.h"
#include "third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_helper.h"
namespace blink {
namespace scheduler {
class TestClass {
public:
TestClass() : weak_factory_(this) {}
void NopTask() {}
base::WeakPtrFactory<TestClass> weak_factory_;
};
class IdleMemoryReclaimerTest : public testing::Test,
public IdleHelper::Delegate {
public:
IdleMemoryReclaimerTest()
: task_environment_(
base::test::ScopedTaskEnvironment::MainThreadType::MOCK_TIME,
base::test::ScopedTaskEnvironment::ExecutionMode::QUEUED),
scheduler_helper_(new MainThreadSchedulerHelper(
base::sequence_manager::SequenceManagerForTest::Create(
nullptr,
task_environment_.GetMainThreadTaskRunner(),
task_environment_.GetMockTickClock()),
nullptr)),
idle_helper_(
new IdleHelper(scheduler_helper_.get(),
this,
"test",
base::TimeDelta::FromSeconds(30),
scheduler_helper_->NewTaskQueue(
MainThreadTaskQueue::QueueCreationParams(
MainThreadTaskQueue::QueueType::kTest)))),
idle_canceled_delayed_taks_sweeper_(
new IdleMemoryReclaimer(scheduler_helper_.get(),
idle_helper_->IdleTaskRunner())),
default_task_queue_(scheduler_helper_->DefaultMainThreadTaskQueue()) {
// Null clock might trigger some assertions.
task_environment_.FastForwardBy(base::TimeDelta::FromMilliseconds(5));
}
~IdleMemoryReclaimerTest() override = default;
void TearDown() override {
// Check that all tests stop posting tasks.
task_environment_.FastForwardUntilNoTasksRemain();
}
// IdleHelper::Delegate implementation:
bool CanEnterLongIdlePeriod(
base::TimeTicks now,
base::TimeDelta* next_long_idle_period_delay_out) override {
return true;
}
void IsNotQuiescent() override {}
void OnIdlePeriodStarted() override {}
void OnIdlePeriodEnded() override {}
void OnPendingTasksChanged(bool has_tasks) override {}
protected:
base::test::ScopedTaskEnvironment task_environment_;
std::unique_ptr<MainThreadSchedulerHelper> scheduler_helper_;
std::unique_ptr<IdleHelper> idle_helper_;
std::unique_ptr<IdleMemoryReclaimer> idle_canceled_delayed_taks_sweeper_;
scoped_refptr<base::sequence_manager::TaskQueue> default_task_queue_;
DISALLOW_COPY_AND_ASSIGN(IdleMemoryReclaimerTest);
};
TEST_F(IdleMemoryReclaimerTest, TestSweep) {
TestClass class1;
TestClass class2;
// Post one task we won't cancel.
default_task_queue_->task_runner()->PostDelayedTask(
FROM_HERE,
base::BindOnce(&TestClass::NopTask, class1.weak_factory_.GetWeakPtr()),
base::TimeDelta::FromSeconds(100));
// And a bunch we will.
default_task_queue_->task_runner()->PostDelayedTask(
FROM_HERE,
base::BindOnce(&TestClass::NopTask, class2.weak_factory_.GetWeakPtr()),
base::TimeDelta::FromSeconds(101));
default_task_queue_->task_runner()->PostDelayedTask(
FROM_HERE,
base::BindOnce(&TestClass::NopTask, class2.weak_factory_.GetWeakPtr()),
base::TimeDelta::FromSeconds(102));
default_task_queue_->task_runner()->PostDelayedTask(
FROM_HERE,
base::BindOnce(&TestClass::NopTask, class2.weak_factory_.GetWeakPtr()),
base::TimeDelta::FromSeconds(103));
default_task_queue_->task_runner()->PostDelayedTask(
FROM_HERE,
base::BindOnce(&TestClass::NopTask, class2.weak_factory_.GetWeakPtr()),
base::TimeDelta::FromSeconds(104));
// Cancel the last four tasks.
class2.weak_factory_.InvalidateWeakPtrs();
// Give the IdleMemoryReclaimer a chance to run but don't let
// the first non canceled delayed task run. This is important because the
// canceled tasks would get removed by TaskQueueImpl::WakeUpForDelayedWork.
task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(40));
idle_helper_->EnableLongIdlePeriod();
task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(40));
EXPECT_EQ(1u, default_task_queue_->GetNumberOfPendingTasks());
}
} // namespace scheduler
} // namespace blink
...@@ -182,7 +182,6 @@ MainThreadSchedulerImpl::MainThreadSchedulerImpl( ...@@ -182,7 +182,6 @@ MainThreadSchedulerImpl::MainThreadSchedulerImpl(
MainThreadTaskQueue::QueueType::kIdle) MainThreadTaskQueue::QueueType::kIdle)
.SetFixedPriority( .SetFixedPriority(
TaskQueue::QueuePriority::kBestEffortPriority))), TaskQueue::QueuePriority::kBestEffortPriority))),
idle_memory_reclaimer_(&helper_, idle_helper_.IdleTaskRunner()),
render_widget_scheduler_signals_(this), render_widget_scheduler_signals_(this),
control_task_queue_(helper_.ControlMainThreadTaskQueue()), control_task_queue_(helper_.ControlMainThreadTaskQueue()),
compositor_task_queue_( compositor_task_queue_(
......
...@@ -27,7 +27,6 @@ ...@@ -27,7 +27,6 @@
#include "third_party/blink/public/platform/scheduler/web_thread_scheduler.h" #include "third_party/blink/public/platform/scheduler/web_thread_scheduler.h"
#include "third_party/blink/renderer/platform/platform_export.h" #include "third_party/blink/renderer/platform/platform_export.h"
#include "third_party/blink/renderer/platform/scheduler/common/idle_helper.h" #include "third_party/blink/renderer/platform/scheduler/common/idle_helper.h"
#include "third_party/blink/renderer/platform/scheduler/common/idle_memory_reclaimer.h"
#include "third_party/blink/renderer/platform/scheduler/common/pollable_thread_safe_flag.h" #include "third_party/blink/renderer/platform/scheduler/common/pollable_thread_safe_flag.h"
#include "third_party/blink/renderer/platform/scheduler/common/thread_scheduler_impl.h" #include "third_party/blink/renderer/platform/scheduler/common/thread_scheduler_impl.h"
#include "third_party/blink/renderer/platform/scheduler/common/tracing_helper.h" #include "third_party/blink/renderer/platform/scheduler/common/tracing_helper.h"
...@@ -743,7 +742,6 @@ class PLATFORM_EXPORT MainThreadSchedulerImpl ...@@ -743,7 +742,6 @@ class PLATFORM_EXPORT MainThreadSchedulerImpl
MainThreadSchedulerHelper helper_; MainThreadSchedulerHelper helper_;
IdleHelper idle_helper_; IdleHelper idle_helper_;
IdleMemoryReclaimer idle_memory_reclaimer_;
std::unique_ptr<TaskQueueThrottler> task_queue_throttler_; std::unique_ptr<TaskQueueThrottler> task_queue_throttler_;
RenderWidgetSignals render_widget_scheduler_signals_; RenderWidgetSignals render_widget_scheduler_signals_;
MemoryPurgeManager memory_purge_manager_; MemoryPurgeManager memory_purge_manager_;
......
...@@ -107,7 +107,6 @@ WorkerThreadScheduler::WorkerThreadScheduler( ...@@ -107,7 +107,6 @@ WorkerThreadScheduler::WorkerThreadScheduler(
"WorkerSchedulerIdlePeriod", "WorkerSchedulerIdlePeriod",
base::TimeDelta::FromMilliseconds(300), base::TimeDelta::FromMilliseconds(300),
helper()->NewTaskQueue(TaskQueue::Spec("worker_idle_tq"))), helper()->NewTaskQueue(TaskQueue::Spec("worker_idle_tq"))),
idle_memory_reclaimer_(helper(), idle_helper_.IdleTaskRunner()),
load_tracker_(helper()->NowTicks(), load_tracker_(helper()->NowTicks(),
base::BindRepeating(&ReportWorkerTaskLoad), base::BindRepeating(&ReportWorkerTaskLoad),
kUnspecifiedWorkerThreadLoadTrackerReportingInterval), kUnspecifiedWorkerThreadLoadTrackerReportingInterval),
......
...@@ -12,7 +12,6 @@ ...@@ -12,7 +12,6 @@
#include "components/scheduling_metrics/task_duration_metric_reporter.h" #include "components/scheduling_metrics/task_duration_metric_reporter.h"
#include "third_party/blink/public/platform/web_thread_type.h" #include "third_party/blink/public/platform/web_thread_type.h"
#include "third_party/blink/renderer/platform/scheduler/common/idle_helper.h" #include "third_party/blink/renderer/platform/scheduler/common/idle_helper.h"
#include "third_party/blink/renderer/platform/scheduler/common/idle_memory_reclaimer.h"
#include "third_party/blink/renderer/platform/scheduler/common/thread_load_tracker.h" #include "third_party/blink/renderer/platform/scheduler/common/thread_load_tracker.h"
#include "third_party/blink/renderer/platform/scheduler/public/frame_scheduler.h" #include "third_party/blink/renderer/platform/scheduler/public/frame_scheduler.h"
#include "third_party/blink/renderer/platform/scheduler/public/frame_status.h" #include "third_party/blink/renderer/platform/scheduler/public/frame_status.h"
...@@ -140,7 +139,6 @@ class PLATFORM_EXPORT WorkerThreadScheduler ...@@ -140,7 +139,6 @@ class PLATFORM_EXPORT WorkerThreadScheduler
const WebThreadType thread_type_; const WebThreadType thread_type_;
IdleHelper idle_helper_; IdleHelper idle_helper_;
IdleMemoryReclaimer idle_memory_reclaimer_;
ThreadLoadTracker load_tracker_; ThreadLoadTracker load_tracker_;
bool initialized_; bool initialized_;
base::TimeTicks thread_start_time_; base::TimeTicks thread_start_time_;
......
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