41447f9d7e5458dfd034b9ff7239a674e1ad020f
[platform/core/ml/nnfw.git] / onert-micro / luci-interpreter / src / core / RuntimeGraph.cpp
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 "core/RuntimeGraph.h"
18 #include "kernels/KernelBuilder.h"
19
20 #include <algorithm>
21 #include <map>
22
23 namespace luci_interpreter
24 {
25
26 // IBaseRuntimeGraph
27 RuntimeGraph::RuntimeGraph(SimpleMemoryManager *memory_manager, CircleReader *circle_reader)
28   : _memory_manager(memory_manager),
29     _tensor_to_data(std::unordered_map<const circle::Tensor *, uint8_t *>{}),
30     _reader(circle_reader), _inplace_op_indexes(std::unordered_set<uint32_t>{})
31 {
32 }
33
34 RuntimeGraph::~RuntimeGraph()
35 {
36   for (auto &idx_to_tensor : _tensor_to_data)
37   {
38     auto *data = idx_to_tensor.second;
39
40     _memory_manager->release_memory(data);
41   }
42 }
43
44 // TODO: modify this
45 void RuntimeGraph::buildAllocDeallocPlan()
46 {
47   invalidate();
48   using Lifetime = std::pair<int32_t, int32_t>;
49   std::map<const circle::Tensor *, Lifetime> lifetimes;
50   const size_t num_kernels = _reader->operators().size();
51
52   for (const auto input_ind : _reader->inputs())
53   {
54     const auto raw_tensor = _reader->tensors()[input_ind];
55
56     assert(lifetimes.count(raw_tensor) == 0);
57     lifetimes[raw_tensor] = Lifetime(-1, 0);
58   }
59
60   for (int32_t index = 0; index < num_kernels; ++index)
61   {
62     const auto kernel = _reader->operators().at(index);
63     assert(kernel != nullptr);
64
65     for (int32_t j = 0; j < kernel->inputs()->size(); ++j)
66     {
67       const auto input_index = kernel->inputs()->operator[](j);
68
69       if (input_index == -1)
70         continue;
71
72       const auto raw_tensor = _reader->tensors()[input_index];
73
74       // Pass constant tensors
75       auto const &buffer = wrap(_reader->buffers()[raw_tensor->buffer()]->data());
76       if (not buffer.empty())
77       {
78         // unknown shape tensor and scalar tensor
79         continue;
80       }
81
82       if (lifetimes.count(raw_tensor) > 0)
83       {
84         if (_inplace_op_indexes.find(index) != _inplace_op_indexes.end())
85           lifetimes.at(raw_tensor).second = -1;
86         else
87           lifetimes.at(raw_tensor).second = index;
88       }
89     }
90
91     for (int32_t j = 0; j < kernel->outputs()->size(); ++j)
92     {
93       const auto output_index = kernel->outputs()->operator[](j);
94       const auto raw_tensor = _reader->tensors()[output_index];
95
96       assert(lifetimes.count(raw_tensor) == 0);
97       if (_inplace_op_indexes.find(index) != _inplace_op_indexes.end())
98         lifetimes[raw_tensor] = Lifetime(-1, index);
99       else
100         lifetimes[raw_tensor] = Lifetime(index, index);
101     }
102   }
103
104   for (const auto output_ind : _reader->outputs())
105   {
106     const auto raw_tensor = _reader->tensors()[output_ind];
107
108     if (lifetimes.count(raw_tensor) > 0)
109       lifetimes.at(raw_tensor).second = num_kernels;
110   }
111
112   _alloc_plan.assign(num_kernels, std::vector<const circle::Tensor *>());
113   _dealloc_plan.assign(num_kernels + 1, std::vector<const circle::Tensor *>());
114   for (const auto &item : lifetimes)
115   {
116     if (item.second.first != -1)
117       _alloc_plan[item.second.first].push_back(item.first);
118     if (item.second.second != -1)
119       _dealloc_plan[item.second.second].push_back(item.first);
120   }
121   _is_valid = true;
122 }
123
124 void RuntimeGraph::allocate(size_t kernel_index)
125 {
126   assert(_is_valid && kernel_index < _alloc_plan.size());
127   for (const circle::Tensor *tensor : _alloc_plan[kernel_index])
128   {
129     if (_tensor_to_data.find(tensor) != _tensor_to_data.end())
130     {
131       auto *data = _tensor_to_data.at(tensor);
132       _memory_manager->release_memory(data);
133     }
134     auto *data = _memory_manager->allocate_memory(tensor);
135     _tensor_to_data[tensor] = data;
136   }
137 }
138
139 void RuntimeGraph::deallocate(size_t kernel_index)
140 {
141   assert(_is_valid && kernel_index < _dealloc_plan.size());
142   for (const circle::Tensor *tensor : _dealloc_plan[kernel_index])
143   {
144     const auto it = _tensor_to_data.find(tensor);
145     assert(it != _tensor_to_data.end());
146
147     auto *data = _tensor_to_data.at(tensor);
148     _memory_manager->release_memory(data);
149
150     _tensor_to_data.erase(it);
151   }
152 }
153
154 void RuntimeGraph::resetOutputTensorsData()
155 {
156   for (int i = 0; i < _reader->outputs().size(); ++i)
157   {
158     const auto tensor_index = _reader->outputs()[i];
159     assert(tensor_index != -1);
160     const auto tensor = _reader->tensors()[tensor_index];
161     assert(tensor != nullptr);
162
163     auto tensor_it = _tensor_to_data.find(tensor);
164     if (tensor_it != _tensor_to_data.end())
165     {
166       auto *data = _tensor_to_data.at(tensor);
167       _memory_manager->release_memory(data);
168       _tensor_to_data.erase(tensor_it);
169     }
170   }
171 }
172
173 uint8_t *RuntimeGraph::configureGraphInput(int32_t input_index)
174 {
175   resetOutputTensorsData();
176
177   const auto tensor_index = _reader->inputs()[input_index];
178   assert(tensor_index != -1);
179   const auto tensor = _reader->tensors()[tensor_index];
180   assert(tensor != nullptr);
181
182   if (_tensor_to_data.find(tensor) != _tensor_to_data.end())
183   {
184     auto *data = _tensor_to_data.at(tensor);
185     _memory_manager->release_memory(data);
186   }
187
188   auto *data = _memory_manager->allocate_memory(tensor);
189   _tensor_to_data[tensor] = data;
190
191   return data;
192 }
193
194 // To save data
195 // TODO maybe remove it
196 void RuntimeGraph::configureGraphInput(int32_t input_index, uint8_t *data)
197 {
198   resetOutputTensorsData();
199
200   const auto tensor_index = _reader->inputs()[input_index];
201   assert(tensor_index != -1);
202   const auto tensor = _reader->tensors()[tensor_index];
203   assert(tensor != nullptr);
204
205   if (_tensor_to_data.find(tensor) != _tensor_to_data.end())
206   {
207     auto *data_prev = _tensor_to_data.at(tensor);
208     _memory_manager->release_memory(data_prev);
209   }
210   _tensor_to_data[tensor] = data;
211 }
212
213 int32_t RuntimeGraph::getInputDataSizeByIndex(int32_t input_index)
214 {
215   const auto tensor_index = _reader->inputs()[input_index];
216   assert(tensor_index != -1);
217   const auto tensor = _reader->tensors()[tensor_index];
218   assert(tensor != nullptr);
219
220   return Tensor::num_elements(tensor) * size(Tensor::element_type(tensor));
221 }
222
223 int32_t RuntimeGraph::getOutputDataSizeByIndex(int32_t output_index)
224 {
225   const auto tensor_index = _reader->outputs()[output_index];
226   assert(tensor_index != -1);
227   const auto tensor = _reader->tensors()[tensor_index];
228   assert(tensor != nullptr);
229
230   return Tensor::num_elements(tensor) * size(Tensor::element_type(tensor));
231 }
232
233 uint8_t *RuntimeGraph::getOutputDataByIndex(int32_t output_index)
234 {
235   const auto tensor_index = _reader->outputs()[output_index];
236   assert(tensor_index != -1);
237   const auto tensor = _reader->tensors()[tensor_index];
238   assert(tensor != nullptr);
239
240   assert(_tensor_to_data.find(tensor) != _tensor_to_data.end());
241
242   return _tensor_to_data[tensor];
243 }
244
245 uint8_t *RuntimeGraph::getDataByTensor(const circle::Tensor *raw_tensor)
246 {
247   if (raw_tensor == nullptr)
248     return nullptr;
249
250   if (_tensor_to_data.find(raw_tensor) == _tensor_to_data.end())
251   {
252     return nullptr;
253   }
254
255   return _tensor_to_data.at(raw_tensor);
256 }
257
258 void RuntimeGraph::makeInplaceOperation(const circle::Tensor *src_tensor,
259                                         const circle::Tensor *dst_tensor)
260 {
261   if (src_tensor == nullptr or dst_tensor == nullptr)
262     return;
263
264   auto src_it = _tensor_to_data.find(src_tensor);
265
266   assert(src_it != _tensor_to_data.end() && "Failed makeInplaceOperation");
267
268   auto *data = _tensor_to_data[src_tensor];
269
270   _tensor_to_data.erase(src_it);
271
272   assert(_tensor_to_data.find(dst_tensor) == _tensor_to_data.end() &&
273          "Failed makeInplaceOperation");
274   _tensor_to_data[dst_tensor] = data;
275 }
276
277 uint8_t *RuntimeGraph::getConstDataByTensor(const circle::Tensor *raw_tensor)
278 {
279   if (raw_tensor == nullptr)
280     return nullptr;
281
282   auto const &buffer = wrap(_reader->buffers()[raw_tensor->buffer()]->data());
283
284   return const_cast<uint8_t *>(buffer.data());
285 }
286
287 const circle::Tensor *RuntimeGraph::getCircleTensorByIndex(int32_t index)
288 {
289   if (index < 0)
290     return nullptr;
291
292   const auto raw_tensor = _reader->tensors()[index];
293
294   return raw_tensor;
295 }
296
297 void RuntimeGraph::configure()
298 {
299   KernelConfigureRegistry kernel_configure;
300
301   for (uint32_t i = 0; i < _reader->operators().size(); ++i)
302   {
303     const auto op = _reader->operators().at(i);
304     assert(op != nullptr);
305
306     const auto opcode = _reader->builtin_code(op);
307
308     kernel_configure.configure_kernel(op, opcode, this);
309   }
310
311   if (not _is_valid)
312     buildAllocDeallocPlan();
313
314   _is_valid = true;
315 }
316
317 void RuntimeGraph::execute()
318 {
319   if (not _is_valid)
320     configure();
321
322   KernelExecuteRegistry kernel_executor;
323
324   for (uint32_t i = 0; i < _reader->operators().size(); ++i)
325   {
326     const auto op = _reader->operators().at(i);
327     assert(op != nullptr);
328
329     const auto opcode = _reader->builtin_code(op);
330
331     allocate(i);
332
333     bool is_inplace = false;
334
335     if (_inplace_op_indexes.find(i) != _inplace_op_indexes.end())
336       is_inplace = true;
337
338     kernel_executor.execute_kernel(op, opcode, this, is_inplace);
339
340     deallocate(i);
341   }
342 }
343
344 } // namespace luci_interpreter