1 //
2 // Copyright © 2017 Arm Ltd. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5 #pragma once
6
7 #ifndef LOG_TAG
8 #define LOG_TAG "ArmnnDriverTests"
9 #endif // LOG_TAG
10
11 #include "../ArmnnDriver.hpp"
12 #include <iosfwd>
13 #include <boost/test/unit_test.hpp>
14
15 #include <android/hidl/allocator/1.0/IAllocator.h>
16
17 using ::android::hidl::allocator::V1_0::IAllocator;
18
19 namespace android
20 {
21 namespace hardware
22 {
23 namespace neuralnetworks
24 {
25 namespace V1_0
26 {
27
28 std::ostream& operator<<(std::ostream& os, V1_0::ErrorStatus stat);
29
30 } // namespace android::hardware::neuralnetworks::V1_0
31
32 #ifdef ARMNN_ANDROID_NN_V1_3
33 namespace V1_3
34 {
35
36 std::ostream& operator<<(std::ostream& os, V1_3::ErrorStatus stat);
37
38 } // namespace android::hardware::neuralnetworks::V1_3
39 #endif
40
41 } // namespace android::hardware::neuralnetworks
42 } // namespace android::hardware
43 } // namespace android
44
45 namespace driverTestHelpers
46 {
47
48 std::ostream& operator<<(std::ostream& os, V1_0::ErrorStatus stat);
49
50 #ifdef ARMNN_ANDROID_NN_V1_3
51 std::ostream& operator<<(std::ostream& os, V1_3::ErrorStatus stat);
52 #endif
53
54 struct ExecutionCallback : public V1_0::IExecutionCallback
55 {
ExecutionCallbackdriverTestHelpers::ExecutionCallback56 ExecutionCallback() : mNotified(false) {}
57 Return<void> notify(V1_0::ErrorStatus status) override;
58 /// wait until the callback has notified us that it is done
59 Return<void> wait();
60
61 private:
62 // use a mutex and a condition variable to wait for asynchronous callbacks
63 std::mutex mMutex;
64 std::condition_variable mCondition;
65 // and a flag, in case we are notified before the wait call
66 bool mNotified;
67 };
68
69 class PreparedModelCallback : public V1_0::IPreparedModelCallback
70 {
71 public:
PreparedModelCallback()72 PreparedModelCallback()
73 : m_ErrorStatus(V1_0::ErrorStatus::NONE)
74 , m_PreparedModel()
75 { }
~PreparedModelCallback()76 ~PreparedModelCallback() override { }
77
78 Return<void> notify(V1_0::ErrorStatus status,
79 const android::sp<V1_0::IPreparedModel>& preparedModel) override;
GetErrorStatus()80 V1_0::ErrorStatus GetErrorStatus() { return m_ErrorStatus; }
GetPreparedModel()81 android::sp<V1_0::IPreparedModel> GetPreparedModel() { return m_PreparedModel; }
82
83 private:
84 V1_0::ErrorStatus m_ErrorStatus;
85 android::sp<V1_0::IPreparedModel> m_PreparedModel;
86 };
87
88 #if defined(ARMNN_ANDROID_NN_V1_2) || defined(ARMNN_ANDROID_NN_V1_3)
89
90 class PreparedModelCallback_1_2 : public V1_2::IPreparedModelCallback
91 {
92 public:
PreparedModelCallback_1_2()93 PreparedModelCallback_1_2()
94 : m_ErrorStatus(V1_0::ErrorStatus::NONE)
95 , m_PreparedModel()
96 , m_PreparedModel_1_2()
97 { }
~PreparedModelCallback_1_2()98 ~PreparedModelCallback_1_2() override { }
99
100 Return<void> notify(V1_0::ErrorStatus status, const android::sp<V1_0::IPreparedModel>& preparedModel) override;
101
102 Return<void> notify_1_2(V1_0::ErrorStatus status, const android::sp<V1_2::IPreparedModel>& preparedModel) override;
103
GetErrorStatus()104 V1_0::ErrorStatus GetErrorStatus() { return m_ErrorStatus; }
105
GetPreparedModel()106 android::sp<V1_0::IPreparedModel> GetPreparedModel() { return m_PreparedModel; }
107
GetPreparedModel_1_2()108 android::sp<V1_2::IPreparedModel> GetPreparedModel_1_2() { return m_PreparedModel_1_2; }
109
110 private:
111 V1_0::ErrorStatus m_ErrorStatus;
112 android::sp<V1_0::IPreparedModel> m_PreparedModel;
113 android::sp<V1_2::IPreparedModel> m_PreparedModel_1_2;
114 };
115
116 #endif
117
118 #ifdef ARMNN_ANDROID_NN_V1_3
119
120 class PreparedModelCallback_1_3 : public V1_3::IPreparedModelCallback
121 {
122 public:
PreparedModelCallback_1_3()123 PreparedModelCallback_1_3()
124 : m_1_0_ErrorStatus(V1_0::ErrorStatus::NONE)
125 , m_1_3_ErrorStatus(V1_3::ErrorStatus::NONE)
126 , m_PreparedModel()
127 , m_PreparedModel_1_2()
128 , m_PreparedModel_1_3()
129 { }
~PreparedModelCallback_1_3()130 ~PreparedModelCallback_1_3() override { }
131
132 Return<void> notify(V1_0::ErrorStatus status, const android::sp<V1_0::IPreparedModel>& preparedModel) override;
133
134 Return<void> notify_1_2(V1_0::ErrorStatus status, const android::sp<V1_2::IPreparedModel>& preparedModel) override;
135
136 Return<void> notify_1_3(V1_3::ErrorStatus status, const android::sp<V1_3::IPreparedModel>& preparedModel) override;
137
GetErrorStatus()138 V1_0::ErrorStatus GetErrorStatus() { return m_1_0_ErrorStatus; }
139
Get_1_3_ErrorStatus()140 V1_3::ErrorStatus Get_1_3_ErrorStatus() { return m_1_3_ErrorStatus; }
141
GetPreparedModel()142 android::sp<V1_0::IPreparedModel> GetPreparedModel() { return m_PreparedModel; }
143
GetPreparedModel_1_2()144 android::sp<V1_2::IPreparedModel> GetPreparedModel_1_2() { return m_PreparedModel_1_2; }
145
GetPreparedModel_1_3()146 android::sp<V1_3::IPreparedModel> GetPreparedModel_1_3() { return m_PreparedModel_1_3; }
147
148 private:
149 V1_0::ErrorStatus m_1_0_ErrorStatus;
150 V1_3::ErrorStatus m_1_3_ErrorStatus;
151 android::sp<V1_0::IPreparedModel> m_PreparedModel;
152 android::sp<V1_2::IPreparedModel> m_PreparedModel_1_2;
153 android::sp<V1_3::IPreparedModel> m_PreparedModel_1_3;
154 };
155
156 #endif
157
158 hidl_memory allocateSharedMemory(int64_t size);
159
160 template<typename T>
AddPoolAndGetData(uint32_t size,V1_0::Request & request)161 android::sp<IMemory> AddPoolAndGetData(uint32_t size, V1_0::Request& request)
162 {
163 hidl_memory pool;
164
165 android::sp<IAllocator> allocator = IAllocator::getService("ashmem");
166 allocator->allocate(sizeof(T) * size, [&](bool success, const hidl_memory& mem) {
167 BOOST_TEST(success);
168 pool = mem;
169 });
170
171 request.pools.resize(request.pools.size() + 1);
172 request.pools[request.pools.size() - 1] = pool;
173
174 android::sp<IMemory> mapped = mapMemory(pool);
175 mapped->update();
176 return mapped;
177 }
178
179 template<typename T>
AddPoolAndSetData(uint32_t size,V1_0::Request & request,const T * data)180 void AddPoolAndSetData(uint32_t size, V1_0::Request& request, const T* data)
181 {
182 android::sp<IMemory> memory = AddPoolAndGetData<T>(size, request);
183
184 T* dst = static_cast<T*>(static_cast<void*>(memory->getPointer()));
185
186 memcpy(dst, data, size * sizeof(T));
187 }
188
189 template<typename HalPolicy,
190 typename HalModel = typename HalPolicy::Model,
191 typename HalOperand = typename HalPolicy::Operand>
AddOperand(HalModel & model,const HalOperand & op)192 void AddOperand(HalModel& model, const HalOperand& op)
193 {
194 model.operands.resize(model.operands.size() + 1);
195 model.operands[model.operands.size() - 1] = op;
196 }
197
198 template<typename HalPolicy, typename HalModel = typename HalPolicy::Model>
AddBoolOperand(HalModel & model,bool value,uint32_t numberOfConsumers=1)199 void AddBoolOperand(HalModel& model, bool value, uint32_t numberOfConsumers = 1)
200 {
201 using HalOperand = typename HalPolicy::Operand;
202 using HalOperandType = typename HalPolicy::OperandType;
203 using HalOperandLifeTime = typename HalPolicy::OperandLifeTime;
204
205 DataLocation location = {};
206 location.offset = model.operandValues.size();
207 location.length = sizeof(uint8_t);
208
209 HalOperand op = {};
210 op.type = HalOperandType::BOOL;
211 op.dimensions = hidl_vec<uint32_t>{};
212 op.lifetime = HalOperandLifeTime::CONSTANT_COPY;
213 op.location = location;
214 op.numberOfConsumers = numberOfConsumers;
215
216 model.operandValues.resize(model.operandValues.size() + location.length);
217 *reinterpret_cast<uint8_t*>(&model.operandValues[location.offset]) = static_cast<uint8_t>(value);
218
219 AddOperand<HalModel>(model, op);
220 }
221
222 template<typename T>
223 OperandType TypeToOperandType();
224
225 template<>
226 OperandType TypeToOperandType<float>();
227
228 template<>
229 OperandType TypeToOperandType<int32_t>();
230
231 template<typename HalPolicy,
232 typename HalModel = typename HalPolicy::Model,
233 typename HalOperandType = typename HalPolicy::OperandType>
AddInputOperand(HalModel & model,const hidl_vec<uint32_t> & dimensions,HalOperandType operandType=HalOperandType::TENSOR_FLOAT32,double scale=0.f,int offset=0,uint32_t numberOfConsumers=1)234 void AddInputOperand(HalModel& model,
235 const hidl_vec<uint32_t>& dimensions,
236 HalOperandType operandType = HalOperandType::TENSOR_FLOAT32,
237 double scale = 0.f,
238 int offset = 0,
239 uint32_t numberOfConsumers = 1)
240 {
241 using HalOperand = typename HalPolicy::Operand;
242 using HalOperandLifeTime = typename HalPolicy::OperandLifeTime;
243
244 HalOperand op = {};
245 op.type = operandType;
246 op.scale = scale;
247 op.zeroPoint = offset;
248 op.dimensions = dimensions;
249 op.lifetime = HalOperandLifeTime::MODEL_INPUT;
250 op.numberOfConsumers = numberOfConsumers;
251
252 AddOperand<HalPolicy>(model, op);
253
254 model.inputIndexes.resize(model.inputIndexes.size() + 1);
255 model.inputIndexes[model.inputIndexes.size() - 1] = model.operands.size() - 1;
256 }
257
258 template<typename HalPolicy,
259 typename HalModel = typename HalPolicy::Model,
260 typename HalOperandType = typename HalPolicy::OperandType>
AddOutputOperand(HalModel & model,const hidl_vec<uint32_t> & dimensions,HalOperandType operandType=HalOperandType::TENSOR_FLOAT32,double scale=0.f,int offset=0,uint32_t numberOfConsumers=0)261 void AddOutputOperand(HalModel& model,
262 const hidl_vec<uint32_t>& dimensions,
263 HalOperandType operandType = HalOperandType::TENSOR_FLOAT32,
264 double scale = 0.f,
265 int offset = 0,
266 uint32_t numberOfConsumers = 0)
267 {
268 using HalOperand = typename HalPolicy::Operand;
269 using HalOperandLifeTime = typename HalPolicy::OperandLifeTime;
270
271 HalOperand op = {};
272 op.type = operandType;
273 op.scale = scale;
274 op.zeroPoint = offset;
275 op.dimensions = dimensions;
276 op.lifetime = HalOperandLifeTime::MODEL_OUTPUT;
277 op.numberOfConsumers = numberOfConsumers;
278
279 AddOperand<HalPolicy>(model, op);
280
281 model.outputIndexes.resize(model.outputIndexes.size() + 1);
282 model.outputIndexes[model.outputIndexes.size() - 1] = model.operands.size() - 1;
283 }
284
285 android::sp<V1_0::IPreparedModel> PrepareModelWithStatus(const V1_0::Model& model,
286 armnn_driver::ArmnnDriver& driver,
287 V1_0::ErrorStatus& prepareStatus,
288 V1_0::ErrorStatus expectedStatus = V1_0::ErrorStatus::NONE);
289
290 #if defined(ARMNN_ANDROID_NN_V1_1) || defined(ARMNN_ANDROID_NN_V1_2) || defined(ARMNN_ANDROID_NN_V1_3)
291
292 android::sp<V1_0::IPreparedModel> PrepareModelWithStatus(const V1_1::Model& model,
293 armnn_driver::ArmnnDriver& driver,
294 V1_0::ErrorStatus& prepareStatus,
295 V1_0::ErrorStatus expectedStatus = V1_0::ErrorStatus::NONE);
296
297 #endif
298
299 template<typename HalModel>
PrepareModel(const HalModel & model,armnn_driver::ArmnnDriver & driver)300 android::sp<V1_0::IPreparedModel> PrepareModel(const HalModel& model,
301 armnn_driver::ArmnnDriver& driver)
302 {
303 V1_0::ErrorStatus prepareStatus = V1_0::ErrorStatus::NONE;
304 return PrepareModelWithStatus(model, driver, prepareStatus);
305 }
306
307 #if defined(ARMNN_ANDROID_NN_V1_2) || defined(ARMNN_ANDROID_NN_V1_3)
308
309 android::sp<V1_2::IPreparedModel> PrepareModelWithStatus_1_2(const armnn_driver::hal_1_2::HalPolicy::Model& model,
310 armnn_driver::ArmnnDriver& driver,
311 V1_0::ErrorStatus& prepareStatus,
312 V1_0::ErrorStatus expectedStatus = V1_0::ErrorStatus::NONE);
313
314 template<typename HalModel>
PrepareModel_1_2(const HalModel & model,armnn_driver::ArmnnDriver & driver)315 android::sp<V1_2::IPreparedModel> PrepareModel_1_2(const HalModel& model,
316 armnn_driver::ArmnnDriver& driver)
317 {
318 V1_0::ErrorStatus prepareStatus = V1_0::ErrorStatus::NONE;
319 return PrepareModelWithStatus_1_2(model, driver, prepareStatus);
320 }
321
322 #endif
323
324 #ifdef ARMNN_ANDROID_NN_V1_3
325
326 template<typename HalPolicy>
AddOperand(armnn_driver::hal_1_3::HalPolicy::Model & model,const armnn_driver::hal_1_3::HalPolicy::Operand & op)327 void AddOperand(armnn_driver::hal_1_3::HalPolicy::Model& model,
328 const armnn_driver::hal_1_3::HalPolicy::Operand& op)
329 {
330 model.main.operands.resize(model.main.operands.size() + 1);
331 model.main.operands[model.main.operands.size() - 1] = op;
332 }
333
334 template<typename HalPolicy>
AddInputOperand(armnn_driver::hal_1_3::HalPolicy::Model & model,const hidl_vec<uint32_t> & dimensions,armnn_driver::hal_1_3::HalPolicy::OperandType operandType=armnn_driver::hal_1_3::HalPolicy::OperandType::TENSOR_FLOAT32,double scale=0.f,int offset=0,uint32_t numberOfConsumers=1)335 void AddInputOperand(armnn_driver::hal_1_3::HalPolicy::Model& model,
336 const hidl_vec<uint32_t>& dimensions,
337 armnn_driver::hal_1_3::HalPolicy::OperandType operandType =
338 armnn_driver::hal_1_3::HalPolicy::OperandType::TENSOR_FLOAT32,
339 double scale = 0.f,
340 int offset = 0,
341 uint32_t numberOfConsumers = 1)
342 {
343 using HalOperand = typename armnn_driver::hal_1_3::HalPolicy::Operand;
344 using HalOperandLifeTime = typename armnn_driver::hal_1_3::HalPolicy::OperandLifeTime;
345
346 HalOperand op = {};
347 op.type = operandType;
348 op.scale = scale;
349 op.zeroPoint = offset;
350 op.dimensions = dimensions;
351 op.lifetime = HalOperandLifeTime::SUBGRAPH_INPUT;
352 op.numberOfConsumers = numberOfConsumers;
353
354 AddOperand<HalPolicy>(model, op);
355
356 model.main.inputIndexes.resize(model.main.inputIndexes.size() + 1);
357 model.main.inputIndexes[model.main.inputIndexes.size() - 1] = model.main.operands.size() - 1;
358 }
359
360 template<typename HalPolicy>
AddOutputOperand(armnn_driver::hal_1_3::HalPolicy::Model & model,const hidl_vec<uint32_t> & dimensions,armnn_driver::hal_1_3::HalPolicy::OperandType operandType=armnn_driver::hal_1_3::HalPolicy::OperandType::TENSOR_FLOAT32,double scale=0.f,int offset=0,uint32_t numberOfConsumers=0)361 void AddOutputOperand(armnn_driver::hal_1_3::HalPolicy::Model& model,
362 const hidl_vec<uint32_t>& dimensions,
363 armnn_driver::hal_1_3::HalPolicy::OperandType operandType =
364 armnn_driver::hal_1_3::HalPolicy::OperandType::TENSOR_FLOAT32,
365 double scale = 0.f,
366 int offset = 0,
367 uint32_t numberOfConsumers = 0)
368 {
369 using HalOperand = typename armnn_driver::hal_1_3::HalPolicy::Operand;
370 using HalOperandLifeTime = typename armnn_driver::hal_1_3::HalPolicy::OperandLifeTime;
371
372 HalOperand op = {};
373 op.type = operandType;
374 op.scale = scale;
375 op.zeroPoint = offset;
376 op.dimensions = dimensions;
377 op.lifetime = HalOperandLifeTime::SUBGRAPH_OUTPUT;
378 op.numberOfConsumers = numberOfConsumers;
379
380 AddOperand<HalPolicy>(model, op);
381
382 model.main.outputIndexes.resize(model.main.outputIndexes.size() + 1);
383 model.main.outputIndexes[model.main.outputIndexes.size() - 1] = model.main.operands.size() - 1;
384 }
385
386 android::sp<V1_3::IPreparedModel> PrepareModelWithStatus_1_3(const armnn_driver::hal_1_3::HalPolicy::Model& model,
387 armnn_driver::ArmnnDriver& driver,
388 V1_3::ErrorStatus& prepareStatus,
389 V1_3::Priority priority = V1_3::Priority::LOW);
390
391 template<typename HalModel>
PrepareModel_1_3(const HalModel & model,armnn_driver::ArmnnDriver & driver)392 android::sp<V1_3::IPreparedModel> PrepareModel_1_3(const HalModel& model,
393 armnn_driver::ArmnnDriver& driver)
394 {
395 V1_3::ErrorStatus prepareStatus = V1_3::ErrorStatus::NONE;
396 return PrepareModelWithStatus_1_3(model, driver, prepareStatus);
397 }
398
399 #endif
400
401 template<typename HalPolicy,
402 typename T,
403 typename HalModel = typename HalPolicy::Model,
404 typename HalOperandType = typename HalPolicy::OperandType,
405 typename HalOperandLifeTime = typename HalPolicy::OperandLifeTime>
AddTensorOperand(HalModel & model,const hidl_vec<uint32_t> & dimensions,const T * values,HalOperandType operandType=HalOperandType::TENSOR_FLOAT32,HalOperandLifeTime operandLifeTime=V1_0::OperandLifeTime::CONSTANT_COPY,double scale=0.f,int offset=0,uint32_t numberOfConsumers=1)406 void AddTensorOperand(HalModel& model,
407 const hidl_vec<uint32_t>& dimensions,
408 const T* values,
409 HalOperandType operandType = HalOperandType::TENSOR_FLOAT32,
410 HalOperandLifeTime operandLifeTime = V1_0::OperandLifeTime::CONSTANT_COPY,
411 double scale = 0.f,
412 int offset = 0,
413 uint32_t numberOfConsumers = 1)
414 {
415 using HalOperand = typename HalPolicy::Operand;
416
417 uint32_t totalElements = 1;
418 for (uint32_t dim : dimensions)
419 {
420 totalElements *= dim;
421 }
422
423 DataLocation location = {};
424 location.length = totalElements * sizeof(T);
425
426 if(operandLifeTime == HalOperandLifeTime::CONSTANT_COPY)
427 {
428 location.offset = model.operandValues.size();
429 }
430
431 HalOperand op = {};
432 op.type = operandType;
433 op.dimensions = dimensions;
434 op.scale = scale;
435 op.zeroPoint = offset;
436 op.lifetime = HalOperandLifeTime::CONSTANT_COPY;
437 op.location = location;
438 op.numberOfConsumers = numberOfConsumers;
439
440 model.operandValues.resize(model.operandValues.size() + location.length);
441 for (uint32_t i = 0; i < totalElements; i++)
442 {
443 *(reinterpret_cast<T*>(&model.operandValues[location.offset]) + i) = values[i];
444 }
445
446 AddOperand<HalPolicy>(model, op);
447 }
448
449 template<typename HalPolicy,
450 typename T,
451 typename HalModel = typename HalPolicy::Model,
452 typename HalOperandType = typename HalPolicy::OperandType,
453 typename HalOperandLifeTime = typename HalPolicy::OperandLifeTime>
AddTensorOperand(HalModel & model,const hidl_vec<uint32_t> & dimensions,const std::vector<T> & values,HalOperandType operandType=HalPolicy::OperandType::TENSOR_FLOAT32,HalOperandLifeTime operandLifeTime=V1_0::OperandLifeTime::CONSTANT_COPY,double scale=0.f,int offset=0,uint32_t numberOfConsumers=1)454 void AddTensorOperand(HalModel& model,
455 const hidl_vec<uint32_t>& dimensions,
456 const std::vector<T>& values,
457 HalOperandType operandType = HalPolicy::OperandType::TENSOR_FLOAT32,
458 HalOperandLifeTime operandLifeTime = V1_0::OperandLifeTime::CONSTANT_COPY,
459 double scale = 0.f,
460 int offset = 0,
461 uint32_t numberOfConsumers = 1)
462 {
463 AddTensorOperand<HalPolicy, T>(model,
464 dimensions,
465 values.data(),
466 operandType,
467 operandLifeTime,
468 scale,
469 offset,
470 numberOfConsumers);
471 }
472
473 template<typename HalPolicy, typename HalModel = typename HalPolicy::Model>
AddIntOperand(HalModel & model,int32_t value,uint32_t numberOfConsumers=1)474 void AddIntOperand(HalModel& model, int32_t value, uint32_t numberOfConsumers = 1)
475 {
476 using HalOperand = typename HalPolicy::Operand;
477 using HalOperandType = typename HalPolicy::OperandType;
478 using HalOperandLifeTime = typename HalPolicy::OperandLifeTime;
479
480 DataLocation location = {};
481 location.offset = model.operandValues.size();
482 location.length = sizeof(int32_t);
483
484 HalOperand op = {};
485 op.type = HalOperandType::INT32;
486 op.dimensions = hidl_vec<uint32_t>{};
487 op.lifetime = HalOperandLifeTime::CONSTANT_COPY;
488 op.location = location;
489 op.numberOfConsumers = numberOfConsumers;
490
491 model.operandValues.resize(model.operandValues.size() + location.length);
492 *reinterpret_cast<int32_t*>(&model.operandValues[location.offset]) = value;
493
494 AddOperand<HalPolicy>(model, op);
495 }
496
497 template<typename HalPolicy, typename HalModel = typename HalPolicy::Model>
AddFloatOperand(HalModel & model,float value,uint32_t numberOfConsumers=1)498 void AddFloatOperand(HalModel& model,
499 float value,
500 uint32_t numberOfConsumers = 1)
501 {
502 using HalOperand = typename HalPolicy::Operand;
503 using HalOperandType = typename HalPolicy::OperandType;
504 using HalOperandLifeTime = typename HalPolicy::OperandLifeTime;
505
506 DataLocation location = {};
507 location.offset = model.operandValues.size();
508 location.length = sizeof(float);
509
510 HalOperand op = {};
511 op.type = HalOperandType::FLOAT32;
512 op.dimensions = hidl_vec<uint32_t>{};
513 op.lifetime = HalOperandLifeTime::CONSTANT_COPY;
514 op.location = location;
515 op.numberOfConsumers = numberOfConsumers;
516
517 model.operandValues.resize(model.operandValues.size() + location.length);
518 *reinterpret_cast<float*>(&model.operandValues[location.offset]) = value;
519
520 AddOperand<HalPolicy>(model, op);
521 }
522
523 V1_0::ErrorStatus Execute(android::sp<V1_0::IPreparedModel> preparedModel,
524 const V1_0::Request& request,
525 V1_0::ErrorStatus expectedStatus = V1_0::ErrorStatus::NONE);
526
527 android::sp<ExecutionCallback> ExecuteNoWait(android::sp<V1_0::IPreparedModel> preparedModel,
528 const V1_0::Request& request);
529
530 } // namespace driverTestHelpers
531