| 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..07d53646eb15b52830ffe84f3b6b6ebd488545cf
|
| --- /dev/null
|
| +++ b/gpu/command_buffer/service/scheduler_unittest.cc
|
| @@ -0,0 +1,333 @@
|
| +// 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(GpuStreamPriority::NORMAL);
|
| +
|
| + 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(GpuStreamPriority::NORMAL);
|
| +
|
| + 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(GpuStreamPriority::LOW);
|
| + bool ran1 = false;
|
| + scheduler()->ScheduleTask(sequence_id1, GetClosure([&] { ran1 = true; }),
|
| + std::vector<SyncToken>());
|
| +
|
| + SequenceId sequence_id2 =
|
| + scheduler()->CreateSequence(GpuStreamPriority::NORMAL);
|
| + bool ran2 = false;
|
| + scheduler()->ScheduleTask(sequence_id2, GetClosure([&] { ran2 = true; }),
|
| + std::vector<SyncToken>());
|
| +
|
| + SequenceId sequence_id3 =
|
| + scheduler()->CreateSequence(GpuStreamPriority::HIGH);
|
| + bool ran3 = false;
|
| + scheduler()->ScheduleTask(sequence_id3, GetClosure([&] { ran3 = true; }),
|
| + std::vector<SyncToken>());
|
| +
|
| + SequenceId sequence_id4 =
|
| + scheduler()->CreateSequence(GpuStreamPriority::REAL_TIME);
|
| + bool ran4 = false;
|
| + scheduler()->ScheduleTask(sequence_id4, GetClosure([&] { ran4 = true; }),
|
| + std::vector<SyncToken>());
|
| +
|
| + task_runner()->RunPendingTasks();
|
| + EXPECT_TRUE(ran4);
|
| +
|
| + 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(GpuStreamPriority::NORMAL);
|
| + bool ran1 = false;
|
| + scheduler()->ScheduleTask(sequence_id1, GetClosure([&] { ran1 = true; }),
|
| + std::vector<SyncToken>());
|
| +
|
| + SequenceId sequence_id2 =
|
| + scheduler()->CreateSequence(GpuStreamPriority::NORMAL);
|
| + bool ran2 = false;
|
| + scheduler()->ScheduleTask(sequence_id2, GetClosure([&] { ran2 = true; }),
|
| + std::vector<SyncToken>());
|
| +
|
| + SequenceId sequence_id3 =
|
| + scheduler()->CreateSequence(GpuStreamPriority::NORMAL);
|
| + bool ran3 = false;
|
| + scheduler()->ScheduleTask(sequence_id3, GetClosure([&] { ran3 = true; }),
|
| + std::vector<SyncToken>());
|
| +
|
| + SequenceId sequence_id4 =
|
| + scheduler()->CreateSequence(GpuStreamPriority::NORMAL);
|
| + 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(GpuStreamPriority::REAL_TIME);
|
| + SequenceId sequence_id2 =
|
| + scheduler()->CreateSequence(GpuStreamPriority::NORMAL);
|
| +
|
| + 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);
|
| +}
|
| +
|
| +TEST_F(SchedulerTest, SequenceDoesNotWaitForInvalidFence) {
|
| + SequenceId sequence_id1 =
|
| + scheduler()->CreateSequence(GpuStreamPriority::NORMAL);
|
| +
|
| + SequenceId sequence_id2 =
|
| + scheduler()->CreateSequence(GpuStreamPriority::NORMAL);
|
| + 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));
|
| +}
|
| +
|
| +TEST_F(SchedulerTest, ReleaseSequenceIsPrioritized) {
|
| + SequenceId sequence_id1 =
|
| + scheduler()->CreateSequence(GpuStreamPriority::NORMAL);
|
| +
|
| + bool ran1 = false;
|
| + scheduler()->ScheduleTask(sequence_id1, GetClosure([&] { ran1 = true; }),
|
| + std::vector<SyncToken>());
|
| +
|
| + SequenceId sequence_id2 = scheduler()->CreateSequence(GpuStreamPriority::LOW);
|
| + 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(GpuStreamPriority::REAL_TIME);
|
| + 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);
|
| +}
|
| +
|
| +TEST_F(SchedulerTest, ReleaseSequenceShouldYield) {
|
| + SequenceId sequence_id1 = scheduler()->CreateSequence(GpuStreamPriority::LOW);
|
| + 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(GpuStreamPriority::REAL_TIME);
|
| + 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);
|
| +}
|
| +
|
| +} // namespace
|
| +} // namespace gpu
|
|
|