#include <compiler/Scheduler.h>
#include <backend/ExecTime.h>
+#include <backend/IShapeFixer.h>
#include <model/Model.h>
#include <model/Shape.h>
// 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"; }
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>()});
}
};
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>()});
}
};
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>()});
}
};
// 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)
{
// 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
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};
std::vector<const Backend *> _mock_backends;
std::string _original_executor;
+ std::string _original_profiling_mode;
};
class SchedulerTestWithExecutorParam : public SchedulerTest,
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