2 * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #include "compiler/Compiler.h"
19 #include "CompilerHelpers.h"
20 #include "ExecutorFactory.h"
21 #include "ShapeValidator.h"
22 #include "pass/ConstantOutputPass.h"
23 #include "pass/OddOutputPass.h"
24 #include "pass/PassRunner.h"
25 #include "pass/UnusedOperandEliminationPass.h"
26 #include "../dumper/dot/DotDumper.h"
27 #include "../exec/SingleModelExecutors.h"
28 #include "../ir/OperationDumper.h"
29 #include "../ir/verifier/Verifier.h"
31 #include "compiler/StaticShapeInferer.h"
33 #include <misc/string_helpers.h>
34 #include <misc/polymorphic_downcast.h>
41 Compiler::Compiler(const std::shared_ptr<ir::Model> &model, CompilerOptions &copt)
42 : _model{model}, _options{&copt}
47 Compiler::Compiler(const std::shared_ptr<ir::NNPkg> &nnpkg,
48 std::vector<std::unique_ptr<CompilerOptions>> &copts)
49 : _model{nnpkg->primary_model()}, _options{copts[0].get()}
51 // Use for single model only
52 assert(nnpkg->model_count() == 1);
55 std::shared_ptr<CompilerArtifact> Compiler::compile(void)
57 /***************************************************
58 * Prepare compilation phase
59 ***************************************************/
61 throw std::runtime_error{"Empty compile option"};
64 // TODO handle option for each model
65 if (_options->he_profiling_mode)
67 if (!_options->he_scheduler)
68 throw std::runtime_error("Heterogeneous scheduler must be enabled during profiling.");
70 if (_options->executor != "Dataflow")
71 throw std::runtime_error("Profiling mode works only with 'Dataflow' executor");
74 if (!_options->minmax_filepath.empty())
76 if (_options->executor != "Linear")
77 throw std::runtime_error("Recording minmax works only with Linear executor");
80 if (!_model->hasOnly<ir::Graph>())
82 throw std::runtime_error("Compiler can only compile models for inference.");
85 _options->forceInternalOptions();
86 _options->verboseOptions();
88 auto custom_kernel_builder = _model->getKernelBuilder();
90 _model->iterate([&](const ir::SubgraphIndex &, ir::IGraph &graph) {
91 auto &subg = nnfw::misc::polymorphic_downcast<ir::Graph &>(graph);
95 .append(std::make_unique<pass::ConstantOutputPass>(subg))
96 .append(std::make_unique<pass::OddOutputPass>(subg))
100 pass::PassRunner{}.append(std::make_unique<pass::UnusedOperandEliminationPass>(subg)).run();
103 /***************************************************
104 * Backend independent analysis & optimization phase
105 ***************************************************/
106 // TODO Handle dump level for each model
107 auto dump_level = static_cast<dumper::dot::DotDumper::Level>(_options->graph_dump_level);
108 onert::dumper::dot::DotDumper dot_dumper(dump_level);
111 auto tracing_ctx = std::make_unique<util::TracingCtx>();
113 // Lower: Assign backend
114 std::unordered_map<ir::SubgraphIndex, std::unique_ptr<compiler::LoweredGraph>> lowered_subgs;
116 _model->iterate([&](const ir::SubgraphIndex &subg_index, ir::IGraph &graph) {
117 auto &subg = nnfw::misc::polymorphic_downcast<ir::Graph &>(graph);
119 // Lower: Assign backend
120 lowered_subgs[subg_index] = std::make_unique<compiler::LoweredGraph>(subg, *_options);
121 // Set tracing_ctx for copied graph
122 if (tracing_ctx != nullptr)
123 tracing_ctx->setSubgraphIndex(&(lowered_subgs[subg_index]->graph()), subg_index.value());
129 for (const auto &pair : lowered_subgs)
131 const auto &subg_index = pair.first;
132 const auto &lowered_subg = pair.second;
133 dot_dumper.dump(*lowered_subg, nnfw::misc::str("after_lower_subg-", subg_index.value()));
138 // Run the StaticShapeInfer of primary subg. All child StaticShapeInferers are called
140 std::unordered_map<ir::SubgraphIndex, std::unique_ptr<StaticShapeInferer>> inferers =
141 createStaticShapeInferers(lowered_subgs);
143 const auto primary_subg_idx = ir::SubgraphIndex{0};
144 inferers.at(primary_subg_idx)->infer();
146 for (const auto &pair_inferer : inferers)
148 const auto inferer = pair_inferer.second.get();
154 // TODO Move shape independent feature check from ShapeValidator to OperationValidator
155 // TODO Move ShapeValidator into shape inference
156 // - Check input tensor shape validation
157 // - Check parameter value validation which valid value is depend on input tensor shape
158 // - Output tensor shape validation check is needless because
159 // static/dynamic shape inferer will make valid output shape
160 for (const auto &pair : lowered_subgs)
162 auto &lowered_subg = pair.second;
163 compiler::ShapeValidator{lowered_subg->graph()}();
166 /*************************************************************
167 * Backend independent analysis & optimization phase finished
168 *************************************************************/
169 auto executors = std::make_shared<exec::SingleModelExecutors>();
170 for (auto &&pair : lowered_subgs)
172 auto const model_index = ir::ModelIndex{0};
173 auto const subg_index = pair.first;
174 auto &lowered_subg = pair.second;
175 auto const indexed_ranks = lowered_subg->indexed_ranks();
177 ir::OperationDumper dumper("Executor generation of Subgraph " +
178 std::to_string(subg_index.value()));
179 lowered_subg->graph().operations().iterate(
180 [&](const ir::OperationIndex &, const ir::IOperation &op) { op.accept(dumper); });
182 ExecutorFactoryArgs args;
183 args.tracing_ctx = tracing_ctx.get();
184 args.options = _options;
185 args.model_index = model_index;
186 args.custom_kernel_builder = custom_kernel_builder;
187 auto executor = std::unique_ptr<exec::IExecutor>{
188 ExecutorFactory::get().create(std::move(lowered_subg), executors, args)};
189 executor->setIndexedRanks(indexed_ranks);
190 executors->emplace(model_index, subg_index, std::move(executor));
193 /********************************
194 * Code generation phase finished
195 ********************************/
196 return std::make_shared<CompilerArtifact>(executors, std::move(tracing_ctx));
199 } // namespace compiler