summaryrefslogtreecommitdiff
path: root/runtime/onert/core/src/compiler/Compiler.cc
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/onert/core/src/compiler/Compiler.cc')
-rw-r--r--runtime/onert/core/src/compiler/Compiler.cc341
1 files changed, 121 insertions, 220 deletions
diff --git a/runtime/onert/core/src/compiler/Compiler.cc b/runtime/onert/core/src/compiler/Compiler.cc
index 93dbbc3b5..ba621bb4f 100644
--- a/runtime/onert/core/src/compiler/Compiler.cc
+++ b/runtime/onert/core/src/compiler/Compiler.cc
@@ -16,284 +16,185 @@
#include "compiler/Compiler.h"
-#include "ParamChecker.h"
+#include "CompilerHelpers.h"
#include "ExecutorFactory.h"
-#include "OperationValidator.h"
-#include "Fp32ToFp16Converter.h"
-
-#include <backend/controlflow/Config.h>
-#include "compiler/BackendManager.h"
-#include "compiler/IScheduler.h"
-#include "compiler/ManualScheduler.h"
-#include "compiler/HEScheduler.h"
-#include "compiler/StaticShapeInference.h"
-#include "exec/ExecTime.h"
-#include "ir/operation/LowerInfo.h"
-#include "dumper/dot/DotDumper.h"
-#include "compiler/Linear.h"
-#include "interp/InterpExecutor.h"
-#include "util/ConfigSource.h"
-#include "util/logging.h"
-#include "ir/OperationDumper.h"
-#include "misc/string_helpers.h"
+#include "ShapeValidator.h"
+#include "pass/ConstantOutputPass.h"
+#include "pass/OddOutputPass.h"
+#include "pass/PassRunner.h"
+#include "pass/UnusedOperandEliminationPass.h"
+#include "../dumper/dot/DotDumper.h"
+#include "../exec/SingleModelExecutors.h"
+#include "../ir/OperationDumper.h"
+#include "../ir/verifier/Verifier.h"
+
+#include "compiler/StaticShapeInferer.h"
+
+#include <misc/string_helpers.h>
+#include <misc/polymorphic_downcast.h>
namespace onert
{
-
namespace compiler
{
-CompilerOptions fetchCompilerOptionsFromGlobalConfig(const ir::Subgraphs &subgs)
+Compiler::Compiler(const std::shared_ptr<ir::Model> &model, CompilerOptions &copt)
+ : _model{model}, _options{&copt}
{
- CompilerOptions options;
- options.backend_list = nnfw::misc::split(util::getConfigString(util::config::BACKENDS), ';');
- options.is_primary_subgraph = false;
- options.trace_filepath = util::getConfigString(util::config::TRACE_FILEPATH);
- options.graph_dump_level = util::getConfigInt(util::config::GRAPH_DOT_DUMP);
- options.op_seq_max_node = util::getConfigInt(util::config::OP_SEQ_MAX_NODE);
- options.executor = util::getConfigString(util::config::EXECUTOR);
- options.he_scheduler = util::getConfigBool(util::config::USE_SCHEDULER);
- options.he_profiling_mode = util::getConfigBool(util::config::PROFILING_MODE);
- options.disable_compile = util::getConfigBool(util::config::DISABLE_COMPILE);
- options.fp16_enable = util::getConfigBool(util::config::FP16_ENABLE);
-#ifdef RUY_PROFILER
- options.op_seq_max_node = 1;
-#endif
-
- {
- // Backend for all
- auto &ms_options = options.manual_scheduler_options;
-
- // Default value for op_backend_all is first element in the backend list
- ms_options.backend_for_all = util::getConfigString(util::config::OP_BACKEND_ALLOPS);
-
-// Opcode to Backend
-#define OP(OpName) \
- { \
- const auto &backend_str = util::getConfigString(util::config::OP_BACKEND_##OpName); \
- if (!backend_str.empty()) \
- { \
- ms_options.opcode_to_backend[ir::OpCode::OpName] = backend_str; \
- } \
- }
-#include "ir/Operations.lst"
-#undef OP
-
- // Index to Backend
- // TODO Support multiple subgraphs for manual scheduling
- auto map_str = util::getConfigString(util::config::OP_BACKEND_MAP);
- auto key_val_list = nnfw::misc::split(map_str, ';');
- for (const auto &key_val_str : key_val_list)
- {
- if (key_val_str.empty())
- {
- continue;
- }
-
- auto key_val = nnfw::misc::split(key_val_str, '=');
- const auto &key_str = key_val.at(0);
- const auto &val = key_val.at(1);
- auto key = static_cast<uint32_t>(std::stoi(key_str));
-
- subgs.at(ir::SubgraphIndex{0})
- ->operations()
- .at(ir::OperationIndex{key}); // Check if exist, or this wil throw
- ms_options.index_to_backend.emplace(ir::OperationIndex{key}, val);
- }
- }
- return options;
+ // DO NOTHING
}
-Compiler::Compiler(const std::shared_ptr<ir::Subgraphs> &subgs)
- : _subgraphs{subgs}, _state{State::CREATED}
+Compiler::Compiler(const std::shared_ptr<ir::NNPkg> &nnpkg,
+ std::vector<std::unique_ptr<CompilerOptions>> &copts)
+ : _model{nnpkg->primary_model()}, _options{copts[0].get()}
{
- // Set default values for CompilerOptions
- // All these default values should not be fetched from Env, when we stop supporting Android NN
- // API.
- _options = fetchCompilerOptionsFromGlobalConfig(*subgs);
+ // Use for single model only
+ assert(nnpkg->model_count() == 1);
}
-void Compiler::enableToFp16() { _options.fp16_enable = true; }
-
-void Compiler::checkProfilerConditions()
+std::shared_ptr<CompilerArtifact> Compiler::compile(void)
{
- if (!_options.he_scheduler)
- throw std::runtime_error("Heterogeneous scheduler must be enabled during profiling.");
-
- if (_options.executor != "Dataflow")
- throw std::runtime_error("Profiling mode works only with 'Dataflow' executor");
-}
+ /***************************************************
+ * Prepare compilation phase
+ ***************************************************/
+ if (!_options)
+ throw std::runtime_error{"Empty compile option"};
-std::shared_ptr<exec::ExecutorMap> Compiler::compile(void)
-{
- // Set control flow backend for control flow operators
+ // Mode check
+ // TODO handle option for each model
+ if (_options->he_profiling_mode)
{
- _options.manual_scheduler_options.opcode_to_backend[ir::OpCode::If] =
- backend::controlflow::Config::ID;
- _options.manual_scheduler_options.opcode_to_backend[ir::OpCode::While] =
- backend::controlflow::Config::ID;
+ if (!_options->he_scheduler)
+ throw std::runtime_error("Heterogeneous scheduler must be enabled during profiling.");
+
+ if (_options->executor != "Dataflow")
+ throw std::runtime_error("Profiling mode works only with 'Dataflow' executor");
}
- // FIXME This is a workaround for bcq operations, should remove it
+ if (!_options->minmax_filepath.empty())
{
- _options.manual_scheduler_options.opcode_to_backend[ir::OpCode::BCQFullyConnected] = "bcq";
- _options.manual_scheduler_options.opcode_to_backend[ir::OpCode::BCQGather] = "bcq";
+ if (_options->executor != "Linear")
+ throw std::runtime_error("Recording minmax works only with Linear executor");
}
+ if (!_model->hasOnly<ir::Graph>())
{
- VERBOSE(Compiler) << std::boolalpha;
- VERBOSE(Compiler) << "==== Compiler Options ====" << std::endl;
- VERBOSE(Compiler) << "backend_list : "
- << nnfw::misc::join(_options.backend_list.begin(),
- _options.backend_list.end(), "/")
- << std::endl;
- VERBOSE(Compiler) << "trace_filepath : " << _options.trace_filepath << std::endl;
- VERBOSE(Compiler) << "graph_dump_level : " << _options.graph_dump_level << std::endl;
- VERBOSE(Compiler) << "op_seq_max_node : " << _options.op_seq_max_node << std::endl;
- VERBOSE(Compiler) << "executor : " << _options.executor << std::endl;
- VERBOSE(Compiler) << "manual_scheduler_options : (Too many things to print)" << std::endl;
- VERBOSE(Compiler) << "he_scheduler : " << _options.he_scheduler << std::endl;
- VERBOSE(Compiler) << "he_profiling_mode : " << _options.he_profiling_mode << std::endl;
- VERBOSE(Compiler) << "disable_compile : " << _options.disable_compile << std::endl;
- VERBOSE(Compiler) << "fp16_enable : " << _options.fp16_enable << std::endl;
- VERBOSE(Compiler) << std::noboolalpha;
+ throw std::runtime_error("Compiler can only compile models for inference.");
}
- /***************************************************
- * Prepare compilation phase
- ***************************************************/
+ _options->forceInternalOptions();
+ _options->verboseOptions();
- auto executors = std::make_shared<exec::ExecutorMap>();
+ auto custom_kernel_builder = _model->getKernelBuilder();
- // Compilable check
- // TODO: Support hybrid execution -
- // execution between interpreter and compiled executor (including control flow)
- if (!checkCompilable())
- {
- _subgraphs->iterate([&](const ir::SubgraphIndex &index, ir::Graph &subg) {
- executors->emplace(index, std::make_unique<interp::InterpExecutor>(subg));
- });
- _state = State::COMPILED;
- return executors;
- }
+ _model->iterate([&](const ir::SubgraphIndex &, ir::IGraph &graph) {
+ auto &subg = nnfw::misc::polymorphic_downcast<ir::Graph &>(graph);
- // Mode check
- if (_options.he_profiling_mode)
- checkProfilerConditions();
+ // Mandatory passes
+ pass::PassRunner{}
+ .append(std::make_unique<pass::ConstantOutputPass>(subg))
+ .append(std::make_unique<pass::OddOutputPass>(subg))
+ .run();
+
+ // Optimizations
+ pass::PassRunner{}.append(std::make_unique<pass::UnusedOperandEliminationPass>(subg)).run();
+ });
/***************************************************
* Backend independent analysis & optimization phase
***************************************************/
- auto dump_level = static_cast<dumper::dot::DotDumper::Level>(_options.graph_dump_level);
+ // TODO Handle dump level for each model
+ auto dump_level = static_cast<dumper::dot::DotDumper::Level>(_options->graph_dump_level);
+ onert::dumper::dot::DotDumper dot_dumper(dump_level);
+
+ // Tracing context
+ auto tracing_ctx = std::make_unique<util::TracingCtx>();
// Lower: Assign backend
std::unordered_map<ir::SubgraphIndex, std::unique_ptr<compiler::LoweredGraph>> lowered_subgs;
- _subgraphs->iterate([&](const ir::SubgraphIndex &index, ir::Graph &subg) {
- _options.is_primary_subgraph = (index == ir::SubgraphIndex{0});
- onert::dumper::dot::DotDumper dot_dumper(subg, dump_level);
- dot_dumper.dump(nnfw::misc::str("before_lower_subg-", index.value()));
-
- // Lower: Assign backend
- lowered_subgs[index] = std::make_unique<compiler::LoweredGraph>(subg, _options);
-
- // Check backend(s) for subgraph support FP16
- bool backends_support_fp16 = true;
- auto &contexts = (*lowered_subgs[index]).backend_contexts();
- for (auto it = contexts.begin(); it != contexts.end(); it++)
- {
- // Controlflow backend is not for actual computaion of operations so it is an exception
- if (it->first->config()->id() != backend::controlflow::Config::ID)
- backends_support_fp16 &= it->first->config()->supportFP16();
- }
-
- if (_options.fp16_enable && backends_support_fp16)
- {
- // NOTE: the only acl_cl backend enables fp16 mode
- Fp32ToFp16Converter(*lowered_subgs[index]).run();
- }
+ {
+ _model->iterate([&](const ir::SubgraphIndex &subg_index, ir::IGraph &graph) {
+ auto &subg = nnfw::misc::polymorphic_downcast<ir::Graph &>(graph);
+
+ // Lower: Assign backend
+ lowered_subgs[subg_index] = std::make_unique<compiler::LoweredGraph>(subg, *_options);
+ // Set tracing_ctx for copied graph
+ if (tracing_ctx != nullptr)
+ tracing_ctx->setSubgraphIndex(&(lowered_subgs[subg_index]->graph()), subg_index.value());
+ });
+ }
- subg.setSubgraphs(nullptr);
- });
+ _model.reset();
- _subgraphs.reset();
+ for (const auto &pair : lowered_subgs)
+ {
+ const auto &subg_index = pair.first;
+ const auto &lowered_subg = pair.second;
+ dot_dumper.dump(*lowered_subg, nnfw::misc::str("after_lower_subg-", subg_index.value()));
+ }
// Shape inference.
{
+ // Run the StaticShapeInfer of primary subg. All child StaticShapeInferers are called
+ // recursively
+ std::unordered_map<ir::SubgraphIndex, std::unique_ptr<StaticShapeInferer>> inferers =
+ createStaticShapeInferers(lowered_subgs);
+
const auto primary_subg_idx = ir::SubgraphIndex{0};
- StaticShapeInferer inferer(primary_subg_idx, lowered_subgs);
- lowered_subgs.at(primary_subg_idx)
- ->iterateTopolOpSeqs([&](const ir::OpSequenceIndex &, ir::OpSequence &op_seq) {
- auto has_dynamic_tensor = inferer.infer(op_seq);
- op_seq.has_dynamic_tensor(has_dynamic_tensor);
- });
- inferer.dump();
- }
+ inferers.at(primary_subg_idx)->infer();
- /*************************************************************
- * Backend independent analysis & optimization phase finished
- *************************************************************/
+ for (const auto &pair_inferer : inferers)
+ {
+ const auto inferer = pair_inferer.second.get();
+ inferer->dump();
+ }
+ }
- // operation validation
- for (auto &pair : lowered_subgs)
+ // Shape validation
+ // TODO Move shape independent feature check from ShapeValidator to OperationValidator
+ // TODO Move ShapeValidator into shape inference
+ // - Check input tensor shape validation
+ // - Check parameter value validation which valid value is depend on input tensor shape
+ // - Output tensor shape validation check is needless because
+ // static/dynamic shape inferer will make valid output shape
+ for (const auto &pair : lowered_subgs)
{
auto &lowered_subg = pair.second;
- compiler::OperationValidator{lowered_subg->graph()}();
+ compiler::ShapeValidator{lowered_subg->graph()}();
}
- executors = std::make_shared<exec::ExecutorMap>();
- for (auto &pair : lowered_subgs)
+ /*************************************************************
+ * Backend independent analysis & optimization phase finished
+ *************************************************************/
+ auto executors = std::make_shared<exec::SingleModelExecutors>();
+ for (auto &&pair : lowered_subgs)
{
- const auto &subg_index = pair.first;
+ auto const model_index = ir::ModelIndex{0};
+ auto const subg_index = pair.first;
auto &lowered_subg = pair.second;
- auto indexed_ranks = lowered_subg->indexed_ranks();
-
- _options.is_primary_subgraph = (subg_index == ir::SubgraphIndex{0});
-
- onert::dumper::dot::DotDumper dot_dumper_lowered(lowered_subg.get(), dump_level);
- dot_dumper_lowered.dump("after_lower_subg-" + std::to_string(subg_index.value()));
+ auto const indexed_ranks = lowered_subg->indexed_ranks();
- ir::OperationDumper dumper("START SUBGRAPH " + std::to_string(subg_index.value()));
+ ir::OperationDumper dumper("Executor generation of Subgraph " +
+ std::to_string(subg_index.value()));
lowered_subg->graph().operations().iterate(
- [&](const ir::OperationIndex &, const ir::Operation &op) { op.accept(dumper); });
+ [&](const ir::OperationIndex &, const ir::IOperation &op) { op.accept(dumper); });
+
+ ExecutorFactoryArgs args;
+ args.tracing_ctx = tracing_ctx.get();
+ args.options = _options;
+ args.model_index = model_index;
+ args.custom_kernel_builder = custom_kernel_builder;
auto executor = std::unique_ptr<exec::IExecutor>{
- ExecutorFactory::get().create(std::move(lowered_subg), _options, executors)};
+ ExecutorFactory::get().create(std::move(lowered_subg), executors, args)};
executor->setIndexedRanks(indexed_ranks);
- executors->insert(std::make_pair(subg_index, std::move(executor)));
+ executors->emplace(model_index, subg_index, std::move(executor));
}
/********************************
* Code generation phase finished
********************************/
- _state = State::COMPILED;
- return executors;
-}
-
-bool Compiler::checkCompilable()
-{
- // Disable compile phase
- // When ready to use interpreter backend, remove this config and use backend setting
- if (_options.disable_compile)
- {
- return false;
- }
-
- // TODO check unspecified operand shape
-
- // Check compilable parameter
- for (uint32_t i = 0; i < _subgraphs->count(); ++i)
- {
- auto graph = _subgraphs->at(ir::SubgraphIndex{i});
- ParamChecker paramChecker{graph};
- paramChecker();
- if (paramChecker.haveNoneConstParam())
- {
- return false;
- }
- }
-
- return true;
+ return std::make_shared<CompilerArtifact>(executors, std::move(tracing_ctx));
}
} // namespace compiler
-
} // namespace onert