inherit_client_priority_voter_unittest.cc 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. // Copyright 2020 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "components/performance_manager/execution_context_priority/inherit_client_priority_voter.h"
  5. #include "base/memory/raw_ptr.h"
  6. #include "components/performance_manager/execution_context/execution_context_registry_impl.h"
  7. #include "components/performance_manager/execution_context_priority/root_vote_observer.h"
  8. #include "components/performance_manager/public/execution_context/execution_context.h"
  9. #include "components/performance_manager/public/graph/graph.h"
  10. #include "components/performance_manager/test_support/graph_test_harness.h"
  11. #include "components/performance_manager/test_support/mock_graphs.h"
  12. #include "components/performance_manager/test_support/test_worker_node_factory.h"
  13. #include "components/performance_manager/test_support/voting.h"
  14. namespace performance_manager {
  15. namespace execution_context_priority {
  16. using DummyVoteObserver = voting::test::DummyVoteObserver<Vote>;
  17. namespace {
  18. const execution_context::ExecutionContext* GetExecutionContext(
  19. const WorkerNode* worker_node) {
  20. return execution_context::ExecutionContextRegistry::GetFromGraph(
  21. worker_node->GetGraph())
  22. ->GetExecutionContextForWorkerNode(worker_node);
  23. }
  24. // All voting system components are expected to live on the graph, without being
  25. // actual GraphOwned objects. This class wraps them to allow this.
  26. class GraphOwnedWrapper : public GraphOwned {
  27. public:
  28. GraphOwnedWrapper() {
  29. VotingChannel voting_channel = dummy_vote_observer_.BuildVotingChannel();
  30. voter_id_ = voting_channel.voter_id();
  31. inherit_client_priority_voter_.SetVotingChannel(std::move(voting_channel));
  32. }
  33. GraphOwnedWrapper(const GraphOwnedWrapper&) = delete;
  34. GraphOwnedWrapper& operator=(const GraphOwnedWrapper&) = delete;
  35. // GraphOwned:
  36. void OnPassedToGraph(Graph* graph) override {
  37. graph->AddFrameNodeObserver(&inherit_client_priority_voter_);
  38. graph->AddWorkerNodeObserver(&inherit_client_priority_voter_);
  39. }
  40. void OnTakenFromGraph(Graph* graph) override {
  41. graph->RemoveWorkerNodeObserver(&inherit_client_priority_voter_);
  42. graph->RemoveFrameNodeObserver(&inherit_client_priority_voter_);
  43. }
  44. // Exposes the vote observer to validate expectations.
  45. const DummyVoteObserver& observer() const { return dummy_vote_observer_; }
  46. VoterId voter_id() { return voter_id_; }
  47. private:
  48. DummyVoteObserver dummy_vote_observer_;
  49. InheritClientPriorityVoter inherit_client_priority_voter_;
  50. // The VoterId of |inherit_client_priority_voter_|.
  51. VoterId voter_id_;
  52. };
  53. } // namespace
  54. class InheritClientPriorityVoterTest : public GraphTestHarness {
  55. public:
  56. using Super = GraphTestHarness;
  57. void SetUp() override {
  58. Super::SetUp();
  59. graph()->PassToGraph(
  60. std::make_unique<execution_context::ExecutionContextRegistryImpl>());
  61. auto wrapper = std::make_unique<GraphOwnedWrapper>();
  62. wrapper_ = wrapper.get();
  63. graph()->PassToGraph(std::move(wrapper));
  64. }
  65. // Exposes the DummyVoteObserver to validate expectations.
  66. const DummyVoteObserver& observer() const { return wrapper_->observer(); }
  67. VoterId voter_id() { return wrapper_->voter_id(); }
  68. private:
  69. raw_ptr<GraphOwnedWrapper> wrapper_ = nullptr;
  70. };
  71. TEST_F(InheritClientPriorityVoterTest, OneWorker) {
  72. MockSinglePageInSingleProcessGraph mock_graph(graph());
  73. TestWorkerNodeFactory test_worker_node_factory_(graph());
  74. ProcessNodeImpl* process_node = mock_graph.process.get();
  75. FrameNodeImpl* frame_node = mock_graph.frame.get();
  76. EXPECT_EQ(observer().GetVoteCount(), 0u);
  77. // Create the worker. A vote will be submitted to inherit the (currently
  78. // default) priority of its client.
  79. WorkerNodeImpl* worker_node =
  80. test_worker_node_factory_.CreateDedicatedWorker(process_node, frame_node);
  81. EXPECT_EQ(observer().GetVoteCount(), 1u);
  82. EXPECT_TRUE(observer().HasVote(
  83. voter_id(), GetExecutionContext(worker_node), base::TaskPriority::LOWEST,
  84. InheritClientPriorityVoter::kPriorityInheritedReason));
  85. // Test that changing the priority for the frame also changes the inherited
  86. // vote.
  87. frame_node->SetPriorityAndReason(
  88. {base::TaskPriority::USER_VISIBLE, "Some reason"});
  89. EXPECT_EQ(observer().GetVoteCount(), 1u);
  90. EXPECT_TRUE(
  91. observer().HasVote(voter_id(), GetExecutionContext(worker_node),
  92. base::TaskPriority::USER_VISIBLE,
  93. InheritClientPriorityVoter::kPriorityInheritedReason));
  94. // Removing the worker also removes the inherited vote.
  95. test_worker_node_factory_.DeleteWorker(worker_node);
  96. EXPECT_EQ(observer().GetVoteCount(), 0u);
  97. }
  98. // A vote is submitted to all children.
  99. TEST_F(InheritClientPriorityVoterTest, MultipleWorkers) {
  100. MockSinglePageInSingleProcessGraph mock_graph(graph());
  101. TestWorkerNodeFactory test_worker_node_factory_(graph());
  102. ProcessNodeImpl* process_node = mock_graph.process.get();
  103. FrameNodeImpl* frame_node = mock_graph.frame.get();
  104. // Set the priority of the frame node.
  105. frame_node->SetPriorityAndReason(
  106. {base::TaskPriority::USER_VISIBLE, "Some reason"});
  107. EXPECT_EQ(observer().GetVoteCount(), 0u);
  108. // Create multiple workers with the same client.
  109. WorkerNodeImpl* worker_node_1 =
  110. test_worker_node_factory_.CreateDedicatedWorker(process_node, frame_node);
  111. WorkerNodeImpl* worker_node_2 =
  112. test_worker_node_factory_.CreateDedicatedWorker(process_node, frame_node);
  113. EXPECT_EQ(observer().GetVoteCount(), 2u);
  114. EXPECT_TRUE(
  115. observer().HasVote(voter_id(), GetExecutionContext(worker_node_1),
  116. base::TaskPriority::USER_VISIBLE,
  117. InheritClientPriorityVoter::kPriorityInheritedReason));
  118. EXPECT_TRUE(
  119. observer().HasVote(voter_id(), GetExecutionContext(worker_node_2),
  120. base::TaskPriority::USER_VISIBLE,
  121. InheritClientPriorityVoter::kPriorityInheritedReason));
  122. }
  123. // Tests that the priority is recursively inherited down a worker tree.
  124. TEST_F(InheritClientPriorityVoterTest, DeepWorkerTree) {
  125. constexpr size_t kTreeDepth = 20;
  126. MockSinglePageInSingleProcessGraph mock_graph(graph());
  127. TestWorkerNodeFactory test_worker_node_factory_(graph());
  128. ProcessNodeImpl* process_node = mock_graph.process.get();
  129. FrameNodeImpl* frame_node = mock_graph.frame.get();
  130. // Set the priority of the frame node.
  131. frame_node->SetPriorityAndReason(
  132. {base::TaskPriority::USER_VISIBLE, "Some reason"});
  133. std::vector<WorkerNodeImpl*> worker_nodes;
  134. worker_nodes.reserve(kTreeDepth);
  135. // Create the first worker. Its client is the only frame.
  136. worker_nodes.push_back(test_worker_node_factory_.CreateDedicatedWorker(
  137. process_node, frame_node));
  138. // The ExecutionContextPriorityDecorator is not hooked up in this test suite
  139. // so the priority is not actually inherited by the node. Set the priority
  140. // manually to at least ensure that the vote contains a non-default value.
  141. worker_nodes.back()->SetPriorityAndReason(
  142. {base::TaskPriority::USER_VISIBLE, "Some reason"});
  143. // Create the other workers, where each of them is the child of the last
  144. // created worker.
  145. for (size_t i = 0; i < kTreeDepth - 1; i++) {
  146. worker_nodes.push_back(test_worker_node_factory_.CreateDedicatedWorker(
  147. process_node, worker_nodes.back()));
  148. worker_nodes.back()->SetPriorityAndReason(
  149. {base::TaskPriority::USER_VISIBLE, "Some reason"});
  150. }
  151. EXPECT_EQ(observer().GetVoteCount(), kTreeDepth);
  152. for (WorkerNodeImpl* worker_node : worker_nodes) {
  153. ASSERT_TRUE(observer().HasVote(
  154. voter_id(), GetExecutionContext(worker_node),
  155. base::TaskPriority::USER_VISIBLE,
  156. InheritClientPriorityVoter::kPriorityInheritedReason));
  157. }
  158. }
  159. // Each client contributes a vote to a worker. Those votes are aggregated to a
  160. // single vote.
  161. TEST_F(InheritClientPriorityVoterTest, MultipleClients) {
  162. MockSinglePageWithMultipleProcessesGraph mock_graph(graph());
  163. TestWorkerNodeFactory test_worker_node_factory_(graph());
  164. ProcessNodeImpl* process_node = mock_graph.process.get();
  165. FrameNodeImpl* frame_node_1 = mock_graph.frame.get();
  166. FrameNodeImpl* frame_node_2 = mock_graph.child_frame.get();
  167. EXPECT_EQ(observer().GetVoteCount(), 0u);
  168. // Create a worker with multiple clients.
  169. WorkerNodeImpl* worker_node = test_worker_node_factory_.CreateSharedWorker(
  170. process_node, {frame_node_1, frame_node_2});
  171. EXPECT_EQ(observer().GetVoteCount(), 1u);
  172. EXPECT_TRUE(observer().HasVote(
  173. voter_id(), GetExecutionContext(worker_node), base::TaskPriority::LOWEST,
  174. InheritClientPriorityVoter::kPriorityInheritedReason));
  175. // Change the priority of the first client.
  176. frame_node_1->SetPriorityAndReason(
  177. {base::TaskPriority::USER_VISIBLE, "Some reason"});
  178. EXPECT_EQ(observer().GetVoteCount(), 1u);
  179. EXPECT_TRUE(
  180. observer().HasVote(voter_id(), GetExecutionContext(worker_node),
  181. base::TaskPriority::USER_VISIBLE,
  182. InheritClientPriorityVoter::kPriorityInheritedReason));
  183. // Change the priority of the second client.
  184. frame_node_2->SetPriorityAndReason(
  185. {base::TaskPriority::USER_BLOCKING, "Some reason"});
  186. EXPECT_EQ(observer().GetVoteCount(), 1u);
  187. EXPECT_TRUE(
  188. observer().HasVote(voter_id(), GetExecutionContext(worker_node),
  189. base::TaskPriority::USER_BLOCKING,
  190. InheritClientPriorityVoter::kPriorityInheritedReason));
  191. }
  192. } // namespace execution_context_priority
  193. } // namespace performance_manager