1 /*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "nnrt_test.h"
17
18 #include "securec.h"
19
20 #include "common/log.h"
21
22 namespace OHOS {
23 namespace NeuralNetworkRuntime {
24 namespace SystemTest {
25 namespace {
TransformQuantParam(const CppQuantParam & cppQuantParam)26 std::unique_ptr<OH_NN_QuantParam> TransformQuantParam(const CppQuantParam& cppQuantParam)
27 {
28 // cppQuantParam.numBits empty means no quantization is applied, return nullptr directly.
29 if (cppQuantParam.numBits.empty()) {
30 return nullptr;
31 }
32
33 std::unique_ptr<OH_NN_QuantParam> quantParam = std::make_unique<OH_NN_QuantParam>();
34 quantParam->numBits = cppQuantParam.numBits.data();
35 quantParam->quantCount = cppQuantParam.numBits.size();
36 quantParam->scale = cppQuantParam.scale.data();
37 quantParam->zeroPoint = cppQuantParam.zeroPoint.data();
38 return quantParam;
39 }
40
TransformUInt32Array(const std::vector<uint32_t> & vector)41 OH_NN_UInt32Array TransformUInt32Array(const std::vector<uint32_t>& vector)
42 {
43 uint32_t* data = (vector.empty()) ? nullptr : const_cast<uint32_t*>(vector.data());
44 return {data, vector.size()};
45 }
46 } // Anonymous namespace
47
48 // AddTensors() expects tensors do not destruct and free before the test case end.
AddTensors(const std::vector<CppTensor> & cppTensors)49 OH_NN_ReturnCode NNRtTest::AddTensors(const std::vector<CppTensor>& cppTensors)
50 {
51 OH_NN_Tensor tensor;
52 OH_NN_ReturnCode status{OH_NN_SUCCESS};
53 for (const CppTensor& cppTensor : cppTensors) {
54 tensor = {
55 .dataType = cppTensor.dataType,
56 .dimensionCount = static_cast<uint32_t>(cppTensor.dimensions.size()),
57 .dimensions = cppTensor.dimensions.empty() ? nullptr : cppTensor.dimensions.data(),
58 .type = cppTensor.type
59 };
60
61 const CppQuantParam& cppQuantParam = cppTensor.quantParam;
62 if ((cppQuantParam.numBits.size() != cppQuantParam.scale.size())
63 || (cppQuantParam.scale.size() != cppQuantParam.zeroPoint.size())) {
64 LOGE("NNRtTest::AddTensors failed, get different number of numBits, scales and zeroPoints.");
65 return OH_NN_INVALID_PARAMETER;
66 }
67 // If no quantization is applied, quantParam == nullptr and no need to check.
68 std::unique_ptr<OH_NN_QuantParam> quantParam = TransformQuantParam(cppQuantParam);
69 tensor.quantParam = quantParam.get();
70
71 m_tensors.emplace_back(tensor);
72 m_quantParams.emplace_back(std::move(quantParam));
73
74 status = OH_NNModel_AddTensor(m_model, &tensor);
75 if (status != OH_NN_SUCCESS) {
76 LOGE("NNRtTest::AddTensors failed, error happens when adding tensor.");
77 m_tensors.clear();
78 m_quantParams.clear();
79 return status;
80 }
81
82 if (cppTensor.data != nullptr) {
83 uint32_t index = m_tensors.size() - 1;
84 status = OH_NNModel_SetTensorData(m_model, index, cppTensor.data, cppTensor.dataLength);
85 if (status != OH_NN_SUCCESS) {
86 LOGE("NNRtTest::AddTensors failed, error happens when setting value.");
87 m_tensors.clear();
88 m_quantParams.clear();
89 return status;
90 }
91 }
92 }
93
94 return status;
95 }
96
AddOperation(OH_NN_OperationType opType,const std::vector<uint32_t> & paramIndices,const std::vector<uint32_t> & inputIndices,const std::vector<uint32_t> & outputIndices)97 OH_NN_ReturnCode NNRtTest::AddOperation(OH_NN_OperationType opType,
98 const std::vector<uint32_t>& paramIndices,
99 const std::vector<uint32_t>& inputIndices,
100 const std::vector<uint32_t>& outputIndices)
101 {
102 const OH_NN_UInt32Array params = TransformUInt32Array(paramIndices);
103 const OH_NN_UInt32Array inputs = TransformUInt32Array(inputIndices);
104 const OH_NN_UInt32Array outputs = TransformUInt32Array(outputIndices);
105
106 OH_NN_ReturnCode status = OH_NNModel_AddOperation(m_model, opType, ¶ms, &inputs, &outputs);
107 if (status == OH_NN_SUCCESS) {
108 Node node = {
109 .opType = opType,
110 .inputs = inputIndices,
111 .outputs = outputIndices,
112 .params = paramIndices
113 };
114 m_nodes.emplace_back(node);
115 }
116
117 return status;
118 }
119
SpecifyInputAndOutput(const std::vector<uint32_t> & inputIndices,const std::vector<uint32_t> & outputIndices)120 OH_NN_ReturnCode NNRtTest::SpecifyInputAndOutput(const std::vector<uint32_t>& inputIndices,
121 const std::vector<uint32_t>& outputIndices)
122 {
123 const OH_NN_UInt32Array inputs = TransformUInt32Array(inputIndices);
124 const OH_NN_UInt32Array outputs = TransformUInt32Array(outputIndices);
125
126 OH_NN_ReturnCode status = OH_NNModel_SpecifyInputsAndOutputs(m_model, &inputs, &outputs);
127 if (status == OH_NN_SUCCESS) {
128 m_inputs = inputIndices;
129 m_outputs = outputIndices;
130 }
131
132 return status;
133 }
134
SetInput(uint32_t index,const std::vector<int32_t> & dimensions,const void * buffer,size_t length)135 OH_NN_ReturnCode NNRtTest::SetInput(uint32_t index,
136 const std::vector<int32_t>& dimensions,
137 const void* buffer,
138 size_t length)
139 {
140 OH_NN_Tensor tensor = m_tensors[m_inputs[index]];
141 tensor.dimensions = dimensions.data();
142
143 return OH_NNExecutor_SetInput(m_executor, index, &tensor, buffer, length);
144 }
145
SetOutput(uint32_t index,void * buffer,size_t length)146 OH_NN_ReturnCode NNRtTest::SetOutput(uint32_t index, void* buffer, size_t length)
147 {
148 return OH_NNExecutor_SetOutput(m_executor, index, buffer, length);
149 }
150
SetInputFromMemory(uint32_t index,const std::vector<int32_t> & dimensions,const void * buffer,size_t length,OH_NN_Memory ** pMemory)151 OH_NN_ReturnCode NNRtTest::SetInputFromMemory(uint32_t index,
152 const std::vector<int32_t>& dimensions,
153 const void* buffer,
154 size_t length,
155 OH_NN_Memory** pMemory)
156 {
157 if (buffer == nullptr) {
158 LOGE("NNRtTest::SetInputFromMemory failed, passed nullptr to buffer.");
159 return OH_NN_INVALID_PARAMETER;
160 }
161
162 if (pMemory == nullptr) {
163 LOGE("NNRtTest::SetInputFromMemory failed, passed nullptr to pMemory.");
164 return OH_NN_INVALID_PARAMETER;
165 }
166
167 OH_NN_Memory* memory = OH_NNExecutor_AllocateInputMemory(m_executor, index, length);
168 if (memory == nullptr) {
169 LOGE("NNRtTest::SetInputFromMemory failed, error happened when creating input memory.");
170 return OH_NN_MEMORY_ERROR;
171 }
172
173 OH_NN_Tensor tensor = m_tensors[m_inputs[index]];
174 tensor.dimensions = dimensions.data();
175
176 OH_NN_ReturnCode status = OH_NNExecutor_SetInputWithMemory(m_executor, index, &tensor, memory);
177 if (status != OH_NN_SUCCESS) {
178 LOGE("NNRtTest::SetInputFromMemory failed, error happened when setting input.");
179 OH_NNExecutor_DestroyInputMemory(m_executor, index, &memory);
180 }
181
182 errno_t error_code = memcpy_s(const_cast<void*>(memory->data), memory->length, buffer, length);
183 if (error_code != EOK) {
184 LOGE("NNRtTest::SetInputFromMemory failed, error happens when copying data to OH_NN_Memory. Error code: %d.",
185 error_code);
186 OH_NNExecutor_DestroyInputMemory(m_executor, index, &memory);
187 return OH_NN_MEMORY_ERROR;
188 }
189
190 *pMemory = memory;
191 return status;
192 }
193
SetOutputFromMemory(uint32_t index,size_t length,OH_NN_Memory ** pMemory)194 OH_NN_ReturnCode NNRtTest::SetOutputFromMemory(uint32_t index, size_t length, OH_NN_Memory** pMemory)
195 {
196 if (pMemory == nullptr) {
197 LOGE("NNRtTest::SetOutputFromMemory failed, passed nullptr to pMemory.");
198 return OH_NN_INVALID_PARAMETER;
199 }
200
201 OH_NN_Memory* memory = OH_NNExecutor_AllocateOutputMemory(m_executor, index, length);
202 if (memory == nullptr) {
203 LOGE("NNRtTest::SetOutputFromMemory failed, error happened when creating output memory.");
204 return OH_NN_MEMORY_ERROR;
205 }
206
207 OH_NN_ReturnCode status = OH_NNExecutor_SetOutputWithMemory(m_executor, index, memory);
208 if (status != OH_NN_SUCCESS) {
209 LOGE("NNRtTest::SetOutputFromMemory failed, error happened when setting output.");
210 OH_NNExecutor_DestroyOutputMemory(m_executor, index, &memory);
211 }
212
213 *pMemory = memory;
214 return status;
215 }
216
GetDevices()217 OH_NN_ReturnCode NNRtTest::GetDevices()
218 {
219 const size_t* devicesID{nullptr};
220 uint32_t count{0};
221 OH_NN_ReturnCode status = OH_NNDevice_GetAllDevicesID(&devicesID, &count);
222 if (status != OH_NN_SUCCESS) {
223 LOGE("NNRtTest::GetDevices failed, get all devices ID failed.");
224 return status;
225 }
226
227 for (uint32_t i = 0; i < count; i++) {
228 m_devices.emplace_back(devicesID[i]);
229 }
230 return OH_NN_SUCCESS;
231 }
232 } // namespace SystemTest
233 } // NeuralNetworkRuntime
234 } // OHOS