Commit 5720368a authored by Takashi Toyoshima's avatar Takashi Toyoshima Committed by Commit Bot

ResourceLoadScheduler: do not take the priority into account

The current logic has an exception not to throttle the kHigh
priority requests even if the request is marked as kThrottleable.

However, this exception makes the per-frame maximum limit useless,
and make requests result in failure for hitting the network service
resource limit.

This patch enforces the normal limit even for the kHigh requests
for both throttling policies. But still kHigh requests can escape
from the tight throttling.

Bug: 1046882
Change-Id: I4e167fdb667f9adc90604fa1d65fc4cd6e650c8c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2028886Reviewed-by: default avatarKinuko Yasuda <kinuko@chromium.org>
Reviewed-by: default avatarYutaka Hirano <yhirano@chromium.org>
Commit-Queue: Takashi Toyoshima <toyoshim@chromium.org>
Cr-Commit-Position: refs/heads/master@{#737677}
parent 5569861e
......@@ -275,7 +275,7 @@ void ResourceLoadScheduler::Request(ResourceLoadSchedulerClient* client,
// Check if the request can be throttled.
ClientIdWithPriority request_info(*id, priority, intra_priority);
if (!IsClientDelayable(request_info, option)) {
if (!IsClientDelayable(option)) {
Run(*id, client, false);
return;
}
......@@ -356,27 +356,15 @@ void ResourceLoadScheduler::SetOutstandingLimitForTesting(size_t tight_limit,
MaybeRun();
}
bool ResourceLoadScheduler::IsClientDelayable(const ClientIdWithPriority& info,
ThrottleOption option) const {
const bool throttleable = option == ThrottleOption::kThrottleable &&
info.priority < ResourceLoadPriority::kHigh;
const bool stoppable = option != ThrottleOption::kCanNotBeStoppedOrThrottled;
// Also takes the lifecycle state of the associated FrameScheduler
// into account to determine if the request should be throttled
// regardless of the priority.
bool ResourceLoadScheduler::IsClientDelayable(ThrottleOption option) const {
switch (frame_scheduler_lifecycle_state_) {
case scheduler::SchedulingLifecycleState::kNotThrottled:
return throttleable;
case scheduler::SchedulingLifecycleState::kHidden:
case scheduler::SchedulingLifecycleState::kThrottled:
return option == ThrottleOption::kThrottleable;
case scheduler::SchedulingLifecycleState::kStopped:
return stoppable;
return option != ThrottleOption::kCanNotBeStoppedOrThrottled;
}
NOTREACHED() << static_cast<int>(frame_scheduler_lifecycle_state_);
return throttleable;
}
void ResourceLoadScheduler::OnLifecycleStateChanged(
......@@ -419,9 +407,6 @@ bool ResourceLoadScheduler::IsPendingRequestEffectivelyEmpty(
}
bool ResourceLoadScheduler::GetNextPendingRequest(ClientId* id) {
bool needs_throttling =
running_throttleable_requests_.size() >= GetOutstandingLimit();
auto& stoppable_queue = pending_requests_[ThrottleOption::kStoppable];
auto& throttleable_queue = pending_requests_[ThrottleOption::kThrottleable];
......@@ -429,14 +414,16 @@ bool ResourceLoadScheduler::GetNextPendingRequest(ClientId* id) {
auto stoppable_it = stoppable_queue.begin();
bool has_runnable_stoppable_request =
stoppable_it != stoppable_queue.end() &&
(!IsClientDelayable(*stoppable_it, ThrottleOption::kStoppable) ||
!needs_throttling);
(!IsClientDelayable(ThrottleOption::kStoppable) ||
running_throttleable_requests_.size() <
GetOutstandingLimit(stoppable_it->priority));
auto throttleable_it = throttleable_queue.begin();
bool has_runnable_throttleable_request =
throttleable_it != throttleable_queue.end() &&
(!IsClientDelayable(*throttleable_it, ThrottleOption::kThrottleable) ||
!needs_throttling);
(!IsClientDelayable(ThrottleOption::kThrottleable) ||
running_throttleable_requests_.size() <
GetOutstandingLimit(throttleable_it->priority));
if (!has_runnable_throttleable_request && !has_runnable_stoppable_request)
return false;
......@@ -489,7 +476,8 @@ void ResourceLoadScheduler::Run(ResourceLoadScheduler::ClientId id,
client->Run();
}
size_t ResourceLoadScheduler::GetOutstandingLimit() const {
size_t ResourceLoadScheduler::GetOutstandingLimit(
ResourceLoadPriority priority) const {
size_t limit = kOutstandingUnlimited;
switch (frame_scheduler_lifecycle_state_) {
......@@ -506,7 +494,9 @@ size_t ResourceLoadScheduler::GetOutstandingLimit() const {
switch (policy_) {
case ThrottlingPolicy::kTight:
limit = std::min(limit, tight_outstanding_limit_);
limit = std::min(limit, priority < ResourceLoadPriority::kHigh
? tight_outstanding_limit_
: normal_outstanding_limit_);
break;
case ThrottlingPolicy::kNormal:
limit = std::min(limit, normal_outstanding_limit_);
......
......@@ -261,10 +261,9 @@ class PLATFORM_EXPORT ResourceLoadScheduler final
// Gets the highest priority pending request that is allowed to be run.
bool GetNextPendingRequest(ClientId* id);
// Returns whether we can throttle a request with the given client info based
// Returns whether we can throttle a request with the given option based
// on life cycle state.
bool IsClientDelayable(const ClientIdWithPriority& info,
ThrottleOption option) const;
bool IsClientDelayable(ThrottleOption option) const;
// Generates the next ClientId.
ClientId GenerateClientId();
......@@ -275,7 +274,7 @@ class PLATFORM_EXPORT ResourceLoadScheduler final
// Grants a client to run,
void Run(ClientId, ResourceLoadSchedulerClient*, bool throttleable);
size_t GetOutstandingLimit() const;
size_t GetOutstandingLimit(ResourceLoadPriority priority) const;
void ShowConsoleMessageIfNeeded();
......@@ -283,7 +282,6 @@ class PLATFORM_EXPORT ResourceLoadScheduler final
resource_fetcher_properties_;
// A flag to indicate an internal running state.
// TODO(toyoshim): We may want to use enum once we start to have more states.
bool is_shutdown_ = false;
ThrottlingPolicy policy_ = ThrottlingPolicy::kNormal;
......
......@@ -349,7 +349,8 @@ TEST_F(ResourceLoadSchedulerTest, PriorityIsConsidered) {
// Push three requests.
MockClient* client1 = MakeGarbageCollected<MockClient>();
Scheduler()->SetOutstandingLimitForTesting(0);
// Allows one kHigh priority request by limits below.
Scheduler()->SetOutstandingLimitForTesting(0, 1);
ResourceLoadScheduler::ClientId id1 = ResourceLoadScheduler::kInvalidClientId;
Scheduler()->Request(client1, ThrottleOption::kThrottleable,
......@@ -383,23 +384,21 @@ TEST_F(ResourceLoadSchedulerTest, PriorityIsConsidered) {
EXPECT_FALSE(client3->WasRun());
EXPECT_TRUE(client4->WasRun());
// Client 4 does not count against the limit as it was not delayable when it
// was created.
Scheduler()->SetOutstandingLimitForTesting(1);
Scheduler()->SetOutstandingLimitForTesting(2);
EXPECT_FALSE(client1->WasRun());
EXPECT_FALSE(client2->WasRun());
EXPECT_TRUE(client3->WasRun());
EXPECT_TRUE(client4->WasRun());
Scheduler()->SetOutstandingLimitForTesting(2);
Scheduler()->SetOutstandingLimitForTesting(3);
EXPECT_FALSE(client1->WasRun());
EXPECT_TRUE(client2->WasRun());
EXPECT_TRUE(client3->WasRun());
EXPECT_TRUE(client4->WasRun());
Scheduler()->SetOutstandingLimitForTesting(3);
Scheduler()->SetOutstandingLimitForTesting(4);
EXPECT_TRUE(client1->WasRun());
EXPECT_TRUE(client2->WasRun());
......@@ -407,7 +406,6 @@ TEST_F(ResourceLoadSchedulerTest, PriorityIsConsidered) {
EXPECT_TRUE(client4->WasRun());
// Release the rest.
EXPECT_TRUE(Release(id4));
EXPECT_TRUE(Release(id3));
EXPECT_TRUE(Release(id2));
EXPECT_TRUE(Release(id1));
......@@ -511,12 +509,11 @@ TEST_F(ResourceLoadSchedulerTest, StoppableRequestResumesWhenThrottled) {
}
TEST_F(ResourceLoadSchedulerTest, SetPriority) {
// Start with the normal scheduling policy.
Scheduler()->LoosenThrottlingPolicy();
// Push three requests.
MockClient* client1 = MakeGarbageCollected<MockClient>();
Scheduler()->SetOutstandingLimitForTesting(0);
// Allows one kHigh priority request by limits below.
Scheduler()->SetOutstandingLimitForTesting(0, 1);
ResourceLoadScheduler::ClientId id1 = ResourceLoadScheduler::kInvalidClientId;
Scheduler()->Request(client1, ThrottleOption::kThrottleable,
......@@ -554,7 +551,16 @@ TEST_F(ResourceLoadSchedulerTest, SetPriority) {
EXPECT_FALSE(client2->WasRun());
EXPECT_FALSE(client3->WasRun());
Scheduler()->SetOutstandingLimitForTesting(2);
// Loosen the policy to adopt the normal limit for all.
Scheduler()->LoosenThrottlingPolicy();
Scheduler()->SetOutstandingLimitForTesting(0, 2);
EXPECT_TRUE(client1->WasRun());
EXPECT_TRUE(client2->WasRun());
EXPECT_FALSE(client3->WasRun());
// kHigh priority does not help here.
Scheduler()->SetPriority(id3, ResourceLoadPriority::kHigh, 0);
EXPECT_TRUE(client1->WasRun());
EXPECT_TRUE(client2->WasRun());
......
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