Imported Upstream version 1.25.0
[platform/core/ml/nnfw.git] / runtime / onert / core / src / compiler / Compiler.cc
1 /*
2  * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
3  *
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
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 #include "compiler/Compiler.h"
18
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"
30
31 #include "compiler/StaticShapeInferer.h"
32
33 #include <misc/string_helpers.h>
34 #include <misc/polymorphic_downcast.h>
35
36 namespace onert
37 {
38 namespace compiler
39 {
40
41 Compiler::Compiler(const std::shared_ptr<ir::Model> &model, CompilerOptions &copt)
42   : _model{model}, _options{&copt}
43 {
44   // DO NOTHING
45 }
46
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()}
50 {
51   // Use for single model only
52   assert(nnpkg->model_count() == 1);
53 }
54
55 std::shared_ptr<CompilerArtifact> Compiler::compile(void)
56 {
57   /***************************************************
58    * Prepare compilation phase
59    ***************************************************/
60   if (!_options)
61     throw std::runtime_error{"Empty compile option"};
62
63   // Mode check
64   // TODO handle option for each model
65   if (_options->he_profiling_mode)
66   {
67     if (!_options->he_scheduler)
68       throw std::runtime_error("Heterogeneous scheduler must be enabled during profiling.");
69
70     if (_options->executor != "Dataflow")
71       throw std::runtime_error("Profiling mode works only with 'Dataflow' executor");
72   }
73
74   if (!_options->minmax_filepath.empty())
75   {
76     if (_options->executor != "Linear")
77       throw std::runtime_error("Recording minmax works only with Linear executor");
78   }
79
80   if (!_model->hasOnly<ir::Graph>())
81   {
82     throw std::runtime_error("Compiler can only compile models for inference.");
83   }
84
85   _options->forceInternalOptions();
86   _options->verboseOptions();
87
88   auto custom_kernel_builder = _model->getKernelBuilder();
89
90   _model->iterate([&](const ir::SubgraphIndex &, ir::IGraph &graph) {
91     auto &subg = nnfw::misc::polymorphic_downcast<ir::Graph &>(graph);
92
93     // Mandatory passes
94     pass::PassRunner{}
95       .append(std::make_unique<pass::ConstantOutputPass>(subg))
96       .append(std::make_unique<pass::OddOutputPass>(subg))
97       .run();
98
99     // Optimizations
100     pass::PassRunner{}.append(std::make_unique<pass::UnusedOperandEliminationPass>(subg)).run();
101   });
102
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);
109
110   // Tracing context
111   auto tracing_ctx = std::make_unique<util::TracingCtx>();
112
113   // Lower: Assign backend
114   std::unordered_map<ir::SubgraphIndex, std::unique_ptr<compiler::LoweredGraph>> lowered_subgs;
115   {
116     _model->iterate([&](const ir::SubgraphIndex &subg_index, ir::IGraph &graph) {
117       auto &subg = nnfw::misc::polymorphic_downcast<ir::Graph &>(graph);
118
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());
124     });
125   }
126
127   _model.reset();
128
129   for (const auto &pair : lowered_subgs)
130   {
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()));
134   }
135
136   // Shape inference.
137   {
138     // Run the StaticShapeInfer of primary subg. All child StaticShapeInferers are called
139     // recursively
140     std::unordered_map<ir::SubgraphIndex, std::unique_ptr<StaticShapeInferer>> inferers =
141       createStaticShapeInferers(lowered_subgs);
142
143     const auto primary_subg_idx = ir::SubgraphIndex{0};
144     inferers.at(primary_subg_idx)->infer();
145
146     for (const auto &pair_inferer : inferers)
147     {
148       const auto inferer = pair_inferer.second.get();
149       inferer->dump();
150     }
151   }
152
153   // Shape validation
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)
161   {
162     auto &lowered_subg = pair.second;
163     compiler::ShapeValidator{lowered_subg->graph()}();
164   }
165
166   /*************************************************************
167    *  Backend independent analysis & optimization phase finished
168    *************************************************************/
169   auto executors = std::make_shared<exec::SingleModelExecutors>();
170   for (auto &&pair : lowered_subgs)
171   {
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();
176
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); });
181
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));
191   }
192
193   /********************************
194    * Code generation phase finished
195    ********************************/
196   return std::make_shared<CompilerArtifact>(executors, std::move(tracing_ctx));
197 }
198
199 } // namespace compiler
200 } // namespace onert