• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2015 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 
5 #include "base/task/sequence_manager/task_queue_selector.h"
6 
7 #include <stddef.h>
8 
9 #include <memory>
10 
11 #include "base/bind.h"
12 #include "base/macros.h"
13 #include "base/memory/ptr_util.h"
14 #include "base/pending_task.h"
15 #include "base/task/sequence_manager/task_queue_impl.h"
16 #include "base/task/sequence_manager/test/mock_time_domain.h"
17 #include "base/task/sequence_manager/work_queue.h"
18 #include "base/task/sequence_manager/work_queue_sets.h"
19 #include "base/test/metrics/histogram_tester.h"
20 #include "testing/gmock/include/gmock/gmock.h"
21 #include "testing/gtest/include/gtest/gtest.h"
22 
23 using testing::_;
24 
25 namespace base {
26 namespace sequence_manager {
27 namespace internal {
28 // To avoid symbol collisions in jumbo builds.
29 namespace task_queue_selector_unittest {
30 
31 class MockObserver : public TaskQueueSelector::Observer {
32  public:
33   MockObserver() = default;
34   ~MockObserver() override = default;
35 
36   MOCK_METHOD1(OnTaskQueueEnabled, void(internal::TaskQueueImpl*));
37 
38  private:
39   DISALLOW_COPY_AND_ASSIGN(MockObserver);
40 };
41 
42 class TaskQueueSelectorForTest : public TaskQueueSelector {
43  public:
44   using TaskQueueSelector::prioritizing_selector_for_test;
45   using TaskQueueSelector::PrioritizingSelector;
46   using TaskQueueSelector::SetImmediateStarvationCountForTest;
47 
48   // Returns the number of highest priority tasks needed to starve high priority
49   // task.
NumberOfHighestPriorityToStarveHighPriority()50   static constexpr size_t NumberOfHighestPriorityToStarveHighPriority() {
51     return (kMaxHighPriorityStarvationScore +
52             kSmallScoreIncrementForHighPriorityStarvation - 1) /
53            kSmallScoreIncrementForHighPriorityStarvation;
54   }
55 
56   // Returns the number of highest priority tasks needed to starve normal
57   // priority tasks.
NumberOfHighestPriorityToStarveNormalPriority()58   static constexpr size_t NumberOfHighestPriorityToStarveNormalPriority() {
59     return (kMaxNormalPriorityStarvationScore +
60             kSmallScoreIncrementForNormalPriorityStarvation - 1) /
61            kSmallScoreIncrementForNormalPriorityStarvation;
62   }
63 
64   // Returns the number of high priority tasks needed to starve normal priority
65   // tasks.
NumberOfHighPriorityToStarveNormalPriority()66   static constexpr size_t NumberOfHighPriorityToStarveNormalPriority() {
67     return (kMaxNormalPriorityStarvationScore +
68             kLargeScoreIncrementForNormalPriorityStarvation - 1) /
69            kLargeScoreIncrementForNormalPriorityStarvation;
70   }
71 
72   // Returns the number of highest priority tasks needed to starve low priority
73   // ones.
NumberOfHighestPriorityToStarveLowPriority()74   static constexpr size_t NumberOfHighestPriorityToStarveLowPriority() {
75     return (kMaxLowPriorityStarvationScore +
76             kSmallScoreIncrementForLowPriorityStarvation - 1) /
77            kSmallScoreIncrementForLowPriorityStarvation;
78   }
79 
80   // Returns the number of high/normal priority tasks needed to starve low
81   // priority ones.
NumberOfHighAndNormalPriorityToStarveLowPriority()82   static constexpr size_t NumberOfHighAndNormalPriorityToStarveLowPriority() {
83     return (kMaxLowPriorityStarvationScore +
84             kLargeScoreIncrementForLowPriorityStarvation - 1) /
85            kLargeScoreIncrementForLowPriorityStarvation;
86   }
87 };
88 
89 class TaskQueueSelectorTest : public testing::Test {
90  public:
TaskQueueSelectorTest()91   TaskQueueSelectorTest()
92       : test_closure_(BindRepeating(&TaskQueueSelectorTest::TestFunction)) {}
93   ~TaskQueueSelectorTest() override = default;
94 
prioritizing_selector()95   TaskQueueSelectorForTest::PrioritizingSelector* prioritizing_selector() {
96     return selector_.prioritizing_selector_for_test();
97   }
98 
delayed_work_queue_sets()99   WorkQueueSets* delayed_work_queue_sets() {
100     return prioritizing_selector()->delayed_work_queue_sets();
101   }
immediate_work_queue_sets()102   WorkQueueSets* immediate_work_queue_sets() {
103     return prioritizing_selector()->immediate_work_queue_sets();
104   }
105 
PushTasks(const size_t queue_indices[],size_t num_tasks)106   void PushTasks(const size_t queue_indices[], size_t num_tasks) {
107     std::set<size_t> changed_queue_set;
108     EnqueueOrder::Generator enqueue_order_generator;
109     for (size_t i = 0; i < num_tasks; i++) {
110       changed_queue_set.insert(queue_indices[i]);
111       task_queues_[queue_indices[i]]->immediate_work_queue()->Push(
112           TaskQueueImpl::Task(TaskQueue::PostedTask(test_closure_, FROM_HERE),
113                               TimeTicks(), EnqueueOrder(),
114                               enqueue_order_generator.GenerateNext()));
115     }
116   }
117 
PushTasksWithEnqueueOrder(const size_t queue_indices[],const size_t enqueue_orders[],size_t num_tasks)118   void PushTasksWithEnqueueOrder(const size_t queue_indices[],
119                                  const size_t enqueue_orders[],
120                                  size_t num_tasks) {
121     std::set<size_t> changed_queue_set;
122     for (size_t i = 0; i < num_tasks; i++) {
123       changed_queue_set.insert(queue_indices[i]);
124       task_queues_[queue_indices[i]]->immediate_work_queue()->Push(
125           TaskQueueImpl::Task(
126               TaskQueue::PostedTask(test_closure_, FROM_HERE), TimeTicks(),
127               EnqueueOrder(),
128               EnqueueOrder::FromIntForTesting(enqueue_orders[i])));
129     }
130   }
131 
PopTasks()132   std::vector<size_t> PopTasks() {
133     std::vector<size_t> order;
134     WorkQueue* chosen_work_queue;
135     while (selector_.SelectWorkQueueToService(&chosen_work_queue)) {
136       size_t chosen_queue_index =
137           queue_to_index_map_.find(chosen_work_queue->task_queue())->second;
138       order.push_back(chosen_queue_index);
139       chosen_work_queue->PopTaskForTesting();
140       immediate_work_queue_sets()->OnPopQueue(chosen_work_queue);
141     }
142     return order;
143   }
144 
TestFunction()145   static void TestFunction() {}
146 
147  protected:
SetUp()148   void SetUp() final {
149     time_domain_ = std::make_unique<MockTimeDomain>(TimeTicks() +
150                                                     TimeDelta::FromSeconds(1));
151     for (size_t i = 0; i < kTaskQueueCount; i++) {
152       std::unique_ptr<TaskQueueImpl> task_queue =
153           std::make_unique<TaskQueueImpl>(nullptr, time_domain_.get(),
154                                           TaskQueue::Spec("test"));
155       selector_.AddQueue(task_queue.get());
156       task_queues_.push_back(std::move(task_queue));
157     }
158     for (size_t i = 0; i < kTaskQueueCount; i++) {
159       EXPECT_EQ(TaskQueue::kNormalPriority, task_queues_[i]->GetQueuePriority())
160           << i;
161       queue_to_index_map_.insert(std::make_pair(task_queues_[i].get(), i));
162     }
163     histogram_tester_.reset(new HistogramTester());
164   }
165 
TearDown()166   void TearDown() final {
167     for (std::unique_ptr<TaskQueueImpl>& task_queue : task_queues_) {
168       // Note since this test doesn't have a SequenceManager we need to
169       // manually remove |task_queue| from the |selector_|.  Normally
170       // UnregisterTaskQueue would do that.
171       selector_.RemoveQueue(task_queue.get());
172       task_queue->UnregisterTaskQueue();
173     }
174   }
175 
NewTaskQueueWithBlockReporting()176   std::unique_ptr<TaskQueueImpl> NewTaskQueueWithBlockReporting() {
177     return std::make_unique<TaskQueueImpl>(nullptr, time_domain_.get(),
178                                            TaskQueue::Spec("test"));
179   }
180 
181   const size_t kTaskQueueCount = 5;
182   RepeatingClosure test_closure_;
183   TaskQueueSelectorForTest selector_;
184   std::unique_ptr<TimeDomain> time_domain_;
185   std::vector<std::unique_ptr<TaskQueueImpl>> task_queues_;
186   std::map<TaskQueueImpl*, size_t> queue_to_index_map_;
187   std::unique_ptr<HistogramTester> histogram_tester_;
188 };
189 
TEST_F(TaskQueueSelectorTest,TestDefaultPriority)190 TEST_F(TaskQueueSelectorTest, TestDefaultPriority) {
191   size_t queue_order[] = {4, 3, 2, 1, 0};
192   PushTasks(queue_order, 5);
193   EXPECT_THAT(PopTasks(), testing::ElementsAre(4, 3, 2, 1, 0));
194   EXPECT_EQ(histogram_tester_->GetBucketCount(
195                 "TaskQueueSelector.TaskServicedPerSelectorLogic",
196                 static_cast<int>(TaskQueueSelectorLogic::kNormalPriorityLogic)),
197             5);
198 }
199 
TEST_F(TaskQueueSelectorTest,TestHighestPriority)200 TEST_F(TaskQueueSelectorTest, TestHighestPriority) {
201   size_t queue_order[] = {0, 1, 2, 3, 4};
202   PushTasks(queue_order, 5);
203   selector_.SetQueuePriority(task_queues_[2].get(),
204                              TaskQueue::kHighestPriority);
205   EXPECT_THAT(PopTasks(), ::testing::ElementsAre(2, 0, 1, 3, 4));
206   EXPECT_EQ(
207       histogram_tester_->GetBucketCount(
208           "TaskQueueSelector.TaskServicedPerSelectorLogic",
209           static_cast<int>(TaskQueueSelectorLogic::kHighestPriorityLogic)),
210       1);
211 }
212 
TEST_F(TaskQueueSelectorTest,TestHighPriority)213 TEST_F(TaskQueueSelectorTest, TestHighPriority) {
214   size_t queue_order[] = {0, 1, 2, 3, 4};
215   PushTasks(queue_order, 5);
216   selector_.SetQueuePriority(task_queues_[2].get(),
217                              TaskQueue::kHighestPriority);
218   selector_.SetQueuePriority(task_queues_[1].get(), TaskQueue::kHighPriority);
219   selector_.SetQueuePriority(task_queues_[0].get(), TaskQueue::kLowPriority);
220   EXPECT_THAT(PopTasks(), ::testing::ElementsAre(2, 1, 3, 4, 0));
221   EXPECT_EQ(histogram_tester_->GetBucketCount(
222                 "TaskQueueSelector.TaskServicedPerSelectorLogic",
223                 static_cast<int>(TaskQueueSelectorLogic::kHighPriorityLogic)),
224             1);
225 }
226 
TEST_F(TaskQueueSelectorTest,TestLowPriority)227 TEST_F(TaskQueueSelectorTest, TestLowPriority) {
228   size_t queue_order[] = {0, 1, 2, 3, 4};
229   PushTasks(queue_order, 5);
230   selector_.SetQueuePriority(task_queues_[2].get(), TaskQueue::kLowPriority);
231   EXPECT_THAT(PopTasks(), testing::ElementsAre(0, 1, 3, 4, 2));
232   EXPECT_EQ(histogram_tester_->GetBucketCount(
233                 "TaskQueueSelector.TaskServicedPerSelectorLogic",
234                 static_cast<int>(TaskQueueSelectorLogic::kLowPriorityLogic)),
235             1);
236 }
237 
TEST_F(TaskQueueSelectorTest,TestBestEffortPriority)238 TEST_F(TaskQueueSelectorTest, TestBestEffortPriority) {
239   size_t queue_order[] = {0, 1, 2, 3, 4};
240   PushTasks(queue_order, 5);
241   selector_.SetQueuePriority(task_queues_[0].get(),
242                              TaskQueue::kBestEffortPriority);
243   selector_.SetQueuePriority(task_queues_[2].get(), TaskQueue::kLowPriority);
244   selector_.SetQueuePriority(task_queues_[3].get(),
245                              TaskQueue::kHighestPriority);
246   EXPECT_THAT(PopTasks(), ::testing::ElementsAre(3, 1, 4, 2, 0));
247   EXPECT_EQ(
248       histogram_tester_->GetBucketCount(
249           "TaskQueueSelector.TaskServicedPerSelectorLogic",
250           static_cast<int>(TaskQueueSelectorLogic::kBestEffortPriorityLogic)),
251       1);
252 }
253 
TEST_F(TaskQueueSelectorTest,TestControlPriority)254 TEST_F(TaskQueueSelectorTest, TestControlPriority) {
255   size_t queue_order[] = {0, 1, 2, 3, 4};
256   PushTasks(queue_order, 5);
257   selector_.SetQueuePriority(task_queues_[4].get(),
258                              TaskQueue::kControlPriority);
259   EXPECT_EQ(TaskQueue::kControlPriority, task_queues_[4]->GetQueuePriority());
260   selector_.SetQueuePriority(task_queues_[2].get(),
261                              TaskQueue::kHighestPriority);
262   EXPECT_EQ(TaskQueue::kHighestPriority, task_queues_[2]->GetQueuePriority());
263   EXPECT_THAT(PopTasks(), ::testing::ElementsAre(4, 2, 0, 1, 3));
264   EXPECT_EQ(
265       histogram_tester_->GetBucketCount(
266           "TaskQueueSelector.TaskServicedPerSelectorLogic",
267           static_cast<int>(TaskQueueSelectorLogic::kControlPriorityLogic)),
268       1);
269 }
270 
TEST_F(TaskQueueSelectorTest,TestObserverWithEnabledQueue)271 TEST_F(TaskQueueSelectorTest, TestObserverWithEnabledQueue) {
272   task_queues_[1]->SetQueueEnabledForTest(false);
273   selector_.DisableQueue(task_queues_[1].get());
274   MockObserver mock_observer;
275   selector_.SetTaskQueueSelectorObserver(&mock_observer);
276   EXPECT_CALL(mock_observer, OnTaskQueueEnabled(_)).Times(1);
277   task_queues_[1]->SetQueueEnabledForTest(true);
278   selector_.EnableQueue(task_queues_[1].get());
279 }
280 
TEST_F(TaskQueueSelectorTest,TestObserverWithSetQueuePriorityAndQueueAlreadyEnabled)281 TEST_F(TaskQueueSelectorTest,
282        TestObserverWithSetQueuePriorityAndQueueAlreadyEnabled) {
283   selector_.SetQueuePriority(task_queues_[1].get(),
284                              TaskQueue::kHighestPriority);
285   MockObserver mock_observer;
286   selector_.SetTaskQueueSelectorObserver(&mock_observer);
287   EXPECT_CALL(mock_observer, OnTaskQueueEnabled(_)).Times(0);
288   selector_.SetQueuePriority(task_queues_[1].get(), TaskQueue::kNormalPriority);
289 }
290 
TEST_F(TaskQueueSelectorTest,TestDisableEnable)291 TEST_F(TaskQueueSelectorTest, TestDisableEnable) {
292   MockObserver mock_observer;
293   selector_.SetTaskQueueSelectorObserver(&mock_observer);
294 
295   size_t queue_order[] = {0, 1, 2, 3, 4};
296   PushTasks(queue_order, 5);
297   task_queues_[2]->SetQueueEnabledForTest(false);
298   selector_.DisableQueue(task_queues_[2].get());
299   task_queues_[4]->SetQueueEnabledForTest(false);
300   selector_.DisableQueue(task_queues_[4].get());
301   // Disabling a queue should not affect its priority.
302   EXPECT_EQ(TaskQueue::kNormalPriority, task_queues_[2]->GetQueuePriority());
303   EXPECT_EQ(TaskQueue::kNormalPriority, task_queues_[4]->GetQueuePriority());
304   EXPECT_THAT(PopTasks(), testing::ElementsAre(0, 1, 3));
305 
306   EXPECT_CALL(mock_observer, OnTaskQueueEnabled(_)).Times(2);
307   task_queues_[2]->SetQueueEnabledForTest(true);
308   selector_.EnableQueue(task_queues_[2].get());
309   selector_.SetQueuePriority(task_queues_[2].get(),
310                              TaskQueue::kBestEffortPriority);
311   EXPECT_THAT(PopTasks(), testing::ElementsAre(2));
312   task_queues_[4]->SetQueueEnabledForTest(true);
313   selector_.EnableQueue(task_queues_[4].get());
314   EXPECT_THAT(PopTasks(), testing::ElementsAre(4));
315 }
316 
TEST_F(TaskQueueSelectorTest,TestDisableChangePriorityThenEnable)317 TEST_F(TaskQueueSelectorTest, TestDisableChangePriorityThenEnable) {
318   EXPECT_TRUE(task_queues_[2]->delayed_work_queue()->Empty());
319   EXPECT_TRUE(task_queues_[2]->immediate_work_queue()->Empty());
320 
321   task_queues_[2]->SetQueueEnabledForTest(false);
322   selector_.SetQueuePriority(task_queues_[2].get(),
323                              TaskQueue::kHighestPriority);
324 
325   size_t queue_order[] = {0, 1, 2, 3, 4};
326   PushTasks(queue_order, 5);
327 
328   EXPECT_TRUE(task_queues_[2]->delayed_work_queue()->Empty());
329   EXPECT_FALSE(task_queues_[2]->immediate_work_queue()->Empty());
330   task_queues_[2]->SetQueueEnabledForTest(true);
331 
332   EXPECT_EQ(TaskQueue::kHighestPriority, task_queues_[2]->GetQueuePriority());
333   EXPECT_THAT(PopTasks(), ::testing::ElementsAre(2, 0, 1, 3, 4));
334 }
335 
TEST_F(TaskQueueSelectorTest,TestEmptyQueues)336 TEST_F(TaskQueueSelectorTest, TestEmptyQueues) {
337   WorkQueue* chosen_work_queue = nullptr;
338   EXPECT_FALSE(selector_.SelectWorkQueueToService(&chosen_work_queue));
339 
340   // Test only disabled queues.
341   size_t queue_order[] = {0};
342   PushTasks(queue_order, 1);
343   task_queues_[0]->SetQueueEnabledForTest(false);
344   selector_.DisableQueue(task_queues_[0].get());
345   EXPECT_FALSE(selector_.SelectWorkQueueToService(&chosen_work_queue));
346 
347   // These tests are unusual since there's no TQM. To avoid a later DCHECK when
348   // deleting the task queue, we re-enable the queue here so the selector
349   // doesn't get out of sync.
350   task_queues_[0]->SetQueueEnabledForTest(true);
351   selector_.EnableQueue(task_queues_[0].get());
352 }
353 
TEST_F(TaskQueueSelectorTest,TestAge)354 TEST_F(TaskQueueSelectorTest, TestAge) {
355   size_t enqueue_order[] = {10, 1, 2, 9, 4};
356   size_t queue_order[] = {0, 1, 2, 3, 4};
357   PushTasksWithEnqueueOrder(queue_order, enqueue_order, 5);
358   EXPECT_THAT(PopTasks(), testing::ElementsAre(1, 2, 4, 3, 0));
359 }
360 
TEST_F(TaskQueueSelectorTest,TestControlStarvesOthers)361 TEST_F(TaskQueueSelectorTest, TestControlStarvesOthers) {
362   size_t queue_order[] = {0, 1, 2, 3};
363   PushTasks(queue_order, 4);
364   selector_.SetQueuePriority(task_queues_[3].get(),
365                              TaskQueue::kControlPriority);
366   selector_.SetQueuePriority(task_queues_[2].get(),
367                              TaskQueue::kHighestPriority);
368   selector_.SetQueuePriority(task_queues_[1].get(),
369                              TaskQueue::kBestEffortPriority);
370   for (int i = 0; i < 100; i++) {
371     WorkQueue* chosen_work_queue = nullptr;
372     ASSERT_TRUE(selector_.SelectWorkQueueToService(&chosen_work_queue));
373     EXPECT_EQ(task_queues_[3].get(), chosen_work_queue->task_queue());
374     // Don't remove task from queue to simulate all queues still being full.
375   }
376 }
377 
TEST_F(TaskQueueSelectorTest,TestHighestPriorityDoesNotStarveHigh)378 TEST_F(TaskQueueSelectorTest, TestHighestPriorityDoesNotStarveHigh) {
379   size_t queue_order[] = {0, 1};
380   PushTasks(queue_order, 2);
381   selector_.SetQueuePriority(task_queues_[0].get(),
382                              TaskQueue::kHighestPriority);
383   selector_.SetQueuePriority(task_queues_[1].get(), TaskQueue::kHighPriority);
384 
385   size_t counts[] = {0, 0};
386   for (int i = 0; i < 100; i++) {
387     WorkQueue* chosen_work_queue = nullptr;
388     ASSERT_TRUE(selector_.SelectWorkQueueToService(&chosen_work_queue));
389     size_t chosen_queue_index =
390         queue_to_index_map_.find(chosen_work_queue->task_queue())->second;
391     counts[chosen_queue_index]++;
392     // Don't remove task from queue to simulate all queues still being full.
393   }
394   EXPECT_GT(counts[1], 0ul);        // Check highest doesn't starve high.
395   EXPECT_GT(counts[0], counts[1]);  // Check highest gets more chance to run.
396 }
397 
TEST_F(TaskQueueSelectorTest,TestHighestPriorityDoesNotStarveHighOrNormal)398 TEST_F(TaskQueueSelectorTest, TestHighestPriorityDoesNotStarveHighOrNormal) {
399   size_t queue_order[] = {0, 1, 2};
400   PushTasks(queue_order, 3);
401   selector_.SetQueuePriority(task_queues_[0].get(),
402                              TaskQueue::kHighestPriority);
403   selector_.SetQueuePriority(task_queues_[1].get(), TaskQueue::kHighPriority);
404 
405   size_t counts[] = {0, 0, 0};
406   for (int i = 0; i < 100; i++) {
407     WorkQueue* chosen_work_queue = nullptr;
408     ASSERT_TRUE(selector_.SelectWorkQueueToService(&chosen_work_queue));
409     size_t chosen_queue_index =
410         queue_to_index_map_.find(chosen_work_queue->task_queue())->second;
411     counts[chosen_queue_index]++;
412     // Don't remove task from queue to simulate all queues still being full.
413   }
414 
415   // Check highest runs more frequently then high.
416   EXPECT_GT(counts[0], counts[1]);
417 
418   // Check high runs at least as frequently as normal.
419   EXPECT_GE(counts[1], counts[2]);
420 
421   // Check normal isn't starved.
422   EXPECT_GT(counts[2], 0ul);
423 }
424 
TEST_F(TaskQueueSelectorTest,TestHighestPriorityDoesNotStarveHighOrNormalOrLow)425 TEST_F(TaskQueueSelectorTest,
426        TestHighestPriorityDoesNotStarveHighOrNormalOrLow) {
427   size_t queue_order[] = {0, 1, 2, 3};
428   PushTasks(queue_order, 4);
429   selector_.SetQueuePriority(task_queues_[0].get(),
430                              TaskQueue::kHighestPriority);
431   selector_.SetQueuePriority(task_queues_[1].get(), TaskQueue::kHighPriority);
432   selector_.SetQueuePriority(task_queues_[3].get(), TaskQueue::kLowPriority);
433 
434   size_t counts[] = {0, 0, 0, 0};
435   for (int i = 0; i < 100; i++) {
436     WorkQueue* chosen_work_queue = nullptr;
437     ASSERT_TRUE(selector_.SelectWorkQueueToService(&chosen_work_queue));
438     size_t chosen_queue_index =
439         queue_to_index_map_.find(chosen_work_queue->task_queue())->second;
440     counts[chosen_queue_index]++;
441     // Don't remove task from queue to simulate all queues still being full.
442   }
443 
444   // Check highest runs more frequently then high.
445   EXPECT_GT(counts[0], counts[1]);
446 
447   // Check high runs at least as frequently as normal.
448   EXPECT_GE(counts[1], counts[2]);
449 
450   // Check normal runs more frequently than low.
451   EXPECT_GT(counts[2], counts[3]);
452 
453   // Check low isn't starved.
454   EXPECT_GT(counts[3], 0ul);
455 }
456 
TEST_F(TaskQueueSelectorTest,TestHighPriorityDoesNotStarveNormal)457 TEST_F(TaskQueueSelectorTest, TestHighPriorityDoesNotStarveNormal) {
458   size_t queue_order[] = {0, 1};
459   PushTasks(queue_order, 2);
460 
461   selector_.SetQueuePriority(task_queues_[0].get(), TaskQueue::kHighPriority);
462 
463   size_t counts[] = {0, 0, 0, 0};
464   for (int i = 0; i < 100; i++) {
465     WorkQueue* chosen_work_queue = nullptr;
466     ASSERT_TRUE(selector_.SelectWorkQueueToService(&chosen_work_queue));
467     size_t chosen_queue_index =
468         queue_to_index_map_.find(chosen_work_queue->task_queue())->second;
469     counts[chosen_queue_index]++;
470     // Don't remove task from queue to simulate all queues still being full.
471   }
472 
473   // Check high runs more frequently then normal.
474   EXPECT_GT(counts[0], counts[1]);
475 
476   // Check low isn't starved.
477   EXPECT_GT(counts[1], 0ul);
478 }
479 
TEST_F(TaskQueueSelectorTest,TestHighPriorityDoesNotStarveNormalOrLow)480 TEST_F(TaskQueueSelectorTest, TestHighPriorityDoesNotStarveNormalOrLow) {
481   size_t queue_order[] = {0, 1, 2};
482   PushTasks(queue_order, 3);
483   selector_.SetQueuePriority(task_queues_[0].get(), TaskQueue::kHighPriority);
484   selector_.SetQueuePriority(task_queues_[2].get(), TaskQueue::kLowPriority);
485 
486   size_t counts[] = {0, 0, 0};
487   for (int i = 0; i < 100; i++) {
488     WorkQueue* chosen_work_queue = nullptr;
489     ASSERT_TRUE(selector_.SelectWorkQueueToService(&chosen_work_queue));
490     size_t chosen_queue_index =
491         queue_to_index_map_.find(chosen_work_queue->task_queue())->second;
492     counts[chosen_queue_index]++;
493     // Don't remove task from queue to simulate all queues still being full.
494   }
495 
496   // Check high runs more frequently than normal.
497   EXPECT_GT(counts[0], counts[1]);
498 
499   // Check normal runs more frequently than low.
500   EXPECT_GT(counts[1], counts[2]);
501 
502   // Check low isn't starved.
503   EXPECT_GT(counts[2], 0ul);
504 }
505 
TEST_F(TaskQueueSelectorTest,TestNormalPriorityDoesNotStarveLow)506 TEST_F(TaskQueueSelectorTest, TestNormalPriorityDoesNotStarveLow) {
507   size_t queue_order[] = {0, 1, 2};
508   PushTasks(queue_order, 3);
509   selector_.SetQueuePriority(task_queues_[0].get(), TaskQueue::kLowPriority);
510   selector_.SetQueuePriority(task_queues_[1].get(),
511                              TaskQueue::kBestEffortPriority);
512   size_t counts[] = {0, 0, 0};
513   for (int i = 0; i < 100; i++) {
514     WorkQueue* chosen_work_queue = nullptr;
515     ASSERT_TRUE(selector_.SelectWorkQueueToService(&chosen_work_queue));
516     size_t chosen_queue_index =
517         queue_to_index_map_.find(chosen_work_queue->task_queue())->second;
518     counts[chosen_queue_index]++;
519     // Don't remove task from queue to simulate all queues still being full.
520   }
521   EXPECT_GT(counts[0], 0ul);        // Check normal doesn't starve low.
522   EXPECT_GT(counts[2], counts[0]);  // Check normal gets more chance to run.
523   EXPECT_EQ(0ul, counts[1]);        // Check best effort is starved.
524 }
525 
TEST_F(TaskQueueSelectorTest,TestBestEffortGetsStarved)526 TEST_F(TaskQueueSelectorTest, TestBestEffortGetsStarved) {
527   size_t queue_order[] = {0, 1};
528   PushTasks(queue_order, 2);
529   selector_.SetQueuePriority(task_queues_[0].get(),
530                              TaskQueue::kBestEffortPriority);
531   EXPECT_EQ(TaskQueue::kNormalPriority, task_queues_[1]->GetQueuePriority());
532 
533   // Check that normal priority tasks starve best effort.
534   WorkQueue* chosen_work_queue = nullptr;
535   for (int i = 0; i < 100; i++) {
536     ASSERT_TRUE(selector_.SelectWorkQueueToService(&chosen_work_queue));
537     EXPECT_EQ(task_queues_[1].get(), chosen_work_queue->task_queue());
538     // Don't remove task from queue to simulate all queues still being full.
539   }
540 
541   // Check that highest priority tasks starve best effort.
542   selector_.SetQueuePriority(task_queues_[1].get(),
543                              TaskQueue::kHighestPriority);
544   for (int i = 0; i < 100; i++) {
545     ASSERT_TRUE(selector_.SelectWorkQueueToService(&chosen_work_queue));
546     EXPECT_EQ(task_queues_[1].get(), chosen_work_queue->task_queue());
547     // Don't remove task from queue to simulate all queues still being full.
548   }
549 
550   // Check that high priority tasks starve best effort.
551   selector_.SetQueuePriority(task_queues_[1].get(), TaskQueue::kHighPriority);
552   for (int i = 0; i < 100; i++) {
553     ASSERT_TRUE(selector_.SelectWorkQueueToService(&chosen_work_queue));
554     EXPECT_EQ(task_queues_[1].get(), chosen_work_queue->task_queue());
555     // Don't remove task from queue to simulate all queues still being full.
556   }
557 
558   // Check that low priority tasks starve best effort.
559   selector_.SetQueuePriority(task_queues_[1].get(), TaskQueue::kLowPriority);
560   for (int i = 0; i < 100; i++) {
561     ASSERT_TRUE(selector_.SelectWorkQueueToService(&chosen_work_queue));
562     EXPECT_EQ(task_queues_[1].get(), chosen_work_queue->task_queue());
563     // Don't remove task from queue to simulate all queues still being full.
564   }
565 
566   // Check that control priority tasks starve best effort.
567   selector_.SetQueuePriority(task_queues_[1].get(),
568                              TaskQueue::kControlPriority);
569   for (int i = 0; i < 100; i++) {
570     ASSERT_TRUE(selector_.SelectWorkQueueToService(&chosen_work_queue));
571     EXPECT_EQ(task_queues_[1].get(), chosen_work_queue->task_queue());
572     // Don't remove task from queue to simulate all queues still being full.
573   }
574 }
575 
TEST_F(TaskQueueSelectorTest,TestHighPriorityStarvationScoreIncreasedOnlyWhenTasksArePresent)576 TEST_F(TaskQueueSelectorTest,
577        TestHighPriorityStarvationScoreIncreasedOnlyWhenTasksArePresent) {
578   size_t queue_order[] = {0, 1};
579   PushTasks(queue_order, 2);
580   selector_.SetQueuePriority(task_queues_[0].get(),
581                              TaskQueue::kHighestPriority);
582   selector_.SetQueuePriority(task_queues_[1].get(),
583                              TaskQueue::kHighestPriority);
584 
585   // Run a number of highest priority tasks needed to starve high priority
586   // tasks (when present).
587   for (size_t num_tasks = 0;
588        num_tasks <=
589        TaskQueueSelectorForTest::NumberOfHighestPriorityToStarveHighPriority();
590        num_tasks++) {
591     WorkQueue* chosen_work_queue = nullptr;
592     ASSERT_TRUE(selector_.SelectWorkQueueToService(&chosen_work_queue));
593     // Don't remove task from queue to simulate the queue is still full.
594   }
595 
596   // Post a high priority task.
597   selector_.SetQueuePriority(task_queues_[1].get(), TaskQueue::kHighPriority);
598   WorkQueue* chosen_work_queue = nullptr;
599   ASSERT_TRUE(selector_.SelectWorkQueueToService(&chosen_work_queue));
600 
601   // Check that the high priority task is not considered starved, and thus isn't
602   // processed.
603   EXPECT_NE(
604       static_cast<int>(
605           queue_to_index_map_.find(chosen_work_queue->task_queue())->second),
606       1);
607 }
608 
TEST_F(TaskQueueSelectorTest,TestNormalPriorityStarvationScoreIncreasedOnllWhenTasksArePresent)609 TEST_F(TaskQueueSelectorTest,
610        TestNormalPriorityStarvationScoreIncreasedOnllWhenTasksArePresent) {
611   size_t queue_order[] = {0, 1};
612   PushTasks(queue_order, 2);
613   selector_.SetQueuePriority(task_queues_[0].get(),
614                              TaskQueue::kHighestPriority);
615   selector_.SetQueuePriority(task_queues_[1].get(),
616                              TaskQueue::kHighestPriority);
617 
618   // Run a number of highest priority tasks needed to starve normal priority
619   // tasks (when present).
620   for (size_t num_tasks = 0;
621        num_tasks <= TaskQueueSelectorForTest::
622                         NumberOfHighestPriorityToStarveNormalPriority();
623        num_tasks++) {
624     WorkQueue* chosen_work_queue = nullptr;
625     ASSERT_TRUE(selector_.SelectWorkQueueToService(&chosen_work_queue));
626     // Don't remove task from queue to simulate the queue is still full.
627   }
628 
629   selector_.SetQueuePriority(task_queues_[0].get(), TaskQueue::kHighPriority);
630   selector_.SetQueuePriority(task_queues_[1].get(), TaskQueue::kHighPriority);
631 
632   // Run a number of high priority tasks needed to starve normal priority
633   // tasks (when present).
634   for (size_t num_tasks = 0;
635        num_tasks <=
636        TaskQueueSelectorForTest::NumberOfHighPriorityToStarveNormalPriority();
637        num_tasks++) {
638     WorkQueue* chosen_work_queue = nullptr;
639     ASSERT_TRUE(selector_.SelectWorkQueueToService(&chosen_work_queue));
640     // Don't remove task from queue to simulate the queue is still full.
641   }
642 
643   // Post a normal priority task.
644   selector_.SetQueuePriority(task_queues_[1].get(), TaskQueue::kNormalPriority);
645   WorkQueue* chosen_work_queue = nullptr;
646   ASSERT_TRUE(selector_.SelectWorkQueueToService(&chosen_work_queue));
647 
648   // Check that the normal priority task is not considered starved, and thus
649   // isn't processed.
650   EXPECT_NE(
651       static_cast<int>(
652           queue_to_index_map_.find(chosen_work_queue->task_queue())->second),
653       1);
654 }
655 
TEST_F(TaskQueueSelectorTest,TestLowPriorityTaskStarvationOnlyIncreasedWhenTasksArePresent)656 TEST_F(TaskQueueSelectorTest,
657        TestLowPriorityTaskStarvationOnlyIncreasedWhenTasksArePresent) {
658   size_t queue_order[] = {0, 1};
659   PushTasks(queue_order, 2);
660   selector_.SetQueuePriority(task_queues_[0].get(),
661                              TaskQueue::kHighestPriority);
662   selector_.SetQueuePriority(task_queues_[1].get(),
663                              TaskQueue::kHighestPriority);
664 
665   // Run a number of highest priority tasks needed to starve low priority
666   // tasks (when present).
667   for (size_t num_tasks = 0;
668        num_tasks <=
669        TaskQueueSelectorForTest::NumberOfHighestPriorityToStarveLowPriority();
670        num_tasks++) {
671     WorkQueue* chosen_work_queue = nullptr;
672     ASSERT_TRUE(selector_.SelectWorkQueueToService(&chosen_work_queue));
673     // Don't remove task from queue to simulate the queue is still full.
674   }
675 
676   selector_.SetQueuePriority(task_queues_[0].get(), TaskQueue::kHighPriority);
677   selector_.SetQueuePriority(task_queues_[1].get(), TaskQueue::kNormalPriority);
678 
679   // Run a number of high/normal priority tasks needed to starve low priority
680   // tasks (when present).
681   for (size_t num_tasks = 0;
682        num_tasks <= TaskQueueSelectorForTest::
683                         NumberOfHighAndNormalPriorityToStarveLowPriority();
684        num_tasks++) {
685     WorkQueue* chosen_work_queue = nullptr;
686     ASSERT_TRUE(selector_.SelectWorkQueueToService(&chosen_work_queue));
687     // Don't remove task from queue to simulate the queue is still full.
688   }
689 
690   // Post a low  priority task.
691   selector_.SetQueuePriority(task_queues_[1].get(), TaskQueue::kLowPriority);
692   WorkQueue* chosen_work_queue = nullptr;
693   ASSERT_TRUE(selector_.SelectWorkQueueToService(&chosen_work_queue));
694 
695   // Check that the low priority task is not considered starved, and thus
696   // isn't processed.
697   EXPECT_NE(
698       static_cast<int>(
699           queue_to_index_map_.find(chosen_work_queue->task_queue())->second),
700       1);
701 }
702 
TEST_F(TaskQueueSelectorTest,AllEnabledWorkQueuesAreEmpty)703 TEST_F(TaskQueueSelectorTest, AllEnabledWorkQueuesAreEmpty) {
704   EXPECT_TRUE(selector_.AllEnabledWorkQueuesAreEmpty());
705   size_t queue_order[] = {0, 1};
706   PushTasks(queue_order, 2);
707 
708   EXPECT_FALSE(selector_.AllEnabledWorkQueuesAreEmpty());
709   PopTasks();
710   EXPECT_TRUE(selector_.AllEnabledWorkQueuesAreEmpty());
711 }
712 
TEST_F(TaskQueueSelectorTest,AllEnabledWorkQueuesAreEmpty_ControlPriority)713 TEST_F(TaskQueueSelectorTest, AllEnabledWorkQueuesAreEmpty_ControlPriority) {
714   size_t queue_order[] = {0};
715   PushTasks(queue_order, 1);
716 
717   selector_.SetQueuePriority(task_queues_[0].get(),
718                              TaskQueue::kControlPriority);
719 
720   EXPECT_FALSE(selector_.AllEnabledWorkQueuesAreEmpty());
721 }
722 
TEST_F(TaskQueueSelectorTest,ChooseOldestWithPriority_Empty)723 TEST_F(TaskQueueSelectorTest, ChooseOldestWithPriority_Empty) {
724   WorkQueue* chosen_work_queue = nullptr;
725   bool chose_delayed_over_immediate = false;
726   EXPECT_FALSE(prioritizing_selector()->ChooseOldestWithPriority(
727       TaskQueue::kNormalPriority, &chose_delayed_over_immediate,
728       &chosen_work_queue));
729   EXPECT_FALSE(chose_delayed_over_immediate);
730 }
731 
TEST_F(TaskQueueSelectorTest,ChooseOldestWithPriority_OnlyDelayed)732 TEST_F(TaskQueueSelectorTest, ChooseOldestWithPriority_OnlyDelayed) {
733   task_queues_[0]->delayed_work_queue()->Push(TaskQueueImpl::Task(
734       TaskQueue::PostedTask(test_closure_, FROM_HERE), TimeTicks(),
735       EnqueueOrder(), EnqueueOrder::FromIntForTesting(2)));
736 
737   WorkQueue* chosen_work_queue = nullptr;
738   bool chose_delayed_over_immediate = false;
739   EXPECT_TRUE(prioritizing_selector()->ChooseOldestWithPriority(
740       TaskQueue::kNormalPriority, &chose_delayed_over_immediate,
741       &chosen_work_queue));
742   EXPECT_EQ(chosen_work_queue, task_queues_[0]->delayed_work_queue());
743   EXPECT_FALSE(chose_delayed_over_immediate);
744 }
745 
TEST_F(TaskQueueSelectorTest,ChooseOldestWithPriority_OnlyImmediate)746 TEST_F(TaskQueueSelectorTest, ChooseOldestWithPriority_OnlyImmediate) {
747   task_queues_[0]->immediate_work_queue()->Push(TaskQueueImpl::Task(
748       TaskQueue::PostedTask(test_closure_, FROM_HERE), TimeTicks(),
749       EnqueueOrder(), EnqueueOrder::FromIntForTesting(2)));
750 
751   WorkQueue* chosen_work_queue = nullptr;
752   bool chose_delayed_over_immediate = false;
753   EXPECT_TRUE(prioritizing_selector()->ChooseOldestWithPriority(
754       TaskQueue::kNormalPriority, &chose_delayed_over_immediate,
755       &chosen_work_queue));
756   EXPECT_EQ(chosen_work_queue, task_queues_[0]->immediate_work_queue());
757   EXPECT_FALSE(chose_delayed_over_immediate);
758 }
759 
TEST_F(TaskQueueSelectorTest,TestObserverWithOneBlockedQueue)760 TEST_F(TaskQueueSelectorTest, TestObserverWithOneBlockedQueue) {
761   TaskQueueSelectorForTest selector;
762   MockObserver mock_observer;
763   selector.SetTaskQueueSelectorObserver(&mock_observer);
764 
765   EXPECT_CALL(mock_observer, OnTaskQueueEnabled(_)).Times(1);
766 
767   std::unique_ptr<TaskQueueImpl> task_queue(NewTaskQueueWithBlockReporting());
768   selector.AddQueue(task_queue.get());
769 
770   task_queue->SetQueueEnabledForTest(false);
771   selector.DisableQueue(task_queue.get());
772 
773   TaskQueueImpl::Task task(TaskQueue::PostedTask(test_closure_, FROM_HERE),
774                            TimeTicks(), EnqueueOrder(),
775                            EnqueueOrder::FromIntForTesting(2));
776   task_queue->immediate_work_queue()->Push(std::move(task));
777 
778   WorkQueue* chosen_work_queue;
779   EXPECT_FALSE(selector.SelectWorkQueueToService(&chosen_work_queue));
780 
781   task_queue->SetQueueEnabledForTest(true);
782   selector.EnableQueue(task_queue.get());
783   selector.RemoveQueue(task_queue.get());
784   task_queue->UnregisterTaskQueue();
785 }
786 
TEST_F(TaskQueueSelectorTest,TestObserverWithTwoBlockedQueues)787 TEST_F(TaskQueueSelectorTest, TestObserverWithTwoBlockedQueues) {
788   TaskQueueSelectorForTest selector;
789   MockObserver mock_observer;
790   selector.SetTaskQueueSelectorObserver(&mock_observer);
791 
792   std::unique_ptr<TaskQueueImpl> task_queue(NewTaskQueueWithBlockReporting());
793   std::unique_ptr<TaskQueueImpl> task_queue2(NewTaskQueueWithBlockReporting());
794   selector.AddQueue(task_queue.get());
795   selector.AddQueue(task_queue2.get());
796 
797   task_queue->SetQueueEnabledForTest(false);
798   task_queue2->SetQueueEnabledForTest(false);
799   selector.DisableQueue(task_queue.get());
800   selector.DisableQueue(task_queue2.get());
801 
802   selector.SetQueuePriority(task_queue2.get(), TaskQueue::kControlPriority);
803 
804   TaskQueueImpl::Task task1(TaskQueue::PostedTask(test_closure_, FROM_HERE),
805                             TimeTicks(), EnqueueOrder::FromIntForTesting(2),
806                             EnqueueOrder::FromIntForTesting(2));
807   TaskQueueImpl::Task task2(TaskQueue::PostedTask(test_closure_, FROM_HERE),
808                             TimeTicks(), EnqueueOrder::FromIntForTesting(3),
809                             EnqueueOrder::FromIntForTesting(3));
810   task_queue->immediate_work_queue()->Push(std::move(task1));
811   task_queue2->immediate_work_queue()->Push(std::move(task2));
812 
813   WorkQueue* chosen_work_queue;
814   EXPECT_FALSE(selector.SelectWorkQueueToService(&chosen_work_queue));
815   testing::Mock::VerifyAndClearExpectations(&mock_observer);
816 
817   EXPECT_CALL(mock_observer, OnTaskQueueEnabled(_)).Times(2);
818 
819   task_queue->SetQueueEnabledForTest(true);
820   selector.EnableQueue(task_queue.get());
821 
822   selector.RemoveQueue(task_queue.get());
823   task_queue->UnregisterTaskQueue();
824   EXPECT_FALSE(selector.SelectWorkQueueToService(&chosen_work_queue));
825 
826   task_queue2->SetQueueEnabledForTest(true);
827   selector.EnableQueue(task_queue2.get());
828   selector.RemoveQueue(task_queue2.get());
829   task_queue2->UnregisterTaskQueue();
830 }
831 
832 struct ChooseOldestWithPriorityTestParam {
833   int delayed_task_enqueue_order;
834   int immediate_task_enqueue_order;
835   int immediate_starvation_count;
836   const char* expected_work_queue_name;
837   bool expected_did_starve_immediate_queue;
838 };
839 
840 static const ChooseOldestWithPriorityTestParam
841     kChooseOldestWithPriorityTestCases[] = {
842         {1, 2, 0, "delayed", true},    {1, 2, 1, "delayed", true},
843         {1, 2, 2, "delayed", true},    {1, 2, 3, "immediate", false},
844         {1, 2, 4, "immediate", false}, {2, 1, 4, "immediate", false},
845         {2, 1, 4, "immediate", false},
846 };
847 
848 class ChooseOldestWithPriorityTest
849     : public TaskQueueSelectorTest,
850       public testing::WithParamInterface<ChooseOldestWithPriorityTestParam> {};
851 
TEST_P(ChooseOldestWithPriorityTest,RoundRobinTest)852 TEST_P(ChooseOldestWithPriorityTest, RoundRobinTest) {
853   task_queues_[0]->immediate_work_queue()->Push(TaskQueueImpl::Task(
854       TaskQueue::PostedTask(test_closure_, FROM_HERE), TimeTicks(),
855       EnqueueOrder::FromIntForTesting(GetParam().immediate_task_enqueue_order),
856       EnqueueOrder::FromIntForTesting(
857           GetParam().immediate_task_enqueue_order)));
858 
859   task_queues_[0]->delayed_work_queue()->Push(TaskQueueImpl::Task(
860       TaskQueue::PostedTask(test_closure_, FROM_HERE), TimeTicks(),
861       EnqueueOrder::FromIntForTesting(GetParam().delayed_task_enqueue_order),
862       EnqueueOrder::FromIntForTesting(GetParam().delayed_task_enqueue_order)));
863 
864   selector_.SetImmediateStarvationCountForTest(
865       GetParam().immediate_starvation_count);
866 
867   WorkQueue* chosen_work_queue = nullptr;
868   bool chose_delayed_over_immediate = false;
869   EXPECT_TRUE(prioritizing_selector()->ChooseOldestWithPriority(
870       TaskQueue::kNormalPriority, &chose_delayed_over_immediate,
871       &chosen_work_queue));
872   EXPECT_EQ(chosen_work_queue->task_queue(), task_queues_[0].get());
873   EXPECT_STREQ(chosen_work_queue->name(), GetParam().expected_work_queue_name);
874   EXPECT_EQ(chose_delayed_over_immediate,
875             GetParam().expected_did_starve_immediate_queue);
876 }
877 
878 INSTANTIATE_TEST_CASE_P(ChooseOldestWithPriorityTest,
879                         ChooseOldestWithPriorityTest,
880                         testing::ValuesIn(kChooseOldestWithPriorityTestCases));
881 
882 }  // namespace task_queue_selector_unittest
883 }  // namespace internal
884 }  // namespace sequence_manager
885 }  // namespace base
886