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