Commit b88db346 authored by Chris Hamilton's avatar Chris Hamilton Committed by Commit Bot

[PM] Create FramePriorityDecorator.

This creates the root of the frame priority voting hierarchy, a
VoteConsumer that takes incoming votes and applies them on nodes in
the graph.

Further CLs will introduce Page and Process priority decorators that
aggregate results from related Frames.

BUG=971272

Change-Id: I3870f28641c67699bed14f7ab293f20ecbfecc59
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1856758
Commit-Queue: Chris Hamilton <chrisha@chromium.org>
Reviewed-by: default avatarSigurður Ásgeirsson <siggi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#706564}
parent f0c04f5e
......@@ -1087,6 +1087,8 @@ jumbo_split_static_library("browser") {
"performance_manager/chrome_browser_main_extra_parts_performance_manager.h",
"performance_manager/chrome_content_browser_client_performance_manager_part.cc",
"performance_manager/chrome_content_browser_client_performance_manager_part.h",
"performance_manager/decorators/frame_priority_decorator.cc",
"performance_manager/decorators/frame_priority_decorator.h",
"performance_manager/decorators/frozen_frame_aggregator.cc",
"performance_manager/decorators/frozen_frame_aggregator.h",
"performance_manager/decorators/page_aggregator.cc",
......
// Copyright 2019 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 "chrome/browser/performance_manager/decorators/frame_priority_decorator.h"
#include "components/performance_manager/graph/frame_node_impl.h"
#include "components/performance_manager/graph/node_attached_data_impl.h"
namespace performance_manager {
// Helper class providing access to FrameNodeImpl::accepted_vote_.
class FramePriorityAccess {
public:
static frame_priority::AcceptedVote* GetAcceptedVote(
FrameNodeImpl* frame_node) {
return &frame_node->accepted_vote_;
}
};
namespace frame_priority {
FramePriorityDecorator::FramePriorityDecorator() : factory_(this) {}
FramePriorityDecorator::~FramePriorityDecorator() = default;
VotingChannel FramePriorityDecorator::GetVotingChannel() {
DCHECK_EQ(0u, factory_.voting_channels_issued());
auto channel = factory_.BuildVotingChannel();
voter_id_ = channel.voter_id();
return channel;
}
VoteReceipt FramePriorityDecorator::SubmitVote(VoterId voter_id,
const Vote& vote) {
DCHECK_EQ(voter_id_, voter_id);
auto* frame_node = FrameNodeImpl::FromNode(vote.frame_node());
auto* accepted_vote = FramePriorityAccess::GetAcceptedVote(frame_node);
DCHECK(!accepted_vote->IsValid());
*accepted_vote = AcceptedVote(this, voter_id, vote);
frame_node->SetPriorityAndReason(
PriorityAndReason(vote.priority(), vote.reason()));
return accepted_vote->IssueReceipt();
}
VoteReceipt FramePriorityDecorator::ChangeVote(VoteReceipt receipt,
AcceptedVote* old_vote,
const Vote& new_vote) {
auto* frame_node = FrameNodeImpl::FromNode(new_vote.frame_node());
auto* accepted_vote = FramePriorityAccess::GetAcceptedVote(frame_node);
DCHECK_EQ(accepted_vote, old_vote);
DCHECK(accepted_vote->IsValid());
accepted_vote->UpdateVote(new_vote);
frame_node->SetPriorityAndReason(
PriorityAndReason(new_vote.priority(), new_vote.reason()));
return receipt;
}
void FramePriorityDecorator::VoteInvalidated(AcceptedVote* vote) {
auto* frame_node = FrameNodeImpl::FromNode(vote->vote().frame_node());
auto* accepted_vote = FramePriorityAccess::GetAcceptedVote(frame_node);
DCHECK_EQ(accepted_vote, vote);
DCHECK(!accepted_vote->IsValid());
// Update the priority by falling back to the default priority.
frame_node->SetPriorityAndReason(PriorityAndReason(
base::TaskPriority::LOWEST, FrameNodeImpl::kDefaultPriorityReason));
}
} // namespace frame_priority
} // namespace performance_manager
// Copyright 2019 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 CHROME_BROWSER_PERFORMANCE_MANAGER_DECORATORS_FRAME_PRIORITY_DECORATOR_H_
#define CHROME_BROWSER_PERFORMANCE_MANAGER_DECORATORS_FRAME_PRIORITY_DECORATOR_H_
#include "components/performance_manager/public/graph/frame_node.h"
#include "components/performance_manager/public/graph/graph.h"
namespace performance_manager {
namespace frame_priority {
// The FramePriorityDecorator acts as the root node of a hierarchy of frame
// priority voters. It is responsible for taking aggregated votes and applying
// them to the actual frame nodes in a graph.
class FramePriorityDecorator : public GraphOwnedDefaultImpl,
public VoteConsumer {
public:
FramePriorityDecorator();
~FramePriorityDecorator() override;
// Issues a voting channel (registers the sole incoming voter).
VotingChannel GetVotingChannel();
protected:
// VoteConsumer implementation:
VoteReceipt SubmitVote(VoterId voter_id, const Vote& vote) override;
VoteReceipt ChangeVote(VoteReceipt receipt,
AcceptedVote* old_vote,
const Vote& new_vote) override;
void VoteInvalidated(AcceptedVote* vote) override;
// Our VotingChannelFactory for providing VotingChannels to our input voters.
VotingChannelFactory factory_;
// The ID of the only voting channel we've vended.
VoterId voter_id_ = kInvalidVoterId;
private:
DISALLOW_COPY_AND_ASSIGN(FramePriorityDecorator);
};
} // namespace frame_priority
} // namespace performance_manager
#endif // CHROME_BROWSER_PERFORMANCE_MANAGER_DECORATORS_FRAME_PRIORITY_DECORATOR_H_
// Copyright 2019 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 "chrome/browser/performance_manager/decorators/frame_priority_decorator.h"
#include "components/performance_manager/graph/frame_node_impl.h"
#include "components/performance_manager/graph/page_node_impl.h"
#include "components/performance_manager/graph/process_node_impl.h"
#include "components/performance_manager/test_support/frame_priority.h"
#include "components/performance_manager/test_support/graph_test_harness.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace performance_manager {
namespace frame_priority {
namespace {
class LenientMockFrameNodeObserver : public FrameNode::ObserverDefaultImpl {
public:
LenientMockFrameNodeObserver() = default;
~LenientMockFrameNodeObserver() override = default;
MOCK_METHOD1(OnPriorityAndReasonChanged, void(const FrameNode*));
private:
DISALLOW_COPY_AND_ASSIGN(LenientMockFrameNodeObserver);
};
using MockFrameNodeObserver =
::testing::StrictMock<LenientMockFrameNodeObserver>;
class FramePriorityDecoratorTest : public GraphTestHarness {
public:
FramePriorityDecoratorTest() = default;
~FramePriorityDecoratorTest() override = default;
};
} // namespace
TEST_F(FramePriorityDecoratorTest, VotesForwardedToGraph) {
FramePriorityDecorator* fpd = new FramePriorityDecorator();
graph()->PassToGraph(base::WrapUnique(fpd));
TestNodeWrapper<ProcessNodeImpl> process = CreateNode<ProcessNodeImpl>();
TestNodeWrapper<PageNodeImpl> page = CreateNode<PageNodeImpl>();
TestNodeWrapper<FrameNodeImpl> frame =
graph()->CreateFrameNodeAutoId(process.get(), page.get());
test::DummyVoter voter;
voter.SetVotingChannel(fpd->GetVotingChannel());
MockFrameNodeObserver obs;
graph()->AddFrameNodeObserver(&obs);
EXPECT_EQ(base::TaskPriority::LOWEST,
frame->priority_and_reason().priority());
EXPECT_EQ(FrameNodeImpl::kDefaultPriorityReason,
frame->priority_and_reason().reason());
// Do not expect a notification when an identical vote is submitted.
voter.EmitVote(frame.get(), frame->priority_and_reason().priority(),
frame->priority_and_reason().reason());
auto& receipt = voter.receipts_[0];
testing::Mock::VerifyAndClear(&obs);
// Update the vote with a new priority and expect that to propagate.
EXPECT_CALL(obs, OnPriorityAndReasonChanged(frame.get()));
receipt.ChangeVote(base::TaskPriority::HIGHEST, test::DummyVoter::kReason);
testing::Mock::VerifyAndClear(&obs);
EXPECT_EQ(base::TaskPriority::HIGHEST,
frame->priority_and_reason().priority());
EXPECT_EQ(test::DummyVoter::kReason, frame->priority_and_reason().reason());
// Cancel the existing vote and expect it to go back to the default.
EXPECT_CALL(obs, OnPriorityAndReasonChanged(frame.get()));
receipt.Reset();
testing::Mock::VerifyAndClear(&obs);
EXPECT_EQ(base::TaskPriority::LOWEST,
frame->priority_and_reason().priority());
EXPECT_EQ(FrameNodeImpl::kDefaultPriorityReason,
frame->priority_and_reason().reason());
graph()->RemoveFrameNodeObserver(&obs);
}
} // namespace frame_priority
} // namespace performance_manager
......@@ -24,8 +24,6 @@ class LenientMockProcessNodeObserver : public ProcessNode::ObserverDefaultImpl {
LenientMockProcessNodeObserver() = default;
~LenientMockProcessNodeObserver() override = default;
virtual bool ShouldObserve(const NodeBase* node) { return false; }
MOCK_METHOD1(OnAllFramesInProcessFrozen, void(const ProcessNode*));
private:
......
......@@ -3102,6 +3102,7 @@ test("unit_tests") {
"../browser/password_manager/chrome_password_manager_client_unittest.cc",
"../browser/password_manager/password_store_x_unittest.cc",
"../browser/payments/payment_handler_permission_context_unittest.cc",
"../browser/performance_manager/decorators/frame_priority_decorator_unittest.cc",
"../browser/performance_manager/decorators/frozen_frame_aggregator_unittest.cc",
"../browser/performance_manager/decorators/page_aggregator_unittest.cc",
"../browser/performance_manager/decorators/page_almost_idle_decorator_unittest.cc",
......
......@@ -88,8 +88,6 @@ source_set("unit_tests") {
"frame_priority/frame_priority_unittest.cc",
"frame_priority/max_vote_aggregator_unittest.cc",
"frame_priority/override_vote_aggregator_unittest.cc",
"frame_priority/unittest_util.cc",
"frame_priority/unittest_util.h",
"graph/frame_node_impl_unittest.cc",
"graph/graph_impl_operations_unittest.cc",
"graph/graph_impl_unittest.cc",
......
......@@ -4,7 +4,7 @@
#include "components/performance_manager/public/frame_priority/frame_priority.h"
#include "components/performance_manager/frame_priority/unittest_util.h"
#include "components/performance_manager/test_support/frame_priority.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace performance_manager {
......@@ -93,12 +93,12 @@ TEST(FramePriorityTest, PriorityAndReason) {
// Comparison with identical priorities, and different reason strings.
PriorityAndReason par4(base::TaskPriority::LOWEST, kReason2);
EXPECT_FALSE(par1 == par2);
EXPECT_TRUE(par1 != par2);
EXPECT_TRUE(par1 <= par2);
EXPECT_FALSE(par1 >= par2);
EXPECT_TRUE(par1 < par2);
EXPECT_FALSE(par1 > par2);
EXPECT_FALSE(par1 == par4);
EXPECT_TRUE(par1 != par4);
EXPECT_TRUE(par1 <= par4);
EXPECT_FALSE(par1 >= par4);
EXPECT_TRUE(par1 < par4);
EXPECT_FALSE(par1 > par4);
// Copy constructor.
PriorityAndReason par5(par3);
......
......@@ -5,7 +5,7 @@
#include "components/performance_manager/public/frame_priority/max_vote_aggregator.h"
#include "base/rand_util.h"
#include "components/performance_manager/frame_priority/unittest_util.h"
#include "components/performance_manager/test_support/frame_priority.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace performance_manager {
......
......@@ -4,7 +4,7 @@
#include "components/performance_manager/public/frame_priority/override_vote_aggregator.h"
#include "components/performance_manager/frame_priority/unittest_util.h"
#include "components/performance_manager/test_support/frame_priority.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace performance_manager {
......
......@@ -14,6 +14,10 @@
namespace performance_manager {
// static
constexpr char FrameNodeImpl::kDefaultPriorityReason[] =
"default frame priority";
using PriorityAndReason = frame_priority::PriorityAndReason;
FrameNodeImpl::FrameNodeImpl(GraphImpl* graph,
......
......@@ -50,6 +50,7 @@ class FrameNodeImpl
public TypedNodeBase<FrameNodeImpl, FrameNode, FrameNodeObserver>,
public mojom::DocumentCoordinationUnit {
public:
static const char kDefaultPriorityReason[];
static constexpr NodeTypeEnum Type() { return NodeTypeEnum::kFrame; }
// Construct a frame node associated with a |process_node|, a |page_node| and
......@@ -120,6 +121,7 @@ class FrameNodeImpl
void SetPriorityAndReason(const PriorityAndReason& priority_and_reason);
private:
friend class FramePriorityAccess;
friend class PageNodeImpl;
friend class ProcessNodeImpl;
......@@ -247,11 +249,15 @@ class FrameNodeImpl
// The child workers of this frame.
base::flat_set<WorkerNodeImpl*> child_worker_nodes_;
// Frame priority information.
// Frame priority information. Set via FramePriorityDecorator.
ObservedProperty::NotifiesOnlyOnChanges<
PriorityAndReason,
&FrameNodeObserver::OnPriorityAndReasonChanged>
priority_and_reason_;
priority_and_reason_{PriorityAndReason(base::TaskPriority::LOWEST,
kDefaultPriorityReason)};
// Inline storage for FramePriorityDecorator data.
frame_priority::AcceptedVote accepted_vote_;
DISALLOW_COPY_AND_ASSIGN(FrameNodeImpl);
};
......
......@@ -270,10 +270,9 @@ TEST_F(FrameNodeImplTest, Priority) {
MockObserver obs;
graph()->AddFrameNodeObserver(&obs);
// By default the priority should be "lowest", and there should be no
// reason.
EXPECT_EQ(PriorityAndReason(base::TaskPriority::LOWEST, nullptr),
frame_node->priority_and_reason());
// By default the priority should be "lowest".
EXPECT_EQ(base::TaskPriority::LOWEST,
frame_node->priority_and_reason().priority());
// Changed the reason only.
static const char kDummyReason[] = "this is a reason!";
......
......@@ -84,7 +84,7 @@ int ReasonCompare(const char* reason1, const char* reason2);
class PriorityAndReason {
public:
PriorityAndReason() = default;
PriorityAndReason(base::TaskPriority priority, const char* reason)
constexpr PriorityAndReason(base::TaskPriority priority, const char* reason)
: priority_(priority), reason_(reason) {}
PriorityAndReason(const PriorityAndReason&) = default;
PriorityAndReason& operator=(const PriorityAndReason&) = default;
......
......@@ -8,6 +8,8 @@ source_set("test_support") {
testonly = true
sources = [
"frame_priority.cc",
"frame_priority.h",
"graph_impl.h",
"graph_test_harness.cc",
"graph_test_harness.h",
......
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/performance_manager/frame_priority/unittest_util.h"
#include "components/performance_manager/test_support/frame_priority.h"
#include "testing/gtest/include/gtest/gtest.h"
......
......@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_PERFORMANCE_MANAGER_FRAME_PRIORITY_UNITTEST_UTIL_H_
#define COMPONENTS_PERFORMANCE_MANAGER_FRAME_PRIORITY_UNITTEST_UTIL_H_
#ifndef COMPONENTS_PERFORMANCE_MANAGER_TEST_SUPPORT_FRAME_PRIORITY_H_
#define COMPONENTS_PERFORMANCE_MANAGER_TEST_SUPPORT_FRAME_PRIORITY_H_
#include "components/performance_manager/public/frame_priority/frame_priority.h"
......@@ -72,4 +72,4 @@ class DummyVoter {
} // namespace frame_priority
} // namespace performance_manager
#endif // COMPONENTS_PERFORMANCE_MANAGER_FRAME_PRIORITY_UNITTEST_UTIL_H_
#endif // COMPONENTS_PERFORMANCE_MANAGER_TEST_SUPPORT_FRAME_PRIORITY_H_
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