Index: gpu/command_buffer/service/scheduler_unittest.cc |
diff --git a/gpu/command_buffer/service/scheduler_unittest.cc b/gpu/command_buffer/service/scheduler_unittest.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..43328b33577c1600cf9870720f9671b4a6b6d08d |
--- /dev/null |
+++ b/gpu/command_buffer/service/scheduler_unittest.cc |
@@ -0,0 +1,335 @@ |
+// Copyright (c) 2017 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/command_buffer/service/scheduler.h" |
+ |
+#include <algorithm> |
+ |
+#include "base/bind.h" |
+#include "base/memory/ptr_util.h" |
+#include "base/test/test_simple_task_runner.h" |
+#include "gpu/command_buffer/service/sync_point_manager.h" |
+#include "testing/gtest/include/gtest/gtest.h" |
+ |
+namespace gpu { |
+namespace { |
+ |
+template <typename T> |
+void RunFunctor(T functor) { |
+ functor(); |
+} |
+ |
+template <typename T> |
+base::OnceClosure GetClosure(T functor) { |
+ return base::BindOnce(&RunFunctor<T>, functor); |
+} |
+ |
+class SchedulerTest : public testing::Test { |
+ public: |
+ SchedulerTest() |
+ : task_runner_(new base::TestSimpleTaskRunner()), |
+ sync_point_manager_(new SyncPointManager), |
+ scheduler_(new Scheduler(task_runner_, sync_point_manager_.get())) {} |
+ |
+ protected: |
+ base::TestSimpleTaskRunner* task_runner() const { return task_runner_.get(); } |
+ |
+ SyncPointManager* sync_point_manager() const { |
+ return sync_point_manager_.get(); |
+ } |
+ |
+ Scheduler* scheduler() const { return scheduler_.get(); } |
+ |
+ private: |
+ scoped_refptr<base::TestSimpleTaskRunner> task_runner_; |
+ std::unique_ptr<SyncPointManager> sync_point_manager_; |
+ std::unique_ptr<Scheduler> scheduler_; |
+}; |
+ |
+TEST_F(SchedulerTest, ScheduledTasksRunInOrder) { |
+ SequenceId sequence_id = |
+ scheduler()->CreateSequence(SchedulingPriority::kNormal); |
+ |
+ bool ran1 = false; |
+ scheduler()->ScheduleTask(sequence_id, GetClosure([&] { ran1 = true; }), |
+ std::vector<SyncToken>()); |
+ |
+ bool ran2 = false; |
+ scheduler()->ScheduleTask(sequence_id, GetClosure([&] { ran2 = true; }), |
+ std::vector<SyncToken>()); |
+ |
+ task_runner()->RunPendingTasks(); |
+ EXPECT_TRUE(ran1); |
+ |
+ task_runner()->RunPendingTasks(); |
+ EXPECT_TRUE(ran2); |
+} |
+ |
+TEST_F(SchedulerTest, ContinuedTasksRunFirst) { |
+ SequenceId sequence_id = |
+ scheduler()->CreateSequence(SchedulingPriority::kNormal); |
+ |
+ bool ran1 = false; |
+ bool continued1 = false; |
+ scheduler()->ScheduleTask(sequence_id, GetClosure([&] { |
+ scheduler()->ContinueTask( |
+ sequence_id, |
+ GetClosure([&] { continued1 = true; })); |
+ ran1 = true; |
+ }), |
+ std::vector<SyncToken>()); |
+ |
+ bool ran2 = false; |
+ scheduler()->ScheduleTask(sequence_id, GetClosure([&] { ran2 = true; }), |
+ std::vector<SyncToken>()); |
+ |
+ task_runner()->RunPendingTasks(); |
+ EXPECT_TRUE(ran1); |
+ EXPECT_FALSE(continued1); |
+ EXPECT_FALSE(ran2); |
+ |
+ task_runner()->RunPendingTasks(); |
+ EXPECT_TRUE(continued1); |
+ EXPECT_FALSE(ran2); |
+ |
+ task_runner()->RunPendingTasks(); |
+ EXPECT_TRUE(ran2); |
+} |
+ |
+TEST_F(SchedulerTest, SequencesRunInPriorityOrder) { |
+ SequenceId sequence_id1 = |
+ scheduler()->CreateSequence(SchedulingPriority::kLowest); |
+ bool ran1 = false; |
+ scheduler()->ScheduleTask(sequence_id1, GetClosure([&] { ran1 = true; }), |
+ std::vector<SyncToken>()); |
+ |
+ SequenceId sequence_id2 = |
+ scheduler()->CreateSequence(SchedulingPriority::kNormal); |
+ bool ran2 = false; |
+ scheduler()->ScheduleTask(sequence_id2, GetClosure([&] { ran2 = true; }), |
+ std::vector<SyncToken>()); |
+ |
+ SequenceId sequence_id3 = |
+ scheduler()->CreateSequence(SchedulingPriority::kHighest); |
+ bool ran3 = false; |
+ scheduler()->ScheduleTask(sequence_id3, GetClosure([&] { ran3 = true; }), |
+ std::vector<SyncToken>()); |
+ |
+ task_runner()->RunPendingTasks(); |
+ EXPECT_TRUE(ran3); |
+ |
+ task_runner()->RunPendingTasks(); |
+ EXPECT_TRUE(ran2); |
+ |
+ task_runner()->RunPendingTasks(); |
+ EXPECT_TRUE(ran1); |
+} |
+ |
+TEST_F(SchedulerTest, SequencesOfSamePriorityRunInOrder) { |
+ SequenceId sequence_id1 = |
+ scheduler()->CreateSequence(SchedulingPriority::kNormal); |
+ bool ran1 = false; |
+ scheduler()->ScheduleTask(sequence_id1, GetClosure([&] { ran1 = true; }), |
+ std::vector<SyncToken>()); |
+ |
+ SequenceId sequence_id2 = |
+ scheduler()->CreateSequence(SchedulingPriority::kNormal); |
+ bool ran2 = false; |
+ scheduler()->ScheduleTask(sequence_id2, GetClosure([&] { ran2 = true; }), |
+ std::vector<SyncToken>()); |
+ |
+ SequenceId sequence_id3 = |
+ scheduler()->CreateSequence(SchedulingPriority::kNormal); |
+ bool ran3 = false; |
+ scheduler()->ScheduleTask(sequence_id3, GetClosure([&] { ran3 = true; }), |
+ std::vector<SyncToken>()); |
+ |
+ SequenceId sequence_id4 = |
+ scheduler()->CreateSequence(SchedulingPriority::kNormal); |
+ bool ran4 = false; |
+ scheduler()->ScheduleTask(sequence_id4, GetClosure([&] { ran4 = true; }), |
+ std::vector<SyncToken>()); |
+ |
+ task_runner()->RunPendingTasks(); |
+ EXPECT_TRUE(ran1); |
+ |
+ task_runner()->RunPendingTasks(); |
+ EXPECT_TRUE(ran2); |
+ |
+ task_runner()->RunPendingTasks(); |
+ EXPECT_TRUE(ran3); |
+ |
+ task_runner()->RunPendingTasks(); |
+ EXPECT_TRUE(ran4); |
+} |
+ |
+TEST_F(SchedulerTest, SequenceWaitsForFence) { |
+ SequenceId sequence_id1 = |
+ scheduler()->CreateSequence(SchedulingPriority::kHighest); |
+ SequenceId sequence_id2 = |
+ scheduler()->CreateSequence(SchedulingPriority::kNormal); |
+ |
+ CommandBufferNamespace namespace_id = CommandBufferNamespace::GPU_IO; |
+ CommandBufferId command_buffer_id = CommandBufferId::FromUnsafeValue(1); |
+ |
+ scoped_refptr<SyncPointClientState> release_state = |
+ sync_point_manager()->CreateSyncPointClientState( |
+ namespace_id, command_buffer_id, sequence_id2); |
+ |
+ uint64_t release = 1; |
+ bool ran2 = false; |
+ scheduler()->ScheduleTask(sequence_id2, GetClosure([&] { |
+ release_state->ReleaseFenceSync(release); |
+ ran2 = true; |
+ }), |
+ std::vector<SyncToken>()); |
+ |
+ SyncToken sync_token(namespace_id, 0 /* extra_data_field */, |
+ command_buffer_id, release); |
+ |
+ bool ran1 = false; |
+ scheduler()->ScheduleTask(sequence_id1, GetClosure([&] { ran1 = true; }), |
+ {sync_token}); |
+ |
+ task_runner()->RunPendingTasks(); |
+ EXPECT_FALSE(ran1); |
+ EXPECT_TRUE(ran2); |
+ EXPECT_TRUE(sync_point_manager()->IsSyncTokenReleased(sync_token)); |
+ |
+ task_runner()->RunPendingTasks(); |
+ EXPECT_TRUE(ran1); |
+ |
+ release_state->Destroy(); |
+} |
+ |
+TEST_F(SchedulerTest, SequenceDoesNotWaitForInvalidFence) { |
+ SequenceId sequence_id1 = |
+ scheduler()->CreateSequence(SchedulingPriority::kNormal); |
+ |
+ SequenceId sequence_id2 = |
+ scheduler()->CreateSequence(SchedulingPriority::kNormal); |
+ CommandBufferNamespace namespace_id = CommandBufferNamespace::GPU_IO; |
+ CommandBufferId command_buffer_id = CommandBufferId::FromUnsafeValue(1); |
+ scoped_refptr<SyncPointClientState> release_state = |
+ sync_point_manager()->CreateSyncPointClientState( |
+ namespace_id, command_buffer_id, sequence_id2); |
+ |
+ uint64_t release = 1; |
+ SyncToken sync_token(namespace_id, 0 /* extra_data_field */, |
+ command_buffer_id, release); |
+ |
+ bool ran1 = false; |
+ scheduler()->ScheduleTask(sequence_id1, GetClosure([&] { ran1 = true; }), |
+ {sync_token}); |
+ |
+ // Release task is scheduled after wait task so release is treated as non- |
+ // existent. |
+ bool ran2 = false; |
+ scheduler()->ScheduleTask(sequence_id2, GetClosure([&] { |
+ release_state->ReleaseFenceSync(release); |
+ ran2 = true; |
+ }), |
+ std::vector<SyncToken>()); |
+ |
+ task_runner()->RunPendingTasks(); |
+ EXPECT_TRUE(ran1); |
+ EXPECT_FALSE(ran2); |
+ EXPECT_FALSE(sync_point_manager()->IsSyncTokenReleased(sync_token)); |
+ |
+ task_runner()->RunPendingTasks(); |
+ EXPECT_TRUE(ran2); |
+ EXPECT_TRUE(sync_point_manager()->IsSyncTokenReleased(sync_token)); |
+ |
+ release_state->Destroy(); |
+} |
+ |
+TEST_F(SchedulerTest, ReleaseSequenceIsPrioritized) { |
+ SequenceId sequence_id1 = |
+ scheduler()->CreateSequence(SchedulingPriority::kNormal); |
+ |
+ bool ran1 = false; |
+ scheduler()->ScheduleTask(sequence_id1, GetClosure([&] { ran1 = true; }), |
+ std::vector<SyncToken>()); |
+ |
+ SequenceId sequence_id2 = |
+ scheduler()->CreateSequence(SchedulingPriority::kLowest); |
+ CommandBufferNamespace namespace_id = CommandBufferNamespace::GPU_IO; |
+ CommandBufferId command_buffer_id = CommandBufferId::FromUnsafeValue(1); |
+ scoped_refptr<SyncPointClientState> release_state = |
+ sync_point_manager()->CreateSyncPointClientState( |
+ namespace_id, command_buffer_id, sequence_id2); |
+ |
+ uint64_t release = 1; |
+ bool ran2 = false; |
+ scheduler()->ScheduleTask(sequence_id2, GetClosure([&] { |
+ release_state->ReleaseFenceSync(release); |
+ ran2 = true; |
+ }), |
+ std::vector<SyncToken>()); |
+ |
+ bool ran3 = false; |
+ SyncToken sync_token(namespace_id, 0 /* extra_data_field */, |
+ command_buffer_id, release); |
+ SequenceId sequence_id3 = |
+ scheduler()->CreateSequence(SchedulingPriority::kHighest); |
+ scheduler()->ScheduleTask(sequence_id3, GetClosure([&] { ran3 = true; }), |
+ {sync_token}); |
+ |
+ task_runner()->RunPendingTasks(); |
+ EXPECT_FALSE(ran1); |
+ EXPECT_TRUE(ran2); |
+ EXPECT_FALSE(ran3); |
+ EXPECT_TRUE(sync_point_manager()->IsSyncTokenReleased(sync_token)); |
+ |
+ task_runner()->RunPendingTasks(); |
+ EXPECT_FALSE(ran1); |
+ EXPECT_TRUE(ran3); |
+ |
+ task_runner()->RunPendingTasks(); |
+ EXPECT_TRUE(ran1); |
+ |
+ release_state->Destroy(); |
+} |
+ |
+TEST_F(SchedulerTest, ReleaseSequenceShouldYield) { |
+ SequenceId sequence_id1 = |
+ scheduler()->CreateSequence(SchedulingPriority::kLowest); |
+ CommandBufferNamespace namespace_id = CommandBufferNamespace::GPU_IO; |
+ CommandBufferId command_buffer_id = CommandBufferId::FromUnsafeValue(1); |
+ scoped_refptr<SyncPointClientState> release_state = |
+ sync_point_manager()->CreateSyncPointClientState( |
+ namespace_id, command_buffer_id, sequence_id1); |
+ |
+ uint64_t release = 1; |
+ bool ran1 = false; |
+ scheduler()->ScheduleTask( |
+ sequence_id1, GetClosure([&] { |
+ EXPECT_FALSE(scheduler()->ShouldYield(sequence_id1)); |
+ release_state->ReleaseFenceSync(release); |
+ EXPECT_TRUE(scheduler()->ShouldYield(sequence_id1)); |
+ ran1 = true; |
+ }), |
+ std::vector<SyncToken>()); |
+ |
+ bool ran2 = false; |
+ SyncToken sync_token(namespace_id, 0 /* extra_data_field */, |
+ command_buffer_id, release); |
+ SequenceId sequence_id2 = |
+ scheduler()->CreateSequence(SchedulingPriority::kHighest); |
+ scheduler()->ScheduleTask(sequence_id2, GetClosure([&] { ran2 = true; }), |
+ {sync_token}); |
+ |
+ task_runner()->RunPendingTasks(); |
+ EXPECT_TRUE(ran1); |
+ EXPECT_FALSE(ran2); |
+ EXPECT_TRUE(sync_point_manager()->IsSyncTokenReleased(sync_token)); |
+ |
+ task_runner()->RunPendingTasks(); |
+ EXPECT_TRUE(ran2); |
+ |
+ release_state->Destroy(); |
+} |
+ |
+} // namespace |
+} // namespace gpu |