ONE - On-device Neural Engine
Loading...
Searching...
No Matches
BackendContext.h
Go to the documentation of this file.
1/*
2 * Copyright (c) 2022 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#ifndef __ONERT_BACKEND_CL_COMMON_BACKEND_CONTEXT_H__
18#define __ONERT_BACKEND_CL_COMMON_BACKEND_CONTEXT_H__
19
21#include <ir/Index.h>
22#include <ir/OperandIndexMap.h>
24#include <util/logging.h>
25
26namespace onert
27{
28namespace backend
29{
30namespace cl_common
31{
32
33// TODO Find better way to handle common code (reduce template)
34template <typename T_TensorBuilder, typename T_ConstantInitializer, typename T_KernelGenerator>
36{
37public:
39 std::shared_ptr<ITensorRegistry> tensor_registry = nullptr,
40 std::shared_ptr<T_TensorBuilder> tensor_builder = nullptr,
41 std::shared_ptr<T_ConstantInitializer> constant_initializer = nullptr,
42 std::shared_ptr<T_KernelGenerator> kernel_gen = nullptr)
46 {
47 }
48
50 {
51 FunctionMap ret;
52
53 // kernel_gen
54 for (auto &&op_ind : _data.op_order)
55 {
56 auto fn_seq = kernel_gen->generate(op_ind);
57 ret.emplace(op_ind, std::move(fn_seq));
58 }
59
60 tensor_builder->allocate();
61 initConsts();
62
63 // NOTE For memory optimization, we want to free some operand data
64 const_cast<ir::Graph &>(*_data.graph)
65 .operands()
66 .iterate([&](const ir::OperandIndex &, ir::Operand &obj) { obj.releaseData(); });
67
68 for (auto &&it : ret)
69 {
70 auto &fn_seq = it.second;
71 fn_seq->iterate([&](exec::IFunction &ifunc) {
72 ifunc.prepare();
73 tensor_builder->postFunctionPrepare();
74 });
75 }
76
77 return ret;
78 }
79
80protected:
82 {
83 _data.graph->operations().iterate([&](const ir::OperationIndex &, const ir::IOperation &op) {
85 });
86
87 _data.graph->operands().iterate([&](const ir::OperandIndex &ind, const ir::Operand &operand) {
88 if (_data.external_operands.contains(ind) || !operand.isConstant())
89 return;
90 const auto &obj = graph()->operands().at(ind);
91 if (obj.isConstant() && !constant_initializer->exist(ind))
92 {
93 constant_initializer->registerDefaultInitializer(ind, obj);
94 }
95 });
96
98 }
99
100 virtual void registerTensorInfo(const ir::OperandIndex &ind, const ir::OperandInfo &info) = 0;
101
103 {
106 ir::OperandIndexSequence constants;
107
108 // Prepare scanning
109 _data.graph->operands().iterate([&](const ir::OperandIndex &ind, const ir::Operand &obj) {
110 if (_data.external_operands.contains(ind))
111 return;
112
113 uses_map[ind] = obj.getUses().size();
114 def_map[ind] = obj.getDef().valid() ? 1 : 0;
115
116 if (obj.isConstant())
117 constants.append(ind);
118
119 if (!tensor_builder->isRegistered(ind))
120 {
121 // These tensors do not exist in any operation (No use and def)
122 const auto &info = obj.info();
124 }
125 });
126
127 // Start scanning to do notify{First|Last}Use for each tensor
128
129 // If a tensor is a constant, increase the use of the tensor and allocate it first.
130 // Increasing use count here makes the tensor never be deallocated, i.e it they will be
131 // deallocated last.
132 VERBOSE(planTensors) << "TENSORS as CONSTANT" << std::endl;
133 for (const auto &ind : constants)
134 {
135 uses_map[ind]++;
136 tensor_builder->notifyFirstUse(ind);
137 }
138
139 // At each operation,
140 // 1. Scan DEF of outputs. If the DEF, allocate it
141 // 2. Scan DEF of inputs. If variable tensor, allocate it
142 // 3. Scan USE of inputs. Decrease the USE and deallocate if the USE is 0
143 for (const auto &op_ind : _data.op_order)
144 {
145 const auto &op = graph()->operations().at(op_ind);
146 auto op_inputs = op.getInputs() | ir::Remove::DUPLICATED | ir::Remove::UNDEFINED;
147 auto op_outputs = op.getOutputs() | ir::Remove::DUPLICATED | ir::Remove::UNDEFINED;
148
149 // Define outputs
150 for (const auto &ind : op_outputs)
151 {
152 if (!tensor_builder->isRegistered(ind))
153 continue;
154 assert(def_map.find(ind) != def_map.end());
155 if (def_map[ind])
156 {
157 def_map[ind] = 0;
158 tensor_builder->notifyFirstUse(ind);
159 }
160 }
161
162 // Scan variable tensors
163 // This tensor has features like constant. But OperandInfo and LowerInfo treat them as
164 // non-constant because of less memory usage by memory planning in here
165 for (const auto &ind : op_inputs)
166 {
167 if (!tensor_builder->isRegistered(ind))
168 continue;
169 const auto &operand = graph()->operands().at(ind);
170 if (operand.info().isVariable())
171 {
172 // The variable tensor with buffer is not supported yet
173 assert(operand.data() == nullptr);
174 assert(operand.getUses().size() == 1 && !operand.getDef().valid());
175 assert(uses_map[ind] == 1 && def_map[ind] == 0);
176 tensor_builder->notifyFirstUse(ind);
177 }
178 }
179
180 for (const auto &ind : op_inputs)
181 {
182 if (!tensor_builder->isRegistered(ind))
183 continue;
184 assert(uses_map.find(ind) != uses_map.end());
185 assert(uses_map[ind] > 0);
186 uses_map[ind]--;
187 if (uses_map[ind] == 0)
188 {
189 // plan for deallocation of static tensornode
190 tensor_builder->notifyLastUse(ind);
191 }
192 }
193 }
194
195 _data.graph->operands().iterate([&](const ir::OperandIndex &ind, const ir::Operand &) {
196 if (uses_map[ind] == 0)
197 {
198 tensor_builder->notifyLastUse(ind);
199 }
200 });
201
202 // Dispose and validate
203 for (const auto &ind : constants)
204 {
205 --uses_map[ind];
206 if (uses_map[ind] == 0) // To prevent notifyLastUse from being called twice
207 {
208 tensor_builder->notifyLastUse(ind);
209 }
210 }
211
212 assert(
213 std::all_of(uses_map.begin(), uses_map.end(),
214 [](std::pair<const ir::OperandIndex, uint32_t> it) { return it.second == 0; }));
215
216 assert(
217 std::all_of(def_map.begin(), def_map.end(),
218 [](std::pair<const ir::OperandIndex, uint32_t> it) { return it.second == 0; }));
219 }
220
221public:
222 // TODO Make it protected
223 std::shared_ptr<T_TensorBuilder> tensor_builder;
224 std::shared_ptr<T_ConstantInitializer> constant_initializer;
225 std::shared_ptr<T_KernelGenerator> kernel_gen;
226};
227
228} // namespace cl_common
229} // namespace backend
230} // namespace onert
231
232#endif // __ONERT_BACKEND_CL_COMMON_BACKEND_CONTEXT_H__
std::shared_ptr< ITensorRegistry > tensor_registry
const ContextData & data() const
const ir::Graph * graph() const
const Backend * backend() const
std::shared_ptr< T_TensorBuilder > tensor_builder
virtual void registerTensorInfo(const ir::OperandIndex &ind, const ir::OperandInfo &info)=0
std::shared_ptr< T_ConstantInitializer > constant_initializer
std::shared_ptr< T_KernelGenerator > kernel_gen
BackendContext(const Backend *backend, ContextData &&data, std::shared_ptr< ITensorRegistry > tensor_registry=nullptr, std::shared_ptr< T_TensorBuilder > tensor_builder=nullptr, std::shared_ptr< T_ConstantInitializer > constant_initializer=nullptr, std::shared_ptr< T_KernelGenerator > kernel_gen=nullptr)
virtual void prepare()
Definition IFunction.h:30
const Operands & operands() const override
Definition Graph.h:112
const Operations & operations() const override
Definition Graph.h:114
bool isConstant(void) const
Get true if Operand is const, otherwise false a.
Definition Operand.h:79
void append(const OperandIndex &index)
Class to save tensor's shape and type.
Definition OperandInfo.h:56
const Object & at(const Index &index) const
Get the object that is associated with the given index.
volatile const char info[]
#define VERBOSE(name, lv)
Definition Log.h:71
std::unordered_map< ir::OperationIndex, std::unique_ptr< exec::FunctionSequence > > FunctionMap
std::unordered_map< OperandIndex, T > OperandIndexMap
std::vector< onert::ir::OperationIndex > op_order
std::unique_ptr< ir::Graph > graph
util::Set< ir::OperandIndex > external_operands
virtual void accept(OperationVisitor &v) const =0