Imported Upstream version 1.9.0
[platform/core/ml/nnfw.git] / runtime / onert / core / src / compiler / Linear.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 <algorithm>
18
19 #include "Linear.h"
20
21 #include "backend/IConfig.h"
22 #include "backend/IConstantInitializer.h"
23 #include "backend/ITensorRegister.h"
24 #include "backend/Backend.h"
25 #include "util/logging.h"
26
27 namespace onert
28 {
29 namespace compiler
30 {
31
32 std::vector<ir::OpSequenceIndex> Linear::linearize(const compiler::LoweredGraph &lowered_graph)
33 {
34   std::vector<ir::OpSequenceIndex> order;
35   lowered_graph.iterateTopolOpSeqs(
36       [&](const ir::OpSequenceIndex &index, const ir::OpSequence &) -> void {
37         order.emplace_back(index);
38       });
39   return order;
40 }
41
42 void Linear::dump(const compiler::LoweredGraph &lowered_graph,
43                   const std::vector<ir::OpSequenceIndex> &order)
44 {
45   {
46     const auto &toString = [](const onert::backend::Backend *backend) {
47       assert(backend);
48       std::string str;
49       str += backend->config()->id();
50       return "{" + str + "}";
51     };
52
53     VERBOSE(Linear) << "Final OpSequence" << std::endl;
54     for (const auto index : order)
55     {
56       const auto &op_seq = lowered_graph.op_seqs().at(index);
57       const auto lower_info = lowered_graph.getLowerInfo(index);
58       const auto &operations = lowered_graph.graph().operations();
59       VERBOSE(Linear) << "* OP_SEQ " << toString(lower_info->backend()) << " "
60                       << ir::getStrFromOpSeq(op_seq, operations) << std::endl;
61     }
62   }
63 }
64
65 void Linear::planTensors(const compiler::LoweredGraph &lowered_graph,
66                          const std::vector<ir::OpSequenceIndex> &order)
67 {
68   const auto &graph = lowered_graph.graph();
69   ir::OperandIndexMap<std::shared_ptr<backend::ITensorBuilder>> tensor_builder_map;
70
71   ir::OperandIndexMap<uint32_t> uses_map;
72   ir::OperandIndexMap<uint32_t> def_map;
73   ir::OperandIndexSequence constants;
74
75   // Prepare scanning
76   graph.operands().iterate([&](const ir::OperandIndex &ind, const ir::Operand &obj) {
77     const auto lower_info = lowered_graph.getLowerInfo(ind);
78     // TODO Remove if onert doesn't support anymore such as
79     // GeneratedTests.reshape_quant8_weights_as_inputs
80     if (lower_info->def_factors().size() == 0 && lower_info->use_factors().size() == 0 &&
81         !graph.getInputs().contains(ind))
82     {
83       VERBOSE(LINEAR) << "Operand #" << ind.value() << " will not be used. no more process."
84                       << std::endl;
85       return;
86     }
87
88     // Unused input of subgraph
89     // TODO Register unused input as nullptr in tensor_builder
90     if (lower_info->def_factors().size() == 0 && lower_info->use_factors().size() == 0 &&
91         graph.getInputs().contains(ind))
92     {
93       VERBOSE(LINEAR) << "Operand #" << ind.value() << " will not be used. no more process."
94                       << std::endl;
95       return;
96     }
97
98     uses_map[ind] = obj.getUses().size();
99     def_map[ind] = obj.getDef().valid() ? 1 : 0;
100
101     bool is_const = obj.isConstant();
102     if (is_const)
103     {
104       constants.append(ind);
105     }
106
107     auto factor = lower_info->def_factors().getOnlyElement();
108     auto backend = factor.backend();
109     auto tensor_builder = lowered_graph.backend_contexts().at(backend)->tensor_builder;
110     if (!tensor_builder->isRegistered(ind))
111     {
112       // These tensors do not exist in any op_seq (No use and def)
113       const auto info = obj.info();
114       const auto backend_layout = factor.layout();
115       // TODO Change tensor info to have permuted shape
116       tensor_builder->registerTensorInfo(ind, info, backend_layout);
117     }
118
119     tensor_builder_map[ind] = tensor_builder;
120   });
121
122   // If a tensor is model output, increase the use of the tensor.
123   // This aim is same to above one.
124   for (const auto &ind : graph.getOutputs() | ir::Remove::DUPLICATED)
125   {
126     uses_map[ind]++;
127   }
128
129   // Start scanning to do notify{First|Last}Use for each tensor
130
131   // If a tensor is a constant, increase the use of the tensor.
132   // It makes the tensor not be dealloced. It means these will be deallocated last.
133   // And allocate constant operands first
134   VERBOSE(LINEAR) << "TENSORS as CONSTANT" << std::endl;
135   for (const auto &ind : constants)
136   {
137     uses_map[ind]++;
138     tensor_builder_map[ind]->notifyFirstUse(ind);
139   }
140
141   // Allocate Model's inputs
142   VERBOSE(LINEAR) << "TENSORS as MODEL INPUT" << std::endl;
143   for (const auto &ind : graph.getInputs() | ir::Remove::DUPLICATED)
144   {
145     auto tensor_builder = tensor_builder_map[ind];
146     if (!tensor_builder) // for GeneratedTests.xxx_weights_as_inputs
147       continue;
148     tensor_builder->notifyFirstUse(ind);
149   }
150
151   // At each operation,
152   // 1. Scan DEF of outputs. If the DEF, allocate it
153   // 2. Scan USE of inputs. Decrease the USE and deallocate if the USE is 0
154   VERBOSE(LINEAR) << "TENSORS" << std::endl;
155   for (const auto op_seq_ind : order)
156   {
157     const auto &op_seq = lowered_graph.op_seqs().at(op_seq_ind);
158     for (const auto &op_idx : op_seq.operations())
159     {
160       for (const auto &ind : graph.operations().at(op_idx).getOutputs() | ir::Remove::DUPLICATED |
161                                  ir::Remove::UNDEFINED)
162       {
163         assert(def_map.find(ind) != def_map.end());
164         if (def_map[ind])
165         {
166           def_map[ind] = 0;
167           tensor_builder_map[ind]->notifyFirstUse(ind);
168         }
169       }
170
171       for (const auto &ind : graph.operations().at(op_idx).getInputs() | ir::Remove::DUPLICATED |
172                                  ir::Remove::UNDEFINED)
173       {
174         assert(uses_map.find(ind) != uses_map.end());
175         assert(uses_map[ind] > 0);
176         uses_map[ind]--;
177         if (uses_map[ind] == 0)
178         {
179           // plan for deallocation of static tensornode
180           tensor_builder_map[ind]->notifyLastUse(ind);
181
182           // plan for deallocation of dynamic tensor
183           auto dyn_tensor_manager = tensor_builder_map[ind]->dynamicTensorManager();
184           if (dyn_tensor_manager)
185             dyn_tensor_manager->planDealloc(op_idx, ind);
186         }
187       }
188     }
189   }
190
191   // Dispose and validate
192   for (const auto &ind : graph.getOutputs() | ir::Remove::DUPLICATED)
193   {
194     --uses_map[ind];
195     if (uses_map[ind] == 0) // To prevent notifyLastUse from being called twice
196     {
197       tensor_builder_map[ind]->notifyLastUse(ind);
198     }
199   }
200
201   for (const auto &ind : constants)
202   {
203     --uses_map[ind];
204     if (uses_map[ind] == 0) // To prevent notifyLastUse from being called twice
205     {
206       tensor_builder_map[ind]->notifyLastUse(ind);
207     }
208   }
209
210   assert(
211       std::all_of(uses_map.begin(), uses_map.end(),
212                   [](std::pair<const ir::OperandIndex, uint32_t> it) { return it.second == 0; }));
213
214   assert(
215       std::all_of(def_map.begin(), def_map.end(),
216                   [](std::pair<const ir::OperandIndex, uint32_t> it) { return it.second == 0; }));
217 }
218
219 } // namespace compiler
220 } // namespace onert