Commit 7420a23d authored by Patrick Monette's avatar Patrick Monette Committed by Chromium LUCI CQ

[PM] Add FrameAudibleVoter

This voter casts a USER_BLOCKING priority vote when a frame is audible.

Bug: 971272
Change-Id: Ic0b777a48451322e8685c3d19e7d95bab89fb273
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2542562
Commit-Queue: Patrick Monette <pmonette@chromium.org>
Reviewed-by: default avatarFrançois Doray <fdoray@chromium.org>
Cr-Commit-Position: refs/heads/master@{#833367}
parent 8a404890
......@@ -35,6 +35,8 @@ static_library("performance_manager") {
"execution_context_priority/execution_context_priority.cc",
"execution_context_priority/execution_context_priority_decorator.cc",
"execution_context_priority/execution_context_priority_decorator.h",
"execution_context_priority/frame_audible_voter.cc",
"execution_context_priority/frame_audible_voter.h",
"execution_context_priority/frame_visibility_voter.cc",
"execution_context_priority/frame_visibility_voter.h",
"execution_context_priority/max_vote_aggregator.cc",
......@@ -232,6 +234,7 @@ source_set("unit_tests") {
"execution_context_priority/ad_frame_voter_unittest.cc",
"execution_context_priority/boosting_vote_aggregator_unittest.cc",
"execution_context_priority/execution_context_priority_unittest.cc",
"execution_context_priority/frame_audible_voter_unittest.cc",
"execution_context_priority/frame_visibility_voter_unittest.cc",
"execution_context_priority/max_vote_aggregator_unittest.cc",
"execution_context_priority/override_vote_aggregator_unittest.cc",
......
......@@ -41,6 +41,8 @@ ExecutionContextPriorityDecorator::ExecutionContextPriorityDecorator() {
// Set up voters.
frame_visibility_voter_.SetVotingChannel(
max_vote_aggregator_.GetVotingChannel());
frame_audible_voter_.SetVotingChannel(
max_vote_aggregator_.GetVotingChannel());
}
ExecutionContextPriorityDecorator::~ExecutionContextPriorityDecorator() =
default;
......@@ -49,10 +51,12 @@ void ExecutionContextPriorityDecorator::OnPassedToGraph(Graph* graph) {
// Subscribe voters to the graph.
graph->AddFrameNodeObserver(&ad_frame_voter_);
graph->AddFrameNodeObserver(&frame_visibility_voter_);
graph->AddFrameNodeObserver(&frame_audible_voter_);
}
void ExecutionContextPriorityDecorator::OnTakenFromGraph(Graph* graph) {
// Unsubscribe voters from the graph.
graph->RemoveFrameNodeObserver(&frame_audible_voter_);
graph->RemoveFrameNodeObserver(&frame_visibility_voter_);
graph->RemoveFrameNodeObserver(&ad_frame_voter_);
}
......
......@@ -6,6 +6,7 @@
#define COMPONENTS_PERFORMANCE_MANAGER_EXECUTION_CONTEXT_PRIORITY_EXECUTION_CONTEXT_PRIORITY_DECORATOR_H_
#include "components/performance_manager/execution_context_priority/ad_frame_voter.h"
#include "components/performance_manager/execution_context_priority/frame_audible_voter.h"
#include "components/performance_manager/execution_context_priority/frame_visibility_voter.h"
#include "components/performance_manager/execution_context_priority/max_vote_aggregator.h"
#include "components/performance_manager/execution_context_priority/override_vote_aggregator.h"
......@@ -52,6 +53,9 @@ class ExecutionContextPriorityDecorator final : public GraphOwned {
// Casts a USER_VISIBLE vote when a frame is visible.
FrameVisibilityVoter frame_visibility_voter_;
// Casts a USER_VISIBLE vote when a frame is audible.
FrameAudibleVoter frame_audible_voter_;
};
} // namespace execution_context_priority
......
// Copyright 2020 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 "components/performance_manager/execution_context_priority/frame_audible_voter.h"
#include <utility>
#include "components/performance_manager/public/execution_context/execution_context_registry.h"
namespace performance_manager {
namespace execution_context_priority {
namespace {
const execution_context::ExecutionContext* GetExecutionContext(
const FrameNode* frame_node) {
return execution_context::ExecutionContextRegistry::GetFromGraph(
frame_node->GetGraph())
->GetExecutionContextForFrameNode(frame_node);
}
// Returns a vote with the appropriate priority depending on if the frame is
// audible.
Vote GetVote(bool is_audible) {
base::TaskPriority priority = is_audible ? base::TaskPriority::USER_BLOCKING
: base::TaskPriority::LOWEST;
return Vote(priority, FrameAudibleVoter::kFrameAudibleReason);
}
} // namespace
// static
const char FrameAudibleVoter::kFrameAudibleReason[] = "Frame audible.";
FrameAudibleVoter::FrameAudibleVoter() = default;
FrameAudibleVoter::~FrameAudibleVoter() = default;
void FrameAudibleVoter::SetVotingChannel(VotingChannel voting_channel) {
voting_channel_.SetVotingChannel(std::move(voting_channel));
}
void FrameAudibleVoter::OnFrameNodeAdded(const FrameNode* frame_node) {
const Vote vote = GetVote(frame_node->IsAudible());
voting_channel_.SubmitVote(GetExecutionContext(frame_node), vote);
}
void FrameAudibleVoter::OnBeforeFrameNodeRemoved(const FrameNode* frame_node) {
voting_channel_.InvalidateVote(GetExecutionContext(frame_node));
}
void FrameAudibleVoter::OnIsAudibleChanged(const FrameNode* frame_node) {
const Vote new_vote = GetVote(frame_node->IsAudible());
voting_channel_.ChangeVote(GetExecutionContext(frame_node), new_vote);
}
} // namespace execution_context_priority
} // namespace performance_manager
// Copyright 2020 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 COMPONENTS_PERFORMANCE_MANAGER_EXECUTION_CONTEXT_PRIORITY_FRAME_AUDIBLE_VOTER_H_
#define COMPONENTS_PERFORMANCE_MANAGER_EXECUTION_CONTEXT_PRIORITY_FRAME_AUDIBLE_VOTER_H_
#include "components/performance_manager/public/execution_context_priority/execution_context_priority.h"
#include "components/performance_manager/public/graph/frame_node.h"
namespace performance_manager {
namespace execution_context_priority {
// This voter casts a TaskPriority::USER_VISIBLE vote to all audible frames, and
// a TaskPriority::LOWEST vote to non-audible frames.
class FrameAudibleVoter : public FrameNode::ObserverDefaultImpl {
public:
static const char kFrameAudibleReason[];
FrameAudibleVoter();
~FrameAudibleVoter() override;
FrameAudibleVoter(const FrameAudibleVoter&) = delete;
FrameAudibleVoter& operator=(const FrameAudibleVoter&) = delete;
// Sets the voting channel where the votes will be cast.
void SetVotingChannel(VotingChannel voting_channel);
// FrameNodeObserver:
void OnFrameNodeAdded(const FrameNode* frame_node) override;
void OnBeforeFrameNodeRemoved(const FrameNode* frame_node) override;
void OnIsAudibleChanged(const FrameNode* frame_node) override;
private:
VotingChannelWrapper voting_channel_;
};
} // namespace execution_context_priority
} // namespace performance_manager
#endif // COMPONENTS_PERFORMANCE_MANAGER_EXECUTION_CONTEXT_PRIORITY_FRAME_AUDIBLE_VOTER_H_
// Copyright 2020 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 "components/performance_manager/execution_context_priority/frame_audible_voter.h"
#include "components/performance_manager/execution_context/execution_context_registry_impl.h"
#include "components/performance_manager/public/execution_context/execution_context.h"
#include "components/performance_manager/public/graph/graph.h"
#include "components/performance_manager/test_support/graph_test_harness.h"
#include "components/performance_manager/test_support/mock_graphs.h"
#include "components/performance_manager/test_support/voting.h"
namespace performance_manager {
namespace execution_context_priority {
using DummyVoteObserver = voting::test::DummyVoteObserver<Vote>;
namespace {
const execution_context::ExecutionContext* GetExecutionContext(
const FrameNode* frame_node) {
return execution_context::ExecutionContextRegistry::GetFromGraph(
frame_node->GetGraph())
->GetExecutionContextForFrameNode(frame_node);
}
// Both the voting channel and the FrameAudibleVoter are expected live on the
// graph, without being actual GraphOwned objects. This class wraps both to
// allow this.
class GraphOwnedWrapper : public GraphOwned {
public:
GraphOwnedWrapper() {
VotingChannel voting_channel = observer_.BuildVotingChannel();
voter_id_ = voting_channel.voter_id();
frame_audible_voter_.SetVotingChannel(std::move(voting_channel));
}
~GraphOwnedWrapper() override = default;
GraphOwnedWrapper(const GraphOwnedWrapper&) = delete;
GraphOwnedWrapper& operator=(const GraphOwnedWrapper&) = delete;
// GraphOwned:
void OnPassedToGraph(Graph* graph) override {
graph->AddFrameNodeObserver(&frame_audible_voter_);
}
void OnTakenFromGraph(Graph* graph) override {
graph->RemoveFrameNodeObserver(&frame_audible_voter_);
}
// Exposes the DummyVoteObserver to validate expectations.
const DummyVoteObserver& observer() const { return observer_; }
VoterId voter_id() const { return voter_id_; }
private:
DummyVoteObserver observer_;
FrameAudibleVoter frame_audible_voter_;
VoterId voter_id_;
};
} // namespace
class FrameAudibleVoterTest : public GraphTestHarness {
public:
FrameAudibleVoterTest() = default;
~FrameAudibleVoterTest() override = default;
FrameAudibleVoterTest(const FrameAudibleVoterTest&) = delete;
FrameAudibleVoterTest& operator=(const FrameAudibleVoterTest&) = delete;
void SetUp() override {
graph()->PassToGraph(
std::make_unique<execution_context::ExecutionContextRegistryImpl>());
auto wrapper = std::make_unique<GraphOwnedWrapper>();
wrapper_ = wrapper.get();
graph()->PassToGraph(std::move(wrapper));
}
// Exposes the DummyVoteObserver to validate expectations.
const DummyVoteObserver& observer() const { return wrapper_->observer(); }
VoterId voter_id() const { return wrapper_->voter_id(); }
private:
GraphOwnedWrapper* wrapper_ = nullptr;
};
// Tests that the FrameAudibleVoter correctly casts a vote for a frame
// depending on its audible state.
TEST_F(FrameAudibleVoterTest, AudibleChanged) {
// Create a graph with a single frame page. Its initial audible state should
// be false, resulting in a low priority.
MockSinglePageInSingleProcessGraph mock_graph(graph());
auto& frame_node = mock_graph.frame;
EXPECT_FALSE(frame_node->is_audible());
EXPECT_EQ(observer().GetVoteCount(), 1u);
EXPECT_TRUE(observer().HasVote(
voter_id(), GetExecutionContext(frame_node.get()),
base::TaskPriority::LOWEST, FrameAudibleVoter::kFrameAudibleReason));
// Make the frame visible. This should increase the priority.
mock_graph.frame->SetIsAudible(true);
EXPECT_EQ(observer().GetVoteCount(), 1u);
EXPECT_TRUE(observer().HasVote(voter_id(),
GetExecutionContext(frame_node.get()),
base::TaskPriority::USER_BLOCKING,
FrameAudibleVoter::kFrameAudibleReason));
// Deleting the frame should invalidate the vote.
frame_node.reset();
EXPECT_EQ(observer().GetVoteCount(), 0u);
}
} // namespace execution_context_priority
} // namespace performance_manager
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