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