Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(709)

Unified Diff: gpu/ipc/service/gpu_scheduler_unittest.cc

Issue 2440093003: WIP GPU scheduler + delayed activation / tile draw
Patch Set: SignalSyncToken -> IsFenceSyncReleased Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « gpu/ipc/service/gpu_scheduler.cc ('k') | ppapi/proxy/ppapi_command_buffer_proxy.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: gpu/ipc/service/gpu_scheduler_unittest.cc
diff --git a/gpu/ipc/service/gpu_scheduler_unittest.cc b/gpu/ipc/service/gpu_scheduler_unittest.cc
new file mode 100644
index 0000000000000000000000000000000000000000..0744c3c34f29918cf44fe7b5f18f0cee33e3fbf7
--- /dev/null
+++ b/gpu/ipc/service/gpu_scheduler_unittest.cc
@@ -0,0 +1,309 @@
+// Copyright (c) 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/ipc/service/gpu_scheduler.h"
+
+#include <algorithm>
+
+#include "base/memory/ptr_util.h"
+#include "base/test/test_mock_time_task_runner.h"
+#include "gpu/ipc/service/gpu_command_stream.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gmock_mutant.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace gpu {
+namespace {
+
+using ::testing::_;
+using ::testing::CreateFunctor;
+using ::testing::Invoke;
+using ::testing::Return;
+using ::testing::StrictMock;
+
+base::TimeDelta kSchedulingGranularity =
+ base::TimeDelta::FromMicroseconds(1000);
+
+base::TimeDelta kTimeSliceRealTime = base::TimeDelta::FromMicroseconds(16000);
+base::TimeDelta kTimeSliceHigh = base::TimeDelta::FromMicroseconds(8000);
+base::TimeDelta kTimeSliceNormal = base::TimeDelta::FromMicroseconds(4000);
+base::TimeDelta kTimeSliceLow = base::TimeDelta::FromMicroseconds(2000);
+
+base::TimeDelta kRealTimeMaxWaitDuration =
+ base::TimeDelta::FromMicroseconds(4000);
+
+base::TimeDelta kSchedulerPollingInterval =
+ base::TimeDelta::FromMicroseconds(100);
+
+class TestTaskRunner : public base::TestMockTimeTaskRunner {
+ public:
+ TestTaskRunner()
+ : TestMockTimeTaskRunner(), run_pending_only_(false), pending_tasks_(0) {}
+
+ void RunPendingTasksUntil(base::TimeTicks target) {
+ run_pending_only_ = true;
+ pending_tasks_ = TestMockTimeTaskRunner::GetPendingTaskCount();
+ base::TimeDelta delta = target - TestMockTimeTaskRunner::NowTicks();
+ TestMockTimeTaskRunner::FastForwardBy(delta);
+ run_pending_only_ = false;
+ }
+
+ protected:
+ ~TestTaskRunner() override {}
+
+ bool IsElapsingStopped() override {
+ if (run_pending_only_)
+ return pending_tasks_ == 0;
+ return TestMockTimeTaskRunner::IsElapsingStopped();
+ }
+
+ void OnAfterTaskRun() override {
+ if (run_pending_only_ && pending_tasks_ > 0)
+ pending_tasks_--;
+ }
+
+ private:
+ bool run_pending_only_;
+ size_t pending_tasks_;
+};
+
+class TestGpuScheduler : public GpuScheduler {
+ public:
+ static std::unique_ptr<TestGpuScheduler> Create(
+ scoped_refptr<TestTaskRunner> task_runner) {
+ GpuSchedulerSettings settings;
+ base::TimeDelta priority_time_slice[kNumGpuStreamPriorities] = {
+ kTimeSliceRealTime, kTimeSliceHigh, kTimeSliceNormal, kTimeSliceLow};
+ std::copy(priority_time_slice,
+ priority_time_slice + kNumGpuStreamPriorities,
+ settings.priority_time_slice);
+ settings.scheduling_granularity = kSchedulingGranularity;
+ settings.real_time_max_wait_duration = kRealTimeMaxWaitDuration;
+
+ return base::WrapUnique(new TestGpuScheduler(settings, task_runner));
+ }
+
+ TestGpuScheduler(const GpuSchedulerSettings& settings,
+ scoped_refptr<TestTaskRunner> task_runner)
+ : GpuScheduler(settings, task_runner, task_runner),
+ task_runner_(task_runner) {}
+ ~TestGpuScheduler() override {}
+
+ void RunPendingTasks() { task_runner_->RunPendingTasksUntil(now_); }
+
+ void AdvanceSchedulingTick() { AdvanceNow(kSchedulingGranularity); }
+
+ void AdvanceNow(base::TimeDelta delta) { now_ += delta; }
+
+ protected:
+ base::TimeTicks Now() const override { return task_runner_->NowTicks(); }
+
+ private:
+ scoped_refptr<TestTaskRunner> task_runner_;
+ base::TimeTicks now_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestGpuScheduler);
+};
+
+class MockGpuCommandStream : public GpuCommandStream {
+ public:
+ MockGpuCommandStream(TestGpuScheduler* scheduler, GpuStreamPriority priority)
+ : scheduler_(scheduler), priority_(priority), can_run_(false) {}
+ ~MockGpuCommandStream() override {}
+
+ bool CanRun() const override { return can_run_; }
+ void set_can_run(bool can_run) { can_run_ = can_run; }
+
+ GpuStreamPriority Priority() const override { return priority_; }
+
+ void EnablePolling() {
+ ON_CALL(*this, Run())
+ .WillByDefault(Invoke(this, &MockGpuCommandStream::PollScheduler));
+ }
+
+ void DisablePolling() { ON_CALL(*this, Run()).WillByDefault(Return()); }
+
+ base::TimeDelta poll_duration() const { return poll_duration_; }
+
+ void PollScheduler() {
+ poll_duration_ = base::TimeDelta();
+ while (!scheduler_->NeedsRescheduling()) {
+ poll_duration_ += kSchedulerPollingInterval;
+ scheduler_->AdvanceNow(kSchedulerPollingInterval);
+ scheduler_->RunPendingTasks();
+ }
+ }
+
+ MOCK_METHOD0(Run, void());
+
+ private:
+ TestGpuScheduler* scheduler_;
+ GpuStreamPriority priority_;
+ bool can_run_;
+ base::TimeDelta poll_duration_;
+};
+
+class GpuSchedulerTest : public testing::Test {
+ public:
+ GpuSchedulerTest()
+ : task_runner_(new TestTaskRunner),
+ scheduler_(TestGpuScheduler::Create(task_runner_)) {}
+ ~GpuSchedulerTest() override {}
+
+ protected:
+ scoped_refptr<TestTaskRunner> task_runner_;
+ std::unique_ptr<TestGpuScheduler> scheduler_;
+};
+
+TEST_F(GpuSchedulerTest, SingleStream) {
+ StrictMock<MockGpuCommandStream> stream(scheduler_.get(),
+ GpuStreamPriority::NORMAL);
+ scheduler_->AddStream(&stream);
+ stream.set_can_run(true);
+ scheduler_->OnStreamCanRun(&stream);
+ for (int i = 0; i < 5; ++i) {
+ EXPECT_CALL(stream, Run());
+ scheduler_->RunPendingTasks();
+ }
+}
+
+TEST_F(GpuSchedulerTest, CanRun) {
+ StrictMock<MockGpuCommandStream> stream(scheduler_.get(),
+ GpuStreamPriority::NORMAL);
+ scheduler_->AddStream(&stream);
+ stream.set_can_run(true);
+ scheduler_->OnStreamCanRun(&stream);
+ for (int i = 0; i < 5; ++i) {
+ EXPECT_CALL(stream, Run());
+ scheduler_->RunPendingTasks();
+ }
+ EXPECT_CALL(stream, Run())
+ .WillOnce(Invoke(CreateFunctor(&MockGpuCommandStream::set_can_run,
+ base::Unretained(&stream), false)));
+ scheduler_->RunPendingTasks();
+ // No more Run.
+ scheduler_->RunPendingTasks();
+}
+
+TEST_F(GpuSchedulerTest, MultipleStreams) {
+ StrictMock<MockGpuCommandStream> stream1(scheduler_.get(),
+ GpuStreamPriority::LOW);
+ scheduler_->AddStream(&stream1);
+ stream1.set_can_run(true);
+ scheduler_->OnStreamCanRun(&stream1);
+
+ StrictMock<MockGpuCommandStream> stream2(scheduler_.get(),
+ GpuStreamPriority::NORMAL);
+ scheduler_->AddStream(&stream2);
+ stream2.set_can_run(true);
+ scheduler_->OnStreamCanRun(&stream2);
+
+ for (int i = 0; i < 5; ++i) {
+ EXPECT_CALL(stream2, Run());
+ scheduler_->RunPendingTasks();
+ EXPECT_CALL(stream1, Run());
+ scheduler_->RunPendingTasks();
+ }
+}
+
+TEST_F(GpuSchedulerTest, Timeslice) {
+ StrictMock<MockGpuCommandStream> stream(scheduler_.get(),
+ GpuStreamPriority::NORMAL);
+ scheduler_->AddStream(&stream);
+ stream.set_can_run(true);
+ scheduler_->OnStreamCanRun(&stream);
+
+ stream.EnablePolling();
+ EXPECT_CALL(stream, Run());
+ scheduler_->RunPendingTasks();
+ EXPECT_EQ(kTimeSliceNormal, stream.poll_duration());
+}
+
+TEST_F(GpuSchedulerTest, Preemption) {
+ StrictMock<MockGpuCommandStream> stream1(scheduler_.get(),
+ GpuStreamPriority::NORMAL);
+ scheduler_->AddStream(&stream1);
+ stream1.set_can_run(true);
+ scheduler_->OnStreamCanRun(&stream1);
+
+ StrictMock<MockGpuCommandStream> stream2(scheduler_.get(),
+ GpuStreamPriority::REAL_TIME);
+ scheduler_->AddStream(&stream2);
+ stream2.set_can_run(true);
+
+ auto kRealTimeRunnableDelay = base::TimeDelta::FromMicroseconds(2500);
+ task_runner_->PostDelayedTask(FROM_HERE,
+ base::Bind(&TestGpuScheduler::OnStreamCanRun,
+ base::Unretained(scheduler_.get()),
+ base::Unretained(&stream2)),
+ kRealTimeRunnableDelay);
+
+ stream1.EnablePolling();
+ EXPECT_CALL(stream1, Run());
+ scheduler_->RunPendingTasks();
+ EXPECT_EQ(kRealTimeRunnableDelay + kSchedulerPollingInterval,
+ stream1.poll_duration());
+}
+
+TEST_F(GpuSchedulerTest, RemoveWhileRunning) {
+ StrictMock<MockGpuCommandStream> stream(scheduler_.get(),
+ GpuStreamPriority::NORMAL);
+ scheduler_->AddStream(&stream);
+ stream.set_can_run(true);
+ scheduler_->OnStreamCanRun(&stream);
+
+ EXPECT_CALL(stream, Run())
+ .WillOnce(Invoke(CreateFunctor(&TestGpuScheduler::RemoveStream,
+ base::Unretained(scheduler_.get()),
+ base::Unretained(&stream))));
+ scheduler_->RunPendingTasks();
+ // No more Run.
+ scheduler_->RunPendingTasks();
+}
+
+TEST_F(GpuSchedulerTest, PriorityInversion) {
+ StrictMock<MockGpuCommandStream> stream1(scheduler_.get(),
+ GpuStreamPriority::REAL_TIME);
+ scheduler_->AddStream(&stream1);
+ stream1.set_can_run(true);
+ scheduler_->OnStreamCanRun(&stream1);
+
+ StrictMock<MockGpuCommandStream> stream2(scheduler_.get(),
+ GpuStreamPriority::NORMAL);
+ scheduler_->AddStream(&stream2);
+ stream2.set_can_run(true);
+ scheduler_->OnStreamCanRun(&stream2);
+
+ StrictMock<MockGpuCommandStream> stream3(scheduler_.get(),
+ GpuStreamPriority::LOW);
+ scheduler_->AddStream(&stream3);
+ stream3.set_can_run(true);
+ scheduler_->OnStreamCanRun(&stream3);
+
+ EXPECT_CALL(stream1, Run())
+ .WillOnce(Invoke(CreateFunctor(&TestGpuScheduler::AddStreamDependency,
+ base::Unretained(scheduler_.get()),
+ base::Unretained(&stream3),
+ base::Unretained(&stream1))));
+ scheduler_->RunPendingTasks();
+
+ EXPECT_CALL(stream3, Run())
+ .WillOnce(Invoke(CreateFunctor(&TestGpuScheduler::RemoveStreamDependency,
+ base::Unretained(scheduler_.get()),
+ base::Unretained(&stream3),
+ base::Unretained(&stream1))));
+ scheduler_->RunPendingTasks();
+
+ EXPECT_CALL(stream2, Run());
+ scheduler_->RunPendingTasks();
+
+ EXPECT_CALL(stream3, Run());
+ scheduler_->RunPendingTasks();
+
+ EXPECT_CALL(stream1, Run());
+ scheduler_->RunPendingTasks();
+}
+
+} // namespace
+} // namespace gpu
« no previous file with comments | « gpu/ipc/service/gpu_scheduler.cc ('k') | ppapi/proxy/ppapi_command_buffer_proxy.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698