2 * Copyright (c) 2019 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.
17 #ifndef __ONERT_BACKEND_ACL_COMMON_TEMPL_TENSOR_BUILDER_H__
18 #define __ONERT_BACKEND_ACL_COMMON_TEMPL_TENSOR_BUILDER_H__
23 #include <arm_compute/core/Types.h>
24 #include "ir/OperandIndexMap.h"
25 #include <ir/Operands.h>
26 #include "AclTensorManager.h"
27 #include "AclTensorRegistry.h"
29 #include "ParentInfo.h"
30 #include <util/Utils.h>
45 template <typename T_ITensor, typename T_Tensor, typename T_SubTensor> class AclTensorBuilder
48 using T_AclTensorManager = AclTensorManager<T_ITensor, T_Tensor, T_SubTensor>;
50 AclTensorBuilder(const ir::Operands &operands, T_AclTensorManager *tensor_mgr);
53 * @brief Register tensor information to allocate on ACL-CL backend
54 * @param[in] ind Operand index
55 * @param[in] info Tensor information
56 * @param[in] layout Tensor data layout
58 void registerTensorInfo(const ir::OperandIndex &ind, const ir::OperandInfo &info,
59 ir::Layout backend_layout);
61 void notifyFirstUse(const ir::OperandIndex &);
62 void notifyLastUse(const ir::OperandIndex &);
64 bool isRegistered(const ir::OperandIndex &) const;
68 void postFunctionPrepare();
70 T_AclTensorManager *acl_tensor_manager(void) { return _tensor_mgr.get(); }
72 void setUsesCount(const ir::OperandIndex &index, size_t num_uses)
74 assert(_uses_count_map.find(index) != _uses_count_map.end() ? _uses_count_map[index] == num_uses
76 _uses_count_map[index] = num_uses;
79 void parent_map(std::unordered_map<ir::OperandIndex, ParentInfo> &&parent_map)
81 _parent_map = std::move(parent_map);
84 bool areSubTensorsOf(const ir::OperandIndex &parent, const ir::OperandIndexSequence &seq);
87 * @brief Check child tensor is allocated as subtensor of parent tensor
88 * @param[in] parent Index of parent
89 * @param[in] child Index of child
90 * @return @c true if child is allocated as subtensor of parent, otherwise @c false
92 bool isSubTensorOf(const ir::OperandIndex &parent, const ir::OperandIndex &child);
95 void buildTensors(void);
96 ir::OperandIndex findRootParent(ir::OperandIndex index);
99 const ir::Operands &_operands;
100 ir::OperandIndexMap<ir::OperandInfo> _tensor_info_map;
101 ir::OperandIndexMap<ir::Layout> _tensor_layout_map;
102 ir::OperandIndexMap<size_t> _uses_count_map;
104 std::unique_ptr<T_AclTensorManager> _tensor_mgr;
106 // for linear executor
107 std::vector<std::pair<UsesType, ir::OperandIndex>> _lifetime_seq;
109 // Extra info for concat elimination
110 ir::OperandIndexMap<ParentInfo> _parent_map;
113 } // namespace acl_common
114 } // namespace backend
122 #include "util/logging.h"
131 template <typename T_ITensor, typename T_Tensor, typename T_SubTensor>
132 AclTensorBuilder<T_ITensor, T_Tensor, T_SubTensor>::AclTensorBuilder(const ir::Operands &operands,
133 T_AclTensorManager *tensor_mgr)
134 : _operands{operands}, _tensor_mgr{tensor_mgr}
139 template <typename T_ITensor, typename T_Tensor, typename T_SubTensor>
140 void AclTensorBuilder<T_ITensor, T_Tensor, T_SubTensor>::registerTensorInfo(
141 const ir::OperandIndex &ind, const ir::OperandInfo &info, ir::Layout backend_layout)
143 assert(_tensor_mgr->constTensors().size() == 0);
144 assert(_tensor_mgr->nonconstTensors().size() == 0);
146 _uses_count_map[ind] = _operands.at(ind).getUses().size();
148 if (_parent_map.count(ind) == 0)
151 _tensor_info_map.emplace(ind, info);
152 _tensor_layout_map.insert({ind, backend_layout});
157 assert(!info.isConstant() && "Subtensors of constants are not supported yet.");
159 // Update offset info and emplace
160 auto &parent_info = _parent_map[ind];
161 const auto &obj = _operands.at(ind);
162 auto parent_index = parent_info.parent;
163 auto &offset = parent_info.coordinates;
164 auto frontend_layout = parent_info.frontend_layout;
166 assert(obj.shape().rank() <= ir::Shape::MAX_RANK);
167 auto shape = obj.shape();
168 if (_operands.at(parent_index).shape().rank() >= 4 && frontend_layout == ir::Layout::NHWC &&
169 backend_layout == ir::Layout::NCHW)
171 // Permutation changing layout beyond 4-D is not supported yet
172 const auto parent_rank = _operands.at(parent_index).shape().rank();
173 assert(parent_rank == 4);
174 shape.extendRank(parent_rank);
175 offset = {offset[0], offset[3], offset[1], offset[2]};
177 else if (_operands.at(parent_index).shape().rank() >= 4 &&
178 frontend_layout == ir::Layout::NHWC && backend_layout == ir::Layout::NCHW)
180 // Permutation changing layout beyond 4-D is not supported yet
181 const auto parent_rank = _operands.at(parent_index).shape().rank();
182 assert(parent_rank == 4);
183 shape.extendRank(parent_rank);
184 offset = {offset[0], offset[2], offset[3], offset[1]};
186 auto new_shape = permuteShape(shape, frontend_layout, backend_layout);
187 auto oi = ir::OperandInfo::createStaticInfo(new_shape, obj.typeInfo());
188 _tensor_info_map.emplace(ind, oi);
192 template <typename T_ITensor, typename T_Tensor, typename T_SubTensor>
193 void AclTensorBuilder<T_ITensor, T_Tensor, T_SubTensor>::notifyFirstUse(const ir::OperandIndex &ind)
195 _lifetime_seq.emplace_back(UsesType::FIRST, ind);
198 template <typename T_ITensor, typename T_Tensor, typename T_SubTensor>
199 void AclTensorBuilder<T_ITensor, T_Tensor, T_SubTensor>::notifyLastUse(const ir::OperandIndex &ind)
201 _lifetime_seq.emplace_back(UsesType::LAST, ind);
204 template <typename T_ITensor, typename T_Tensor, typename T_SubTensor>
205 bool AclTensorBuilder<T_ITensor, T_Tensor, T_SubTensor>::isRegistered(
206 const ir::OperandIndex &ind) const
208 return _tensor_info_map.find(ind) != _tensor_info_map.end();
211 template <typename T_ITensor, typename T_Tensor, typename T_SubTensor>
212 void AclTensorBuilder<T_ITensor, T_Tensor, T_SubTensor>::prepare(void)
217 template <typename T_ITensor, typename T_Tensor, typename T_SubTensor>
218 void AclTensorBuilder<T_ITensor, T_Tensor, T_SubTensor>::allocate(void)
220 // Update lifetime sequence to apply subtensor optimization
222 std::unordered_map<ir::OperandIndex, ir::OperandIndex> root_map;
223 std::function<ir::OperandIndex &(ir::OperandIndex)> find_root =
224 [&](ir::OperandIndex ind) -> ir::OperandIndex & {
225 ir::OperandIndex &ret = root_map[ind];
227 // We know the root parent value already
231 auto itr = _parent_map.find(ind);
232 if (itr == _parent_map.end())
234 // If there is no parent, let's store the value of itself
239 return ret = find_root(itr->second.parent);
243 ir::OperandIndexMap<bool> first_use_check;
244 ir::OperandIndexMap<bool> last_use_check;
245 std::map<size_t, std::pair<UsesType, ir::OperandIndex>> lifetime_map;
246 for (size_t i = 0; i < _lifetime_seq.size(); i++)
248 auto &entry = _lifetime_seq[i];
249 if (entry.first != UsesType::FIRST)
251 auto root_ind = find_root(entry.second);
252 if (first_use_check[root_ind])
254 first_use_check[root_ind] = true;
255 lifetime_map[i] = {UsesType::FIRST, root_ind};
258 for (int i = _lifetime_seq.size() - 1; i >= 0; i--)
260 auto &entry = _lifetime_seq[i];
261 if (entry.first != UsesType::LAST)
263 auto root_ind = find_root(entry.second);
264 if (last_use_check[root_ind])
266 last_use_check[root_ind] = true;
267 lifetime_map[i] = {UsesType::LAST, root_ind};
270 for (auto &entry : lifetime_map)
272 auto &use = entry.second;
273 auto use_type = use.first;
274 auto use_index = use.second;
275 assert(use_index.valid());
276 if (use_type == UsesType::FIRST)
277 _tensor_mgr->startLifetime(use_index);
279 _tensor_mgr->finishLifetime(use_index);
282 _tensor_mgr->allocateConsts();
284 // TODO Since `_parent_map` is filled for all Concat nodes even if the node this backend uses
285 // After refactoring BackendContext we can uncomment this
286 // assert(_tensor_info_map.size() ==
287 // _tensor_mgr->nonconstTensors().size() + num of constants of _tensor_info_map +
288 // _parent_map.size());
289 _tensor_mgr->allocateNonconsts();
291 _tensor_mgr->allocateInternalBufferManager();
294 template <typename T_ITensor, typename T_Tensor, typename T_SubTensor>
295 void AclTensorBuilder<T_ITensor, T_Tensor, T_SubTensor>::postFunctionPrepare(void)
297 _tensor_mgr->tryDeallocConstants();
300 template <typename T_ITensor, typename T_Tensor, typename T_SubTensor>
301 void AclTensorBuilder<T_ITensor, T_Tensor, T_SubTensor>::buildTensors(void)
303 assert(_tensor_mgr->constTensors().size() == 0);
304 assert(_tensor_mgr->nonconstTensors().size() == 0);
307 for (auto &entry : _tensor_info_map)
309 auto ind = entry.first;
310 if (_parent_map.count(ind) > 0)
313 const auto &info = entry.second;
314 const auto &backend_layout = _tensor_layout_map[ind];
316 asTensorInfo(info.shape(), info.typeInfo(), ir::Layout::UNKNOWN, backend_layout, true);
317 _tensor_mgr->buildTensor(ind, tensor_info, info.shape().rank(), info.isConstant(),
318 _uses_count_map[ind]);
322 assert(_tensor_mgr->nonconstSubtensors().size() == 0);
323 // TODO Iterate `_parent_map` instead, once the optimizer bug is fixed
324 // `Optimizer` iterates the entire OpSequences, so there is a bug if iterating _parent_map
325 for (auto &entry : _tensor_info_map)
327 auto ind = entry.first;
328 if (_parent_map.count(ind) == 0)
331 // To make subtensor, parent tensor must be made first
332 // For this condition, use stack
333 // 1) Push one subtensor index to stack (iterate subtensors)
334 // 2) If tensor at stack top is already made, pop and go to 4)
335 // 3) If tensor pushed at 1) is not made, check parent tensor
336 // 3-1) If parent tensor is already made, we can make child tensor
337 // Make child tensor and pop, go to 4)
338 // 3-2) If parent tensor is not made, we can't make child tensor yet
339 // Push parent tensor index to stack and return to 4)
340 // 4) If stack is empty, return to 1), else return to 2)
341 auto &subtensors = _tensor_mgr->nonconstSubtensors();
343 std::stack<ir::OperandIndex> stack;
346 while (!stack.empty())
348 const auto current = stack.top();
349 const auto &tensor_info = _tensor_info_map.at(current);
350 const auto &parent_info = _parent_map.at(current);
352 // Already generated SubTensor
353 if (subtensors.find(current) != subtensors.end())
359 auto parent = parent_info.parent;
360 std::shared_ptr<T_ITensor> parent_tensor = _tensor_mgr->findTensorAsParent(parent);
363 // Cannot find allocated parent tensor: allocate parent first
364 assert(_parent_map.count(parent) > 0);
368 assert(parent_tensor != nullptr);
370 // Child's type should be same with parent
371 assert(tensor_info.typeInfo().offset() ==
372 parent_tensor->info()->quantization_info().uniform().offset);
373 assert(tensor_info.typeInfo().scale() ==
374 parent_tensor->info()->quantization_info().uniform().scale);
375 assert(tensor_info.typeInfo().type() == parent_tensor->data_type());
377 // NOTE SubTensor's layout must be the same with layout of parent tensor
378 const auto &root_parent = findRootParent(parent);
379 const auto &backend_layout = _tensor_layout_map[root_parent];
381 auto shape = asTensorShape(tensor_info.shape(), ir::Layout::UNKNOWN, backend_layout, true);
382 ::arm_compute::Coordinates coordinates =
383 asTensorCoordinate(parent_info.coordinates, ir::Layout::UNKNOWN, backend_layout);
384 _tensor_mgr->buildSubtensor(parent, current, shape, coordinates, tensor_info.shape().rank(),
391 template <typename T_ITensor, typename T_Tensor, typename T_SubTensor>
392 bool AclTensorBuilder<T_ITensor, T_Tensor, T_SubTensor>::areSubTensorsOf(
393 const ir::OperandIndex &parent, const ir::OperandIndexSequence &seq)
395 for (auto &cand : seq)
397 if (!isSubTensorOf(parent, cand))
405 template <typename T_ITensor, typename T_Tensor, typename T_SubTensor>
406 bool AclTensorBuilder<T_ITensor, T_Tensor, T_SubTensor>::isSubTensorOf(
407 const ir::OperandIndex &parent, const ir::OperandIndex &child)
409 auto itr = _parent_map.find(child);
410 if (itr == _parent_map.end())
415 return itr->second.parent == parent;
418 template <typename T_ITensor, typename T_Tensor, typename T_SubTensor>
420 AclTensorBuilder<T_ITensor, T_Tensor, T_SubTensor>::findRootParent(ir::OperandIndex ind)
422 if (_parent_map.find(ind) == _parent_map.end())
425 auto parent_ind = _parent_map.at(ind).parent;
426 return findRootParent(parent_ind);
429 } // namespace acl_common
430 } // namespace backend
433 #endif // __ONERT_BACKEND_ACL_COMMON_TEMPL_TENSOR_BUILDER_H__