Commit 77efd70d authored by Greg Kraynov's avatar Greg Kraynov Committed by Commit Bot

Blink Scheduler: Trace main frame as a special origin state.

Change-Id: I3913efea5dd760e3496b971d871d22939c34e1af
Reviewed-on: https://chromium-review.googlesource.com/968493
Commit-Queue: Greg Kraynov <kraynov@chromium.org>
Reviewed-by: default avatarAlexander Timin <altimin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#545546}
parent 49c09c58
......@@ -4,6 +4,7 @@
#include "platform/scheduler/renderer/frame_origin_type.h"
#include "base/macros.h"
#include "platform/WebFrameScheduler.h"
namespace blink {
......@@ -22,5 +23,20 @@ FrameOriginType GetFrameOriginType(WebFrameScheduler* scheduler) {
}
}
const char* FrameOriginTypeToString(FrameOriginType origin) {
switch (origin) {
case FrameOriginType::kMainFrame:
return "main-frame";
case FrameOriginType::kSameOriginFrame:
return "same-origin";
case FrameOriginType::kCrossOriginFrame:
return "cross-origin";
case FrameOriginType::kCount:
NOTREACHED();
}
NOTREACHED();
return nullptr;
}
} // namespace scheduler
} // namespace blink
......@@ -22,6 +22,8 @@ enum class FrameOriginType {
FrameOriginType GetFrameOriginType(WebFrameScheduler* frame_scheduler);
const char* FrameOriginTypeToString(FrameOriginType origin);
} // namespace scheduler
} // namespace blink
......
......@@ -97,14 +97,6 @@ const char* AudioPlayingStateToString(bool is_audio_playing) {
}
}
const char* YesNoStateToString(bool is_yes) {
if (is_yes) {
return "yes";
} else {
return "no";
}
}
const char* RendererProcessTypeToString(RendererProcessType process_type) {
switch (process_type) {
case RendererProcessType::kRenderer:
......
......@@ -51,14 +51,6 @@ const char* FrozenStateToString(bool is_frozen) {
}
}
const char* CrossOriginStateToString(bool is_cross_origin) {
if (is_cross_origin) {
return "cross-origin";
} else {
return "same-origin";
}
}
} // namespace
WebFrameSchedulerImpl::ActiveConnectionHandleImpl::ActiveConnectionHandleImpl(
......@@ -89,7 +81,8 @@ WebFrameSchedulerImpl::WebFrameSchedulerImpl(
PageSchedulerImpl* parent_page_scheduler,
base::trace_event::BlameContext* blame_context,
WebFrameScheduler::FrameType frame_type)
: renderer_scheduler_(renderer_scheduler),
: frame_type_(frame_type),
renderer_scheduler_(renderer_scheduler),
parent_page_scheduler_(parent_page_scheduler),
blame_context_(blame_context),
throttling_state_(WebFrameScheduler::ThrottlingState::kNotThrottled),
......@@ -113,13 +106,19 @@ WebFrameSchedulerImpl::WebFrameSchedulerImpl(
this,
&tracing_controller_,
PausedStateToString),
cross_origin_(false,
"WebFrameScheduler.Origin",
this,
&tracing_controller_,
CrossOriginStateToString),
frame_origin_type_(frame_type == FrameType::kMainFrame
? FrameOriginType::kMainFrame
: FrameOriginType::kSameOriginFrame,
"WebFrameScheduler.Origin",
this,
&tracing_controller_,
FrameOriginTypeToString),
url_tracer_("WebFrameScheduler.URL", this),
frame_type_(frame_type),
task_queue_throttled_(false,
"WebFrameScheduler.TaskQueueThrottled",
this,
&tracing_controller_,
YesNoStateToString),
active_connection_count_(0),
weak_factory_(this) {
DCHECK_EQ(throttling_state_, CalculateThrottlingState());
......@@ -203,9 +202,8 @@ void WebFrameSchedulerImpl::SetFrameVisible(bool frame_visible) {
if (frame_visible_ == frame_visible)
return;
UMA_HISTOGRAM_BOOLEAN("RendererScheduler.IPC.FrameVisibility", frame_visible);
bool was_throttled = ShouldThrottleTimers();
frame_visible_ = frame_visible;
UpdateThrottling(was_throttled);
UpdateTaskQueueThrottling();
}
bool WebFrameSchedulerImpl::IsFrameVisible() const {
......@@ -214,15 +212,20 @@ bool WebFrameSchedulerImpl::IsFrameVisible() const {
void WebFrameSchedulerImpl::SetCrossOrigin(bool cross_origin) {
DCHECK(parent_page_scheduler_);
if (cross_origin_ == cross_origin)
if (frame_origin_type_ == FrameOriginType::kMainFrame) {
DCHECK(!cross_origin);
return;
bool was_throttled = ShouldThrottleTimers();
cross_origin_ = cross_origin;
UpdateThrottling(was_throttled);
}
if (cross_origin) {
frame_origin_type_ = FrameOriginType::kCrossOriginFrame;
} else {
frame_origin_type_ = FrameOriginType::kSameOriginFrame;
}
UpdateTaskQueueThrottling();
}
bool WebFrameSchedulerImpl::IsCrossOrigin() const {
return cross_origin_;
return frame_origin_type_ == FrameOriginType::kCrossOriginFrame;
}
void WebFrameSchedulerImpl::TraceUrlChange(const String& url) {
......@@ -346,11 +349,7 @@ scoped_refptr<TaskQueue> WebFrameSchedulerImpl::ThrottleableTaskQueue() {
time_budget_pool->AddQueue(renderer_scheduler_->tick_clock()->NowTicks(),
throttleable_task_queue_.get());
}
if (ShouldThrottleTimers()) {
renderer_scheduler_->task_queue_throttler()->IncreaseThrottleRefCount(
throttleable_task_queue_.get());
}
UpdateTaskQueueThrottling();
}
return throttleable_task_queue_;
}
......@@ -449,7 +448,7 @@ void WebFrameSchedulerImpl::AsValueInto(
state->SetBoolean("frame_visible", frame_visible_);
state->SetBoolean("page_visible",
page_visibility_ == PageVisibilityState::kVisible);
state->SetBoolean("cross_origin", cross_origin_);
state->SetBoolean("cross_origin", IsCrossOrigin());
state->SetString("frame_type",
frame_type_ == WebFrameScheduler::FrameType::kMainFrame
? "MainFrame"
......@@ -493,13 +492,12 @@ void WebFrameSchedulerImpl::SetPageVisibility(
DCHECK(parent_page_scheduler_);
if (page_visibility_ == page_visibility)
return;
bool was_throttled = ShouldThrottleTimers();
page_visibility_ = page_visibility;
if (page_visibility_ == PageVisibilityState::kVisible)
page_frozen_ = false; // visible page must not be frozen.
// TODO(altimin): Avoid having to call all these methods here.
UpdateTaskQueues();
UpdateThrottling(was_throttled);
UpdateTaskQueueThrottling();
UpdateThrottlingState();
}
......@@ -584,13 +582,21 @@ bool WebFrameSchedulerImpl::ShouldThrottleTimers() const {
if (page_visibility_ == PageVisibilityState::kHidden)
return true;
return RuntimeEnabledFeatures::TimerThrottlingForHiddenFramesEnabled() &&
!frame_visible_ && cross_origin_;
!frame_visible_ && IsCrossOrigin();
}
void WebFrameSchedulerImpl::UpdateThrottling(bool was_throttled) {
void WebFrameSchedulerImpl::UpdateTaskQueueThrottling() {
// Before we initialize a trottleable task queue, |task_queue_throttled_|
// stays false and this function ensures it indicates whether are we holding
// a queue reference for throttler or not.
// Don't modify that value neither amend the reference counter anywhere else.
if (!throttleable_task_queue_)
return;
bool should_throttle = ShouldThrottleTimers();
if (was_throttled == should_throttle || !throttleable_task_queue_)
if (task_queue_throttled_ == should_throttle)
return;
task_queue_throttled_ = should_throttle;
if (should_throttle) {
renderer_scheduler_->task_queue_throttler()->IncreaseThrottleRefCount(
throttleable_task_queue_.get());
......
......@@ -16,6 +16,7 @@
#include "platform/scheduler/base/task_queue.h"
#include "platform/scheduler/child/page_visibility_state.h"
#include "platform/scheduler/child/worker_scheduler_proxy.h"
#include "platform/scheduler/renderer/frame_origin_type.h"
#include "platform/scheduler/util/tracing_helper.h"
namespace base {
......@@ -124,7 +125,7 @@ class PLATFORM_EXPORT WebFrameSchedulerImpl : public WebFrameScheduler {
void RemoveThrottleableQueueFromBackgroundCPUTimeBudgetPool();
void ApplyPolicyToThrottleableQueue();
bool ShouldThrottleTimers() const;
void UpdateThrottling(bool was_throttled);
void UpdateTaskQueueThrottling();
WebFrameScheduler::ThrottlingState CalculateThrottlingState() const;
void UpdateThrottlingState();
void RemoveThrottlingObserver(Observer* observer);
......@@ -144,6 +145,8 @@ class PLATFORM_EXPORT WebFrameSchedulerImpl : public WebFrameScheduler {
base::WeakPtr<WebFrameSchedulerImpl> GetWeakPtr();
const WebFrameScheduler::FrameType frame_type_;
TraceableVariableController tracing_controller_;
scoped_refptr<MainThreadTaskQueue> loading_task_queue_;
scoped_refptr<MainThreadTaskQueue> loading_control_task_queue_;
......@@ -168,9 +171,10 @@ class PLATFORM_EXPORT WebFrameSchedulerImpl : public WebFrameScheduler {
page_visibility_;
TraceableState<bool, kTracingCategoryNameInfo> page_frozen_;
TraceableState<bool, kTracingCategoryNameInfo> frame_paused_;
TraceableState<bool, kTracingCategoryNameInfo> cross_origin_;
TraceableState<FrameOriginType, kTracingCategoryNameInfo> frame_origin_type_;
StateTracer<kTracingCategoryNameInfo> url_tracer_;
WebFrameScheduler::FrameType frame_type_;
// |task_queue_throttled_| is false if |throttleable_task_queue_| is absent.
TraceableState<bool, kTracingCategoryNameDebug> task_queue_throttled_;
int active_connection_count_;
base::WeakPtrFactory<WebFrameSchedulerImpl> weak_factory_;
......
......@@ -49,6 +49,16 @@ class WebFrameSchedulerImplTest : public ::testing::Test {
}
protected:
scoped_refptr<TaskQueue> throttleable_task_queue() {
return web_frame_scheduler_->throttleable_task_queue_;
}
void LazyInitThrottleableTaskQueue() {
EXPECT_FALSE(throttleable_task_queue());
web_frame_scheduler_->ThrottleableTaskQueue();
EXPECT_TRUE(throttleable_task_queue());
}
scoped_refptr<TaskQueue> ThrottleableTaskQueue() {
return web_frame_scheduler_->ThrottleableTaskQueue();
}
......@@ -69,6 +79,12 @@ class WebFrameSchedulerImplTest : public ::testing::Test {
return web_frame_scheduler_->UnpausableTaskQueue();
}
bool IsThrottled() {
EXPECT_TRUE(throttleable_task_queue());
return scheduler_->task_queue_throttler()->IsThrottled(
throttleable_task_queue().get());
}
base::SimpleTestTickClock clock_;
scoped_refptr<cc::OrderedSimpleTaskRunner> mock_task_runner_;
std::unique_ptr<RendererSchedulerImpl> scheduler_;
......@@ -113,128 +129,128 @@ class MockThrottlingObserver final : public WebFrameScheduler::Observer {
size_t stopped_count_;
};
void RunRepeatingTask(scoped_refptr<TaskQueue> task_queue, int* run_count);
base::OnceClosure MakeRepeatingTask(scoped_refptr<TaskQueue> task_queue,
int* run_count) {
return base::BindOnce(&RunRepeatingTask, std::move(task_queue),
base::Unretained(run_count));
}
void RunRepeatingTask(scoped_refptr<TaskQueue> task_queue, int* run_count) {
++*run_count;
TaskQueue* task_queue_ptr = task_queue.get();
task_queue_ptr->PostDelayedTask(
FROM_HERE, MakeRepeatingTask(std::move(task_queue), run_count),
TimeDelta::FromMilliseconds(1));
}
void IncrementCounter(int* counter) {
++*counter;
}
} // namespace
TEST_F(WebFrameSchedulerImplTest, RepeatingTimer_PageInForeground) {
ScopedTimerThrottlingForHiddenFramesForTest
timer_throttling_for_hidden_frames(true);
int run_count = 0;
ThrottleableTaskQueue()->PostDelayedTask(
FROM_HERE, MakeRepeatingTask(ThrottleableTaskQueue(), &run_count),
TimeDelta::FromMilliseconds(1));
mock_task_runner_->RunForPeriod(base::TimeDelta::FromSeconds(1));
EXPECT_EQ(1000, run_count);
// Throttleable task queue is initialized lazily, so there're two scenarios:
// - Task queue created first and throttling decision made later;
// - Scheduler receives relevant signals to make a throttling decision but
// applies one once task queue gets created.
// We test both (ExplicitInit/LazyInit) of them.
TEST_F(WebFrameSchedulerImplTest, PageVisible) {
ScopedTimerThrottlingForHiddenFramesForTest throttle_hidden_frames(true);
EXPECT_FALSE(throttleable_task_queue());
LazyInitThrottleableTaskQueue();
EXPECT_FALSE(IsThrottled());
}
TEST_F(WebFrameSchedulerImplTest, RepeatingTimer_PageInBackground) {
ScopedTimerThrottlingForHiddenFramesForTest
timer_throttling_for_hidden_frames(true);
TEST_F(WebFrameSchedulerImplTest, PageHidden_ExplicitInit) {
ScopedTimerThrottlingForHiddenFramesForTest throttle_hidden_frames(true);
LazyInitThrottleableTaskQueue();
EXPECT_FALSE(IsThrottled());
page_scheduler_->SetPageVisible(false);
EXPECT_TRUE(IsThrottled());
}
int run_count = 0;
ThrottleableTaskQueue()->PostDelayedTask(
FROM_HERE, MakeRepeatingTask(ThrottleableTaskQueue(), &run_count),
TimeDelta::FromMilliseconds(1));
TEST_F(WebFrameSchedulerImplTest, PageHidden_LazyInit) {
ScopedTimerThrottlingForHiddenFramesForTest throttle_hidden_frames(false);
page_scheduler_->SetPageVisible(false);
LazyInitThrottleableTaskQueue();
EXPECT_TRUE(IsThrottled());
}
mock_task_runner_->RunForPeriod(base::TimeDelta::FromSeconds(1));
EXPECT_EQ(1, run_count);
TEST_F(WebFrameSchedulerImplTest, PageHiddenThenVisible_ExplicitInit) {
ScopedTimerThrottlingForHiddenFramesForTest throttle_hidden_frames(false);
LazyInitThrottleableTaskQueue();
EXPECT_FALSE(IsThrottled());
page_scheduler_->SetPageVisible(false);
EXPECT_TRUE(IsThrottled());
page_scheduler_->SetPageVisible(true);
EXPECT_FALSE(IsThrottled());
page_scheduler_->SetPageVisible(false);
EXPECT_TRUE(IsThrottled());
}
TEST_F(WebFrameSchedulerImplTest, RepeatingTimer_FrameHidden_SameOrigin) {
ScopedTimerThrottlingForHiddenFramesForTest
timer_throttling_for_hidden_frames(true);
TEST_F(WebFrameSchedulerImplTest,
FrameHiddenThenVisible_CrossOrigin_ExplicitInit) {
ScopedTimerThrottlingForHiddenFramesForTest throttle_hidden_frames(true);
LazyInitThrottleableTaskQueue();
EXPECT_FALSE(IsThrottled());
web_frame_scheduler_->SetFrameVisible(false);
int run_count = 0;
ThrottleableTaskQueue()->PostDelayedTask(
FROM_HERE, MakeRepeatingTask(ThrottleableTaskQueue(), &run_count),
TimeDelta::FromMilliseconds(1));
mock_task_runner_->RunForPeriod(base::TimeDelta::FromSeconds(1));
EXPECT_EQ(1000, run_count);
web_frame_scheduler_->SetCrossOrigin(true);
web_frame_scheduler_->SetCrossOrigin(false);
EXPECT_FALSE(IsThrottled());
web_frame_scheduler_->SetCrossOrigin(true);
EXPECT_TRUE(IsThrottled());
web_frame_scheduler_->SetFrameVisible(true);
EXPECT_FALSE(IsThrottled());
web_frame_scheduler_->SetFrameVisible(false);
EXPECT_TRUE(IsThrottled());
}
TEST_F(WebFrameSchedulerImplTest, RepeatingTimer_FrameVisible_CrossOrigin) {
ScopedTimerThrottlingForHiddenFramesForTest
timer_throttling_for_hidden_frames(true);
web_frame_scheduler_->SetFrameVisible(true);
TEST_F(WebFrameSchedulerImplTest, FrameHidden_CrossOrigin_LazyInit) {
ScopedTimerThrottlingForHiddenFramesForTest throttle_hidden_frames(true);
web_frame_scheduler_->SetFrameVisible(false);
web_frame_scheduler_->SetCrossOrigin(true);
int run_count = 0;
ThrottleableTaskQueue()->PostDelayedTask(
FROM_HERE, MakeRepeatingTask(ThrottleableTaskQueue(), &run_count),
TimeDelta::FromMilliseconds(1));
mock_task_runner_->RunForPeriod(base::TimeDelta::FromSeconds(1));
EXPECT_EQ(1000, run_count);
LazyInitThrottleableTaskQueue();
EXPECT_TRUE(IsThrottled());
}
TEST_F(WebFrameSchedulerImplTest, RepeatingTimer_FrameHidden_CrossOrigin) {
ScopedTimerThrottlingForHiddenFramesForTest
timer_throttling_for_hidden_frames(true);
TEST_F(WebFrameSchedulerImplTest,
FrameHidden_CrossOrigin_NoThrottling_ExplicitInit) {
ScopedTimerThrottlingForHiddenFramesForTest throttle_hidden_frames(false);
LazyInitThrottleableTaskQueue();
EXPECT_FALSE(IsThrottled());
web_frame_scheduler_->SetFrameVisible(false);
web_frame_scheduler_->SetCrossOrigin(true);
int run_count = 0;
ThrottleableTaskQueue()->PostDelayedTask(
FROM_HERE, MakeRepeatingTask(ThrottleableTaskQueue(), &run_count),
TimeDelta::FromMilliseconds(1));
mock_task_runner_->RunForPeriod(base::TimeDelta::FromSeconds(1));
EXPECT_EQ(1, run_count);
EXPECT_FALSE(IsThrottled());
}
TEST_F(WebFrameSchedulerImplTest, PageInBackground_ThrottlingDisabled) {
ScopedTimerThrottlingForHiddenFramesForTest
timer_throttling_for_hidden_frames(false);
page_scheduler_->SetPageVisible(false);
int run_count = 0;
ThrottleableTaskQueue()->PostDelayedTask(
FROM_HERE, MakeRepeatingTask(ThrottleableTaskQueue(), &run_count),
TimeDelta::FromMilliseconds(1));
TEST_F(WebFrameSchedulerImplTest,
FrameHidden_CrossOrigin_NoThrottling_LazyInit) {
ScopedTimerThrottlingForHiddenFramesForTest throttle_hidden_frames(false);
web_frame_scheduler_->SetFrameVisible(false);
web_frame_scheduler_->SetCrossOrigin(true);
LazyInitThrottleableTaskQueue();
EXPECT_FALSE(IsThrottled());
}
mock_task_runner_->RunForPeriod(base::TimeDelta::FromSeconds(1));
EXPECT_EQ(1, run_count);
TEST_F(WebFrameSchedulerImplTest, FrameHidden_SameOrigin_ExplicitInit) {
ScopedTimerThrottlingForHiddenFramesForTest throttle_hidden_frames(true);
LazyInitThrottleableTaskQueue();
EXPECT_FALSE(IsThrottled());
web_frame_scheduler_->SetFrameVisible(false);
EXPECT_FALSE(IsThrottled());
}
TEST_F(WebFrameSchedulerImplTest,
RepeatingTimer_FrameHidden_CrossOrigin_ThrottlingDisabled) {
ScopedTimerThrottlingForHiddenFramesForTest
timer_throttling_for_hidden_frames(false);
TEST_F(WebFrameSchedulerImplTest, FrameHidden_SameOrigin_LazyInit) {
ScopedTimerThrottlingForHiddenFramesForTest throttle_hidden_frames(true);
web_frame_scheduler_->SetFrameVisible(false);
web_frame_scheduler_->SetCrossOrigin(true);
LazyInitThrottleableTaskQueue();
EXPECT_FALSE(IsThrottled());
}
int run_count = 0;
ThrottleableTaskQueue()->PostDelayedTask(
FROM_HERE, MakeRepeatingTask(ThrottleableTaskQueue(), &run_count),
TimeDelta::FromMilliseconds(1));
TEST_F(WebFrameSchedulerImplTest, FrameVisible_CrossOrigin_ExplicitInit) {
ScopedTimerThrottlingForHiddenFramesForTest throttle_hidden_frames(true);
LazyInitThrottleableTaskQueue();
EXPECT_FALSE(IsThrottled());
EXPECT_TRUE(throttleable_task_queue());
web_frame_scheduler_->SetFrameVisible(true);
EXPECT_FALSE(IsThrottled());
web_frame_scheduler_->SetCrossOrigin(true);
EXPECT_FALSE(IsThrottled());
}
mock_task_runner_->RunForPeriod(base::TimeDelta::FromSeconds(1));
EXPECT_EQ(1000, run_count);
TEST_F(WebFrameSchedulerImplTest, FrameVisible_CrossOrigin_LazyInit) {
ScopedTimerThrottlingForHiddenFramesForTest throttle_hidden_frames(true);
web_frame_scheduler_->SetFrameVisible(true);
web_frame_scheduler_->SetCrossOrigin(true);
LazyInitThrottleableTaskQueue();
EXPECT_FALSE(IsThrottled());
}
TEST_F(WebFrameSchedulerImplTest, PauseAndResume) {
......
......@@ -65,6 +65,14 @@ double TimeDeltaToMilliseconds(const base::TimeDelta& value) {
return value.InMillisecondsF();
}
const char* YesNoStateToString(bool is_yes) {
if (is_yes) {
return "yes";
} else {
return "no";
}
}
TraceableVariableController::TraceableVariableController() {
}
......
......@@ -40,6 +40,8 @@ PLATFORM_EXPORT std::string PointerToString(const void* pointer);
PLATFORM_EXPORT double TimeDeltaToMilliseconds(const base::TimeDelta& value);
PLATFORM_EXPORT const char* YesNoStateToString(bool is_yes);
class TraceableVariable;
// Unfortunately, using |base::trace_event::TraceLog::EnabledStateObserver|
......
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