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, &params, &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