| OLD | NEW |
| (Empty) | |
| 1 // Copyright (c) 2016 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 "gpu/ipc/service/gpu_scheduler.h" |
| 6 |
| 7 #include <algorithm> |
| 8 |
| 9 #include "base/memory/ptr_util.h" |
| 10 #include "base/test/test_mock_time_task_runner.h" |
| 11 #include "gpu/ipc/service/gpu_command_stream.h" |
| 12 #include "testing/gmock/include/gmock/gmock.h" |
| 13 #include "testing/gmock_mutant.h" |
| 14 #include "testing/gtest/include/gtest/gtest.h" |
| 15 |
| 16 namespace gpu { |
| 17 namespace { |
| 18 |
| 19 using ::testing::_; |
| 20 using ::testing::CreateFunctor; |
| 21 using ::testing::Invoke; |
| 22 using ::testing::Return; |
| 23 using ::testing::StrictMock; |
| 24 |
| 25 base::TimeDelta kSchedulingGranularity = |
| 26 base::TimeDelta::FromMicroseconds(1000); |
| 27 |
| 28 base::TimeDelta kTimeSliceRealTime = base::TimeDelta::FromMicroseconds(16000); |
| 29 base::TimeDelta kTimeSliceHigh = base::TimeDelta::FromMicroseconds(8000); |
| 30 base::TimeDelta kTimeSliceNormal = base::TimeDelta::FromMicroseconds(4000); |
| 31 base::TimeDelta kTimeSliceLow = base::TimeDelta::FromMicroseconds(2000); |
| 32 |
| 33 base::TimeDelta kRealTimeMaxWaitDuration = |
| 34 base::TimeDelta::FromMicroseconds(4000); |
| 35 |
| 36 base::TimeDelta kSchedulerPollingInterval = |
| 37 base::TimeDelta::FromMicroseconds(100); |
| 38 |
| 39 class TestTaskRunner : public base::TestMockTimeTaskRunner { |
| 40 public: |
| 41 TestTaskRunner() |
| 42 : TestMockTimeTaskRunner(), run_pending_only_(false), pending_tasks_(0) {} |
| 43 |
| 44 void RunPendingTasksUntil(base::TimeTicks target) { |
| 45 run_pending_only_ = true; |
| 46 pending_tasks_ = TestMockTimeTaskRunner::GetPendingTaskCount(); |
| 47 base::TimeDelta delta = target - TestMockTimeTaskRunner::NowTicks(); |
| 48 TestMockTimeTaskRunner::FastForwardBy(delta); |
| 49 run_pending_only_ = false; |
| 50 } |
| 51 |
| 52 protected: |
| 53 ~TestTaskRunner() override {} |
| 54 |
| 55 bool IsElapsingStopped() override { |
| 56 if (run_pending_only_) |
| 57 return pending_tasks_ == 0; |
| 58 return TestMockTimeTaskRunner::IsElapsingStopped(); |
| 59 } |
| 60 |
| 61 void OnAfterTaskRun() override { |
| 62 if (run_pending_only_ && pending_tasks_ > 0) |
| 63 pending_tasks_--; |
| 64 } |
| 65 |
| 66 private: |
| 67 bool run_pending_only_; |
| 68 size_t pending_tasks_; |
| 69 }; |
| 70 |
| 71 class TestGpuScheduler : public GpuScheduler { |
| 72 public: |
| 73 static std::unique_ptr<TestGpuScheduler> Create( |
| 74 scoped_refptr<TestTaskRunner> task_runner) { |
| 75 GpuSchedulerSettings settings; |
| 76 base::TimeDelta priority_time_slice[kNumGpuStreamPriorities] = { |
| 77 kTimeSliceRealTime, kTimeSliceHigh, kTimeSliceNormal, kTimeSliceLow}; |
| 78 std::copy(priority_time_slice, |
| 79 priority_time_slice + kNumGpuStreamPriorities, |
| 80 settings.priority_time_slice); |
| 81 settings.scheduling_granularity = kSchedulingGranularity; |
| 82 settings.real_time_max_wait_duration = kRealTimeMaxWaitDuration; |
| 83 |
| 84 return base::WrapUnique(new TestGpuScheduler(settings, task_runner)); |
| 85 } |
| 86 |
| 87 TestGpuScheduler(const GpuSchedulerSettings& settings, |
| 88 scoped_refptr<TestTaskRunner> task_runner) |
| 89 : GpuScheduler(settings, task_runner, task_runner), |
| 90 task_runner_(task_runner) {} |
| 91 ~TestGpuScheduler() override {} |
| 92 |
| 93 void RunPendingTasks() { task_runner_->RunPendingTasksUntil(now_); } |
| 94 |
| 95 void AdvanceSchedulingTick() { AdvanceNow(kSchedulingGranularity); } |
| 96 |
| 97 void AdvanceNow(base::TimeDelta delta) { now_ += delta; } |
| 98 |
| 99 protected: |
| 100 base::TimeTicks Now() const override { return task_runner_->NowTicks(); } |
| 101 |
| 102 private: |
| 103 scoped_refptr<TestTaskRunner> task_runner_; |
| 104 base::TimeTicks now_; |
| 105 |
| 106 DISALLOW_COPY_AND_ASSIGN(TestGpuScheduler); |
| 107 }; |
| 108 |
| 109 class MockGpuCommandStream : public GpuCommandStream { |
| 110 public: |
| 111 MockGpuCommandStream(TestGpuScheduler* scheduler, GpuStreamPriority priority) |
| 112 : scheduler_(scheduler), priority_(priority), can_run_(false) {} |
| 113 ~MockGpuCommandStream() override {} |
| 114 |
| 115 bool CanRun() const override { return can_run_; } |
| 116 void set_can_run(bool can_run) { can_run_ = can_run; } |
| 117 |
| 118 GpuStreamPriority Priority() const override { return priority_; } |
| 119 |
| 120 void EnablePolling() { |
| 121 ON_CALL(*this, Run()) |
| 122 .WillByDefault(Invoke(this, &MockGpuCommandStream::PollScheduler)); |
| 123 } |
| 124 |
| 125 void DisablePolling() { ON_CALL(*this, Run()).WillByDefault(Return()); } |
| 126 |
| 127 base::TimeDelta poll_duration() const { return poll_duration_; } |
| 128 |
| 129 void PollScheduler() { |
| 130 poll_duration_ = base::TimeDelta(); |
| 131 while (!scheduler_->NeedsRescheduling()) { |
| 132 poll_duration_ += kSchedulerPollingInterval; |
| 133 scheduler_->AdvanceNow(kSchedulerPollingInterval); |
| 134 scheduler_->RunPendingTasks(); |
| 135 } |
| 136 } |
| 137 |
| 138 MOCK_METHOD0(Run, void()); |
| 139 |
| 140 private: |
| 141 TestGpuScheduler* scheduler_; |
| 142 GpuStreamPriority priority_; |
| 143 bool can_run_; |
| 144 base::TimeDelta poll_duration_; |
| 145 }; |
| 146 |
| 147 class GpuSchedulerTest : public testing::Test { |
| 148 public: |
| 149 GpuSchedulerTest() |
| 150 : task_runner_(new TestTaskRunner), |
| 151 scheduler_(TestGpuScheduler::Create(task_runner_)) {} |
| 152 ~GpuSchedulerTest() override {} |
| 153 |
| 154 protected: |
| 155 scoped_refptr<TestTaskRunner> task_runner_; |
| 156 std::unique_ptr<TestGpuScheduler> scheduler_; |
| 157 }; |
| 158 |
| 159 TEST_F(GpuSchedulerTest, SingleStream) { |
| 160 StrictMock<MockGpuCommandStream> stream(scheduler_.get(), |
| 161 GpuStreamPriority::NORMAL); |
| 162 scheduler_->AddStream(&stream); |
| 163 stream.set_can_run(true); |
| 164 scheduler_->OnStreamCanRun(&stream); |
| 165 for (int i = 0; i < 5; ++i) { |
| 166 EXPECT_CALL(stream, Run()); |
| 167 scheduler_->RunPendingTasks(); |
| 168 } |
| 169 } |
| 170 |
| 171 TEST_F(GpuSchedulerTest, CanRun) { |
| 172 StrictMock<MockGpuCommandStream> stream(scheduler_.get(), |
| 173 GpuStreamPriority::NORMAL); |
| 174 scheduler_->AddStream(&stream); |
| 175 stream.set_can_run(true); |
| 176 scheduler_->OnStreamCanRun(&stream); |
| 177 for (int i = 0; i < 5; ++i) { |
| 178 EXPECT_CALL(stream, Run()); |
| 179 scheduler_->RunPendingTasks(); |
| 180 } |
| 181 EXPECT_CALL(stream, Run()) |
| 182 .WillOnce(Invoke(CreateFunctor(&MockGpuCommandStream::set_can_run, |
| 183 base::Unretained(&stream), false))); |
| 184 scheduler_->RunPendingTasks(); |
| 185 // No more Run. |
| 186 scheduler_->RunPendingTasks(); |
| 187 } |
| 188 |
| 189 TEST_F(GpuSchedulerTest, MultipleStreams) { |
| 190 StrictMock<MockGpuCommandStream> stream1(scheduler_.get(), |
| 191 GpuStreamPriority::LOW); |
| 192 scheduler_->AddStream(&stream1); |
| 193 stream1.set_can_run(true); |
| 194 scheduler_->OnStreamCanRun(&stream1); |
| 195 |
| 196 StrictMock<MockGpuCommandStream> stream2(scheduler_.get(), |
| 197 GpuStreamPriority::NORMAL); |
| 198 scheduler_->AddStream(&stream2); |
| 199 stream2.set_can_run(true); |
| 200 scheduler_->OnStreamCanRun(&stream2); |
| 201 |
| 202 for (int i = 0; i < 5; ++i) { |
| 203 EXPECT_CALL(stream2, Run()); |
| 204 scheduler_->RunPendingTasks(); |
| 205 EXPECT_CALL(stream1, Run()); |
| 206 scheduler_->RunPendingTasks(); |
| 207 } |
| 208 } |
| 209 |
| 210 TEST_F(GpuSchedulerTest, Timeslice) { |
| 211 StrictMock<MockGpuCommandStream> stream(scheduler_.get(), |
| 212 GpuStreamPriority::NORMAL); |
| 213 scheduler_->AddStream(&stream); |
| 214 stream.set_can_run(true); |
| 215 scheduler_->OnStreamCanRun(&stream); |
| 216 |
| 217 stream.EnablePolling(); |
| 218 EXPECT_CALL(stream, Run()); |
| 219 scheduler_->RunPendingTasks(); |
| 220 EXPECT_EQ(kTimeSliceNormal, stream.poll_duration()); |
| 221 } |
| 222 |
| 223 TEST_F(GpuSchedulerTest, Preemption) { |
| 224 StrictMock<MockGpuCommandStream> stream1(scheduler_.get(), |
| 225 GpuStreamPriority::NORMAL); |
| 226 scheduler_->AddStream(&stream1); |
| 227 stream1.set_can_run(true); |
| 228 scheduler_->OnStreamCanRun(&stream1); |
| 229 |
| 230 StrictMock<MockGpuCommandStream> stream2(scheduler_.get(), |
| 231 GpuStreamPriority::REAL_TIME); |
| 232 scheduler_->AddStream(&stream2); |
| 233 stream2.set_can_run(true); |
| 234 |
| 235 auto kRealTimeRunnableDelay = base::TimeDelta::FromMicroseconds(2500); |
| 236 task_runner_->PostDelayedTask(FROM_HERE, |
| 237 base::Bind(&TestGpuScheduler::OnStreamCanRun, |
| 238 base::Unretained(scheduler_.get()), |
| 239 base::Unretained(&stream2)), |
| 240 kRealTimeRunnableDelay); |
| 241 |
| 242 stream1.EnablePolling(); |
| 243 EXPECT_CALL(stream1, Run()); |
| 244 scheduler_->RunPendingTasks(); |
| 245 EXPECT_EQ(kRealTimeRunnableDelay + kSchedulerPollingInterval, |
| 246 stream1.poll_duration()); |
| 247 } |
| 248 |
| 249 TEST_F(GpuSchedulerTest, RemoveWhileRunning) { |
| 250 StrictMock<MockGpuCommandStream> stream(scheduler_.get(), |
| 251 GpuStreamPriority::NORMAL); |
| 252 scheduler_->AddStream(&stream); |
| 253 stream.set_can_run(true); |
| 254 scheduler_->OnStreamCanRun(&stream); |
| 255 |
| 256 EXPECT_CALL(stream, Run()) |
| 257 .WillOnce(Invoke(CreateFunctor(&TestGpuScheduler::RemoveStream, |
| 258 base::Unretained(scheduler_.get()), |
| 259 base::Unretained(&stream)))); |
| 260 scheduler_->RunPendingTasks(); |
| 261 // No more Run. |
| 262 scheduler_->RunPendingTasks(); |
| 263 } |
| 264 |
| 265 TEST_F(GpuSchedulerTest, PriorityInversion) { |
| 266 StrictMock<MockGpuCommandStream> stream1(scheduler_.get(), |
| 267 GpuStreamPriority::REAL_TIME); |
| 268 scheduler_->AddStream(&stream1); |
| 269 stream1.set_can_run(true); |
| 270 scheduler_->OnStreamCanRun(&stream1); |
| 271 |
| 272 StrictMock<MockGpuCommandStream> stream2(scheduler_.get(), |
| 273 GpuStreamPriority::NORMAL); |
| 274 scheduler_->AddStream(&stream2); |
| 275 stream2.set_can_run(true); |
| 276 scheduler_->OnStreamCanRun(&stream2); |
| 277 |
| 278 StrictMock<MockGpuCommandStream> stream3(scheduler_.get(), |
| 279 GpuStreamPriority::LOW); |
| 280 scheduler_->AddStream(&stream3); |
| 281 stream3.set_can_run(true); |
| 282 scheduler_->OnStreamCanRun(&stream3); |
| 283 |
| 284 EXPECT_CALL(stream1, Run()) |
| 285 .WillOnce(Invoke(CreateFunctor(&TestGpuScheduler::AddStreamDependency, |
| 286 base::Unretained(scheduler_.get()), |
| 287 base::Unretained(&stream3), |
| 288 base::Unretained(&stream1)))); |
| 289 scheduler_->RunPendingTasks(); |
| 290 |
| 291 EXPECT_CALL(stream3, Run()) |
| 292 .WillOnce(Invoke(CreateFunctor(&TestGpuScheduler::RemoveStreamDependency, |
| 293 base::Unretained(scheduler_.get()), |
| 294 base::Unretained(&stream3), |
| 295 base::Unretained(&stream1)))); |
| 296 scheduler_->RunPendingTasks(); |
| 297 |
| 298 EXPECT_CALL(stream2, Run()); |
| 299 scheduler_->RunPendingTasks(); |
| 300 |
| 301 EXPECT_CALL(stream3, Run()); |
| 302 scheduler_->RunPendingTasks(); |
| 303 |
| 304 EXPECT_CALL(stream1, Run()); |
| 305 scheduler_->RunPendingTasks(); |
| 306 } |
| 307 |
| 308 } // namespace |
| 309 } // namespace gpu |
| OLD | NEW |