blob: 106f33279df5d2dfcba7e8460570e41c1c8749de [file] [log] [blame]
I-Jui (Ray) Sung2c4e1362017-09-06 02:15:54 -07001/*
2 * Copyright (C) 2017 The Android Open Source Project
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
Xusong Wang96e68dc2019-01-18 17:28:26 -080017#include "GeneratedTestHarness.h"
Michael Butlercf22a572017-09-22 13:26:12 -070018#include "Callbacks.h"
Michael Butler29471a82019-01-15 11:02:55 -080019#include "ExecutionBurstController.h"
I-Jui (Ray) Sung2c4e1362017-09-06 02:15:54 -070020#include "TestHarness.h"
Miao Wang4862d612018-02-05 17:26:54 -080021#include "Utils.h"
I-Jui (Ray) Sung2c4e1362017-09-06 02:15:54 -070022
23#include <android-base/logging.h>
Miao Wang4862d612018-02-05 17:26:54 -080024#include <android/hardware/neuralnetworks/1.0/IDevice.h>
25#include <android/hardware/neuralnetworks/1.0/IExecutionCallback.h>
26#include <android/hardware/neuralnetworks/1.0/IPreparedModel.h>
27#include <android/hardware/neuralnetworks/1.0/IPreparedModelCallback.h>
28#include <android/hardware/neuralnetworks/1.0/types.h>
Xusong Wang1a06e772018-10-31 08:43:12 -070029#include <android/hardware/neuralnetworks/1.1/IDevice.h>
30#include <android/hardware/neuralnetworks/1.2/IDevice.h>
31#include <android/hardware/neuralnetworks/1.2/IExecutionCallback.h>
32#include <android/hardware/neuralnetworks/1.2/IPreparedModel.h>
33#include <android/hardware/neuralnetworks/1.2/IPreparedModelCallback.h>
Miao Wang4862d612018-02-05 17:26:54 -080034#include <android/hidl/allocator/1.0/IAllocator.h>
I-Jui (Ray) Sung2c4e1362017-09-06 02:15:54 -070035#include <android/hidl/memory/1.0/IMemory.h>
36#include <hidlmemory/mapping.h>
Michael Butler0897ab32017-10-04 02:38:42 -070037#include <iostream>
I-Jui (Ray) Sung2c4e1362017-09-06 02:15:54 -070038
39namespace android {
40namespace hardware {
41namespace neuralnetworks {
I-Jui (Ray) Sung2c4e1362017-09-06 02:15:54 -070042
43namespace generated_tests {
Xusong Wang1a06e772018-10-31 08:43:12 -070044using ::android::hardware::neuralnetworks::V1_2::implementation::ExecutionCallback;
45using ::android::hardware::neuralnetworks::V1_2::implementation::PreparedModelCallback;
Slava Shklyaevdc98cb02018-11-30 17:55:12 +000046using ::test_helper::bool8;
Michael K. Sandersda3bdbc2018-10-19 14:39:09 +010047using ::test_helper::compare;
48using ::test_helper::expectMultinomialDistributionWithinTolerance;
Mika Raentod534d322018-04-17 16:49:50 +010049using ::test_helper::filter;
50using ::test_helper::for_all;
51using ::test_helper::for_each;
Michael K. Sandersda3bdbc2018-10-19 14:39:09 +010052using ::test_helper::MixedTyped;
53using ::test_helper::MixedTypedExample;
Michael K. Sandersda3bdbc2018-10-19 14:39:09 +010054using ::test_helper::resize_accordingly;
Xusong Wanged0822b2019-02-25 16:58:58 -080055using HidlToken = hidl_array<uint8_t, static_cast<uint32_t>(Constant::BYTE_SIZE_OF_CACHE_TOKEN)>;
I-Jui (Ray) Sungf6b85502017-09-20 13:45:50 -070056
I-Jui (Ray) Sung5bf4edf2017-10-06 13:22:39 -070057template <typename T>
David Gross55a3d322019-01-23 14:01:52 -080058void copy_back_(std::map<int, std::vector<T>>* dst, const std::vector<RequestArgument>& ra,
59 char* src) {
60 for_each<T>(*dst, [&ra, src](int index, std::vector<T>& m) {
I-Jui (Ray) Sung5bf4edf2017-10-06 13:22:39 -070061 ASSERT_EQ(m.size(), ra[index].location.length / sizeof(T));
I-Jui (Ray) Sungf6b85502017-09-20 13:45:50 -070062 char* begin = src + ra[index].location.offset;
63 memcpy(m.data(), begin, ra[index].location.length);
64 });
65}
66
67void copy_back(MixedTyped* dst, const std::vector<RequestArgument>& ra, char* src) {
David Gross55a3d322019-01-23 14:01:52 -080068 copy_back_(&dst->float32Operands, ra, src);
69 copy_back_(&dst->int32Operands, ra, src);
70 copy_back_(&dst->quant8AsymmOperands, ra, src);
71 copy_back_(&dst->quant16SymmOperands, ra, src);
72 copy_back_(&dst->float16Operands, ra, src);
73 copy_back_(&dst->bool8Operands, ra, src);
74 copy_back_(&dst->quant8ChannelOperands, ra, src);
75 copy_back_(&dst->quant16AsymmOperands, ra, src);
Lev Proleev603244c2019-02-20 12:49:14 +000076 copy_back_(&dst->quant8SymmOperands, ra, src);
77 static_assert(9 == MixedTyped::kNumTypes,
Lev Proleevd36b7a82018-11-02 12:44:11 +000078 "Number of types in MixedTyped changed, but copy_back function wasn't updated");
I-Jui (Ray) Sungf6b85502017-09-20 13:45:50 -070079}
80
Xusong Wang0237edd2019-03-12 14:40:32 -070081static bool isZeroSized(const MixedTyped& example, uint32_t index) {
82 for (auto i : example.operandDimensions.at(index)) {
83 if (i == 0) return true;
84 }
85 return false;
86}
87
I-Jui (Ray) Sung2c4e1362017-09-06 02:15:54 -070088// Top level driver for models and examples generated by test_generator.py
89// Test driver for those generated from ml/nn/runtime/test/spec
Xusong Wang1a06e772018-10-31 08:43:12 -070090static Return<ErrorStatus> ExecutePreparedModel(sp<V1_0::IPreparedModel>& preparedModel,
David Gross55a3d322019-01-23 14:01:52 -080091 const Request& request, MeasureTiming,
Xusong Wang1a06e772018-10-31 08:43:12 -070092 sp<ExecutionCallback>& callback) {
93 return preparedModel->execute(request, callback);
94}
95static Return<ErrorStatus> ExecutePreparedModel(sp<V1_2::IPreparedModel>& preparedModel,
David Gross55a3d322019-01-23 14:01:52 -080096 const Request& request, MeasureTiming measure,
Xusong Wang1a06e772018-10-31 08:43:12 -070097 sp<ExecutionCallback>& callback) {
David Gross55a3d322019-01-23 14:01:52 -080098 return preparedModel->execute_1_2(request, measure, callback);
Xusong Wang1a06e772018-10-31 08:43:12 -070099}
Xusong Wangb50bc312018-11-07 09:33:59 -0800100static Return<ErrorStatus> ExecutePreparedModel(sp<V1_0::IPreparedModel>&, const Request&,
David Gross55a3d322019-01-23 14:01:52 -0800101 MeasureTiming, hidl_vec<OutputShape>*, Timing*) {
David Gross4592ed12018-12-21 11:20:26 -0800102 ADD_FAILURE() << "asking for synchronous execution at V1_0";
103 return ErrorStatus::GENERAL_FAILURE;
104}
105static Return<ErrorStatus> ExecutePreparedModel(sp<V1_2::IPreparedModel>& preparedModel,
David Gross55a3d322019-01-23 14:01:52 -0800106 const Request& request, MeasureTiming measure,
107 hidl_vec<OutputShape>* outputShapes,
108 Timing* timing) {
Xusong Wangb50bc312018-11-07 09:33:59 -0800109 ErrorStatus result;
110 Return<void> ret = preparedModel->executeSynchronously(
David Gross55a3d322019-01-23 14:01:52 -0800111 request, measure,
112 [&result, outputShapes, timing](ErrorStatus error, const hidl_vec<OutputShape>& shapes,
113 const Timing& time) {
114 result = error;
115 *outputShapes = shapes;
116 *timing = time;
117 });
Xusong Wangb50bc312018-11-07 09:33:59 -0800118 if (!ret.isOk()) {
119 return ErrorStatus::GENERAL_FAILURE;
120 }
121 return result;
David Gross4592ed12018-12-21 11:20:26 -0800122}
Michael Butler29471a82019-01-15 11:02:55 -0800123static std::unique_ptr<::android::nn::ExecutionBurstController> CreateBurst(
124 const sp<V1_0::IPreparedModel>&) {
125 ADD_FAILURE() << "asking for burst execution at V1_0";
126 return nullptr;
127}
128static std::unique_ptr<::android::nn::ExecutionBurstController> CreateBurst(
129 const sp<V1_2::IPreparedModel>& preparedModel) {
130 return ::android::nn::createExecutionBurstController(preparedModel, /*blocking=*/true);
131}
132enum class Executor { ASYNC, SYNC, BURST };
Xusong Wang4faf0722019-01-27 23:08:12 -0800133enum class OutputType { FULLY_SPECIFIED, UNSPECIFIED, INSUFFICIENT };
David Gross4592ed12018-12-21 11:20:26 -0800134const float kDefaultAtol = 1e-5f;
135const float kDefaultRtol = 1e-5f;
Xusong Wang1a06e772018-10-31 08:43:12 -0700136template <typename T_IPreparedModel>
137void EvaluatePreparedModel(sp<T_IPreparedModel>& preparedModel, std::function<bool(int)> is_ignored,
Xusong Wang4faf0722019-01-27 23:08:12 -0800138 const std::vector<MixedTypedExample>& examples,
139 bool hasRelaxedFloat32Model, float fpAtol, float fpRtol,
140 Executor executor, MeasureTiming measure, OutputType outputType) {
I-Jui (Ray) Sung2c4e1362017-09-06 02:15:54 -0700141 const uint32_t INPUT = 0;
142 const uint32_t OUTPUT = 1;
143
144 int example_no = 1;
145 for (auto& example : examples) {
146 SCOPED_TRACE(example_no++);
Michael K. Sandersda3bdbc2018-10-19 14:39:09 +0100147 const MixedTyped& inputs = example.operands.first;
148 const MixedTyped& golden = example.operands.second;
I-Jui (Ray) Sung2c4e1362017-09-06 02:15:54 -0700149
David Gross55a3d322019-01-23 14:01:52 -0800150 const bool hasFloat16Inputs = !inputs.float16Operands.empty();
Michael K. Sanders650fd182018-10-30 14:44:48 +0000151 if (hasRelaxedFloat32Model || hasFloat16Inputs) {
152 // TODO: Adjust the error limit based on testing.
153 // If in relaxed mode, set the absolute tolerance to be 5ULP of FP16.
154 fpAtol = 5.0f * 0.0009765625f;
155 // Set the relative tolerance to be 5ULP of the corresponding FP precision.
156 fpRtol = 5.0f * 0.0009765625f;
157 }
158
I-Jui (Ray) Sung2c4e1362017-09-06 02:15:54 -0700159 std::vector<RequestArgument> inputs_info, outputs_info;
160 uint32_t inputSize = 0, outputSize = 0;
I-Jui (Ray) Sung2c4e1362017-09-06 02:15:54 -0700161 // This function only partially specifies the metadata (vector of RequestArguments).
162 // The contents are copied over below.
163 for_all(inputs, [&inputs_info, &inputSize](int index, auto, auto s) {
164 if (inputs_info.size() <= static_cast<size_t>(index)) inputs_info.resize(index + 1);
165 RequestArgument arg = {
166 .location = {.poolIndex = INPUT, .offset = 0, .length = static_cast<uint32_t>(s)},
167 .dimensions = {},
168 };
I-Jui (Ray) Sung959cd782017-10-04 20:49:57 -0700169 RequestArgument arg_empty = {
170 .hasNoValue = true,
171 };
172 inputs_info[index] = s ? arg : arg_empty;
I-Jui (Ray) Sung2c4e1362017-09-06 02:15:54 -0700173 inputSize += s;
174 });
175 // Compute offset for inputs 1 and so on
176 {
177 size_t offset = 0;
178 for (auto& i : inputs_info) {
I-Jui (Ray) Sung959cd782017-10-04 20:49:57 -0700179 if (!i.hasNoValue) i.location.offset = offset;
I-Jui (Ray) Sung2c4e1362017-09-06 02:15:54 -0700180 offset += i.location.length;
181 }
182 }
183
184 MixedTyped test; // holding test results
185
186 // Go through all outputs, initialize RequestArgument descriptors
I-Jui (Ray) Sungf6b85502017-09-20 13:45:50 -0700187 resize_accordingly(golden, test);
Xusong Wang4faf0722019-01-27 23:08:12 -0800188 bool sizeLargerThanOne = true;
Xusong Wang0237edd2019-03-12 14:40:32 -0700189 for_all(golden, [&golden, &outputs_info, &outputSize, &outputType, &sizeLargerThanOne](
Xusong Wang4faf0722019-01-27 23:08:12 -0800190 int index, auto, auto s) {
I-Jui (Ray) Sung2c4e1362017-09-06 02:15:54 -0700191 if (outputs_info.size() <= static_cast<size_t>(index)) outputs_info.resize(index + 1);
Xusong Wang4faf0722019-01-27 23:08:12 -0800192 if (index == 0) {
193 // On OutputType::INSUFFICIENT, set the output operand with index 0 with
194 // buffer size one byte less than needed.
195 if (outputType == OutputType::INSUFFICIENT) {
Xusong Wang0237edd2019-03-12 14:40:32 -0700196 if (s > 1 && !isZeroSized(golden, index)) {
Xusong Wang4faf0722019-01-27 23:08:12 -0800197 s -= 1;
Xusong Wang0237edd2019-03-12 14:40:32 -0700198 } else {
Xusong Wang4faf0722019-01-27 23:08:12 -0800199 sizeLargerThanOne = false;
Xusong Wang0237edd2019-03-12 14:40:32 -0700200 }
Xusong Wang4faf0722019-01-27 23:08:12 -0800201 }
202 }
I-Jui (Ray) Sung2c4e1362017-09-06 02:15:54 -0700203 RequestArgument arg = {
204 .location = {.poolIndex = OUTPUT, .offset = 0, .length = static_cast<uint32_t>(s)},
205 .dimensions = {},
206 };
207 outputs_info[index] = arg;
208 outputSize += s;
209 });
Xusong Wang4faf0722019-01-27 23:08:12 -0800210 // If output0 does not have size larger than one byte,
211 // we can not provide an insufficient buffer
212 if (!sizeLargerThanOne && outputType == OutputType::INSUFFICIENT) return;
I-Jui (Ray) Sung2c4e1362017-09-06 02:15:54 -0700213 // Compute offset for outputs 1 and so on
214 {
215 size_t offset = 0;
216 for (auto& i : outputs_info) {
217 i.location.offset = offset;
218 offset += i.location.length;
219 }
220 }
Miao Wang4862d612018-02-05 17:26:54 -0800221 std::vector<hidl_memory> pools = {nn::allocateSharedMemory(inputSize),
222 nn::allocateSharedMemory(outputSize)};
I-Jui (Ray) Sung2c4e1362017-09-06 02:15:54 -0700223 ASSERT_NE(0ull, pools[INPUT].size());
224 ASSERT_NE(0ull, pools[OUTPUT].size());
225
226 // load data
227 sp<IMemory> inputMemory = mapMemory(pools[INPUT]);
228 sp<IMemory> outputMemory = mapMemory(pools[OUTPUT]);
229 ASSERT_NE(nullptr, inputMemory.get());
230 ASSERT_NE(nullptr, outputMemory.get());
231 char* inputPtr = reinterpret_cast<char*>(static_cast<void*>(inputMemory->getPointer()));
232 char* outputPtr = reinterpret_cast<char*>(static_cast<void*>(outputMemory->getPointer()));
233 ASSERT_NE(nullptr, inputPtr);
234 ASSERT_NE(nullptr, outputPtr);
235 inputMemory->update();
236 outputMemory->update();
237
238 // Go through all inputs, copy the values
239 for_all(inputs, [&inputs_info, inputPtr](int index, auto p, auto s) {
240 char* begin = (char*)p;
241 char* end = begin + s;
242 // TODO: handle more than one input
243 std::copy(begin, end, inputPtr + inputs_info[index].location.offset);
244 });
245
246 inputMemory->commit();
247 outputMemory->commit();
Michael Butlercf22a572017-09-22 13:26:12 -0700248
Michael Butler29471a82019-01-15 11:02:55 -0800249 const Request request = {.inputs = inputs_info, .outputs = outputs_info, .pools = pools};
250
Xusong Wangb50bc312018-11-07 09:33:59 -0800251 ErrorStatus executionStatus;
252 hidl_vec<OutputShape> outputShapes;
David Gross55a3d322019-01-23 14:01:52 -0800253 Timing timing;
Michael Butler29471a82019-01-15 11:02:55 -0800254 switch (executor) {
255 case Executor::ASYNC: {
256 SCOPED_TRACE("asynchronous");
Michael Butlercf22a572017-09-22 13:26:12 -0700257
Michael Butler29471a82019-01-15 11:02:55 -0800258 // launch execution
259 sp<ExecutionCallback> executionCallback = new ExecutionCallback();
260 ASSERT_NE(nullptr, executionCallback.get());
261 Return<ErrorStatus> executionLaunchStatus =
262 ExecutePreparedModel(preparedModel, request, measure, executionCallback);
263 ASSERT_TRUE(executionLaunchStatus.isOk());
264 EXPECT_EQ(ErrorStatus::NONE, static_cast<ErrorStatus>(executionLaunchStatus));
David Gross4592ed12018-12-21 11:20:26 -0800265
Michael Butler29471a82019-01-15 11:02:55 -0800266 // retrieve execution status
267 executionCallback->wait();
268 executionStatus = executionCallback->getStatus();
269 outputShapes = executionCallback->getOutputShapes();
270 timing = executionCallback->getTiming();
David Gross4592ed12018-12-21 11:20:26 -0800271
Michael Butler29471a82019-01-15 11:02:55 -0800272 break;
273 }
274 case Executor::SYNC: {
275 SCOPED_TRACE("synchronous");
276
277 // execute
278 Return<ErrorStatus> executionReturnStatus = ExecutePreparedModel(
279 preparedModel, request, measure, &outputShapes, &timing);
280 ASSERT_TRUE(executionReturnStatus.isOk());
281 executionStatus = static_cast<ErrorStatus>(executionReturnStatus);
282
283 break;
284 }
285 case Executor::BURST: {
286 SCOPED_TRACE("burst");
287
288 // create burst
289 const std::unique_ptr<::android::nn::ExecutionBurstController> controller =
290 CreateBurst(preparedModel);
291 ASSERT_NE(nullptr, controller.get());
292
293 // create memory keys
294 std::vector<intptr_t> keys(request.pools.size());
295 for (size_t i = 0; i < keys.size(); ++i) {
296 keys[i] = reinterpret_cast<intptr_t>(&request.pools[i]);
297 }
298
299 // execute burst
300 std::tie(executionStatus, outputShapes, timing) =
301 controller->compute(request, measure, keys);
302
303 break;
304 }
David Gross4592ed12018-12-21 11:20:26 -0800305 }
I-Jui (Ray) Sung2c4e1362017-09-06 02:15:54 -0700306
Xusong Wang4faf0722019-01-27 23:08:12 -0800307 if (outputType != OutputType::FULLY_SPECIFIED &&
308 executionStatus == ErrorStatus::GENERAL_FAILURE) {
David Gross55a3d322019-01-23 14:01:52 -0800309 LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot "
310 "execute model that it does not support.";
311 std::cout << "[ ] Early termination of test because vendor service cannot "
312 "execute model that it does not support."
313 << std::endl;
Xusong Wang4faf0722019-01-27 23:08:12 -0800314 GTEST_SKIP();
David Gross55a3d322019-01-23 14:01:52 -0800315 }
David Gross55a3d322019-01-23 14:01:52 -0800316 if (measure == MeasureTiming::NO) {
317 EXPECT_EQ(UINT64_MAX, timing.timeOnDevice);
318 EXPECT_EQ(UINT64_MAX, timing.timeInDriver);
319 } else {
320 if (timing.timeOnDevice != UINT64_MAX && timing.timeInDriver != UINT64_MAX) {
321 EXPECT_LE(timing.timeOnDevice, timing.timeInDriver);
322 }
323 }
324
Xusong Wang4faf0722019-01-27 23:08:12 -0800325 switch (outputType) {
326 case OutputType::FULLY_SPECIFIED:
327 // If the model output operands are fully specified, outputShapes must be either
328 // either empty, or have the same number of elements as the number of outputs.
329 ASSERT_EQ(ErrorStatus::NONE, executionStatus);
330 ASSERT_TRUE(outputShapes.size() == 0 ||
331 outputShapes.size() == test.operandDimensions.size());
332 break;
333 case OutputType::UNSPECIFIED:
334 // If the model output operands are not fully specified, outputShapes must have
335 // the same number of elements as the number of outputs.
336 ASSERT_EQ(ErrorStatus::NONE, executionStatus);
337 ASSERT_EQ(outputShapes.size(), test.operandDimensions.size());
338 break;
339 case OutputType::INSUFFICIENT:
340 ASSERT_EQ(ErrorStatus::OUTPUT_INSUFFICIENT_SIZE, executionStatus);
341 ASSERT_EQ(outputShapes.size(), test.operandDimensions.size());
342 ASSERT_FALSE(outputShapes[0].isSufficient);
343 return;
344 }
David Gross55a3d322019-01-23 14:01:52 -0800345 // Go through all outputs, overwrite output dimensions with returned output shapes
Xusong Wang4faf0722019-01-27 23:08:12 -0800346 if (outputShapes.size() > 0) {
David Gross55a3d322019-01-23 14:01:52 -0800347 for_each<uint32_t>(test.operandDimensions,
348 [&outputShapes](int idx, std::vector<uint32_t>& dim) {
349 dim = outputShapes[idx].dimensions;
350 });
351 }
Xusong Wangb50bc312018-11-07 09:33:59 -0800352
I-Jui (Ray) Sung2c4e1362017-09-06 02:15:54 -0700353 // validate results
354 outputMemory->read();
I-Jui (Ray) Sungf6b85502017-09-20 13:45:50 -0700355 copy_back(&test, outputs_info, outputPtr);
I-Jui (Ray) Sung2c4e1362017-09-06 02:15:54 -0700356 outputMemory->commit();
I-Jui (Ray) Sung7d765bd2017-09-13 18:47:12 -0700357 // Filter out don't cares
I-Jui (Ray) Sung5bf4edf2017-10-06 13:22:39 -0700358 MixedTyped filtered_golden = filter(golden, is_ignored);
359 MixedTyped filtered_test = filter(test, is_ignored);
I-Jui (Ray) Sung7d765bd2017-09-13 18:47:12 -0700360
I-Jui (Ray) Sung2c4e1362017-09-06 02:15:54 -0700361 // We want "close-enough" results for float
Xusong Wangf6235f82018-08-28 16:50:01 -0700362 compare(filtered_golden, filtered_test, fpAtol, fpRtol);
Michael K. Sandersda3bdbc2018-10-19 14:39:09 +0100363
364 if (example.expectedMultinomialDistributionTolerance > 0) {
365 expectMultinomialDistributionWithinTolerance(test, example);
366 }
I-Jui (Ray) Sung2c4e1362017-09-06 02:15:54 -0700367 }
368}
David Gross4592ed12018-12-21 11:20:26 -0800369template <typename T_IPreparedModel>
370void EvaluatePreparedModel(sp<T_IPreparedModel>& preparedModel, std::function<bool(int)> is_ignored,
Xusong Wang4faf0722019-01-27 23:08:12 -0800371 const std::vector<MixedTypedExample>& examples,
372 bool hasRelaxedFloat32Model, Executor executor, MeasureTiming measure,
373 OutputType outputType) {
David Gross4592ed12018-12-21 11:20:26 -0800374 EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, kDefaultAtol,
Xusong Wang4faf0722019-01-27 23:08:12 -0800375 kDefaultRtol, executor, measure, outputType);
David Gross4592ed12018-12-21 11:20:26 -0800376}
I-Jui (Ray) Sung2c4e1362017-09-06 02:15:54 -0700377
Xusong Wang96e68dc2019-01-18 17:28:26 -0800378void EvaluatePreparedModel(sp<V1_2::IPreparedModel>& preparedModel,
379 std::function<bool(int)> is_ignored,
380 const std::vector<MixedTypedExample>& examples,
381 bool hasRelaxedFloat32Model, bool testDynamicOutputShape) {
382 if (testDynamicOutputShape) {
383 EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
384 Executor::ASYNC, MeasureTiming::NO, OutputType::UNSPECIFIED);
385 EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
386 Executor::SYNC, MeasureTiming::NO, OutputType::UNSPECIFIED);
387 EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
388 Executor::BURST, MeasureTiming::NO, OutputType::UNSPECIFIED);
389 EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
390 Executor::ASYNC, MeasureTiming::YES, OutputType::UNSPECIFIED);
391 EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
392 Executor::SYNC, MeasureTiming::YES, OutputType::UNSPECIFIED);
393 EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
394 Executor::BURST, MeasureTiming::YES, OutputType::UNSPECIFIED);
395 EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
396 Executor::ASYNC, MeasureTiming::NO, OutputType::INSUFFICIENT);
397 EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
398 Executor::SYNC, MeasureTiming::NO, OutputType::INSUFFICIENT);
399 EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
400 Executor::BURST, MeasureTiming::NO, OutputType::INSUFFICIENT);
401 EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
402 Executor::ASYNC, MeasureTiming::YES, OutputType::INSUFFICIENT);
403 EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
404 Executor::SYNC, MeasureTiming::YES, OutputType::INSUFFICIENT);
405 EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
406 Executor::BURST, MeasureTiming::YES, OutputType::INSUFFICIENT);
407 } else {
408 EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
409 Executor::ASYNC, MeasureTiming::NO, OutputType::FULLY_SPECIFIED);
410 EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
411 Executor::SYNC, MeasureTiming::NO, OutputType::FULLY_SPECIFIED);
412 EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
413 Executor::BURST, MeasureTiming::NO, OutputType::FULLY_SPECIFIED);
414 EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
415 Executor::ASYNC, MeasureTiming::YES, OutputType::FULLY_SPECIFIED);
416 EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
417 Executor::SYNC, MeasureTiming::YES, OutputType::FULLY_SPECIFIED);
418 EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
419 Executor::BURST, MeasureTiming::YES, OutputType::FULLY_SPECIFIED);
420 }
421}
422
Xusong Wang1a06e772018-10-31 08:43:12 -0700423static void getPreparedModel(sp<PreparedModelCallback> callback,
424 sp<V1_0::IPreparedModel>* preparedModel) {
425 *preparedModel = callback->getPreparedModel();
426}
427static void getPreparedModel(sp<PreparedModelCallback> callback,
428 sp<V1_2::IPreparedModel>* preparedModel) {
429 sp<V1_0::IPreparedModel> preparedModelV1_0 = callback->getPreparedModel();
430 *preparedModel = V1_2::IPreparedModel::castFrom(preparedModelV1_0).withDefault(nullptr);
431}
432
Michael Butler7ed61352018-03-22 16:37:57 -0700433void Execute(const sp<V1_0::IDevice>& device, std::function<V1_0::Model(void)> create_model,
Michael K. Sandersda3bdbc2018-10-19 14:39:09 +0100434 std::function<bool(int)> is_ignored, const std::vector<MixedTypedExample>& examples) {
Miao Wang4862d612018-02-05 17:26:54 -0800435 V1_0::Model model = create_model();
436
437 // see if service can handle model
438 bool fullySupportsModel = false;
Miao Wang4862d612018-02-05 17:26:54 -0800439 Return<void> supportedCall = device->getSupportedOperations(
Michael Butler1ae02d62018-02-26 15:24:46 -0800440 model, [&fullySupportsModel](ErrorStatus status, const hidl_vec<bool>& supported) {
441 ASSERT_EQ(ErrorStatus::NONE, status);
Miao Wang4862d612018-02-05 17:26:54 -0800442 ASSERT_NE(0ul, supported.size());
443 fullySupportsModel =
444 std::all_of(supported.begin(), supported.end(), [](bool valid) { return valid; });
445 });
446 ASSERT_TRUE(supportedCall.isOk());
Michael Butler1ae02d62018-02-26 15:24:46 -0800447
448 // launch prepare model
449 sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
450 ASSERT_NE(nullptr, preparedModelCallback.get());
Miao Wang4862d612018-02-05 17:26:54 -0800451 Return<ErrorStatus> prepareLaunchStatus = device->prepareModel(model, preparedModelCallback);
452 ASSERT_TRUE(prepareLaunchStatus.isOk());
Michael Butler1ae02d62018-02-26 15:24:46 -0800453 ASSERT_EQ(ErrorStatus::NONE, static_cast<ErrorStatus>(prepareLaunchStatus));
Miao Wang4862d612018-02-05 17:26:54 -0800454
455 // retrieve prepared model
456 preparedModelCallback->wait();
457 ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus();
Xusong Wang1a06e772018-10-31 08:43:12 -0700458 sp<V1_0::IPreparedModel> preparedModel;
459 getPreparedModel(preparedModelCallback, &preparedModel);
Miao Wang4862d612018-02-05 17:26:54 -0800460
461 // early termination if vendor service cannot fully prepare model
Michael Butler1ae02d62018-02-26 15:24:46 -0800462 if (!fullySupportsModel && prepareReturnStatus != ErrorStatus::NONE) {
Miao Wang4862d612018-02-05 17:26:54 -0800463 ASSERT_EQ(nullptr, preparedModel.get());
464 LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot "
465 "prepare model that it does not support.";
466 std::cout << "[ ] Early termination of test because vendor service cannot "
467 "prepare model that it does not support."
468 << std::endl;
Miao Wangd2668b52019-01-08 12:27:35 -0800469 GTEST_SKIP();
Miao Wang4862d612018-02-05 17:26:54 -0800470 }
Michael Butler1ae02d62018-02-26 15:24:46 -0800471 EXPECT_EQ(ErrorStatus::NONE, prepareReturnStatus);
Miao Wang4862d612018-02-05 17:26:54 -0800472 ASSERT_NE(nullptr, preparedModel.get());
473
Xusong Wangf6235f82018-08-28 16:50:01 -0700474 float fpAtol = 1e-5f, fpRtol = 5.0f * 1.1920928955078125e-7f;
Michael K. Sanders650fd182018-10-30 14:44:48 +0000475 EvaluatePreparedModel(preparedModel, is_ignored, examples,
Xusong Wang4faf0722019-01-27 23:08:12 -0800476 /*hasRelaxedFloat32Model=*/false, fpAtol, fpRtol, Executor::ASYNC,
477 MeasureTiming::NO, OutputType::FULLY_SPECIFIED);
Miao Wang4862d612018-02-05 17:26:54 -0800478}
479
Michael Butler7ed61352018-03-22 16:37:57 -0700480void Execute(const sp<V1_1::IDevice>& device, std::function<V1_1::Model(void)> create_model,
Michael K. Sandersda3bdbc2018-10-19 14:39:09 +0100481 std::function<bool(int)> is_ignored, const std::vector<MixedTypedExample>& examples) {
Miao Wang4862d612018-02-05 17:26:54 -0800482 V1_1::Model model = create_model();
483
484 // see if service can handle model
485 bool fullySupportsModel = false;
Miao Wang4862d612018-02-05 17:26:54 -0800486 Return<void> supportedCall = device->getSupportedOperations_1_1(
Michael Butler1ae02d62018-02-26 15:24:46 -0800487 model, [&fullySupportsModel](ErrorStatus status, const hidl_vec<bool>& supported) {
488 ASSERT_EQ(ErrorStatus::NONE, status);
Miao Wang4862d612018-02-05 17:26:54 -0800489 ASSERT_NE(0ul, supported.size());
490 fullySupportsModel =
491 std::all_of(supported.begin(), supported.end(), [](bool valid) { return valid; });
492 });
493 ASSERT_TRUE(supportedCall.isOk());
Michael Butler1ae02d62018-02-26 15:24:46 -0800494
495 // launch prepare model
496 sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
497 ASSERT_NE(nullptr, preparedModelCallback.get());
Michael Butlerf02692d2018-04-11 16:30:09 -0700498 Return<ErrorStatus> prepareLaunchStatus = device->prepareModel_1_1(
499 model, ExecutionPreference::FAST_SINGLE_ANSWER, preparedModelCallback);
Miao Wang4862d612018-02-05 17:26:54 -0800500 ASSERT_TRUE(prepareLaunchStatus.isOk());
Michael Butler1ae02d62018-02-26 15:24:46 -0800501 ASSERT_EQ(ErrorStatus::NONE, static_cast<ErrorStatus>(prepareLaunchStatus));
Miao Wang4862d612018-02-05 17:26:54 -0800502
503 // retrieve prepared model
504 preparedModelCallback->wait();
505 ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus();
Xusong Wang1a06e772018-10-31 08:43:12 -0700506 sp<V1_0::IPreparedModel> preparedModel;
507 getPreparedModel(preparedModelCallback, &preparedModel);
Miao Wang4862d612018-02-05 17:26:54 -0800508
509 // early termination if vendor service cannot fully prepare model
Michael Butler1ae02d62018-02-26 15:24:46 -0800510 if (!fullySupportsModel && prepareReturnStatus != ErrorStatus::NONE) {
Miao Wang4862d612018-02-05 17:26:54 -0800511 ASSERT_EQ(nullptr, preparedModel.get());
512 LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot "
513 "prepare model that it does not support.";
514 std::cout << "[ ] Early termination of test because vendor service cannot "
515 "prepare model that it does not support."
516 << std::endl;
Miao Wangd2668b52019-01-08 12:27:35 -0800517 GTEST_SKIP();
Miao Wang4862d612018-02-05 17:26:54 -0800518 }
Michael Butler1ae02d62018-02-26 15:24:46 -0800519 EXPECT_EQ(ErrorStatus::NONE, prepareReturnStatus);
Miao Wang4862d612018-02-05 17:26:54 -0800520 ASSERT_NE(nullptr, preparedModel.get());
521
Michael K. Sanders650fd182018-10-30 14:44:48 +0000522 EvaluatePreparedModel(preparedModel, is_ignored, examples,
Xusong Wang4faf0722019-01-27 23:08:12 -0800523 model.relaxComputationFloat32toFloat16, 1e-5f, 1e-5f, Executor::ASYNC,
524 MeasureTiming::NO, OutputType::FULLY_SPECIFIED);
Miao Wang4862d612018-02-05 17:26:54 -0800525}
526
Xusong Wang96e68dc2019-01-18 17:28:26 -0800527void PrepareModel(const sp<V1_2::IDevice>& device, const V1_2::Model& model,
528 sp<V1_2::IPreparedModel>* preparedModel) {
Slava Shklyaevfeb87a92018-09-12 14:52:02 +0100529 // see if service can handle model
530 bool fullySupportsModel = false;
531 Return<void> supportedCall = device->getSupportedOperations_1_2(
532 model, [&fullySupportsModel](ErrorStatus status, const hidl_vec<bool>& supported) {
533 ASSERT_EQ(ErrorStatus::NONE, status);
534 ASSERT_NE(0ul, supported.size());
535 fullySupportsModel =
536 std::all_of(supported.begin(), supported.end(), [](bool valid) { return valid; });
537 });
538 ASSERT_TRUE(supportedCall.isOk());
539
540 // launch prepare model
541 sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
542 ASSERT_NE(nullptr, preparedModelCallback.get());
543 Return<ErrorStatus> prepareLaunchStatus = device->prepareModel_1_2(
Xusong Wanged0822b2019-02-25 16:58:58 -0800544 model, ExecutionPreference::FAST_SINGLE_ANSWER, hidl_vec<hidl_handle>(),
545 hidl_vec<hidl_handle>(), HidlToken(), preparedModelCallback);
Slava Shklyaevfeb87a92018-09-12 14:52:02 +0100546 ASSERT_TRUE(prepareLaunchStatus.isOk());
547 ASSERT_EQ(ErrorStatus::NONE, static_cast<ErrorStatus>(prepareLaunchStatus));
548
549 // retrieve prepared model
550 preparedModelCallback->wait();
551 ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus();
Xusong Wang96e68dc2019-01-18 17:28:26 -0800552 getPreparedModel(preparedModelCallback, preparedModel);
Slava Shklyaevfeb87a92018-09-12 14:52:02 +0100553
554 // early termination if vendor service cannot fully prepare model
555 if (!fullySupportsModel && prepareReturnStatus != ErrorStatus::NONE) {
Xusong Wang96e68dc2019-01-18 17:28:26 -0800556 ASSERT_EQ(nullptr, preparedModel->get());
Slava Shklyaevfeb87a92018-09-12 14:52:02 +0100557 LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot "
558 "prepare model that it does not support.";
559 std::cout << "[ ] Early termination of test because vendor service cannot "
560 "prepare model that it does not support."
561 << std::endl;
Miao Wang6e06a5c2019-02-01 14:00:08 -0800562 return;
Slava Shklyaevfeb87a92018-09-12 14:52:02 +0100563 }
564 EXPECT_EQ(ErrorStatus::NONE, prepareReturnStatus);
Xusong Wang96e68dc2019-01-18 17:28:26 -0800565 ASSERT_NE(nullptr, preparedModel->get());
566}
Slava Shklyaevfeb87a92018-09-12 14:52:02 +0100567
Xusong Wang96e68dc2019-01-18 17:28:26 -0800568// TODO: Reduce code duplication.
569void Execute(const sp<V1_2::IDevice>& device, std::function<V1_2::Model(void)> create_model,
570 std::function<bool(int)> is_ignored, const std::vector<MixedTypedExample>& examples,
571 bool testDynamicOutputShape) {
572 V1_2::Model model = create_model();
573 sp<V1_2::IPreparedModel> preparedModel = nullptr;
574 PrepareModel(device, model, &preparedModel);
Miao Wang6e06a5c2019-02-01 14:00:08 -0800575 if (preparedModel == nullptr) {
576 GTEST_SKIP();
577 }
Xusong Wang96e68dc2019-01-18 17:28:26 -0800578 EvaluatePreparedModel(preparedModel, is_ignored, examples,
579 model.relaxComputationFloat32toFloat16, testDynamicOutputShape);
Slava Shklyaevfeb87a92018-09-12 14:52:02 +0100580}
581
I-Jui (Ray) Sung2c4e1362017-09-06 02:15:54 -0700582} // namespace generated_tests
583
I-Jui (Ray) Sung2c4e1362017-09-06 02:15:54 -0700584} // namespace neuralnetworks
585} // namespace hardware
586} // namespace android