5fa20e15d5929824a4bfffec095eb6941f1f4447
[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
25 namespace onert
26 {
27 namespace backend
28 {
29 namespace cpu_common
30 {
31
32 class DynamicMemoryManager;
33
34 class Tensor : public IPortableTensor
35 {
36 public:
37   Tensor() = delete;
38   virtual ~Tensor();
39
40 public:
41   Tensor(const ir::OperandInfo &info, const ir::Layout layout,
42          DynamicMemoryManager *dynamic_mem_mgr)
43       : IPortableTensor(info), _layout(layout), _buffer(nullptr), _num_references(0),
44         _dynamic_mem_mgr(dynamic_mem_mgr), _allocator(nullptr)
45   {
46     // DO NOTHING
47   }
48
49 public:
50   // Only one of two method 'setBuffer' must be called once
51
52   /**
53    * @brief Set the Buffer object. This method is called for static and non-const tensor
54    */
55   void setBuffer(uint8_t *buffer)
56   {
57     assert(_buffer == nullptr);
58     _buffer = buffer;
59   }
60
61   /**
62    * @brief Set the Buffer object. This method is called for dynamic or const tensor
63    */
64   void setBuffer(const std::shared_ptr<Allocator> &alloc)
65   {
66     assert(_buffer == nullptr);
67     _allocator = alloc;
68     _buffer = alloc->base();
69   }
70
71   // This works just as setBuffer but it simply overwrite existing Allocator without nullptr check
72   void overwriteBuffer(const std::shared_ptr<Allocator> &alloc)
73   {
74     _allocator = alloc;
75     _buffer = alloc->base();
76   }
77
78   /**
79    * @brief Mark this tensor does not have memory.
80    *        Real memory deallocation should be done by caller.
81    */
82   void resetBuffer()
83   {
84     _allocator.reset();
85     _buffer = nullptr;
86   }
87
88 public:
89   uint8_t *buffer() const override { return _buffer; }
90   /**
91    * @brief Get dimension by index
92    *
93    * @param index Index to get diemension
94    * @return size_t Dimension at index
95    * @note N : dimension(0)
96    *       H : dimension(1)
97    *       W : dimension(2)
98    *       C : dimension(3)
99    */
100   size_t dimension(size_t index) const final override { return _info.shape().dim(index); }
101   size_t num_dimensions() const override { return _info.shape().rank(); }
102   size_t total_size() const override { return _info.total_size(); }
103   size_t calcOffset(const ir::Coordinates &coords) const override;
104   ir::Layout layout() const override { return _layout; }
105   ir::DataType data_type() const override { return _info.typeInfo().type(); }
106   float data_scale() const override { return _info.typeInfo().scale(); }
107   int32_t data_offset() const override { return _info.typeInfo().offset(); }
108   bool is_constant() const override { return _info.isConstant(); }
109   bool is_dynamic() const override { return _info.isDynamic(); }
110   void set_dynamic() override { _info.setDynamic(); }
111   bool applyShape(const ir::Shape &new_shape) override;
112   const ir::Sparsity *sparsity() const override { return _info.typeInfo().sparsity(); }
113
114   virtual void increase_ref()
115   {
116     assert(is_dynamic() ||
117            // when not dynamic
118            (_buffer != nullptr));
119
120     ++_num_references;
121   }
122
123   virtual void decrease_ref()
124   {
125     assert(_buffer != nullptr || _allocator != nullptr);
126     assert(_num_references > 0);
127     --_num_references;
128     // constant tensor and dynamic tensor has _allocator
129     if (_num_references == 0)
130     {
131       if (_buffer != nullptr)
132         _buffer = nullptr;
133       if (_allocator != nullptr)
134       {
135         _allocator->release();
136         _allocator = nullptr;
137       }
138     }
139   }
140
141   /**
142    * @brief Reset reference count to zero and release data
143    */
144   virtual void reset_ref()
145   {
146     assert(_buffer != nullptr || _allocator != nullptr);
147     assert(_num_references > 0);
148     _num_references = 0;
149
150     // Only constant tensor has allocator pointer
151     if (_buffer != nullptr)
152       _buffer = nullptr;
153     else
154     {
155       _allocator->release();
156       _allocator = nullptr;
157     }
158   }
159
160   virtual int32_t num_references() { return _num_references; }
161
162   void setShape(const ir::Shape &new_shape) override;
163
164 protected:
165   ir::Layout _layout;
166   uint8_t *_buffer;
167   int32_t _num_references;
168   DynamicMemoryManager *_dynamic_mem_mgr;
169
170 private:
171   /**
172    * @brief Memory allocator for dynamic tensor and const tensor
173    *        Since maintaing _allocator and also _buffer makes confusion,
174    *        we will mainly use _buffer (not _allocator.base()) for memory pointer in this code.
175    *        _allocator(shared_ptr) is used to guarantee that we have valid _buffer.
176    */
177   std::shared_ptr<Allocator> _allocator;
178 };
179
180 } // namespace cpu_common
181 } // namespace backend
182 } // namespace onert
183
184 #endif // __ONERT_BACKEND_CPU_COMMON_TENSOR_H__