Imported Upstream version 1.12.0
[platform/core/ml/nnfw.git] / runtime / onert / core / include / backend / cpu_common / Tensor.h
1 /*
2  * Copyright (c) 2018 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_CPU_COMMON_TENSOR_H__
18 #define __ONERT_BACKEND_CPU_COMMON_TENSOR_H__
19
20 #include "Allocator.h"
21
22 #include <backend/IPortableTensor.h>
23 #include <ir/OperandInfo.h>
24 #include <ir/Data.h>
25
26 namespace onert
27 {
28 namespace backend
29 {
30 namespace cpu_common
31 {
32
33 class DynamicMemoryManager;
34
35 class Tensor : public IPortableTensor
36 {
37 public:
38   Tensor() = delete;
39   virtual ~Tensor();
40
41 public:
42   Tensor(const ir::OperandInfo &info, const ir::Layout layout,
43          DynamicMemoryManager *dynamic_mem_mgr)
44       : IPortableTensor(info), _layout(layout), _buffer(nullptr), _num_references(0),
45         _dynamic_mem_mgr(dynamic_mem_mgr), _allocator(nullptr)
46   {
47     // DO NOTHING
48   }
49
50 public:
51   // Only one of two method 'setBuffer' must be called once
52
53   /**
54    * @brief Set the Buffer object. This method is called for static and non-const tensor
55    */
56   void setBuffer(uint8_t *buffer)
57   {
58     assert(_buffer == nullptr);
59     _buffer = buffer;
60   }
61
62   /**
63    * @brief Set the Buffer object. This method is called for dynamic or const tensor
64    */
65   void setBuffer(const std::shared_ptr<Allocator> &alloc)
66   {
67     assert(_buffer == nullptr);
68     _allocator = alloc;
69     _buffer = alloc->base();
70   }
71
72   // This works just as setBuffer but it simply overwrite existing Allocator without nullptr check
73   void overwriteBuffer(const std::shared_ptr<Allocator> &alloc)
74   {
75     _allocator = alloc;
76     _buffer = alloc->base();
77   }
78
79   /**
80    * @brief Mark this tensor does not have memory.
81    *        Real memory deallocation should be done by caller.
82    */
83   void resetBuffer()
84   {
85     _allocator.reset();
86     _buffer = nullptr;
87   }
88
89 public:
90   uint8_t *buffer() const override { return _buffer; }
91   /**
92    * @brief Get dimension by index
93    *
94    * @param index Index to get diemension
95    * @return size_t Dimension at index
96    * @note N : dimension(0)
97    *       H : dimension(1)
98    *       W : dimension(2)
99    *       C : dimension(3)
100    */
101   size_t dimension(size_t index) const final override { return _info.shape().dim(index); }
102   size_t num_dimensions() const override { return _info.shape().rank(); }
103   size_t total_size() const override { return _info.total_size(); }
104   size_t calcOffset(const ir::Coordinates &coords) const override;
105   ir::Layout layout() const override { return _layout; }
106   ir::DataType data_type() const override { return _info.typeInfo().type(); }
107   float data_scale() const override { return _info.typeInfo().scale(); }
108   int32_t data_offset() const override { return _info.typeInfo().offset(); }
109   bool is_constant() const override { return _info.isConstant(); }
110   bool is_dynamic() const override { return _info.isDynamic(); }
111   void set_dynamic() override { _info.setDynamic(); }
112   bool applyShape(const ir::Shape &new_shape) override;
113   const ir::Sparsity *sparsity() const override { return _info.typeInfo().sparsity(); }
114
115   virtual void increase_ref()
116   {
117     assert(is_dynamic() ||
118            // when not dynamic
119            (_buffer != nullptr));
120
121     ++_num_references;
122   }
123
124   virtual void decrease_ref()
125   {
126     assert(_buffer != nullptr || _allocator != nullptr);
127     assert(_num_references > 0);
128     --_num_references;
129     // constant tensor and dynamic tensor has _allocator
130     if (_num_references == 0)
131     {
132       if (_buffer != nullptr)
133         _buffer = nullptr;
134       if (_allocator != nullptr)
135       {
136         _allocator->release();
137         _allocator = nullptr;
138       }
139     }
140   }
141
142   /**
143    * @brief Reset reference count to zero and release data
144    */
145   virtual void reset_ref()
146   {
147     assert(_buffer != nullptr || _allocator != nullptr);
148     assert(_num_references > 0);
149     _num_references = 0;
150
151     // Only constant tensor has allocator pointer
152     if (_buffer != nullptr)
153       _buffer = nullptr;
154     else
155     {
156       _allocator->release();
157       _allocator = nullptr;
158     }
159   }
160
161   virtual int32_t num_references() { return _num_references; }
162
163   void setShape(const ir::Shape &new_shape) override;
164
165 protected:
166   ir::Layout _layout;
167   uint8_t *_buffer;
168   int32_t _num_references;
169   DynamicMemoryManager *_dynamic_mem_mgr;
170
171 private:
172   /**
173    * @brief Memory allocator for dynamic tensor and const tensor
174    *        Since maintaing _allocator and also _buffer makes confusion,
175    *        we will mainly use _buffer (not _allocator.base()) for memory pointer in this code.
176    *        _allocator(shared_ptr) is used to guarantee that we have valid _buffer.
177    */
178   std::shared_ptr<Allocator> _allocator;
179 };
180
181 /**
182  * @brief Class that uses data from external memory that is not managed by a backend
183  *        instead of allocating and copying the data. ExternalTensor's data pointer points to
184  *        an address of memory such as where memory is already allocated, or mmapped area.
185  *        This is meaning that ExternalTensor can take all of types' ir::Data.
186  *        To support this, assume below things no padding, always NHWC layout,
187  *        constant tensor and not dynamic.
188  */
189 class ExternalTensor : public Tensor
190 {
191 public:
192   ExternalTensor() = delete;
193   virtual ~ExternalTensor();
194
195 public:
196   ExternalTensor(const ir::OperandInfo &info, const ir::Layout layout)
197       : Tensor(info, layout, nullptr)
198   {
199     assert(_layout == ir::Layout::NHWC);
200     assert(_info.isConstant());
201     assert(_info.isDynamic() == false);
202   }
203
204 public:
205   /**
206    * @brief     set Data to be shared from external so that this ExternalTensor will not be
207    *            allocated on CPU backend
208    * @param[in] data    data of Operand to be set
209    */
210   void setData(const std::shared_ptr<ir::Data> data)
211   {
212     assert(data != nullptr);
213     _data = data;
214     // Note. Some op such as cker::Conv could take buffer as nullptr.
215     // That's why _buffer also would be used
216     _buffer = const_cast<uint8_t *>(_data->base());
217   }
218
219 public:
220   uint8_t *buffer() const override { return _buffer; }
221
222   bool is_constant() const override { return true; }
223   bool is_dynamic() const override { return false; }
224   void set_dynamic() override
225   {
226     throw std::runtime_error("This tensor does not support changing dynamic");
227   }
228
229   void setShape(const ir::Shape &) override
230   {
231     throw std::runtime_error("This tensor does not support changing shape");
232   }
233
234   void increase_ref() override { ++_num_references; }
235
236   void decrease_ref() override
237   {
238     assert(_data != nullptr);
239     assert(_num_references > 0);
240     --_num_references;
241     if (_num_references == 0)
242     {
243       _data.reset();
244       _buffer = nullptr;
245     }
246   }
247
248   /**
249    * @brief Reset reference count to zero and release data
250    */
251   void reset_ref() override
252   {
253     assert(_data != nullptr);
254     assert(_num_references > 0);
255     _num_references = 0;
256
257     _data.reset();
258     _buffer = nullptr;
259   }
260
261   int32_t num_references() override { return _num_references; }
262
263 private:
264   std::shared_ptr<const ir::Data> _data;
265 };
266 } // namespace cpu_common
267 } // namespace backend
268 } // namespace onert
269
270 #endif // __ONERT_BACKEND_CPU_COMMON_TENSOR_H__