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.
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"
32 std::vector<ir::OpSequenceIndex> Linear::linearize(const ir::LoweredGraph &lowered_graph)
34 std::vector<ir::OpSequenceIndex> order;
35 lowered_graph.iterateTopolOpSeqs(
36 [&](const ir::OpSequenceIndex &index, const ir::OpSequence &) -> void {
37 order.emplace_back(index);
42 void Linear::dump(const ir::LoweredGraph &lowered_graph,
43 const std::vector<ir::OpSequenceIndex> &order)
46 const auto &toString = [](const onert::backend::Backend *backend) {
49 str += backend->config()->id();
50 return "{" + str + "}";
53 VERBOSE(Linear) << "Final OpSequence" << std::endl;
54 for (const auto index : order)
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;
65 void Linear::planTensors(const ir::LoweredGraph &lowered_graph,
66 const std::vector<ir::OpSequenceIndex> &order)
68 const auto &graph = lowered_graph.graph();
69 ir::OperandIndexMap<std::shared_ptr<backend::ITensorBuilder>> tensor_builder_map;
71 ir::OperandIndexMap<uint32_t> uses_map;
72 ir::OperandIndexMap<uint32_t> def_map;
73 ir::OperandIndexSequence constants;
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))
83 VERBOSE(LINEAR) << "Operand #" << ind.value() << " will not be used. no more process."
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))
93 VERBOSE(LINEAR) << "Operand #" << ind.value() << " will not be used. no more process."
98 uses_map[ind] = obj.getUses().size();
99 def_map[ind] = obj.getDef().valid() ? 1 : 0;
101 bool is_const = obj.isConstant();
104 constants.append(ind);
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))
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);
119 tensor_builder_map[ind] = tensor_builder;
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)
129 // Start scanning to do notify{First|Last}Use for each tensor
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)
138 tensor_builder_map[ind]->notifyFirstUse(ind);
141 // Allocate Model's inputs
142 VERBOSE(LINEAR) << "TENSORS as MODEL INPUT" << std::endl;
143 for (const auto &ind : graph.getInputs() | ir::Remove::DUPLICATED)
145 auto tensor_builder = tensor_builder_map[ind];
146 if (!tensor_builder) // for GeneratedTests.xxx_weights_as_inputs
148 tensor_builder->notifyFirstUse(ind);
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)
157 const auto &op_seq = lowered_graph.op_seqs().at(op_seq_ind);
158 for (const auto &op_idx : op_seq.operations())
160 for (const auto &ind : graph.operations().at(op_idx).getOutputs() | ir::Remove::DUPLICATED |
161 ir::Remove::UNDEFINED)
163 assert(def_map.find(ind) != def_map.end());
167 tensor_builder_map[ind]->notifyFirstUse(ind);
171 for (const auto &ind : graph.operations().at(op_idx).getInputs() | ir::Remove::DUPLICATED |
172 ir::Remove::UNDEFINED)
174 assert(uses_map.find(ind) != uses_map.end());
175 assert(uses_map[ind] > 0);
177 if (uses_map[ind] == 0)
179 // plan for deallocation of static tensornode
180 tensor_builder_map[ind]->notifyLastUse(ind);
182 // plan for deallocation of dynamic tensor
183 if (tensor_builder_map[ind]->supportDynamicTensor())
185 assert(tensor_builder_map[ind]->dynamicTensorManager());
186 tensor_builder_map[ind]->dynamicTensorManager()->planDealloc(op_idx, ind);
193 // Dispose and validate
194 for (const auto &ind : graph.getOutputs() | ir::Remove::DUPLICATED)
197 if (uses_map[ind] == 0) // To prevent notifyLastUse from being called twice
199 tensor_builder_map[ind]->notifyLastUse(ind);
203 for (const auto &ind : constants)
206 if (uses_map[ind] == 0) // To prevent notifyLastUse from being called twice
208 tensor_builder_map[ind]->notifyLastUse(ind);
213 std::all_of(uses_map.begin(), uses_map.end(),
214 [](std::pair<const ir::OperandIndex, uint32_t> it) { return it.second == 0; }));
217 std::all_of(def_map.begin(), def_map.end(),
218 [](std::pair<const ir::OperandIndex, uint32_t> it) { return it.second == 0; }));
221 } // namespace compiler