[neurun] Implemented test for scheduler profiling mode (#7034)
authorIvan Vagin/AI Tools Lab /SRR/Engineer/삼성전자 <ivan.vagin@samsung.com>
Fri, 6 Sep 2019 05:53:07 +0000 (08:53 +0300)
committer오형석/On-Device Lab(SR)/Staff Engineer/삼성전자 <hseok82.oh@samsung.com>
Fri, 6 Sep 2019 05:53:07 +0000 (14:53 +0900)
Implemented test for scheduler with enabled profiling mode
Fixed scheduling order by increasing et of one branch

Signed-off-by: Ivan Vagin <ivan.vagin@samsung.com>
runtimes/neurun/test/core/compiler/Scheduler.cc

index 44431b7..8b7af07 100644 (file)
@@ -16,6 +16,7 @@
 
 #include <compiler/Scheduler.h>
 #include <backend/ExecTime.h>
+#include <backend/IShapeFixer.h>
 
 #include <model/Model.h>
 #include <model/Shape.h>
@@ -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<ITensorBuilder> 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<backend::custom::KernelRegistry> &) const override
   {
     return std::unique_ptr<BackendContext>(
-        new BackendContext{this, nullptr, nullptr, nullptr, nullptr});
+        new BackendContext{this, nullptr, nullptr, nullptr, std::make_shared<MockShapeFixer>()});
   }
 };
 
@@ -75,7 +87,7 @@ struct MockBackendGPU : public Backend
              const std::shared_ptr<backend::custom::KernelRegistry> &) const override
   {
     return std::unique_ptr<BackendContext>(
-        new BackendContext{this, nullptr, nullptr, nullptr, nullptr});
+        new BackendContext{this, nullptr, nullptr, nullptr, std::make_shared<MockShapeFixer>()});
   }
 };
 
@@ -94,7 +106,7 @@ struct MockBackendNPU : public Backend
              const std::shared_ptr<backend::custom::KernelRegistry> &) const override
   {
     return std::unique_ptr<BackendContext>(
-        new BackendContext{this, nullptr, nullptr, nullptr, nullptr});
+        new BackendContext{this, nullptr, nullptr, nullptr, std::make_shared<MockShapeFixer>()});
   }
 };
 
@@ -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::Graph> &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<const Backend *> _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