Imported Upstream version 1.8.0
[platform/core/ml/nnfw.git] / runtime / onert / core / src / backend / controlflow / DynamicTensorManager.cc
1 /*
2  * Copyright (c) 2020 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 #include "DynamicTensorManager.h"
18
19 #include "util/logging.h"
20
21 namespace onert
22 {
23 namespace backend
24 {
25 namespace controlflow
26 {
27
28 DynamicTensorManager::DynamicTensorManager(const std::shared_ptr<cpu_common::TensorRegistry> &reg,
29                                            const std::shared_ptr<UserTensorRegistry> &user_reg)
30     : _dynamic_mem_mgr{new cpu_common::DynamicMemoryManager()}, _tensors{reg},
31       _user_tensors{user_reg}
32 {
33   // DO NOTHING
34 }
35
36 void DynamicTensorManager::applyShape(const ir::OperandIndex &ind, const ir::Shape &new_shape)
37 {
38   // NOTE Handle user tensors first
39   auto user_tensor = _user_tensors->getNativeTensor(ind);
40   if (user_tensor)
41   {
42     // User tensors cannot be reallocated.
43     auto buffer_size = user_tensor->total_size();
44     auto new_size = new_shape.num_elements() * sizeOfDataType(user_tensor->data_type());
45     if (buffer_size < new_size)
46       throw std::runtime_error{"ExecutorBase: output buffer size is less than output tensor size"};
47     user_tensor->setShape(new_shape);
48     return;
49   }
50
51   // NOTE Then handle native tensors
52   auto tensor = _tensors->getNativeTensor(ind);
53   assert(tensor);
54
55   bool previously_dynamic = tensor->is_dynamic();
56
57   auto allocTensorMem = [&](bool overwrite = false) {
58     auto capacity = tensor->total_size();
59     auto alloc = _dynamic_mem_mgr->allocate(ind, capacity);
60
61     if (overwrite)
62       tensor->overwriteBuffer(alloc);
63     else
64       tensor->setBuffer(alloc);
65   };
66
67   if (!previously_dynamic)
68   {
69     // TODO deallocate tensor->buffer()
70     // issue is that staticTensorManager might have allocate this memory
71     tensor->setShape(new_shape);
72     tensor->set_dynamic();
73     allocTensorMem(true);
74   }
75   else if (tensor->buffer() == nullptr)
76   {
77     tensor->setShape(new_shape);
78     tensor->set_dynamic();
79     allocTensorMem();
80   }
81   // when buffer was already allocated and new_shape requires different size
82   else
83   {
84     auto previous_size = tensor->total_size();
85     auto new_size = new_shape.num_elements() * sizeOfDataType(tensor->data_type());
86     if (previous_size != new_size)
87     {
88       _dynamic_mem_mgr->deallocate(ind);
89
90       tensor->setShape(new_shape);
91       tensor->set_dynamic();
92       allocTensorMem(true);
93     }
94     else
95     { // when buffer with same size was already allocated, shape could differ
96       tensor->setShape(new_shape);
97     }
98   }
99 }
100
101 void DynamicTensorManager::buildTensor(const ir::OperandIndex &ind,
102                                        const ir::OperandInfo &tensor_info,
103                                        ir::Layout backend_layout)
104 {
105   assert(_tensors->getNativeTensor(ind) == nullptr);
106   auto tensor = std::make_shared<cpu_common::Tensor>(tensor_info, backend_layout, this);
107   _tensors->setNativeTensor(ind, tensor);
108 }
109
110 void DynamicTensorManager::planDealloc(ir::OperationIndex op_ind, ir::OperandIndex operand_ind)
111 {
112   auto find = _dealloc_tensor_map.find(op_ind);
113   if (find != _dealloc_tensor_map.end())
114   {
115     auto &input_set = find->second;
116     input_set.emplace(operand_ind);
117   }
118   else
119   {
120     _dealloc_tensor_map.emplace(
121         std::make_pair(op_ind, std::unordered_set<ir::OperandIndex>{operand_ind}));
122   }
123 }
124
125 void DynamicTensorManager::deallocInput(ir::OperationIndex op_ind)
126 {
127   auto find = _dealloc_tensor_map.find(op_ind);
128   if (find == _dealloc_tensor_map.end())
129     return;
130
131   auto &input_set = find->second;
132   for (auto input_ind : input_set)
133   {
134     if (!_tensors->getNativeTensor(input_ind)->is_dynamic())
135       continue;
136
137     _dynamic_mem_mgr->deallocate(input_ind);
138     VERBOSE(DynamicTensorManager) << "Deallocating #" << input_ind.value()
139                                   << " (input of op_ind: " << op_ind.value() << ")" << std::endl;
140   }
141 }
142
143 void DynamicTensorManager::deallocSubgraphOutput(ir::OperandIndex output_ind)
144 {
145   if (!_tensors->getNativeTensor(output_ind)->is_dynamic())
146     return;
147
148   _dynamic_mem_mgr->deallocate(output_ind);
149   VERBOSE(DynamicTensorManager) << "Deallocating #" << output_ind.value()
150                                 << " (output of a subgraph)" << std::endl;
151 }
152
153 } // namespace controlflow
154 } // namespace backend
155 } // namespace onert