boosting_vote_aggregator_unittest.cc 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600
  1. // Copyright 2019 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/boosting_vote_aggregator.h"
  5. #include "components/performance_manager/test_support/voting.h"
  6. #include "testing/gtest/include/gtest/gtest.h"
  7. namespace performance_manager {
  8. namespace execution_context_priority {
  9. namespace {
  10. using DummyVoteObserver = voting::test::DummyVoteObserver<Vote>;
  11. // Some dummy execution contexts.
  12. const ExecutionContext* kExecutionContext0 =
  13. reinterpret_cast<const ExecutionContext*>(0xF5A33000);
  14. const ExecutionContext* kExecutionContext1 =
  15. reinterpret_cast<const ExecutionContext*>(0xF5A33001);
  16. const ExecutionContext* kExecutionContext2 =
  17. reinterpret_cast<const ExecutionContext*>(0xF5A33002);
  18. const ExecutionContext* kExecutionContext3 =
  19. reinterpret_cast<const ExecutionContext*>(0xF5A33003);
  20. const ExecutionContext* kExecutionContext4 =
  21. reinterpret_cast<const ExecutionContext*>(0xF5A33004);
  22. static const char kReasonBoost[] = "boosted!";
  23. static const Vote kLowPriorityVote0(base::TaskPriority::LOWEST, "low reason 0");
  24. static const Vote kLowPriorityVote1(base::TaskPriority::LOWEST, "low reason 1");
  25. static const Vote kMediumPriorityVote0(base::TaskPriority::USER_VISIBLE,
  26. "medium reason 0");
  27. static const Vote kMediumPriorityVote1(base::TaskPriority::USER_VISIBLE,
  28. "medium reason 1");
  29. static const Vote kHighPriorityVote0(base::TaskPriority::HIGHEST,
  30. "high reason 0");
  31. static const Vote kHighPriorityVote1(base::TaskPriority::HIGHEST,
  32. "high reason 1");
  33. class TestBoostingVoteAggregator : public BoostingVoteAggregator {
  34. public:
  35. using BoostingVoteAggregator::forward_edges_;
  36. using BoostingVoteAggregator::NodeData;
  37. using BoostingVoteAggregator::nodes_;
  38. using BoostingVoteAggregator::reverse_edges_;
  39. };
  40. using NodeData = TestBoostingVoteAggregator::NodeData;
  41. class BoostingVoteAggregatorTest : public testing::Test {
  42. public:
  43. void SetUp() override {
  44. // Set up |aggregator_| so that it upstreams votes to |observer_|.
  45. auto channel = observer_.BuildVotingChannel();
  46. aggregator_voter_id_ = channel.voter_id();
  47. aggregator_.SetUpstreamVotingChannel(std::move(channel));
  48. voter_ = aggregator_.GetVotingChannel();
  49. EXPECT_TRUE(aggregator_.nodes_.empty());
  50. EXPECT_TRUE(aggregator_.forward_edges_.empty());
  51. EXPECT_TRUE(aggregator_.reverse_edges_.empty());
  52. }
  53. VoterId aggregator_voter_id() const { return aggregator_voter_id_; }
  54. const DummyVoteObserver& observer() const { return observer_; }
  55. TestBoostingVoteAggregator* aggregator() { return &aggregator_; }
  56. VotingChannel* voter() { return &voter_; }
  57. void ExpectEdges(size_t count) {
  58. EXPECT_EQ(count, aggregator_.forward_edges_.size());
  59. EXPECT_EQ(count, aggregator_.reverse_edges_.size());
  60. }
  61. void ExpectIsActive(const NodeData& node_data,
  62. bool mid_priority,
  63. bool high_priority) {
  64. EXPECT_EQ(mid_priority, node_data.IsActive(1));
  65. EXPECT_EQ(high_priority, node_data.IsActive(2));
  66. }
  67. private:
  68. // The id of |aggregator_| as seen by its upstream |observer_|.
  69. voting::VoterId<Vote> aggregator_voter_id_;
  70. DummyVoteObserver observer_;
  71. TestBoostingVoteAggregator aggregator_;
  72. VotingChannel voter_;
  73. };
  74. } // namespace
  75. TEST_F(BoostingVoteAggregatorTest, VotesUpstreamingWorks) {
  76. EXPECT_FALSE(observer().HasVote(aggregator_voter_id(), kExecutionContext0));
  77. // Submit a default vote to the boosting aggregator, and expect it not to be
  78. // upstreamed.
  79. voter()->SubmitVote(kExecutionContext0, kLowPriorityVote0);
  80. EXPECT_EQ(observer().GetVoteCount(), 0u);
  81. EXPECT_FALSE(observer().HasVote(aggregator_voter_id(), kExecutionContext0));
  82. // Change the priority to a non-default one..
  83. voter()->ChangeVote(kExecutionContext0, kHighPriorityVote0);
  84. EXPECT_EQ(observer().GetVoteCount(), 1u);
  85. EXPECT_TRUE(observer().HasVote(aggregator_voter_id(), kExecutionContext0,
  86. kHighPriorityVote0));
  87. // Change only the reason.
  88. voter()->ChangeVote(kExecutionContext0, kHighPriorityVote1);
  89. EXPECT_EQ(observer().GetVoteCount(), 1u);
  90. EXPECT_TRUE(observer().HasVote(aggregator_voter_id(), kExecutionContext0,
  91. kHighPriorityVote1));
  92. // Add a non-default vote for a different execution context.
  93. voter()->SubmitVote(kExecutionContext1, kMediumPriorityVote0);
  94. EXPECT_EQ(observer().GetVoteCount(), 2u);
  95. EXPECT_TRUE(observer().HasVote(aggregator_voter_id(), kExecutionContext0,
  96. kHighPriorityVote1));
  97. EXPECT_TRUE(observer().HasVote(aggregator_voter_id(), kExecutionContext1,
  98. kMediumPriorityVote0));
  99. // Change the vote for the second execution context to another non-default
  100. // value.
  101. voter()->ChangeVote(kExecutionContext1, kHighPriorityVote0);
  102. EXPECT_EQ(observer().GetVoteCount(), 2u);
  103. EXPECT_TRUE(observer().HasVote(aggregator_voter_id(), kExecutionContext0,
  104. kHighPriorityVote1));
  105. EXPECT_TRUE(observer().HasVote(aggregator_voter_id(), kExecutionContext1,
  106. kHighPriorityVote0));
  107. // Change the vote for the second execution context to the default vote value
  108. // and expect it to be invalidated upstream.
  109. voter()->ChangeVote(kExecutionContext1, kLowPriorityVote1);
  110. EXPECT_EQ(observer().GetVoteCount(), 1u);
  111. EXPECT_TRUE(observer().HasVote(aggregator_voter_id(), kExecutionContext0,
  112. kHighPriorityVote1));
  113. EXPECT_FALSE(observer().HasVote(aggregator_voter_id(), kExecutionContext1));
  114. // Invalidate vote for the first execution context.
  115. voter()->InvalidateVote(kExecutionContext0);
  116. EXPECT_EQ(observer().GetVoteCount(), 0u);
  117. EXPECT_FALSE(observer().HasVote(aggregator_voter_id(), kExecutionContext0));
  118. EXPECT_FALSE(observer().HasVote(aggregator_voter_id(), kExecutionContext0));
  119. // Then the second.
  120. voter()->InvalidateVote(kExecutionContext1);
  121. EXPECT_EQ(observer().GetVoteCount(), 0u);
  122. EXPECT_FALSE(observer().HasVote(aggregator_voter_id(), kExecutionContext0));
  123. EXPECT_FALSE(observer().HasVote(aggregator_voter_id(), kExecutionContext0));
  124. }
  125. TEST_F(BoostingVoteAggregatorTest, BoostingWorks) {
  126. // Add a boosting vote, with no actual incoming votes. This should produce
  127. // the two nodes associated with the edge but not upstream any votes.
  128. BoostingVote boost01a(aggregator(), kExecutionContext0, kExecutionContext1,
  129. kReasonBoost);
  130. const auto& data0 = aggregator()->nodes_.find(kExecutionContext0)->second;
  131. const auto& data1 = aggregator()->nodes_.find(kExecutionContext1)->second;
  132. ExpectEdges(1);
  133. EXPECT_EQ(observer().GetVoteCount(), 0u);
  134. EXPECT_EQ(2u, aggregator()->nodes_.size());
  135. EXPECT_EQ(1u, data0.edge_count_for_testing());
  136. EXPECT_EQ(1u, data1.edge_count_for_testing());
  137. ExpectIsActive(data0, false, false);
  138. ExpectIsActive(data1, false, false);
  139. // Create a second boosting vote. This duplicates the edge.
  140. BoostingVote boost01b(aggregator(), kExecutionContext0, kExecutionContext1,
  141. kReasonBoost);
  142. ExpectEdges(1);
  143. EXPECT_EQ(observer().GetVoteCount(), 0u);
  144. EXPECT_EQ(2u, aggregator()->nodes_.size());
  145. EXPECT_EQ(1u, data0.edge_count_for_testing());
  146. EXPECT_EQ(1u, data1.edge_count_for_testing());
  147. ExpectIsActive(data0, false, false);
  148. ExpectIsActive(data1, false, false);
  149. // Create a mid priority vote for execution context 1. This should cause a
  150. // single vote to be emitted for that node.
  151. voter()->SubmitVote(kExecutionContext1, kMediumPriorityVote1);
  152. EXPECT_EQ(2u, aggregator()->nodes_.size());
  153. ExpectEdges(1);
  154. EXPECT_EQ(observer().GetVoteCount(), 1u);
  155. EXPECT_TRUE(observer().HasVote(aggregator_voter_id(), kExecutionContext1,
  156. kMediumPriorityVote1));
  157. EXPECT_EQ(1u, data0.edge_count_for_testing());
  158. EXPECT_EQ(1u, data1.edge_count_for_testing());
  159. ExpectIsActive(data0, false, false);
  160. ExpectIsActive(data1, true, false);
  161. // Create a mid priority vote for execution context 0. This should cause
  162. // another vote to be emitted.
  163. voter()->SubmitVote(kExecutionContext0, kMediumPriorityVote0);
  164. EXPECT_EQ(2u, aggregator()->nodes_.size());
  165. ExpectEdges(1);
  166. EXPECT_EQ(observer().GetVoteCount(), 2u);
  167. EXPECT_TRUE(observer().HasVote(aggregator_voter_id(), kExecutionContext0,
  168. kMediumPriorityVote0));
  169. EXPECT_TRUE(observer().HasVote(aggregator_voter_id(), kExecutionContext1,
  170. kMediumPriorityVote1));
  171. EXPECT_EQ(1u, data0.edge_count_for_testing());
  172. EXPECT_EQ(1u, data1.edge_count_for_testing());
  173. ExpectIsActive(data0, true, false);
  174. ExpectIsActive(data1, true, false);
  175. // Cancel the priority 1 vote for execution context 1. The boosting should
  176. // maintain the output priority for that node.
  177. voter()->InvalidateVote(kExecutionContext1);
  178. EXPECT_EQ(2u, aggregator()->nodes_.size());
  179. ExpectEdges(1);
  180. EXPECT_EQ(observer().GetVoteCount(), 2u);
  181. EXPECT_TRUE(observer().HasVote(aggregator_voter_id(), kExecutionContext0,
  182. kMediumPriorityVote0));
  183. EXPECT_TRUE(observer().HasVote(aggregator_voter_id(), kExecutionContext1,
  184. kMediumPriorityVote0.value(), kReasonBoost));
  185. EXPECT_EQ(1u, data0.edge_count_for_testing());
  186. EXPECT_EQ(1u, data1.edge_count_for_testing());
  187. ExpectIsActive(data0, true, false);
  188. ExpectIsActive(data1, true, false);
  189. // Create a default vote for a third execution context. Other than creating
  190. // the node data and the vote this shouldn't do anything.
  191. voter()->SubmitVote(kExecutionContext2, kLowPriorityVote0);
  192. const auto& data2 = aggregator()->nodes_.find(kExecutionContext2)->second;
  193. EXPECT_EQ(3u, aggregator()->nodes_.size());
  194. ExpectEdges(1);
  195. EXPECT_EQ(observer().GetVoteCount(), 2u);
  196. EXPECT_TRUE(observer().HasVote(aggregator_voter_id(), kExecutionContext0,
  197. kMediumPriorityVote0));
  198. EXPECT_TRUE(observer().HasVote(aggregator_voter_id(), kExecutionContext1,
  199. kMediumPriorityVote0.value(), kReasonBoost));
  200. EXPECT_EQ(1u, data0.edge_count_for_testing());
  201. EXPECT_EQ(1u, data1.edge_count_for_testing());
  202. EXPECT_EQ(0u, data2.edge_count_for_testing());
  203. ExpectIsActive(data0, true, false);
  204. ExpectIsActive(data1, true, false);
  205. ExpectIsActive(data2, false, false);
  206. // Create a boosting vote from execution context 2 to execution context 0.
  207. // This should create an edge.
  208. BoostingVote boost20(aggregator(), kExecutionContext2, kExecutionContext0,
  209. kReasonBoost);
  210. EXPECT_EQ(3u, aggregator()->nodes_.size());
  211. ExpectEdges(2);
  212. EXPECT_EQ(observer().GetVoteCount(), 2u);
  213. EXPECT_TRUE(observer().HasVote(aggregator_voter_id(), kExecutionContext0,
  214. kMediumPriorityVote0));
  215. EXPECT_TRUE(observer().HasVote(aggregator_voter_id(), kExecutionContext1,
  216. kMediumPriorityVote0.value(), kReasonBoost));
  217. EXPECT_EQ(2u, data0.edge_count_for_testing());
  218. EXPECT_EQ(1u, data1.edge_count_for_testing());
  219. EXPECT_EQ(1u, data2.edge_count_for_testing());
  220. ExpectIsActive(data0, true, false);
  221. ExpectIsActive(data1, true, false);
  222. ExpectIsActive(data2, false, false);
  223. // Change the vote for execution context 2 to a higher one. This should boost
  224. // execution contexts 0 and 1 as well.
  225. voter()->ChangeVote(kExecutionContext2, kHighPriorityVote0);
  226. EXPECT_EQ(3u, aggregator()->nodes_.size());
  227. ExpectEdges(2);
  228. EXPECT_EQ(observer().GetVoteCount(), 3u);
  229. EXPECT_TRUE(observer().HasVote(aggregator_voter_id(), kExecutionContext0,
  230. kHighPriorityVote0.value(), kReasonBoost));
  231. EXPECT_TRUE(observer().HasVote(aggregator_voter_id(), kExecutionContext1,
  232. kHighPriorityVote0.value(), kReasonBoost));
  233. EXPECT_TRUE(observer().HasVote(aggregator_voter_id(), kExecutionContext2,
  234. kHighPriorityVote0));
  235. EXPECT_EQ(2u, data0.edge_count_for_testing());
  236. EXPECT_EQ(1u, data1.edge_count_for_testing());
  237. EXPECT_EQ(1u, data2.edge_count_for_testing());
  238. ExpectIsActive(data0, true, true);
  239. ExpectIsActive(data1, true, true);
  240. ExpectIsActive(data2, false, true);
  241. // Emit a highest priority vote for execution context 1. This should change
  242. // the vote reason.
  243. voter()->SubmitVote(kExecutionContext1, kHighPriorityVote1);
  244. EXPECT_EQ(3u, aggregator()->nodes_.size());
  245. ExpectEdges(2);
  246. EXPECT_EQ(observer().GetVoteCount(), 3u);
  247. EXPECT_TRUE(observer().HasVote(aggregator_voter_id(), kExecutionContext0,
  248. kHighPriorityVote0.value(), kReasonBoost));
  249. EXPECT_TRUE(observer().HasVote(aggregator_voter_id(), kExecutionContext1,
  250. kHighPriorityVote1));
  251. EXPECT_TRUE(observer().HasVote(aggregator_voter_id(), kExecutionContext2,
  252. kHighPriorityVote0));
  253. EXPECT_EQ(2u, data0.edge_count_for_testing());
  254. EXPECT_EQ(1u, data1.edge_count_for_testing());
  255. EXPECT_EQ(1u, data2.edge_count_for_testing());
  256. ExpectIsActive(data0, true, true);
  257. ExpectIsActive(data1, true, true);
  258. ExpectIsActive(data2, false, true);
  259. // Kill the vote for execution context 2. This should kill the upstream vote
  260. // for execution context 2 entirely, reduce the priority of execution context
  261. // 0, and keep execution context 1 the same.
  262. voter()->InvalidateVote(kExecutionContext2);
  263. EXPECT_EQ(3u, aggregator()->nodes_.size());
  264. ExpectEdges(2);
  265. EXPECT_EQ(observer().GetVoteCount(), 2u);
  266. EXPECT_TRUE(observer().HasVote(aggregator_voter_id(), kExecutionContext0,
  267. kMediumPriorityVote0));
  268. EXPECT_TRUE(observer().HasVote(aggregator_voter_id(), kExecutionContext1,
  269. kHighPriorityVote1));
  270. EXPECT_FALSE(observer().HasVote(aggregator_voter_id(), kExecutionContext2));
  271. EXPECT_EQ(2u, data0.edge_count_for_testing());
  272. EXPECT_EQ(1u, data1.edge_count_for_testing());
  273. EXPECT_EQ(1u, data2.edge_count_for_testing());
  274. ExpectIsActive(data0, true, false);
  275. ExpectIsActive(data1, true, true);
  276. ExpectIsActive(data2, false, false);
  277. // Kill the direct vote for execution context 1 so it goes back to being
  278. // boosted by execution context 0.
  279. voter()->InvalidateVote(kExecutionContext1);
  280. EXPECT_EQ(3u, aggregator()->nodes_.size());
  281. ExpectEdges(2);
  282. EXPECT_EQ(observer().GetVoteCount(), 2u);
  283. EXPECT_TRUE(observer().HasVote(aggregator_voter_id(), kExecutionContext0,
  284. kMediumPriorityVote0));
  285. EXPECT_TRUE(observer().HasVote(aggregator_voter_id(), kExecutionContext1,
  286. kMediumPriorityVote0.value(), kReasonBoost));
  287. EXPECT_FALSE(observer().HasVote(aggregator_voter_id(), kExecutionContext2));
  288. EXPECT_EQ(2u, data0.edge_count_for_testing());
  289. EXPECT_EQ(1u, data1.edge_count_for_testing());
  290. EXPECT_EQ(1u, data2.edge_count_for_testing());
  291. ExpectIsActive(data0, true, false);
  292. ExpectIsActive(data1, true, false);
  293. ExpectIsActive(data2, false, false);
  294. // Kill the first boosting vote from 0 to 1. This should do nothing but change
  295. // the multiplicity of the edge.
  296. boost01a.Reset();
  297. EXPECT_EQ(3u, aggregator()->nodes_.size());
  298. ExpectEdges(2);
  299. EXPECT_EQ(observer().GetVoteCount(), 2u);
  300. EXPECT_TRUE(observer().HasVote(aggregator_voter_id(), kExecutionContext0,
  301. kMediumPriorityVote0));
  302. EXPECT_TRUE(observer().HasVote(aggregator_voter_id(), kExecutionContext1,
  303. kMediumPriorityVote0.value(), kReasonBoost));
  304. EXPECT_FALSE(observer().HasVote(aggregator_voter_id(), kExecutionContext2));
  305. EXPECT_EQ(2u, data0.edge_count_for_testing());
  306. EXPECT_EQ(1u, data1.edge_count_for_testing());
  307. EXPECT_EQ(1u, data2.edge_count_for_testing());
  308. ExpectIsActive(data0, true, false);
  309. ExpectIsActive(data1, true, false);
  310. ExpectIsActive(data2, false, false);
  311. // Kill the second boosting vote from 0 to 1. This should change edge counts,
  312. // and remove both the vote and the node data. The variable |data1| is now
  313. // invalid.
  314. boost01b.Reset();
  315. EXPECT_EQ(2u, aggregator()->nodes_.size());
  316. ExpectEdges(1);
  317. EXPECT_EQ(observer().GetVoteCount(), 1u);
  318. EXPECT_TRUE(observer().HasVote(aggregator_voter_id(), kExecutionContext0,
  319. kMediumPriorityVote0));
  320. EXPECT_FALSE(observer().HasVote(aggregator_voter_id(), kExecutionContext1));
  321. EXPECT_FALSE(observer().HasVote(aggregator_voter_id(), kExecutionContext2));
  322. EXPECT_EQ(1u, data0.edge_count_for_testing());
  323. EXPECT_EQ(1u, data2.edge_count_for_testing());
  324. ExpectIsActive(data0, true, false);
  325. ExpectIsActive(data2, false, false);
  326. // Move the boosting vote. The move should not cause any outwardly visible
  327. // changes.
  328. BoostingVote boost20b(std::move(boost20));
  329. EXPECT_EQ(aggregator(), boost20b.aggregator());
  330. EXPECT_EQ(kExecutionContext2, boost20b.input_execution_context());
  331. EXPECT_EQ(kExecutionContext0, boost20b.output_execution_context());
  332. EXPECT_EQ(kReasonBoost, boost20b.reason());
  333. EXPECT_FALSE(boost20.aggregator());
  334. EXPECT_FALSE(boost20.input_execution_context());
  335. EXPECT_FALSE(boost20.output_execution_context());
  336. EXPECT_FALSE(boost20.reason());
  337. EXPECT_EQ(2u, aggregator()->nodes_.size());
  338. ExpectEdges(1);
  339. EXPECT_EQ(observer().GetVoteCount(), 1u);
  340. EXPECT_TRUE(observer().HasVote(aggregator_voter_id(), kExecutionContext0,
  341. kMediumPriorityVote0));
  342. EXPECT_FALSE(observer().HasVote(aggregator_voter_id(), kExecutionContext1));
  343. EXPECT_FALSE(observer().HasVote(aggregator_voter_id(), kExecutionContext2));
  344. EXPECT_EQ(1u, data0.edge_count_for_testing());
  345. EXPECT_EQ(1u, data2.edge_count_for_testing());
  346. ExpectIsActive(data0, true, false);
  347. ExpectIsActive(data2, false, false);
  348. // Remove the boosting vote from 2 to 0. This should change edge counts, and
  349. // also remove the node data associated with node 2. |data2| is now invalid.
  350. boost20b.Reset();
  351. EXPECT_EQ(1u, aggregator()->nodes_.size());
  352. ExpectEdges(0);
  353. EXPECT_EQ(observer().GetVoteCount(), 1u);
  354. EXPECT_TRUE(observer().HasVote(aggregator_voter_id(), kExecutionContext0,
  355. kMediumPriorityVote0));
  356. EXPECT_FALSE(observer().HasVote(aggregator_voter_id(), kExecutionContext1));
  357. EXPECT_FALSE(observer().HasVote(aggregator_voter_id(), kExecutionContext2));
  358. EXPECT_EQ(0u, data0.edge_count_for_testing());
  359. ExpectIsActive(data0, true, false);
  360. // Finally remove the last vote. The aggregator should effectively be empty at
  361. // this point. |data0| also becomes invalid after this.
  362. voter()->InvalidateVote(kExecutionContext0);
  363. EXPECT_EQ(0u, aggregator()->nodes_.size());
  364. ExpectEdges(0);
  365. EXPECT_EQ(observer().GetVoteCount(), 0u);
  366. EXPECT_FALSE(observer().HasVote(aggregator_voter_id(), kExecutionContext0));
  367. EXPECT_FALSE(observer().HasVote(aggregator_voter_id(), kExecutionContext1));
  368. EXPECT_FALSE(observer().HasVote(aggregator_voter_id(), kExecutionContext2));
  369. }
  370. TEST_F(BoostingVoteAggregatorTest, DiamondPattern) {
  371. // Create a diamond boosting vote pattern:
  372. //
  373. // 1
  374. // / \
  375. // 0 3
  376. // \ /
  377. // 2
  378. BoostingVote boost01(aggregator(), kExecutionContext0, kExecutionContext1,
  379. kReasonBoost);
  380. BoostingVote boost02(aggregator(), kExecutionContext0, kExecutionContext2,
  381. kReasonBoost);
  382. BoostingVote boost13(aggregator(), kExecutionContext1, kExecutionContext3,
  383. kReasonBoost);
  384. BoostingVote boost23(aggregator(), kExecutionContext2, kExecutionContext3,
  385. kReasonBoost);
  386. const auto& data0 = aggregator()->nodes_.find(kExecutionContext0)->second;
  387. const auto& data1 = aggregator()->nodes_.find(kExecutionContext1)->second;
  388. const auto& data2 = aggregator()->nodes_.find(kExecutionContext2)->second;
  389. const auto& data3 = aggregator()->nodes_.find(kExecutionContext3)->second;
  390. ExpectIsActive(data0, false, false);
  391. ExpectIsActive(data1, false, false);
  392. ExpectIsActive(data2, false, false);
  393. ExpectIsActive(data3, false, false);
  394. // Add a vote to node 0. This should cause all nodes to be boosted.
  395. voter()->SubmitVote(kExecutionContext0, kHighPriorityVote0);
  396. ExpectIsActive(data0, false, true);
  397. ExpectIsActive(data1, false, true);
  398. ExpectIsActive(data2, false, true);
  399. ExpectIsActive(data3, false, true);
  400. // Cancel the vote. All boosting should disappear.
  401. voter()->InvalidateVote(kExecutionContext0);
  402. ExpectIsActive(data0, false, false);
  403. ExpectIsActive(data1, false, false);
  404. ExpectIsActive(data2, false, false);
  405. ExpectIsActive(data3, false, false);
  406. }
  407. TEST_F(BoostingVoteAggregatorTest, DiamondPatternMultipleVotes) {
  408. // Create another diamond boosting vote pattern:
  409. //
  410. // 1
  411. // / \
  412. // 4 - 0 3
  413. // \ /
  414. // 2
  415. BoostingVote boost01(aggregator(), kExecutionContext0, kExecutionContext1,
  416. kReasonBoost);
  417. BoostingVote boost02(aggregator(), kExecutionContext0, kExecutionContext2,
  418. kReasonBoost);
  419. BoostingVote boost13(aggregator(), kExecutionContext1, kExecutionContext3,
  420. kReasonBoost);
  421. BoostingVote boost23(aggregator(), kExecutionContext2, kExecutionContext3,
  422. kReasonBoost);
  423. const auto& data0 = aggregator()->nodes_.find(kExecutionContext0)->second;
  424. const auto& data1 = aggregator()->nodes_.find(kExecutionContext1)->second;
  425. const auto& data2 = aggregator()->nodes_.find(kExecutionContext2)->second;
  426. const auto& data3 = aggregator()->nodes_.find(kExecutionContext3)->second;
  427. ExpectIsActive(data0, false, false);
  428. ExpectIsActive(data1, false, false);
  429. ExpectIsActive(data2, false, false);
  430. ExpectIsActive(data3, false, false);
  431. // Add a vote to node 0. This should cause all downstream nodes to be boosted.
  432. voter()->SubmitVote(kExecutionContext0, kHighPriorityVote0);
  433. ExpectIsActive(data0, false, true);
  434. ExpectIsActive(data1, false, true);
  435. ExpectIsActive(data2, false, true);
  436. ExpectIsActive(data3, false, true);
  437. // Add a lower vote to execution context 0 via execution context 4. This
  438. // should also propagate through the network in a similar way.
  439. BoostingVote boost40(aggregator(), kExecutionContext4, kExecutionContext0,
  440. kReasonBoost);
  441. const auto& data4 = aggregator()->nodes_.find(kExecutionContext4)->second;
  442. voter()->SubmitVote(kExecutionContext4, kMediumPriorityVote0);
  443. ExpectIsActive(data0, true, true);
  444. ExpectIsActive(data1, true, true);
  445. ExpectIsActive(data2, true, true);
  446. ExpectIsActive(data3, true, true);
  447. ExpectIsActive(data4, true, false);
  448. // Cleanup.
  449. voter()->InvalidateVote(kExecutionContext0);
  450. voter()->InvalidateVote(kExecutionContext4);
  451. }
  452. TEST_F(BoostingVoteAggregatorTest, RemoveEdgeFromCycle) {
  453. BoostingVote boost01(aggregator(), kExecutionContext0, kExecutionContext1,
  454. kReasonBoost);
  455. BoostingVote boost12(aggregator(), kExecutionContext1, kExecutionContext2,
  456. kReasonBoost);
  457. BoostingVote boost23(aggregator(), kExecutionContext2, kExecutionContext3,
  458. kReasonBoost);
  459. BoostingVote boost30(aggregator(), kExecutionContext3, kExecutionContext0,
  460. kReasonBoost);
  461. const auto& data0 = aggregator()->nodes_.find(kExecutionContext0)->second;
  462. const auto& data1 = aggregator()->nodes_.find(kExecutionContext1)->second;
  463. const auto& data2 = aggregator()->nodes_.find(kExecutionContext2)->second;
  464. const auto& data3 = aggregator()->nodes_.find(kExecutionContext3)->second;
  465. ExpectIsActive(data0, false, false);
  466. ExpectIsActive(data1, false, false);
  467. ExpectIsActive(data2, false, false);
  468. ExpectIsActive(data3, false, false);
  469. // Add a vote to node 0.
  470. voter()->SubmitVote(kExecutionContext0, kHighPriorityVote0);
  471. ExpectIsActive(data0, false, true);
  472. ExpectIsActive(data1, false, true);
  473. ExpectIsActive(data2, false, true);
  474. ExpectIsActive(data3, false, true);
  475. // Remove an edge from the cycle. The first half of the cycle should still
  476. // be boosted, the second half should not.
  477. boost12.Reset();
  478. ExpectIsActive(data0, false, true);
  479. ExpectIsActive(data1, false, true);
  480. ExpectIsActive(data2, false, false);
  481. ExpectIsActive(data3, false, false);
  482. // Cleanup.
  483. voter()->InvalidateVote(kExecutionContext0);
  484. }
  485. TEST_F(BoostingVoteAggregatorTest, MoveCancelsPreviousBoostingVote) {
  486. BoostingVote boost01(aggregator(), kExecutionContext0, kExecutionContext1,
  487. kReasonBoost);
  488. BoostingVote boost12(aggregator(), kExecutionContext1, kExecutionContext2,
  489. kReasonBoost);
  490. // Expect nodes to have been created for all nodes involved in boosting votes.
  491. EXPECT_TRUE(aggregator()->nodes_.count(kExecutionContext0));
  492. EXPECT_TRUE(aggregator()->nodes_.count(kExecutionContext1));
  493. EXPECT_TRUE(aggregator()->nodes_.count(kExecutionContext2));
  494. // Move one boosting vote into the other. This should cause the latter to be
  495. // canceled. In this case that means node0 should be removed.
  496. boost01 = std::move(boost12);
  497. EXPECT_FALSE(aggregator()->nodes_.count(kExecutionContext0));
  498. EXPECT_TRUE(aggregator()->nodes_.count(kExecutionContext1));
  499. EXPECT_TRUE(aggregator()->nodes_.count(kExecutionContext2));
  500. }
  501. TEST_F(BoostingVoteAggregatorTest, BoostingVoteAfterNormalVotes) {
  502. voter()->SubmitVote(kExecutionContext0, kHighPriorityVote0);
  503. EXPECT_TRUE(aggregator()->nodes_.count(kExecutionContext0));
  504. EXPECT_EQ(1u, aggregator()->nodes_.size());
  505. const auto& data0 = aggregator()->nodes_.find(kExecutionContext0)->second;
  506. ExpectIsActive(data0, false, true);
  507. BoostingVote boost12(aggregator(), kExecutionContext1, kExecutionContext2,
  508. kReasonBoost);
  509. EXPECT_TRUE(aggregator()->nodes_.count(kExecutionContext0));
  510. EXPECT_TRUE(aggregator()->nodes_.count(kExecutionContext1));
  511. EXPECT_TRUE(aggregator()->nodes_.count(kExecutionContext2));
  512. EXPECT_EQ(3u, aggregator()->nodes_.size());
  513. const auto& data1 = aggregator()->nodes_.find(kExecutionContext1)->second;
  514. const auto& data2 = aggregator()->nodes_.find(kExecutionContext2)->second;
  515. ExpectIsActive(data0, false, true);
  516. ExpectIsActive(data1, false, false);
  517. ExpectIsActive(data2, false, false);
  518. BoostingVote boost01(aggregator(), kExecutionContext0, kExecutionContext1,
  519. kReasonBoost);
  520. EXPECT_TRUE(aggregator()->nodes_.count(kExecutionContext0));
  521. EXPECT_TRUE(aggregator()->nodes_.count(kExecutionContext1));
  522. EXPECT_TRUE(aggregator()->nodes_.count(kExecutionContext2));
  523. EXPECT_EQ(3u, aggregator()->nodes_.size());
  524. ExpectIsActive(data0, false, true);
  525. ExpectIsActive(data1, false, true);
  526. ExpectIsActive(data2, false, true);
  527. // Cleanup.
  528. voter()->InvalidateVote(kExecutionContext0);
  529. }
  530. } // namespace execution_context_priority
  531. } // namespace performance_manager