From 36f41ae45a753573e51631536f946a6915a464d3 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Ivan=20Vagin/AI=20Tools=20Lab=20/SRR/Engineer/=EC=82=BC?= =?utf8?q?=EC=84=B1=EC=A0=84=EC=9E=90?= Date: Fri, 6 Sep 2019 08:53:07 +0300 Subject: [PATCH] [neurun] Implemented test for scheduler profiling mode (#7034) Implemented test for scheduler with enabled profiling mode Fixed scheduling order by increasing et of one branch Signed-off-by: Ivan Vagin --- runtimes/neurun/test/core/compiler/Scheduler.cc | 97 ++++++++++++++++++++++++- 1 file changed, 93 insertions(+), 4 deletions(-) diff --git a/runtimes/neurun/test/core/compiler/Scheduler.cc b/runtimes/neurun/test/core/compiler/Scheduler.cc index 44431b7..8b7af07 100644 --- a/runtimes/neurun/test/core/compiler/Scheduler.cc +++ b/runtimes/neurun/test/core/compiler/Scheduler.cc @@ -16,6 +16,7 @@ #include #include +#include #include #include @@ -41,6 +42,17 @@ using namespace operation; // Mock backends classes // +// Backend could be created without ShapeFixer. +// But it is used by scheduler to detect which operations are supported by backend. +struct MockShapeFixer : IShapeFixer +{ + void visit(const model::operation::AddNode &) override{}; + void visit(const model::operation::SubNode &) override{}; + void visit(const model::operation::MulNode &) override{}; + void visit(const model::operation::FullyConnectedNode &) override{}; + std::shared_ptr tensor_builder() override { return nullptr; }; +}; + struct MockConfigCPU : public IConfig { std::string id() override { return "cpu"; } @@ -56,7 +68,7 @@ struct MockBackendCPU : public Backend const std::shared_ptr &) const override { return std::unique_ptr( - new BackendContext{this, nullptr, nullptr, nullptr, nullptr}); + new BackendContext{this, nullptr, nullptr, nullptr, std::make_shared()}); } }; @@ -75,7 +87,7 @@ struct MockBackendGPU : public Backend const std::shared_ptr &) const override { return std::unique_ptr( - new BackendContext{this, nullptr, nullptr, nullptr, nullptr}); + new BackendContext{this, nullptr, nullptr, nullptr, std::make_shared()}); } }; @@ -94,7 +106,7 @@ struct MockBackendNPU : public Backend const std::shared_ptr &) const override { return std::unique_ptr( - new BackendContext{this, nullptr, nullptr, nullptr, nullptr}); + new BackendContext{this, nullptr, nullptr, nullptr, std::make_shared()}); } }; @@ -117,6 +129,9 @@ const std::string PARALLEL("Parallel"); // Set executor through environment variable void setExecutor(const std::string &executor) { setenv("EXECUTOR", executor.c_str(), true); } +// Set profiling mode through environment variable +void setProfilingMode(const bool value) { setenv("PROFILING_MODE", value ? "1" : "0", true); } + // Calculate operation size by addition sizes of all input and output operands uint32_t calcOpSize(const std::shared_ptr &graph, const OperationIndex &op_idx) { @@ -302,6 +317,10 @@ protected: // Remember original value of 'EXECUTOR' environment variable char *executor = std::getenv("EXECUTOR"); _original_executor = executor == nullptr ? "" : executor; + + // Remember original value of 'PROFILING_MODE' environment variable + char *profiling_mode = std::getenv("PROFILING_MODE"); + _original_profiling_mode = profiling_mode == nullptr ? "" : profiling_mode; } void TearDown() override @@ -311,6 +330,7 @@ protected: delete _npu_backend; EXPECT_EQ(remove("exec_time.json"), 0); setenv("EXECUTOR", _original_executor.c_str(), true); + setenv("PROFILING_MODE", _original_profiling_mode.c_str(), true); } const MockBackendCPU *_cpu_backend{nullptr}; @@ -319,6 +339,7 @@ protected: std::vector _mock_backends; std::string _original_executor; + std::string _original_profiling_mode; }; class SchedulerTestWithExecutorParam : public SchedulerTest, @@ -459,7 +480,75 @@ TEST_P(SchedulerTestWithExecutorParam, branched_graph_known_exec_time) INSTANTIATE_TEST_CASE_P(AllExecutors, SchedulerTestWithExecutorParam, testing::Values(LINEAR, DATAFLOW, PARALLEL)); +// Test scheduler behavior for branched graph and enabled profiling mode +TEST_F(SchedulerTest, branched_graph_profiling_mode) +{ + const int ET = 1e5; + + // Turn on profiling mode + setProfilingMode(true); + setExecutor(DATAFLOW); + + // Prepare graph + auto graph(createBranchedGraph()); + OperationIndex add_op_idx(0), mul1_op_idx(1), mul2_op_idx(2), fc1_op_idx(3), fc2_op_idx(4), + sub_op_idx(5); + + // Test 1 + // Expected behaviour: scheduler assigns backends to nodes with unknown execution time + { + // Set execution time for all backends/nodes except for cpu/Sub, npu/Mul, gpu/FC + ExecTime et(_mock_backends); + setOperationExecTime(et, _cpu_backend, "Add", false, OPERATION_SIZE, ET); + setOperationExecTime(et, _cpu_backend, "Mul", false, OPERATION_SIZE, ET + 1); + setOperationExecTime(et, _cpu_backend, "FullyConnected", false, OPERATION_SIZE, ET); + setOperationExecTime(et, _npu_backend, "Add", false, OPERATION_SIZE, ET); + setOperationExecTime(et, _npu_backend, "FullyConnected", false, OPERATION_SIZE, ET); + setOperationExecTime(et, _npu_backend, "Sub", false, OPERATION_SIZE, ET); + setOperationExecTime(et, _gpu_backend, "Add", false, OPERATION_SIZE, ET); + setOperationExecTime(et, _gpu_backend, "Mul", false, OPERATION_SIZE, ET + 1); + setOperationExecTime(et, _gpu_backend, "Sub", false, OPERATION_SIZE, ET); + et.uploadOperationsExecTime(); + + // Test scheduler + auto scheduler = compiler::Scheduler(graph->operands(), _mock_backends, nullptr); + const auto br = scheduler.schedule(*graph); + ASSERT_EQ(br->getBackend(mul1_op_idx)->config()->id(), "npu"); + ASSERT_EQ(br->getBackend(mul2_op_idx)->config()->id(), "npu"); + ASSERT_EQ(br->getBackend(fc1_op_idx)->config()->id(), "gpu"); + ASSERT_EQ(br->getBackend(fc2_op_idx)->config()->id(), "gpu"); + ASSERT_EQ(br->getBackend(sub_op_idx)->config()->id(), "cpu"); + } + + // Test 2 + // Expected behaviour: scheduler shuffling backends, so different backends are assigned to + // neighbor nodes + { + // Set execution time for rest backends/nodes (cpu/Sub, npu/Mul, gpu/FC) + ExecTime et(_mock_backends); + setOperationExecTime(et, _cpu_backend, "Sub", false, OPERATION_SIZE, ET); + setOperationExecTime(et, _npu_backend, "Mul", false, OPERATION_SIZE, ET + 1); + setOperationExecTime(et, _gpu_backend, "FullyConnected", false, OPERATION_SIZE, ET); + et.uploadOperationsExecTime(); + + // Test scheduler + auto scheduler = compiler::Scheduler(graph->operands(), _mock_backends, nullptr); + const auto br = scheduler.schedule(*graph); + ASSERT_NE(br->getBackend(add_op_idx)->config()->id(), + br->getBackend(mul1_op_idx)->config()->id()); + ASSERT_NE(br->getBackend(add_op_idx)->config()->id(), + br->getBackend(fc1_op_idx)->config()->id()); + ASSERT_NE(br->getBackend(mul1_op_idx)->config()->id(), + br->getBackend(mul2_op_idx)->config()->id()); + ASSERT_NE(br->getBackend(fc1_op_idx)->config()->id(), + br->getBackend(fc2_op_idx)->config()->id()); + ASSERT_NE(br->getBackend(mul2_op_idx)->config()->id(), + br->getBackend(sub_op_idx)->config()->id()); + ASSERT_NE(br->getBackend(fc2_op_idx)->config()->id(), + br->getBackend(sub_op_idx)->config()->id()); + } +} + // TODO: Add tests with unknown execution and permutation time -// TODO: Add tests for scheduler profiling mode } // unnamed namespace -- 2.7.4