1 /*
2 * Copyright (c) Qualcomm Innovation Center, Inc.
3 * All rights reserved.
4 *
5 * This source code is licensed under the BSD-style license found in the
6 * LICENSE file in the root directory of this source tree.
7 */
8
9 #include <executorch/backends/qualcomm/aot/wrappers/TensorWrapper.h>
10
11 #include <atomic>
12 #include <cstring>
13 #include <limits>
14 #include <numeric>
15 namespace executorch {
16 namespace backends {
17 namespace qnn {
18
19 using executorch::runtime::Error;
20
GetDataTypeSize(Qnn_DataType_t data_type)21 std::uint32_t GetDataTypeSize(Qnn_DataType_t data_type) {
22 std::uint32_t size = 0;
23
24 switch (data_type) {
25 case QNN_DATATYPE_INT_8:
26 case QNN_DATATYPE_UINT_8:
27 case QNN_DATATYPE_SFIXED_POINT_8:
28 case QNN_DATATYPE_UFIXED_POINT_8:
29 case QNN_DATATYPE_BOOL_8:
30 size = sizeof(std::uint8_t);
31 break;
32 case QNN_DATATYPE_INT_16:
33 case QNN_DATATYPE_UINT_16:
34 case QNN_DATATYPE_FLOAT_16:
35 case QNN_DATATYPE_SFIXED_POINT_16:
36 case QNN_DATATYPE_UFIXED_POINT_16:
37 size = sizeof(std::uint16_t);
38 break;
39 case QNN_DATATYPE_INT_32:
40 case QNN_DATATYPE_UINT_32:
41 case QNN_DATATYPE_FLOAT_32:
42 case QNN_DATATYPE_SFIXED_POINT_32:
43 case QNN_DATATYPE_UFIXED_POINT_32:
44 size = sizeof(float);
45 break;
46 case QNN_DATATYPE_INT_64:
47 case QNN_DATATYPE_UINT_64:
48 size = sizeof(std::uint64_t);
49 break;
50 case QNN_DATATYPE_UNDEFINED:
51 default:
52 size = 0;
53 }
54
55 return size;
56 }
57
58 std::atomic<std::uint32_t> intermediate_tensor_id{
59 std::numeric_limits<std::uint32_t>::max()};
60
CreateIntermediateTensorId()61 std::uint32_t CreateIntermediateTensorId() {
62 return --intermediate_tensor_id;
63 }
64
TensorWrapper(const std::string & tensor_name,Qnn_TensorType_t tensor_type,Qnn_DataType_t data_type,std::unique_ptr<QuantizeParamsWrapper> quantize_param_wrapper,std::uint32_t rank,const std::uint32_t dims[],std::uint32_t bytes,const void * data,bool copy_data)65 TensorWrapper::TensorWrapper(
66 const std::string& tensor_name,
67 Qnn_TensorType_t tensor_type,
68 Qnn_DataType_t data_type,
69 std::unique_ptr<QuantizeParamsWrapper> quantize_param_wrapper,
70 std::uint32_t rank,
71 const std::uint32_t dims[],
72 std::uint32_t bytes,
73 const void* data,
74 bool copy_data)
75 : qnn_tensor_name_(tensor_name),
76 quantize_param_wrapper_(std::move(quantize_param_wrapper)),
77 dims_(dims, dims + rank),
78 bytes_(bytes),
79 owned_data_(nullptr) {
80 // "version" is the only exception that we don't need QNN_VER_PTR wrapper.
81 tensor_.version = QNN_TENSOR_VERSION_1;
82
83 // Don't assign .id because it's an output field.
84 QNN_VER_PTR(tensor_)->name = qnn_tensor_name_.c_str();
85 QNN_VER_PTR(tensor_)->dimensions = dims_.data();
86 QNN_VER_PTR(tensor_)->type = tensor_type;
87 QNN_VER_PTR(tensor_)->dataFormat = QNN_TENSOR_DATA_FORMAT_FLAT_BUFFER;
88 QNN_VER_PTR(tensor_)->dataType = data_type;
89 QNN_VER_PTR(tensor_)->quantizeParams =
90 quantize_param_wrapper_->CreateQuantizeParams();
91 QNN_VER_PTR(tensor_)->rank = rank;
92 QNN_VER_PTR(tensor_)->memType = QNN_TENSORMEMTYPE_RAW;
93
94 if (data != nullptr) {
95 QNN_VER_PTR(tensor_)->clientBuf.dataSize = bytes;
96
97 if (tensor_type != QNN_TENSOR_TYPE_STATIC) {
98 QNN_VER_PTR(tensor_)->clientBuf.data = nullptr;
99 } else if (copy_data) {
100 owned_data_ = std::make_unique<char[]>(bytes);
101 const char* src_data = static_cast<const char*>(data);
102 std::memcpy(owned_data_.get(), src_data, bytes);
103 QNN_VER_PTR(tensor_)->clientBuf.data = owned_data_.get();
104 } else {
105 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
106 QNN_VER_PTR(tensor_)->clientBuf.data = const_cast<void*>(data);
107 }
108 }
109 }
110
FillDataBuffer(const void * data,bool copy_data)111 Error TensorWrapper::FillDataBuffer(const void* data, bool copy_data) {
112 if (data != nullptr) {
113 QNN_VER_PTR(tensor_)->memType = QNN_TENSORMEMTYPE_RAW;
114 QNN_VER_PTR(tensor_)->clientBuf.dataSize = bytes_;
115 if (copy_data) {
116 owned_data_ = std::make_unique<char[]>(bytes_);
117 const char* src_data = static_cast<const char*>(data);
118 std::memcpy(owned_data_.get(), src_data, bytes_);
119 QNN_VER_PTR(tensor_)->clientBuf.data = owned_data_.get();
120 } else {
121 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
122 QNN_VER_PTR(tensor_)->clientBuf.data = const_cast<void*>(data);
123 }
124 } else {
125 QNN_EXECUTORCH_LOG_WARN("Data pointer is nullptr");
126 }
127 return Error::Ok;
128 }
129
AllocateDataBuffer()130 Error TensorWrapper::AllocateDataBuffer() {
131 char* static_data_buffer = new (std::nothrow) char[bytes_]; // NOLINT
132 if (static_data_buffer == nullptr) {
133 return Error::Internal;
134 }
135 owned_data_ = std::unique_ptr<char[]>(static_data_buffer);
136 QNN_VER_PTR(tensor_)->memType = QNN_TENSORMEMTYPE_RAW;
137 QNN_VER_PTR(tensor_)->clientBuf.dataSize = bytes_;
138 QNN_VER_PTR(tensor_)->clientBuf.data = owned_data_.get();
139
140 return Error::Ok;
141 }
142
UpdateQnnTensorMeta(const Qnn_Tensor_t & tensor_src)143 void TensorWrapper::UpdateQnnTensorMeta(const Qnn_Tensor_t& tensor_src) {
144 QNN_VER_PTR(tensor_)->id = QNN_VER_PTR(tensor_src)->id;
145 }
146
SetName(const std::string & name)147 Error TensorWrapper::SetName(const std::string& name) {
148 qnn_tensor_name_ = name;
149 QNN_VER_PTR(tensor_)->name = qnn_tensor_name_.c_str();
150 return Error::Ok;
151 }
152
SetMemHandle(Qnn_MemHandle_t mem_handle)153 Error TensorWrapper::SetMemHandle(Qnn_MemHandle_t mem_handle) {
154 QNN_VER_PTR(tensor_)->memType = QNN_TENSORMEMTYPE_MEMHANDLE;
155 QNN_VER_PTR(tensor_)->memHandle = mem_handle;
156 return Error::Ok;
157 }
158
159 // base function for Create TensorWrapper
CreateTensorWrapper(const std::string & tensor_name,Qnn_TensorType_t tensor_type,Qnn_DataType_t data_type,std::unique_ptr<QuantizeParamsWrapper> quantize_param_wrapper,std::uint32_t rank,const std::uint32_t dims[],std::uint32_t bytes,const void * data,bool copy_data)160 std::shared_ptr<TensorWrapper> CreateTensorWrapper(
161 const std::string& tensor_name,
162 Qnn_TensorType_t tensor_type,
163 Qnn_DataType_t data_type,
164 std::unique_ptr<QuantizeParamsWrapper> quantize_param_wrapper,
165 std::uint32_t rank,
166 const std::uint32_t dims[],
167 std::uint32_t bytes,
168 const void* data,
169 bool copy_data) {
170 if (bytes == 0) {
171 bytes = std::accumulate(
172 dims, dims + rank, GetDataTypeSize(data_type), std::multiplies<>());
173 }
174 return std::make_shared<TensorWrapper>(
175 tensor_name,
176 tensor_type,
177 data_type,
178 std::move(quantize_param_wrapper),
179 rank,
180 dims,
181 bytes,
182 data,
183 copy_data);
184 }
185
CreateTensorWrapper(Qnn_TensorType_t tensor_type,Qnn_DataType_t data_type,std::unique_ptr<QuantizeParamsWrapper> quantize_param_wrapper,std::uint32_t rank,const std::uint32_t dims[],std::uint32_t bytes,const void * data,bool copy_data)186 std::shared_ptr<TensorWrapper> CreateTensorWrapper(
187 Qnn_TensorType_t tensor_type,
188 Qnn_DataType_t data_type,
189 std::unique_ptr<QuantizeParamsWrapper> quantize_param_wrapper,
190 std::uint32_t rank,
191 const std::uint32_t dims[],
192 std::uint32_t bytes,
193 const void* data,
194 bool copy_data) {
195 return CreateTensorWrapper(
196 std::to_string(CreateIntermediateTensorId()),
197 tensor_type,
198 data_type,
199 std::move(quantize_param_wrapper),
200 rank,
201 dims,
202 bytes,
203 data,
204 copy_data);
205 }
206
207 // Factory functions to create TensorWrappers
CreateTensorWrapper(const Qnn_Tensor_t & tensor)208 std::shared_ptr<TensorWrapper> CreateTensorWrapper(const Qnn_Tensor_t& tensor) {
209 return CreateTensorWrapper(
210 std::string(QNN_VER_PTR(tensor)->name),
211 QNN_VER_PTR(tensor)->type,
212 QNN_VER_PTR(tensor)->dataType,
213 CreateQuantizationParamWrapper(QNN_VER_PTR(tensor)->quantizeParams),
214 QNN_VER_PTR(tensor)->rank,
215 QNN_VER_PTR(tensor)->dimensions,
216 QNN_VER_PTR(tensor)->clientBuf.dataSize,
217 QNN_VER_PTR(tensor)->clientBuf.data);
218 }
219 } // namespace qnn
220 } // namespace backends
221 } // namespace executorch
222