blob: 3b6f0f8300d0c3facbb2d885e6b97f6157b9b508 [file] [log] [blame]
Michael Butler7ed61352018-03-22 16:37:57 -07001/*
2 * Copyright (C) 2018 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
17#define LOG_TAG "neuralnetworks_hidl_hal_test"
18
Slava Shklyaev1d6b4652019-05-14 14:15:14 +010019#include "1.0/Callbacks.h"
20#include "1.0/Utils.h"
Xusong Wang9e2b97b2019-08-23 16:10:54 -070021#include "GeneratedTestHarness.h"
Michael Butler7ed61352018-03-22 16:37:57 -070022#include "VtsHalNeuralnetworks.h"
23
Michael Butlerbbe5dad2019-08-26 23:55:47 -070024namespace android::hardware::neuralnetworks::V1_1::vts::functional {
Michael Butler7ed61352018-03-22 16:37:57 -070025
Michael Butlerbbe5dad2019-08-26 23:55:47 -070026using V1_0::ErrorStatus;
27using V1_0::IPreparedModel;
28using V1_0::Operand;
29using V1_0::OperandLifeTime;
30using V1_0::OperandType;
31using V1_0::implementation::PreparedModelCallback;
Michael Butler7ed61352018-03-22 16:37:57 -070032
Michael Butlerda1a6922020-03-11 18:45:45 -070033using PrepareModelMutation = std::function<void(Model*, ExecutionPreference*)>;
34
Michael Butler7ed61352018-03-22 16:37:57 -070035///////////////////////// UTILITY FUNCTIONS /////////////////////////
36
37static void validateGetSupportedOperations(const sp<IDevice>& device, const std::string& message,
Michael Butlere16af0a2019-08-29 22:17:24 -070038 const Model& model) {
Michael Butler7ed61352018-03-22 16:37:57 -070039 SCOPED_TRACE(message + " [getSupportedOperations_1_1]");
40
Slava Shklyaev1d6b4652019-05-14 14:15:14 +010041 Return<void> ret = device->getSupportedOperations_1_1(
42 model, [&](ErrorStatus status, const hidl_vec<bool>&) {
43 EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, status);
44 });
Michael Butler7ed61352018-03-22 16:37:57 -070045 EXPECT_TRUE(ret.isOk());
46}
47
48static void validatePrepareModel(const sp<IDevice>& device, const std::string& message,
Michael Butlere16af0a2019-08-29 22:17:24 -070049 const Model& model, ExecutionPreference preference) {
Michael Butler7ed61352018-03-22 16:37:57 -070050 SCOPED_TRACE(message + " [prepareModel_1_1]");
51
52 sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
Michael Butler7ed61352018-03-22 16:37:57 -070053 Return<ErrorStatus> prepareLaunchStatus =
Slava Shklyaev1d6b4652019-05-14 14:15:14 +010054 device->prepareModel_1_1(model, preference, preparedModelCallback);
Michael Butler7ed61352018-03-22 16:37:57 -070055 ASSERT_TRUE(prepareLaunchStatus.isOk());
56 ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, static_cast<ErrorStatus>(prepareLaunchStatus));
57
58 preparedModelCallback->wait();
59 ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus();
60 ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, prepareReturnStatus);
61 sp<IPreparedModel> preparedModel = preparedModelCallback->getPreparedModel();
62 ASSERT_EQ(nullptr, preparedModel.get());
63}
64
Michael Butlerf02692d2018-04-11 16:30:09 -070065static bool validExecutionPreference(ExecutionPreference preference) {
66 return preference == ExecutionPreference::LOW_POWER ||
67 preference == ExecutionPreference::FAST_SINGLE_ANSWER ||
68 preference == ExecutionPreference::SUSTAINED_SPEED;
69}
70
Michael Butler7ed61352018-03-22 16:37:57 -070071// Primary validation function. This function will take a valid model, apply a
Michael Butlerda1a6922020-03-11 18:45:45 -070072// mutation to invalidate either the model or the execution preference, then
73// pass these to supportedOperations and/or prepareModel if that method is
74// called with an invalid argument.
75static void validate(const sp<IDevice>& device, const std::string& message,
76 const Model& originalModel, const PrepareModelMutation& mutate) {
77 Model model = originalModel;
78 ExecutionPreference preference = ExecutionPreference::FAST_SINGLE_ANSWER;
79 mutate(&model, &preference);
80
Michael Butlerf02692d2018-04-11 16:30:09 -070081 if (validExecutionPreference(preference)) {
82 validateGetSupportedOperations(device, message, model);
83 }
Michael Butlerda1a6922020-03-11 18:45:45 -070084
Michael Butlerf02692d2018-04-11 16:30:09 -070085 validatePrepareModel(device, message, model, preference);
Michael Butler7ed61352018-03-22 16:37:57 -070086}
87
Michael Butler7ed61352018-03-22 16:37:57 -070088static uint32_t addOperand(Model* model) {
89 return hidl_vec_push_back(&model->operands,
90 {
Slava Shklyaev1d6b4652019-05-14 14:15:14 +010091 .type = OperandType::INT32,
92 .dimensions = {},
93 .numberOfConsumers = 0,
94 .scale = 0.0f,
95 .zeroPoint = 0,
96 .lifetime = OperandLifeTime::MODEL_INPUT,
97 .location = {.poolIndex = 0, .offset = 0, .length = 0},
Michael Butler7ed61352018-03-22 16:37:57 -070098 });
99}
100
101static uint32_t addOperand(Model* model, OperandLifeTime lifetime) {
102 uint32_t index = addOperand(model);
103 model->operands[index].numberOfConsumers = 1;
104 model->operands[index].lifetime = lifetime;
105 return index;
106}
107
108///////////////////////// VALIDATE MODEL OPERAND TYPE /////////////////////////
109
110static const int32_t invalidOperandTypes[] = {
Slava Shklyaev1d6b4652019-05-14 14:15:14 +0100111 static_cast<int32_t>(OperandType::FLOAT32) - 1, // lower bound fundamental
112 static_cast<int32_t>(OperandType::TENSOR_QUANT8_ASYMM) + 1, // upper bound fundamental
113 static_cast<int32_t>(OperandType::OEM) - 1, // lower bound OEM
114 static_cast<int32_t>(OperandType::TENSOR_OEM_BYTE) + 1, // upper bound OEM
Michael Butler7ed61352018-03-22 16:37:57 -0700115};
116
Michael Butlere16af0a2019-08-29 22:17:24 -0700117static void mutateOperandTypeTest(const sp<IDevice>& device, const Model& model) {
Michael Butler7ed61352018-03-22 16:37:57 -0700118 for (size_t operand = 0; operand < model.operands.size(); ++operand) {
119 for (int32_t invalidOperandType : invalidOperandTypes) {
120 const std::string message = "mutateOperandTypeTest: operand " +
121 std::to_string(operand) + " set to value " +
122 std::to_string(invalidOperandType);
Michael Butlerda1a6922020-03-11 18:45:45 -0700123 validate(device, message, model,
124 [operand, invalidOperandType](Model* model, ExecutionPreference*) {
125 model->operands[operand].type =
126 static_cast<OperandType>(invalidOperandType);
127 });
Michael Butler7ed61352018-03-22 16:37:57 -0700128 }
129 }
130}
131
132///////////////////////// VALIDATE OPERAND RANK /////////////////////////
133
134static uint32_t getInvalidRank(OperandType type) {
135 switch (type) {
136 case OperandType::FLOAT32:
137 case OperandType::INT32:
138 case OperandType::UINT32:
139 return 1;
140 case OperandType::TENSOR_FLOAT32:
141 case OperandType::TENSOR_INT32:
142 case OperandType::TENSOR_QUANT8_ASYMM:
143 return 0;
144 default:
145 return 0;
146 }
147}
148
Michael Butlere16af0a2019-08-29 22:17:24 -0700149static void mutateOperandRankTest(const sp<IDevice>& device, const Model& model) {
Michael Butler7ed61352018-03-22 16:37:57 -0700150 for (size_t operand = 0; operand < model.operands.size(); ++operand) {
151 const uint32_t invalidRank = getInvalidRank(model.operands[operand].type);
152 const std::string message = "mutateOperandRankTest: operand " + std::to_string(operand) +
153 " has rank of " + std::to_string(invalidRank);
Michael Butlerda1a6922020-03-11 18:45:45 -0700154 validate(device, message, model,
155 [operand, invalidRank](Model* model, ExecutionPreference*) {
156 model->operands[operand].dimensions = std::vector<uint32_t>(invalidRank, 0);
157 });
Michael Butler7ed61352018-03-22 16:37:57 -0700158 }
159}
160
161///////////////////////// VALIDATE OPERAND SCALE /////////////////////////
162
163static float getInvalidScale(OperandType type) {
164 switch (type) {
165 case OperandType::FLOAT32:
166 case OperandType::INT32:
167 case OperandType::UINT32:
168 case OperandType::TENSOR_FLOAT32:
169 return 1.0f;
170 case OperandType::TENSOR_INT32:
171 return -1.0f;
172 case OperandType::TENSOR_QUANT8_ASYMM:
173 return 0.0f;
174 default:
175 return 0.0f;
176 }
177}
178
Michael Butlere16af0a2019-08-29 22:17:24 -0700179static void mutateOperandScaleTest(const sp<IDevice>& device, const Model& model) {
Michael Butler7ed61352018-03-22 16:37:57 -0700180 for (size_t operand = 0; operand < model.operands.size(); ++operand) {
181 const float invalidScale = getInvalidScale(model.operands[operand].type);
182 const std::string message = "mutateOperandScaleTest: operand " + std::to_string(operand) +
183 " has scale of " + std::to_string(invalidScale);
Michael Butlerda1a6922020-03-11 18:45:45 -0700184 validate(device, message, model,
185 [operand, invalidScale](Model* model, ExecutionPreference*) {
186 model->operands[operand].scale = invalidScale;
187 });
Michael Butler7ed61352018-03-22 16:37:57 -0700188 }
189}
190
191///////////////////////// VALIDATE OPERAND ZERO POINT /////////////////////////
192
193static std::vector<int32_t> getInvalidZeroPoints(OperandType type) {
194 switch (type) {
195 case OperandType::FLOAT32:
196 case OperandType::INT32:
197 case OperandType::UINT32:
198 case OperandType::TENSOR_FLOAT32:
199 case OperandType::TENSOR_INT32:
200 return {1};
201 case OperandType::TENSOR_QUANT8_ASYMM:
202 return {-1, 256};
203 default:
204 return {};
205 }
206}
207
Michael Butlere16af0a2019-08-29 22:17:24 -0700208static void mutateOperandZeroPointTest(const sp<IDevice>& device, const Model& model) {
Michael Butler7ed61352018-03-22 16:37:57 -0700209 for (size_t operand = 0; operand < model.operands.size(); ++operand) {
210 const std::vector<int32_t> invalidZeroPoints =
Slava Shklyaev1d6b4652019-05-14 14:15:14 +0100211 getInvalidZeroPoints(model.operands[operand].type);
Michael Butler7ed61352018-03-22 16:37:57 -0700212 for (int32_t invalidZeroPoint : invalidZeroPoints) {
213 const std::string message = "mutateOperandZeroPointTest: operand " +
214 std::to_string(operand) + " has zero point of " +
215 std::to_string(invalidZeroPoint);
Michael Butlerda1a6922020-03-11 18:45:45 -0700216 validate(device, message, model,
217 [operand, invalidZeroPoint](Model* model, ExecutionPreference*) {
218 model->operands[operand].zeroPoint = invalidZeroPoint;
219 });
Michael Butler7ed61352018-03-22 16:37:57 -0700220 }
221 }
222}
223
224///////////////////////// VALIDATE EXTRA ??? /////////////////////////
225
226// TODO: Operand::lifetime
227// TODO: Operand::location
228
229///////////////////////// VALIDATE OPERATION OPERAND TYPE /////////////////////////
230
231static void mutateOperand(Operand* operand, OperandType type) {
232 Operand newOperand = *operand;
233 newOperand.type = type;
234 switch (type) {
235 case OperandType::FLOAT32:
236 case OperandType::INT32:
237 case OperandType::UINT32:
238 newOperand.dimensions = hidl_vec<uint32_t>();
239 newOperand.scale = 0.0f;
240 newOperand.zeroPoint = 0;
241 break;
242 case OperandType::TENSOR_FLOAT32:
243 newOperand.dimensions =
Slava Shklyaev1d6b4652019-05-14 14:15:14 +0100244 operand->dimensions.size() > 0 ? operand->dimensions : hidl_vec<uint32_t>({1});
Michael Butler7ed61352018-03-22 16:37:57 -0700245 newOperand.scale = 0.0f;
246 newOperand.zeroPoint = 0;
247 break;
248 case OperandType::TENSOR_INT32:
249 newOperand.dimensions =
Slava Shklyaev1d6b4652019-05-14 14:15:14 +0100250 operand->dimensions.size() > 0 ? operand->dimensions : hidl_vec<uint32_t>({1});
Michael Butler7ed61352018-03-22 16:37:57 -0700251 newOperand.zeroPoint = 0;
252 break;
253 case OperandType::TENSOR_QUANT8_ASYMM:
254 newOperand.dimensions =
Slava Shklyaev1d6b4652019-05-14 14:15:14 +0100255 operand->dimensions.size() > 0 ? operand->dimensions : hidl_vec<uint32_t>({1});
Michael Butler7ed61352018-03-22 16:37:57 -0700256 newOperand.scale = operand->scale != 0.0f ? operand->scale : 1.0f;
257 break;
258 case OperandType::OEM:
259 case OperandType::TENSOR_OEM_BYTE:
260 default:
261 break;
262 }
263 *operand = newOperand;
264}
265
Michael Butlere16af0a2019-08-29 22:17:24 -0700266static bool mutateOperationOperandTypeSkip(size_t operand, const Model& model) {
Michael Butler7ed61352018-03-22 16:37:57 -0700267 // LSH_PROJECTION's second argument is allowed to have any type. This is the
268 // only operation that currently has a type that can be anything independent
269 // from any other type. Changing the operand type to any other type will
270 // result in a valid model for LSH_PROJECTION. If this is the case, skip the
271 // test.
272 for (const Operation& operation : model.operations) {
273 if (operation.type == OperationType::LSH_PROJECTION && operand == operation.inputs[1]) {
274 return true;
275 }
276 }
277 return false;
278}
279
Michael Butlere16af0a2019-08-29 22:17:24 -0700280static void mutateOperationOperandTypeTest(const sp<IDevice>& device, const Model& model) {
Michael Butler7ed61352018-03-22 16:37:57 -0700281 for (size_t operand = 0; operand < model.operands.size(); ++operand) {
282 if (mutateOperationOperandTypeSkip(operand, model)) {
283 continue;
284 }
Steven Moreland303afec2018-04-25 12:49:05 -0700285 for (OperandType invalidOperandType : hidl_enum_range<OperandType>{}) {
Michael Butler7ed61352018-03-22 16:37:57 -0700286 // Do not test OEM types
287 if (invalidOperandType == model.operands[operand].type ||
288 invalidOperandType == OperandType::OEM ||
289 invalidOperandType == OperandType::TENSOR_OEM_BYTE) {
290 continue;
291 }
292 const std::string message = "mutateOperationOperandTypeTest: operand " +
293 std::to_string(operand) + " set to type " +
294 toString(invalidOperandType);
Michael Butlerda1a6922020-03-11 18:45:45 -0700295 validate(device, message, model,
296 [operand, invalidOperandType](Model* model, ExecutionPreference*) {
297 mutateOperand(&model->operands[operand], invalidOperandType);
298 });
Michael Butler7ed61352018-03-22 16:37:57 -0700299 }
300 }
301}
302
303///////////////////////// VALIDATE MODEL OPERATION TYPE /////////////////////////
304
305static const int32_t invalidOperationTypes[] = {
Slava Shklyaev1d6b4652019-05-14 14:15:14 +0100306 static_cast<int32_t>(OperationType::ADD) - 1, // lower bound fundamental
307 static_cast<int32_t>(OperationType::TRANSPOSE) + 1, // upper bound fundamental
308 static_cast<int32_t>(OperationType::OEM_OPERATION) - 1, // lower bound OEM
309 static_cast<int32_t>(OperationType::OEM_OPERATION) + 1, // upper bound OEM
Michael Butler7ed61352018-03-22 16:37:57 -0700310};
311
Michael Butlere16af0a2019-08-29 22:17:24 -0700312static void mutateOperationTypeTest(const sp<IDevice>& device, const Model& model) {
Michael Butler7ed61352018-03-22 16:37:57 -0700313 for (size_t operation = 0; operation < model.operations.size(); ++operation) {
314 for (int32_t invalidOperationType : invalidOperationTypes) {
315 const std::string message = "mutateOperationTypeTest: operation " +
316 std::to_string(operation) + " set to value " +
317 std::to_string(invalidOperationType);
Michael Butlerda1a6922020-03-11 18:45:45 -0700318 validate(device, message, model,
319 [operation, invalidOperationType](Model* model, ExecutionPreference*) {
320 model->operations[operation].type =
321 static_cast<OperationType>(invalidOperationType);
322 });
Michael Butler7ed61352018-03-22 16:37:57 -0700323 }
324 }
325}
326
327///////////////////////// VALIDATE MODEL OPERATION INPUT OPERAND INDEX /////////////////////////
328
Michael Butlere16af0a2019-08-29 22:17:24 -0700329static void mutateOperationInputOperandIndexTest(const sp<IDevice>& device, const Model& model) {
Michael Butler7ed61352018-03-22 16:37:57 -0700330 for (size_t operation = 0; operation < model.operations.size(); ++operation) {
331 const uint32_t invalidOperand = model.operands.size();
332 for (size_t input = 0; input < model.operations[operation].inputs.size(); ++input) {
333 const std::string message = "mutateOperationInputOperandIndexTest: operation " +
334 std::to_string(operation) + " input " +
335 std::to_string(input);
Michael Butlerda1a6922020-03-11 18:45:45 -0700336 validate(device, message, model,
337 [operation, input, invalidOperand](Model* model, ExecutionPreference*) {
338 model->operations[operation].inputs[input] = invalidOperand;
339 });
Michael Butler7ed61352018-03-22 16:37:57 -0700340 }
341 }
342}
343
344///////////////////////// VALIDATE MODEL OPERATION OUTPUT OPERAND INDEX /////////////////////////
345
Michael Butlere16af0a2019-08-29 22:17:24 -0700346static void mutateOperationOutputOperandIndexTest(const sp<IDevice>& device, const Model& model) {
Michael Butler7ed61352018-03-22 16:37:57 -0700347 for (size_t operation = 0; operation < model.operations.size(); ++operation) {
348 const uint32_t invalidOperand = model.operands.size();
349 for (size_t output = 0; output < model.operations[operation].outputs.size(); ++output) {
350 const std::string message = "mutateOperationOutputOperandIndexTest: operation " +
351 std::to_string(operation) + " output " +
352 std::to_string(output);
Michael Butlerda1a6922020-03-11 18:45:45 -0700353 validate(device, message, model,
354 [operation, output, invalidOperand](Model* model, ExecutionPreference*) {
355 model->operations[operation].outputs[output] = invalidOperand;
356 });
Michael Butler7ed61352018-03-22 16:37:57 -0700357 }
358 }
359}
360
361///////////////////////// REMOVE OPERAND FROM EVERYTHING /////////////////////////
362
363static void removeValueAndDecrementGreaterValues(hidl_vec<uint32_t>* vec, uint32_t value) {
364 if (vec) {
365 // remove elements matching "value"
366 auto last = std::remove(vec->begin(), vec->end(), value);
367 vec->resize(std::distance(vec->begin(), last));
368
369 // decrement elements exceeding "value"
370 std::transform(vec->begin(), vec->end(), vec->begin(),
371 [value](uint32_t v) { return v > value ? v-- : v; });
372 }
373}
374
375static void removeOperand(Model* model, uint32_t index) {
376 hidl_vec_removeAt(&model->operands, index);
377 for (Operation& operation : model->operations) {
378 removeValueAndDecrementGreaterValues(&operation.inputs, index);
379 removeValueAndDecrementGreaterValues(&operation.outputs, index);
380 }
381 removeValueAndDecrementGreaterValues(&model->inputIndexes, index);
382 removeValueAndDecrementGreaterValues(&model->outputIndexes, index);
383}
384
Michael Butlere16af0a2019-08-29 22:17:24 -0700385static void removeOperandTest(const sp<IDevice>& device, const Model& model) {
Michael Butler7ed61352018-03-22 16:37:57 -0700386 for (size_t operand = 0; operand < model.operands.size(); ++operand) {
387 const std::string message = "removeOperandTest: operand " + std::to_string(operand);
388 validate(device, message, model,
Michael Butlerda1a6922020-03-11 18:45:45 -0700389 [operand](Model* model, ExecutionPreference*) { removeOperand(model, operand); });
Michael Butler7ed61352018-03-22 16:37:57 -0700390 }
391}
392
393///////////////////////// REMOVE OPERATION /////////////////////////
394
395static void removeOperation(Model* model, uint32_t index) {
396 for (uint32_t operand : model->operations[index].inputs) {
397 model->operands[operand].numberOfConsumers--;
398 }
399 hidl_vec_removeAt(&model->operations, index);
400}
401
Michael Butlere16af0a2019-08-29 22:17:24 -0700402static void removeOperationTest(const sp<IDevice>& device, const Model& model) {
Michael Butler7ed61352018-03-22 16:37:57 -0700403 for (size_t operation = 0; operation < model.operations.size(); ++operation) {
404 const std::string message = "removeOperationTest: operation " + std::to_string(operation);
Michael Butlerda1a6922020-03-11 18:45:45 -0700405 validate(device, message, model, [operation](Model* model, ExecutionPreference*) {
406 removeOperation(model, operation);
407 });
Michael Butler7ed61352018-03-22 16:37:57 -0700408 }
409}
410
411///////////////////////// REMOVE OPERATION INPUT /////////////////////////
412
Michael Butlere16af0a2019-08-29 22:17:24 -0700413static void removeOperationInputTest(const sp<IDevice>& device, const Model& model) {
Michael Butler7ed61352018-03-22 16:37:57 -0700414 for (size_t operation = 0; operation < model.operations.size(); ++operation) {
415 for (size_t input = 0; input < model.operations[operation].inputs.size(); ++input) {
Michael Butlere16af0a2019-08-29 22:17:24 -0700416 const Operation& op = model.operations[operation];
Michael Butler7ed61352018-03-22 16:37:57 -0700417 // CONCATENATION has at least 2 inputs, with the last element being
418 // INT32. Skip this test if removing one of CONCATENATION's
419 // inputs still produces a valid model.
Michael Butlere16af0a2019-08-29 22:17:24 -0700420 if (op.type == OperationType::CONCATENATION && op.inputs.size() > 2 &&
Michael Butler7ed61352018-03-22 16:37:57 -0700421 input != op.inputs.size() - 1) {
422 continue;
423 }
424 const std::string message = "removeOperationInputTest: operation " +
425 std::to_string(operation) + ", input " +
426 std::to_string(input);
Michael Butlerda1a6922020-03-11 18:45:45 -0700427 validate(device, message, model,
428 [operation, input](Model* model, ExecutionPreference*) {
429 uint32_t operand = model->operations[operation].inputs[input];
430 model->operands[operand].numberOfConsumers--;
431 hidl_vec_removeAt(&model->operations[operation].inputs, input);
432 });
Michael Butler7ed61352018-03-22 16:37:57 -0700433 }
434 }
435}
436
437///////////////////////// REMOVE OPERATION OUTPUT /////////////////////////
438
Michael Butlere16af0a2019-08-29 22:17:24 -0700439static void removeOperationOutputTest(const sp<IDevice>& device, const Model& model) {
Michael Butler7ed61352018-03-22 16:37:57 -0700440 for (size_t operation = 0; operation < model.operations.size(); ++operation) {
441 for (size_t output = 0; output < model.operations[operation].outputs.size(); ++output) {
442 const std::string message = "removeOperationOutputTest: operation " +
443 std::to_string(operation) + ", output " +
444 std::to_string(output);
Michael Butlerda1a6922020-03-11 18:45:45 -0700445 validate(device, message, model,
446 [operation, output](Model* model, ExecutionPreference*) {
447 hidl_vec_removeAt(&model->operations[operation].outputs, output);
448 });
Michael Butler7ed61352018-03-22 16:37:57 -0700449 }
450 }
451}
452
453///////////////////////// MODEL VALIDATION /////////////////////////
454
455// TODO: remove model input
456// TODO: remove model output
457// TODO: add unused operation
458
459///////////////////////// ADD OPERATION INPUT /////////////////////////
460
Michael Butlere16af0a2019-08-29 22:17:24 -0700461static void addOperationInputTest(const sp<IDevice>& device, const Model& model) {
Michael Butler7ed61352018-03-22 16:37:57 -0700462 for (size_t operation = 0; operation < model.operations.size(); ++operation) {
463 const std::string message = "addOperationInputTest: operation " + std::to_string(operation);
Michael Butlerda1a6922020-03-11 18:45:45 -0700464 validate(device, message, model, [operation](Model* model, ExecutionPreference*) {
Michael Butler7ed61352018-03-22 16:37:57 -0700465 uint32_t index = addOperand(model, OperandLifeTime::MODEL_INPUT);
466 hidl_vec_push_back(&model->operations[operation].inputs, index);
467 hidl_vec_push_back(&model->inputIndexes, index);
468 });
469 }
470}
471
472///////////////////////// ADD OPERATION OUTPUT /////////////////////////
473
Michael Butlere16af0a2019-08-29 22:17:24 -0700474static void addOperationOutputTest(const sp<IDevice>& device, const Model& model) {
Michael Butler7ed61352018-03-22 16:37:57 -0700475 for (size_t operation = 0; operation < model.operations.size(); ++operation) {
476 const std::string message =
Slava Shklyaev1d6b4652019-05-14 14:15:14 +0100477 "addOperationOutputTest: operation " + std::to_string(operation);
Michael Butlerda1a6922020-03-11 18:45:45 -0700478 validate(device, message, model, [operation](Model* model, ExecutionPreference*) {
Michael Butler7ed61352018-03-22 16:37:57 -0700479 uint32_t index = addOperand(model, OperandLifeTime::MODEL_OUTPUT);
480 hidl_vec_push_back(&model->operations[operation].outputs, index);
481 hidl_vec_push_back(&model->outputIndexes, index);
482 });
483 }
484}
485
Michael Butlerf02692d2018-04-11 16:30:09 -0700486///////////////////////// VALIDATE EXECUTION PREFERENCE /////////////////////////
487
488static const int32_t invalidExecutionPreferences[] = {
Slava Shklyaev1d6b4652019-05-14 14:15:14 +0100489 static_cast<int32_t>(ExecutionPreference::LOW_POWER) - 1, // lower bound
490 static_cast<int32_t>(ExecutionPreference::SUSTAINED_SPEED) + 1, // upper bound
Michael Butlerf02692d2018-04-11 16:30:09 -0700491};
492
Michael Butlere16af0a2019-08-29 22:17:24 -0700493static void mutateExecutionPreferenceTest(const sp<IDevice>& device, const Model& model) {
Michael Butlerda1a6922020-03-11 18:45:45 -0700494 for (int32_t invalidPreference : invalidExecutionPreferences) {
Michael Butlerf02692d2018-04-11 16:30:09 -0700495 const std::string message =
Michael Butlerda1a6922020-03-11 18:45:45 -0700496 "mutateExecutionPreferenceTest: preference " + std::to_string(invalidPreference);
497 validate(device, message, model,
498 [invalidPreference](Model*, ExecutionPreference* preference) {
499 *preference = static_cast<ExecutionPreference>(invalidPreference);
500 });
Michael Butlerf02692d2018-04-11 16:30:09 -0700501 }
502}
503
Michael Butler7ed61352018-03-22 16:37:57 -0700504////////////////////////// ENTRY POINT //////////////////////////////
505
Michael Butlere16af0a2019-08-29 22:17:24 -0700506void validateModel(const sp<IDevice>& device, const Model& model) {
Michael Butler7ed61352018-03-22 16:37:57 -0700507 mutateOperandTypeTest(device, model);
508 mutateOperandRankTest(device, model);
509 mutateOperandScaleTest(device, model);
510 mutateOperandZeroPointTest(device, model);
511 mutateOperationOperandTypeTest(device, model);
512 mutateOperationTypeTest(device, model);
513 mutateOperationInputOperandIndexTest(device, model);
514 mutateOperationOutputOperandIndexTest(device, model);
515 removeOperandTest(device, model);
516 removeOperationTest(device, model);
517 removeOperationInputTest(device, model);
518 removeOperationOutputTest(device, model);
519 addOperationInputTest(device, model);
520 addOperationOutputTest(device, model);
Michael Butlerf02692d2018-04-11 16:30:09 -0700521 mutateExecutionPreferenceTest(device, model);
Michael Butler7ed61352018-03-22 16:37:57 -0700522}
523
Michael Butlerbbe5dad2019-08-26 23:55:47 -0700524} // namespace android::hardware::neuralnetworks::V1_1::vts::functional