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 <backend/ITensorBuilder.h>
25 #include "ir/OperandIndexMap.h"
26 #include <ir/Operands.h>
27 #include "AclTensorManager.h"
28 #include "AclTensorRegistry.h"
30 #include "ParentInfo.h"
31 #include <util/Utils.h>
46 template <typename T_ITensor, typename T_Tensor, typename T_SubTensor>
47 class AclTensorBuilder : public ITensorBuilder
50 using T_AclTensorManager = AclTensorManager<T_ITensor, T_Tensor, T_SubTensor>;
52 AclTensorBuilder(const ir::Operands &operands, T_AclTensorManager *tensor_mgr,
53 const std::shared_ptr<AclTensorRegistry<T_AclTensorManager>> &tensor_reg);
56 * @brief Register tensor information to allocate on ACL-CL backend
57 * @param[in] ind Operand index
58 * @param[in] info Tensor information
59 * @param[in] layout Tensor data layout
61 void registerTensorInfo(const ir::OperandIndex &ind, const ir::OperandInfo &info,
62 ir::Layout backend_layout) override;
64 void notifyFirstUse(const ir::OperandIndex &) override;
65 void notifyLastUse(const ir::OperandIndex &) override;
67 bool isRegistered(const ir::OperandIndex &) const override;
69 void prepare(void) override;
70 void allocate() override;
71 void postFunctionPrepare() override;
73 T_AclTensorManager *acl_tensor_manager(void) { return _tensor_mgr.get(); }
75 void setUsesCount(const ir::OperandIndex &index, size_t num_uses)
77 assert(_uses_count_map.find(index) != _uses_count_map.end() ? _uses_count_map[index] == num_uses
79 _uses_count_map[index] = num_uses;
82 void parent_map(std::unordered_map<ir::OperandIndex, ParentInfo> &&parent_map)
84 _parent_map = std::move(parent_map);
87 bool areSubTensorsOf(const ir::OperandIndex &parent, const ir::OperandIndexSequence &seq);
90 * @brief Check child tensor is allocated as subtensor of parent tensor
91 * @param[in] parent Index of parent
92 * @param[in] child Index of child
93 * @return @c true if child is allocated as subtensor of parent, otherwise @c false
95 bool isSubTensorOf(const ir::OperandIndex &parent, const ir::OperandIndex &child);
98 void buildTensors(void);
99 ir::OperandIndex findRootParent(ir::OperandIndex index);
102 const ir::Operands &_operands;
103 ir::OperandIndexMap<ir::OperandInfo> _tensor_info_map;
104 ir::OperandIndexMap<ir::Layout> _tensor_layout_map;
105 ir::OperandIndexMap<size_t> _uses_count_map;
107 std::unique_ptr<T_AclTensorManager> _tensor_mgr;
108 std::shared_ptr<AclTensorRegistry<T_AclTensorManager>> _tensor_reg;
110 // for linear executor
111 std::vector<std::pair<UsesType, ir::OperandIndex>> _lifetime_seq;
113 // Extra info for concat elimination
114 ir::OperandIndexMap<ParentInfo> _parent_map;
117 } // namespace acl_common
118 } // namespace backend
126 #include "util/logging.h"
135 template <typename T_ITensor, typename T_Tensor, typename T_SubTensor>
136 AclTensorBuilder<T_ITensor, T_Tensor, T_SubTensor>::AclTensorBuilder(
137 const ir::Operands &operands, T_AclTensorManager *tensor_mgr,
138 const std::shared_ptr<AclTensorRegistry<T_AclTensorManager>> &tensor_reg)
139 : _operands{operands}, _tensor_mgr{tensor_mgr}, _tensor_reg{tensor_reg}
144 template <typename T_ITensor, typename T_Tensor, typename T_SubTensor>
145 void AclTensorBuilder<T_ITensor, T_Tensor, T_SubTensor>::registerTensorInfo(
146 const ir::OperandIndex &ind, const ir::OperandInfo &info, ir::Layout backend_layout)
148 assert(_tensor_mgr->constTensors().size() == 0);
149 assert(_tensor_mgr->nonconstTensors().size() == 0);
151 _uses_count_map[ind] = _operands.at(ind).getUses().size();
153 if (_parent_map.count(ind) == 0)
156 _tensor_info_map.emplace(ind, info);
157 _tensor_layout_map.insert({ind, backend_layout});
162 assert(!info.isConstant() && "Subtensors of constants are not supported yet.");
164 // Update offset info and emplace
165 auto &parent_info = _parent_map[ind];
166 const auto &obj = _operands.at(ind);
167 auto parent_index = parent_info.parent;
168 auto &offset = parent_info.coordinates;
169 auto frontend_layout = parent_info.frontend_layout;
171 assert(obj.shape().rank() <= ir::Shape::MAX_RANK);
172 auto shape = obj.shape();
173 if (_operands.at(parent_index).shape().rank() >= 4 && frontend_layout == ir::Layout::NHWC &&
174 backend_layout == ir::Layout::NCHW)
176 // Permutation changing layout beyond 4-D is not supported yet
177 const auto parent_rank = _operands.at(parent_index).shape().rank();
178 assert(parent_rank == 4);
179 shape.extendRank(parent_rank);
180 offset = {offset[0], offset[3], offset[1], offset[2]};
182 else if (_operands.at(parent_index).shape().rank() >= 4 &&
183 frontend_layout == ir::Layout::NHWC && backend_layout == ir::Layout::NCHW)
185 // Permutation changing layout beyond 4-D is not supported yet
186 const auto parent_rank = _operands.at(parent_index).shape().rank();
187 assert(parent_rank == 4);
188 shape.extendRank(parent_rank);
189 offset = {offset[0], offset[2], offset[3], offset[1]};
191 auto new_shape = permuteShape(shape, frontend_layout, backend_layout);
192 auto oi = ir::OperandInfo::createStaticInfo(new_shape, obj.typeInfo());
193 _tensor_info_map.emplace(ind, oi);
197 template <typename T_ITensor, typename T_Tensor, typename T_SubTensor>
198 void AclTensorBuilder<T_ITensor, T_Tensor, T_SubTensor>::notifyFirstUse(const ir::OperandIndex &ind)
200 _lifetime_seq.emplace_back(UsesType::FIRST, ind);
203 template <typename T_ITensor, typename T_Tensor, typename T_SubTensor>
204 void AclTensorBuilder<T_ITensor, T_Tensor, T_SubTensor>::notifyLastUse(const ir::OperandIndex &ind)
206 _lifetime_seq.emplace_back(UsesType::LAST, ind);
209 template <typename T_ITensor, typename T_Tensor, typename T_SubTensor>
210 bool AclTensorBuilder<T_ITensor, T_Tensor, T_SubTensor>::isRegistered(
211 const ir::OperandIndex &ind) const
213 return _tensor_info_map.find(ind) != _tensor_info_map.end();
216 template <typename T_ITensor, typename T_Tensor, typename T_SubTensor>
217 void AclTensorBuilder<T_ITensor, T_Tensor, T_SubTensor>::prepare(void)
222 template <typename T_ITensor, typename T_Tensor, typename T_SubTensor>
223 void AclTensorBuilder<T_ITensor, T_Tensor, T_SubTensor>::allocate(void)
225 // Update lifetime sequence to apply subtensor optimization
227 std::unordered_map<ir::OperandIndex, ir::OperandIndex> root_map;
228 std::function<ir::OperandIndex &(ir::OperandIndex)> find_root =
229 [&](ir::OperandIndex ind) -> ir::OperandIndex & {
230 ir::OperandIndex &ret = root_map[ind];
232 // We know the root parent value already
236 auto itr = _parent_map.find(ind);
237 if (itr == _parent_map.end())
239 // If there is no parent, let's store the value of itself
244 return ret = find_root(itr->second.parent);
248 ir::OperandIndexMap<bool> first_use_check;
249 ir::OperandIndexMap<bool> last_use_check;
250 std::map<size_t, std::pair<UsesType, ir::OperandIndex>> lifetime_map;
251 for (size_t i = 0; i < _lifetime_seq.size(); i++)
253 auto &entry = _lifetime_seq[i];
254 if (entry.first != UsesType::FIRST)
256 auto root_ind = find_root(entry.second);
257 if (first_use_check[root_ind])
259 first_use_check[root_ind] = true;
260 lifetime_map[i] = {UsesType::FIRST, root_ind};
263 for (int i = _lifetime_seq.size() - 1; i >= 0; i--)
265 auto &entry = _lifetime_seq[i];
266 if (entry.first != UsesType::LAST)
268 auto root_ind = find_root(entry.second);
269 if (last_use_check[root_ind])
271 last_use_check[root_ind] = true;
272 lifetime_map[i] = {UsesType::LAST, root_ind};
275 for (auto &entry : lifetime_map)
277 auto &use = entry.second;
278 auto use_type = use.first;
279 auto use_index = use.second;
280 assert(use_index.valid());
281 if (use_type == UsesType::FIRST)
282 _tensor_mgr->startLifetime(use_index);
284 _tensor_mgr->finishLifetime(use_index);
287 _tensor_mgr->allocateConsts();
289 // TODO Since `_parent_map` is filled for all Concat nodes even if the node this backend uses
290 // After refactoring BackendContext we can uncomment this
291 // assert(_tensor_info_map.size() ==
292 // _tensor_mgr->nonconstTensors().size() + num of constants of _tensor_info_map +
293 // _parent_map.size());
294 _tensor_mgr->allocateNonconsts();
296 _tensor_mgr->allocateInternalBufferManager();
299 template <typename T_ITensor, typename T_Tensor, typename T_SubTensor>
300 void AclTensorBuilder<T_ITensor, T_Tensor, T_SubTensor>::postFunctionPrepare(void)
302 _tensor_mgr->tryDeallocConstants();
305 template <typename T_ITensor, typename T_Tensor, typename T_SubTensor>
306 void AclTensorBuilder<T_ITensor, T_Tensor, T_SubTensor>::buildTensors(void)
308 assert(_tensor_mgr->constTensors().size() == 0);
309 assert(_tensor_mgr->nonconstTensors().size() == 0);
312 for (auto &entry : _tensor_info_map)
314 auto ind = entry.first;
315 if (_parent_map.count(ind) > 0)
318 const auto &info = entry.second;
319 const auto &backend_layout = _tensor_layout_map[ind];
321 asTensorInfo(info.shape(), info.typeInfo(), ir::Layout::UNKNOWN, backend_layout, true);
322 _tensor_mgr->buildTensor(ind, tensor_info, info.shape().rank(), info.isConstant(),
323 _uses_count_map[ind]);
327 assert(_tensor_mgr->nonconstSubtensors().size() == 0);
328 // TODO Iterate `_parent_map` instead, once the optimizer bug is fixed
329 // `Optimizer` iterates the entire OpSequences, so there is a bug if iterating _parent_map
330 for (auto &entry : _tensor_info_map)
332 auto ind = entry.first;
333 if (_parent_map.count(ind) == 0)
336 // To make subtensor, parent tensor must be made first
337 // For this condition, use stack
338 // 1) Push one subtensor index to stack (iterate subtensors)
339 // 2) If tensor at stack top is already made, pop and go to 4)
340 // 3) If tensor pushed at 1) is not made, check parent tensor
341 // 3-1) If parent tensor is already made, we can make child tensor
342 // Make child tensor and pop, go to 4)
343 // 3-2) If parent tensor is not made, we can't make child tensor yet
344 // Push parent tensor index to stack and return to 4)
345 // 4) If stack is empty, return to 1), else return to 2)
346 auto &subtensors = _tensor_mgr->nonconstSubtensors();
348 std::stack<ir::OperandIndex> stack;
351 while (!stack.empty())
353 const auto current = stack.top();
354 const auto &tensor_info = _tensor_info_map.at(current);
355 const auto &parent_info = _parent_map.at(current);
357 // Already generated SubTensor
358 if (subtensors.find(current) != subtensors.end())
364 auto parent = parent_info.parent;
365 std::shared_ptr<T_ITensor> parent_tensor = _tensor_mgr->findTensorAsParent(parent);
368 // Cannot find allocated parent tensor: allocate parent first
369 assert(_parent_map.count(parent) > 0);
373 assert(parent_tensor != nullptr);
375 // Child's type should be same with parent
376 assert(tensor_info.typeInfo().offset() ==
377 parent_tensor->info()->quantization_info().uniform().offset);
378 assert(tensor_info.typeInfo().scale() ==
379 parent_tensor->info()->quantization_info().uniform().scale);
380 assert(tensor_info.typeInfo().type() == parent_tensor->data_type());
382 // NOTE SubTensor's layout must be the same with layout of parent tensor
383 const auto &root_parent = findRootParent(parent);
384 const auto &backend_layout = _tensor_layout_map[root_parent];
386 auto shape = asTensorShape(tensor_info.shape(), ir::Layout::UNKNOWN, backend_layout, true);
387 ::arm_compute::Coordinates coordinates =
388 asTensorCoordinate(parent_info.coordinates, ir::Layout::UNKNOWN, backend_layout);
389 _tensor_mgr->buildSubtensor(parent, current, shape, coordinates, tensor_info.shape().rank(),
396 template <typename T_ITensor, typename T_Tensor, typename T_SubTensor>
397 bool AclTensorBuilder<T_ITensor, T_Tensor, T_SubTensor>::areSubTensorsOf(
398 const ir::OperandIndex &parent, const ir::OperandIndexSequence &seq)
400 for (auto &cand : seq)
402 if (!isSubTensorOf(parent, cand))
410 template <typename T_ITensor, typename T_Tensor, typename T_SubTensor>
411 bool AclTensorBuilder<T_ITensor, T_Tensor, T_SubTensor>::isSubTensorOf(
412 const ir::OperandIndex &parent, const ir::OperandIndex &child)
414 auto itr = _parent_map.find(child);
415 if (itr == _parent_map.end())
420 return itr->second.parent == parent;
423 template <typename T_ITensor, typename T_Tensor, typename T_SubTensor>
425 AclTensorBuilder<T_ITensor, T_Tensor, T_SubTensor>::findRootParent(ir::OperandIndex ind)
427 if (_parent_map.find(ind) == _parent_map.end())
430 auto parent_ind = _parent_map.at(ind).parent;
431 return findRootParent(parent_ind);
434 } // namespace acl_common
435 } // namespace backend
438 #endif // __ONERT_BACKEND_ACL_COMMON_TEMPL_TENSOR_BUILDER_H__