| OLD | NEW | 
 | (Empty) | 
|    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 "content/renderer/scheduler/task_queue_manager.h" |  | 
|    6  |  | 
|    7 #include "base/bind.h" |  | 
|    8 #include "base/threading/thread.h" |  | 
|    9 #include "content/renderer/scheduler/renderer_scheduler_message_loop_delegate.h" |  | 
|   10 #include "content/renderer/scheduler/task_queue_selector.h" |  | 
|   11 #include "testing/gtest/include/gtest/gtest.h" |  | 
|   12 #include "testing/perf/perf_test.h" |  | 
|   13  |  | 
|   14 namespace content { |  | 
|   15  |  | 
|   16 namespace { |  | 
|   17  |  | 
|   18 class SelectorForTest : public TaskQueueSelector { |  | 
|   19  public: |  | 
|   20   SelectorForTest() {} |  | 
|   21  |  | 
|   22   void RegisterWorkQueues( |  | 
|   23       const std::vector<const base::TaskQueue*>& work_queues) override { |  | 
|   24     work_queues_ = work_queues; |  | 
|   25   } |  | 
|   26  |  | 
|   27   bool SelectWorkQueueToService(size_t* out_queue_index) override { |  | 
|   28     // Choose the oldest task, if any. |  | 
|   29     bool found_one = false; |  | 
|   30     for (size_t i = 0; i < work_queues_.size(); i++) { |  | 
|   31       if (work_queues_[i]->empty()) |  | 
|   32         continue; |  | 
|   33       // Note: the < comparison is correct due to the fact that the PendingTask |  | 
|   34       // operator inverts its comparison operation in order to work well in a |  | 
|   35       // heap based priority queue. |  | 
|   36       if (!found_one || |  | 
|   37           work_queues_[*out_queue_index]->front() < work_queues_[i]->front()) |  | 
|   38         *out_queue_index = i; |  | 
|   39       found_one = true; |  | 
|   40     } |  | 
|   41     CHECK(found_one); |  | 
|   42     return found_one; |  | 
|   43   } |  | 
|   44  |  | 
|   45   void AsValueInto(base::trace_event::TracedValue* state) const override {} |  | 
|   46  |  | 
|   47  private: |  | 
|   48   std::vector<const base::TaskQueue*> work_queues_; |  | 
|   49  |  | 
|   50   DISALLOW_COPY_AND_ASSIGN(SelectorForTest); |  | 
|   51 }; |  | 
|   52  |  | 
|   53 }  // namespace |  | 
|   54  |  | 
|   55 class TaskQueueManagerPerfTest : public testing::Test { |  | 
|   56  public: |  | 
|   57   TaskQueueManagerPerfTest() |  | 
|   58       : num_queues_(0), |  | 
|   59         max_tasks_in_flight_(0), |  | 
|   60         num_tasks_in_flight_(0), |  | 
|   61         num_tasks_to_post_(0), |  | 
|   62         num_tasks_to_run_(0) {} |  | 
|   63  |  | 
|   64   void Initialize(size_t num_queues) { |  | 
|   65     num_queues_ = num_queues; |  | 
|   66     message_loop_.reset(new base::MessageLoop()); |  | 
|   67     selector_ = make_scoped_ptr(new SelectorForTest); |  | 
|   68     manager_ = make_scoped_ptr(new TaskQueueManager( |  | 
|   69         num_queues, |  | 
|   70         RendererSchedulerMessageLoopDelegate::Create(message_loop_.get()), |  | 
|   71         selector_.get())); |  | 
|   72   } |  | 
|   73  |  | 
|   74   void TestDelayedTask() { |  | 
|   75     if (--num_tasks_to_run_ == 0) { |  | 
|   76       message_loop_->Quit(); |  | 
|   77     } |  | 
|   78  |  | 
|   79     num_tasks_in_flight_--; |  | 
|   80     // NOTE there are only up to max_tasks_in_flight_ pending delayed tasks at |  | 
|   81     // any one time.  Thanks to the lower_num_tasks_to_post going to zero if |  | 
|   82     // there are a lot of tasks in flight, the total number of task in flight at |  | 
|   83     // any one time is very variable. |  | 
|   84     unsigned int lower_num_tasks_to_post = |  | 
|   85         num_tasks_in_flight_ < (max_tasks_in_flight_ / 2) ? 1 : 0; |  | 
|   86     unsigned int max_tasks_to_post = |  | 
|   87         num_tasks_to_post_ % 2 ? lower_num_tasks_to_post : 10; |  | 
|   88     for (unsigned int i = 0; |  | 
|   89          i < max_tasks_to_post && num_tasks_in_flight_ < max_tasks_in_flight_ && |  | 
|   90              num_tasks_to_post_ > 0; |  | 
|   91          i++) { |  | 
|   92       // Choose a queue weighted towards queue 0. |  | 
|   93       unsigned int queue = num_tasks_to_post_ % (num_queues_ + 1); |  | 
|   94       if (queue == num_queues_) { |  | 
|   95         queue = 0; |  | 
|   96       } |  | 
|   97       // Simulate a mix of short and longer delays. |  | 
|   98       unsigned int delay = |  | 
|   99           num_tasks_to_post_ % 2 ? 1 : (10 + num_tasks_to_post_ % 10); |  | 
|  100       scoped_refptr<base::SingleThreadTaskRunner> runner = |  | 
|  101           manager_->TaskRunnerForQueue(queue); |  | 
|  102       runner->PostDelayedTask( |  | 
|  103           FROM_HERE, base::Bind(&TaskQueueManagerPerfTest::TestDelayedTask, |  | 
|  104                                 base::Unretained(this)), |  | 
|  105           base::TimeDelta::FromMicroseconds(delay)); |  | 
|  106       num_tasks_in_flight_++; |  | 
|  107       num_tasks_to_post_--; |  | 
|  108     } |  | 
|  109   } |  | 
|  110  |  | 
|  111   void ResetAndCallTestDelayedTask(unsigned int num_tasks_to_run) { |  | 
|  112     num_tasks_in_flight_ = 1; |  | 
|  113     num_tasks_to_post_ = num_tasks_to_run; |  | 
|  114     num_tasks_to_run_ = num_tasks_to_run; |  | 
|  115     TestDelayedTask(); |  | 
|  116   } |  | 
|  117  |  | 
|  118   void Benchmark(const std::string& trace, const base::Closure& test_task) { |  | 
|  119     base::TimeTicks start = base::TimeTicks::Now(); |  | 
|  120     base::TimeTicks now; |  | 
|  121     unsigned long long num_iterations = 0; |  | 
|  122     do { |  | 
|  123       test_task.Run(); |  | 
|  124       message_loop_->Run(); |  | 
|  125       now = base::TimeTicks::Now(); |  | 
|  126       num_iterations++; |  | 
|  127     } while (now - start < base::TimeDelta::FromSeconds(5)); |  | 
|  128     perf_test::PrintResult( |  | 
|  129         "task", "", trace, |  | 
|  130         (now - start).InMicroseconds() / static_cast<double>(num_iterations), |  | 
|  131         "us/run", true); |  | 
|  132   } |  | 
|  133  |  | 
|  134   size_t num_queues_; |  | 
|  135   unsigned int max_tasks_in_flight_; |  | 
|  136   unsigned int num_tasks_in_flight_; |  | 
|  137   unsigned int num_tasks_to_post_; |  | 
|  138   unsigned int num_tasks_to_run_; |  | 
|  139   scoped_ptr<SelectorForTest> selector_; |  | 
|  140   scoped_ptr<TaskQueueManager> manager_; |  | 
|  141   scoped_ptr<base::MessageLoop> message_loop_; |  | 
|  142 }; |  | 
|  143  |  | 
|  144 TEST_F(TaskQueueManagerPerfTest, RunTenThousandDelayedTasks_OneQueue) { |  | 
|  145   Initialize(1u); |  | 
|  146  |  | 
|  147   max_tasks_in_flight_ = 200; |  | 
|  148   Benchmark("run 10000 delayed tasks with one queue", |  | 
|  149             base::Bind(&TaskQueueManagerPerfTest::ResetAndCallTestDelayedTask, |  | 
|  150                        base::Unretained(this), 10000)); |  | 
|  151 } |  | 
|  152  |  | 
|  153 TEST_F(TaskQueueManagerPerfTest, RunTenThousandDelayedTasks_FourQueues) { |  | 
|  154   Initialize(4u); |  | 
|  155  |  | 
|  156   max_tasks_in_flight_ = 200; |  | 
|  157   Benchmark("run 10000 delayed tasks with four queues", |  | 
|  158             base::Bind(&TaskQueueManagerPerfTest::ResetAndCallTestDelayedTask, |  | 
|  159                        base::Unretained(this), 10000)); |  | 
|  160 } |  | 
|  161  |  | 
|  162 TEST_F(TaskQueueManagerPerfTest, RunTenThousandDelayedTasks_EightQueues) { |  | 
|  163   Initialize(8u); |  | 
|  164  |  | 
|  165   max_tasks_in_flight_ = 200; |  | 
|  166   Benchmark("run 10000 delayed tasks with eight queues", |  | 
|  167             base::Bind(&TaskQueueManagerPerfTest::ResetAndCallTestDelayedTask, |  | 
|  168                        base::Unretained(this), 10000)); |  | 
|  169 } |  | 
|  170  |  | 
|  171 // TODO(alexclarke): Add additional tests with different mixes of non-delayed vs |  | 
|  172 // delayed tasks. |  | 
|  173  |  | 
|  174 }  // namespace content |  | 
| OLD | NEW |