1 /*
2 * Copyright (C) 2020 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 #include "MockBurstContext.h"
18 #include "MockFencedExecutionCallback.h"
19 #include "MockPreparedModel.h"
20
21 #include <android/hardware/neuralnetworks/1.3/IExecutionCallback.h>
22 #include <android/hardware/neuralnetworks/1.3/IFencedExecutionCallback.h>
23 #include <gmock/gmock.h>
24 #include <gtest/gtest.h>
25 #include <nnapi/IExecution.h>
26 #include <nnapi/IPreparedModel.h>
27 #include <nnapi/TypeUtils.h>
28 #include <nnapi/Types.h>
29 #include <nnapi/hal/1.3/PreparedModel.h>
30
31 #include <functional>
32 #include <memory>
33
34 namespace android::hardware::neuralnetworks::V1_3::utils {
35 namespace {
36
37 using ::testing::_;
38 using ::testing::Invoke;
39 using ::testing::InvokeWithoutArgs;
40
41 const sp<V1_3::IPreparedModel> kInvalidPreparedModel;
42 constexpr auto kNoTiming = V1_2::Timing{.timeOnDevice = std::numeric_limits<uint64_t>::max(),
43 .timeInDriver = std::numeric_limits<uint64_t>::max()};
44
createMockPreparedModel()45 sp<MockPreparedModel> createMockPreparedModel() {
46 const auto mockPreparedModel = MockPreparedModel::create();
47
48 // Ensure that older calls are not used.
49 EXPECT_CALL(*mockPreparedModel, execute(_, _)).Times(0);
50 EXPECT_CALL(*mockPreparedModel, execute_1_2(_, _, _)).Times(0);
51 EXPECT_CALL(*mockPreparedModel, executeSynchronously(_, _, _)).Times(0);
52
53 return mockPreparedModel;
54 }
55
makeExecuteSynchronously(V1_3::ErrorStatus status,const std::vector<V1_2::OutputShape> & outputShapes,const V1_2::Timing & timing)56 auto makeExecuteSynchronously(V1_3::ErrorStatus status,
57 const std::vector<V1_2::OutputShape>& outputShapes,
58 const V1_2::Timing& timing) {
59 return [status, outputShapes, timing](
60 const V1_3::Request& /*request*/, V1_2::MeasureTiming /*measureTiming*/,
61 const V1_3::OptionalTimePoint& /*deadline*/,
62 const V1_3::OptionalTimeoutDuration& /*loopTimeoutDuration*/,
63 const V1_3::IPreparedModel::executeSynchronously_1_3_cb& cb) {
64 cb(status, outputShapes, timing);
65 return hardware::Void();
66 };
67 }
makeExecuteAsynchronously(V1_3::ErrorStatus launchStatus,V1_3::ErrorStatus returnStatus,const std::vector<V1_2::OutputShape> & outputShapes,const V1_2::Timing & timing)68 auto makeExecuteAsynchronously(V1_3::ErrorStatus launchStatus, V1_3::ErrorStatus returnStatus,
69 const std::vector<V1_2::OutputShape>& outputShapes,
70 const V1_2::Timing& timing) {
71 return [launchStatus, returnStatus, outputShapes, timing](
72 const V1_3::Request& /*request*/, V1_2::MeasureTiming /*measureTiming*/,
73 const V1_3::OptionalTimePoint& /*deadline*/,
74 const V1_3::OptionalTimeoutDuration& /*loopTimeoutDuration*/,
75 const sp<V1_3::IExecutionCallback>& cb) -> Return<V1_3::ErrorStatus> {
76 cb->notify_1_3(returnStatus, outputShapes, timing);
77 return launchStatus;
78 };
79 }
makeExecuteFencedReturn(V1_3::ErrorStatus status,const hardware::hidl_handle & syncFence,const sp<V1_3::IFencedExecutionCallback> & dispatchCallback)80 auto makeExecuteFencedReturn(V1_3::ErrorStatus status, const hardware::hidl_handle& syncFence,
81 const sp<V1_3::IFencedExecutionCallback>& dispatchCallback) {
82 return [status, syncFence, dispatchCallback](
83 const V1_3::Request& /*request*/,
84 const hardware::hidl_vec<hardware::hidl_handle>& /*waitFor*/,
85 V1_2::MeasureTiming /*measure*/, const V1_3::OptionalTimePoint& /*deadline*/,
86 const V1_3::OptionalTimeoutDuration& /*loopTimeoutDuration*/,
87 const V1_3::OptionalTimeoutDuration& /*duration*/,
88 const V1_3::IPreparedModel::executeFenced_cb& cb) {
89 cb(status, syncFence, dispatchCallback);
90 return hardware::Void();
91 };
92 }
makeExecuteFencedCallbackReturn(V1_3::ErrorStatus status,const V1_2::Timing & timingA,const V1_2::Timing & timingB)93 auto makeExecuteFencedCallbackReturn(V1_3::ErrorStatus status, const V1_2::Timing& timingA,
94 const V1_2::Timing& timingB) {
95 return [status, timingA,
96 timingB](const V1_3::IFencedExecutionCallback::getExecutionInfo_cb& cb) {
97 cb(status, timingA, timingB);
98 return hardware::Void();
99 };
100 }
makeConfigureExecutionBurstReturn(V1_0::ErrorStatus status,const sp<MockBurstContext> & burstContext)101 auto makeConfigureExecutionBurstReturn(V1_0::ErrorStatus status,
102 const sp<MockBurstContext>& burstContext) {
103 return [status, burstContext](
104 const sp<V1_2::IBurstCallback>& /*callback*/,
105 const MQDescriptorSync<V1_2::FmqRequestDatum>& /*requestChannel*/,
106 const MQDescriptorSync<V1_2::FmqResultDatum>& /*resultChannel*/,
107 V1_2::IPreparedModel::configureExecutionBurst_cb cb) -> hardware::Return<void> {
108 cb(status, burstContext);
109 return hardware::Void();
110 };
111 }
112
makeTransportFailure(status_t status)113 std::function<hardware::Status()> makeTransportFailure(status_t status) {
114 return [status] { return hardware::Status::fromStatusT(status); };
115 }
116
117 const auto makeGeneralTransportFailure = makeTransportFailure(NO_MEMORY);
118 const auto makeDeadObjectFailure = makeTransportFailure(DEAD_OBJECT);
119
120 } // namespace
121
TEST(PreparedModelTest,invalidPreparedModel)122 TEST(PreparedModelTest, invalidPreparedModel) {
123 // run test
124 const auto result = PreparedModel::create(kInvalidPreparedModel, /*executeSynchronously=*/true);
125
126 // verify result
127 ASSERT_FALSE(result.has_value());
128 EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
129 }
130
TEST(PreparedModelTest,linkToDeathError)131 TEST(PreparedModelTest, linkToDeathError) {
132 // setup call
133 const auto mockPreparedModel = createMockPreparedModel();
134 const auto ret = []() -> Return<bool> { return false; };
135 EXPECT_CALL(*mockPreparedModel, linkToDeathRet()).Times(1).WillOnce(InvokeWithoutArgs(ret));
136
137 // run test
138 const auto result = PreparedModel::create(mockPreparedModel, /*executeSynchronously=*/true);
139
140 // verify result
141 ASSERT_FALSE(result.has_value());
142 EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
143 }
144
TEST(PreparedModelTest,linkToDeathTransportFailure)145 TEST(PreparedModelTest, linkToDeathTransportFailure) {
146 // setup call
147 const auto mockPreparedModel = createMockPreparedModel();
148 EXPECT_CALL(*mockPreparedModel, linkToDeathRet())
149 .Times(1)
150 .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure));
151
152 // run test
153 const auto result = PreparedModel::create(mockPreparedModel, /*executeSynchronously=*/true);
154
155 // verify result
156 ASSERT_FALSE(result.has_value());
157 EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
158 }
159
TEST(PreparedModelTest,linkToDeathDeadObject)160 TEST(PreparedModelTest, linkToDeathDeadObject) {
161 // setup call
162 const auto mockPreparedModel = createMockPreparedModel();
163 EXPECT_CALL(*mockPreparedModel, linkToDeathRet())
164 .Times(1)
165 .WillOnce(InvokeWithoutArgs(makeDeadObjectFailure));
166
167 // run test
168 const auto result = PreparedModel::create(mockPreparedModel, /*executeSynchronously=*/true);
169
170 // verify result
171 ASSERT_FALSE(result.has_value());
172 EXPECT_EQ(result.error().code, nn::ErrorStatus::DEAD_OBJECT);
173 }
174
TEST(PreparedModelTest,executeSync)175 TEST(PreparedModelTest, executeSync) {
176 // setup call
177 const auto mockPreparedModel = createMockPreparedModel();
178 const auto preparedModel =
179 PreparedModel::create(mockPreparedModel, /*executeSynchronously=*/true).value();
180 EXPECT_CALL(*mockPreparedModel, executeSynchronously_1_3(_, _, _, _, _))
181 .Times(1)
182 .WillOnce(Invoke(makeExecuteSynchronously(V1_3::ErrorStatus::NONE, {}, kNoTiming)));
183
184 // run test
185 const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
186
187 // verify result
188 EXPECT_TRUE(result.has_value())
189 << "Failed with " << result.error().code << ": " << result.error().message;
190 }
191
TEST(PreparedModelTest,executeSyncError)192 TEST(PreparedModelTest, executeSyncError) {
193 // setup test
194 const auto mockPreparedModel = createMockPreparedModel();
195 const auto preparedModel =
196 PreparedModel::create(mockPreparedModel, /*executeSynchronously=*/true).value();
197 EXPECT_CALL(*mockPreparedModel, executeSynchronously_1_3(_, _, _, _, _))
198 .Times(1)
199 .WillOnce(Invoke(
200 makeExecuteSynchronously(V1_3::ErrorStatus::GENERAL_FAILURE, {}, kNoTiming)));
201
202 // run test
203 const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
204
205 // verify result
206 ASSERT_FALSE(result.has_value());
207 EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
208 }
209
TEST(PreparedModelTest,executeSyncTransportFailure)210 TEST(PreparedModelTest, executeSyncTransportFailure) {
211 // setup test
212 const auto mockPreparedModel = createMockPreparedModel();
213 const auto preparedModel =
214 PreparedModel::create(mockPreparedModel, /*executeSynchronously=*/true).value();
215 EXPECT_CALL(*mockPreparedModel, executeSynchronously_1_3(_, _, _, _, _))
216 .Times(1)
217 .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure));
218
219 // run test
220 const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
221
222 // verify result
223 ASSERT_FALSE(result.has_value());
224 EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
225 }
226
TEST(PreparedModelTest,executeSyncDeadObject)227 TEST(PreparedModelTest, executeSyncDeadObject) {
228 // setup test
229 const auto mockPreparedModel = createMockPreparedModel();
230 const auto preparedModel =
231 PreparedModel::create(mockPreparedModel, /*executeSynchronously=*/true).value();
232 EXPECT_CALL(*mockPreparedModel, executeSynchronously_1_3(_, _, _, _, _))
233 .Times(1)
234 .WillOnce(InvokeWithoutArgs(makeDeadObjectFailure));
235
236 // run test
237 const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
238
239 // verify result
240 ASSERT_FALSE(result.has_value());
241 EXPECT_EQ(result.error().code, nn::ErrorStatus::DEAD_OBJECT);
242 }
243
TEST(PreparedModelTest,executeAsync)244 TEST(PreparedModelTest, executeAsync) {
245 // setup call
246 const auto mockPreparedModel = createMockPreparedModel();
247 const auto preparedModel =
248 PreparedModel::create(mockPreparedModel, /*executeSynchronously=*/false).value();
249 EXPECT_CALL(*mockPreparedModel, execute_1_3(_, _, _, _, _))
250 .Times(1)
251 .WillOnce(Invoke(makeExecuteAsynchronously(V1_3::ErrorStatus::NONE,
252 V1_3::ErrorStatus::NONE, {}, kNoTiming)));
253
254 // run test
255 const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
256
257 // verify result
258 EXPECT_TRUE(result.has_value())
259 << "Failed with " << result.error().code << ": " << result.error().message;
260 }
261
TEST(PreparedModelTest,executeAsyncLaunchError)262 TEST(PreparedModelTest, executeAsyncLaunchError) {
263 // setup test
264 const auto mockPreparedModel = createMockPreparedModel();
265 const auto preparedModel =
266 PreparedModel::create(mockPreparedModel, /*executeSynchronously=*/false).value();
267 EXPECT_CALL(*mockPreparedModel, execute_1_3(_, _, _, _, _))
268 .Times(1)
269 .WillOnce(Invoke(makeExecuteAsynchronously(V1_3::ErrorStatus::GENERAL_FAILURE,
270 V1_3::ErrorStatus::GENERAL_FAILURE, {},
271 kNoTiming)));
272
273 // run test
274 const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
275
276 // verify result
277 ASSERT_FALSE(result.has_value());
278 EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
279 }
280
TEST(PreparedModelTest,executeAsyncReturnError)281 TEST(PreparedModelTest, executeAsyncReturnError) {
282 // setup test
283 const auto mockPreparedModel = createMockPreparedModel();
284 const auto preparedModel =
285 PreparedModel::create(mockPreparedModel, /*executeSynchronously=*/false).value();
286 EXPECT_CALL(*mockPreparedModel, execute_1_3(_, _, _, _, _))
287 .Times(1)
288 .WillOnce(Invoke(makeExecuteAsynchronously(
289 V1_3::ErrorStatus::NONE, V1_3::ErrorStatus::GENERAL_FAILURE, {}, kNoTiming)));
290
291 // run test
292 const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
293
294 // verify result
295 ASSERT_FALSE(result.has_value());
296 EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
297 }
298
TEST(PreparedModelTest,executeAsyncTransportFailure)299 TEST(PreparedModelTest, executeAsyncTransportFailure) {
300 // setup test
301 const auto mockPreparedModel = createMockPreparedModel();
302 const auto preparedModel =
303 PreparedModel::create(mockPreparedModel, /*executeSynchronously=*/false).value();
304 EXPECT_CALL(*mockPreparedModel, execute_1_3(_, _, _, _, _))
305 .Times(1)
306 .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure));
307
308 // run test
309 const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
310
311 // verify result
312 ASSERT_FALSE(result.has_value());
313 EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
314 }
315
TEST(PreparedModelTest,executeAsyncDeadObject)316 TEST(PreparedModelTest, executeAsyncDeadObject) {
317 // setup test
318 const auto mockPreparedModel = createMockPreparedModel();
319 const auto preparedModel =
320 PreparedModel::create(mockPreparedModel, /*executeSynchronously=*/false).value();
321 EXPECT_CALL(*mockPreparedModel, execute_1_3(_, _, _, _, _))
322 .Times(1)
323 .WillOnce(InvokeWithoutArgs(makeDeadObjectFailure));
324
325 // run test
326 const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
327
328 // verify result
329 ASSERT_FALSE(result.has_value());
330 EXPECT_EQ(result.error().code, nn::ErrorStatus::DEAD_OBJECT);
331 }
332
TEST(PreparedModelTest,executeAsyncCrash)333 TEST(PreparedModelTest, executeAsyncCrash) {
334 // setup test
335 const auto mockPreparedModel = createMockPreparedModel();
336 const auto preparedModel =
337 PreparedModel::create(mockPreparedModel, /*executeSynchronously=*/false).value();
338 const auto ret = [&mockPreparedModel]() -> hardware::Return<V1_3::ErrorStatus> {
339 mockPreparedModel->simulateCrash();
340 return V1_3::ErrorStatus::NONE;
341 };
342 EXPECT_CALL(*mockPreparedModel, execute_1_3(_, _, _, _, _))
343 .Times(1)
344 .WillOnce(InvokeWithoutArgs(ret));
345
346 // run test
347 const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
348
349 // verify result
350 ASSERT_FALSE(result.has_value());
351 EXPECT_EQ(result.error().code, nn::ErrorStatus::DEAD_OBJECT);
352 }
353
TEST(PreparedModelTest,executeFenced)354 TEST(PreparedModelTest, executeFenced) {
355 // setup call
356 const auto mockPreparedModel = createMockPreparedModel();
357 const auto preparedModel =
358 PreparedModel::create(mockPreparedModel, /*executeSynchronously=*/true).value();
359 const auto mockCallback = MockFencedExecutionCallback::create();
360 EXPECT_CALL(*mockCallback, getExecutionInfo(_))
361 .Times(1)
362 .WillOnce(Invoke(makeExecuteFencedCallbackReturn(V1_3::ErrorStatus::NONE, kNoTiming,
363 kNoTiming)));
364 EXPECT_CALL(*mockPreparedModel, executeFenced(_, _, _, _, _, _, _))
365 .Times(1)
366 .WillOnce(Invoke(makeExecuteFencedReturn(V1_3::ErrorStatus::NONE, {}, mockCallback)));
367
368 // run test
369 const auto result = preparedModel->executeFenced({}, {}, {}, {}, {}, {}, {}, {});
370
371 // verify result
372 ASSERT_TRUE(result.has_value())
373 << "Failed with " << result.error().code << ": " << result.error().message;
374 const auto& [syncFence, callback] = result.value();
375 EXPECT_EQ(syncFence.syncWait({}), nn::SyncFence::FenceState::SIGNALED);
376 ASSERT_NE(callback, nullptr);
377
378 // get results from callback
379 const auto callbackResult = callback();
380 ASSERT_TRUE(callbackResult.has_value()) << "Failed with " << callbackResult.error().code << ": "
381 << callbackResult.error().message;
382 }
383
TEST(PreparedModelTest,executeFencedCallbackError)384 TEST(PreparedModelTest, executeFencedCallbackError) {
385 // setup call
386 const auto mockPreparedModel = createMockPreparedModel();
387 const auto preparedModel =
388 PreparedModel::create(mockPreparedModel, /*executeSynchronously=*/true).value();
389 const auto mockCallback = MockFencedExecutionCallback::create();
390 EXPECT_CALL(*mockCallback, getExecutionInfo(_))
391 .Times(1)
392 .WillOnce(Invoke(makeExecuteFencedCallbackReturn(V1_3::ErrorStatus::GENERAL_FAILURE,
393 kNoTiming, kNoTiming)));
394 EXPECT_CALL(*mockPreparedModel, executeFenced(_, _, _, _, _, _, _))
395 .Times(1)
396 .WillOnce(Invoke(makeExecuteFencedReturn(V1_3::ErrorStatus::NONE, {}, mockCallback)));
397
398 // run test
399 const auto result = preparedModel->executeFenced({}, {}, {}, {}, {}, {}, {}, {});
400
401 // verify result
402 ASSERT_TRUE(result.has_value())
403 << "Failed with " << result.error().code << ": " << result.error().message;
404 const auto& [syncFence, callback] = result.value();
405 EXPECT_NE(syncFence.syncWait({}), nn::SyncFence::FenceState::ACTIVE);
406 ASSERT_NE(callback, nullptr);
407
408 // verify callback failure
409 const auto callbackResult = callback();
410 ASSERT_FALSE(callbackResult.has_value());
411 EXPECT_EQ(callbackResult.error().code, nn::ErrorStatus::GENERAL_FAILURE);
412 }
413
TEST(PreparedModelTest,executeFencedError)414 TEST(PreparedModelTest, executeFencedError) {
415 // setup test
416 const auto mockPreparedModel = createMockPreparedModel();
417 const auto preparedModel =
418 PreparedModel::create(mockPreparedModel, /*executeSynchronously=*/true).value();
419 EXPECT_CALL(*mockPreparedModel, executeFenced(_, _, _, _, _, _, _))
420 .Times(1)
421 .WillOnce(Invoke(
422 makeExecuteFencedReturn(V1_3::ErrorStatus::GENERAL_FAILURE, {}, nullptr)));
423
424 // run test
425 const auto result = preparedModel->executeFenced({}, {}, {}, {}, {}, {}, {}, {});
426
427 // verify result
428 ASSERT_FALSE(result.has_value());
429 EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
430 }
431
TEST(PreparedModelTest,executeFencedTransportFailure)432 TEST(PreparedModelTest, executeFencedTransportFailure) {
433 // setup test
434 const auto mockPreparedModel = createMockPreparedModel();
435 const auto preparedModel =
436 PreparedModel::create(mockPreparedModel, /*executeSynchronously=*/true).value();
437 EXPECT_CALL(*mockPreparedModel, executeFenced(_, _, _, _, _, _, _))
438 .Times(1)
439 .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure));
440
441 // run test
442 const auto result = preparedModel->executeFenced({}, {}, {}, {}, {}, {}, {}, {});
443
444 // verify result
445 ASSERT_FALSE(result.has_value());
446 EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
447 }
448
TEST(PreparedModelTest,executeFencedDeadObject)449 TEST(PreparedModelTest, executeFencedDeadObject) {
450 // setup test
451 const auto mockPreparedModel = createMockPreparedModel();
452 const auto preparedModel =
453 PreparedModel::create(mockPreparedModel, /*executeSynchronously=*/true).value();
454 EXPECT_CALL(*mockPreparedModel, executeFenced(_, _, _, _, _, _, _))
455 .Times(1)
456 .WillOnce(InvokeWithoutArgs(makeDeadObjectFailure));
457
458 // run test
459 const auto result = preparedModel->executeFenced({}, {}, {}, {}, {}, {}, {}, {});
460
461 // verify result
462 ASSERT_FALSE(result.has_value());
463 EXPECT_EQ(result.error().code, nn::ErrorStatus::DEAD_OBJECT);
464 }
465
TEST(PreparedModelTest,reusableExecuteSync)466 TEST(PreparedModelTest, reusableExecuteSync) {
467 // setup call
468 const uint32_t kNumberOfComputations = 2;
469 const auto mockPreparedModel = createMockPreparedModel();
470 const auto preparedModel =
471 PreparedModel::create(mockPreparedModel, /*executeSynchronously=*/true).value();
472 EXPECT_CALL(*mockPreparedModel, executeSynchronously_1_3(_, _, _, _, _))
473 .Times(kNumberOfComputations)
474 .WillRepeatedly(
475 Invoke(makeExecuteSynchronously(V1_3::ErrorStatus::NONE, {}, kNoTiming)));
476
477 // create execution
478 const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
479 ASSERT_TRUE(createResult.has_value())
480 << "Failed with " << createResult.error().code << ": " << createResult.error().message;
481 ASSERT_NE(createResult.value(), nullptr);
482
483 // invoke compute repeatedly
484 for (uint32_t i = 0; i < kNumberOfComputations; i++) {
485 const auto computeResult = createResult.value()->compute({});
486 EXPECT_TRUE(computeResult.has_value()) << "Failed with " << computeResult.error().code
487 << ": " << computeResult.error().message;
488 }
489 }
490
TEST(PreparedModelTest,reusableExecuteSyncError)491 TEST(PreparedModelTest, reusableExecuteSyncError) {
492 // setup test
493 const auto mockPreparedModel = createMockPreparedModel();
494 const auto preparedModel =
495 PreparedModel::create(mockPreparedModel, /*executeSynchronously=*/true).value();
496 EXPECT_CALL(*mockPreparedModel, executeSynchronously_1_3(_, _, _, _, _))
497 .Times(1)
498 .WillOnce(Invoke(
499 makeExecuteSynchronously(V1_3::ErrorStatus::GENERAL_FAILURE, {}, kNoTiming)));
500
501 // create execution
502 const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
503 ASSERT_TRUE(createResult.has_value())
504 << "Failed with " << createResult.error().code << ": " << createResult.error().message;
505 ASSERT_NE(createResult.value(), nullptr);
506
507 // invoke compute
508 const auto computeResult = createResult.value()->compute({});
509 ASSERT_FALSE(computeResult.has_value());
510 EXPECT_EQ(computeResult.error().code, nn::ErrorStatus::GENERAL_FAILURE);
511 }
512
TEST(PreparedModelTest,reusableExecuteSyncTransportFailure)513 TEST(PreparedModelTest, reusableExecuteSyncTransportFailure) {
514 // setup test
515 const auto mockPreparedModel = createMockPreparedModel();
516 const auto preparedModel =
517 PreparedModel::create(mockPreparedModel, /*executeSynchronously=*/true).value();
518 EXPECT_CALL(*mockPreparedModel, executeSynchronously_1_3(_, _, _, _, _))
519 .Times(1)
520 .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure));
521
522 // create execution
523 const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
524 ASSERT_TRUE(createResult.has_value())
525 << "Failed with " << createResult.error().code << ": " << createResult.error().message;
526 ASSERT_NE(createResult.value(), nullptr);
527
528 // invoke compute
529 const auto computeResult = createResult.value()->compute({});
530 ASSERT_FALSE(computeResult.has_value());
531 EXPECT_EQ(computeResult.error().code, nn::ErrorStatus::GENERAL_FAILURE);
532 }
533
TEST(PreparedModelTest,reusableExecuteSyncDeadObject)534 TEST(PreparedModelTest, reusableExecuteSyncDeadObject) {
535 // setup test
536 const auto mockPreparedModel = createMockPreparedModel();
537 const auto preparedModel =
538 PreparedModel::create(mockPreparedModel, /*executeSynchronously=*/true).value();
539 EXPECT_CALL(*mockPreparedModel, executeSynchronously_1_3(_, _, _, _, _))
540 .Times(1)
541 .WillOnce(InvokeWithoutArgs(makeDeadObjectFailure));
542
543 // create execution
544 const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
545 ASSERT_TRUE(createResult.has_value())
546 << "Failed with " << createResult.error().code << ": " << createResult.error().message;
547 ASSERT_NE(createResult.value(), nullptr);
548
549 // invoke compute
550 const auto computeResult = createResult.value()->compute({});
551 ASSERT_FALSE(computeResult.has_value());
552 EXPECT_EQ(computeResult.error().code, nn::ErrorStatus::DEAD_OBJECT);
553 }
554
TEST(PreparedModelTest,reusableExecuteAsync)555 TEST(PreparedModelTest, reusableExecuteAsync) {
556 // setup call
557 const uint32_t kNumberOfComputations = 2;
558 const auto mockPreparedModel = createMockPreparedModel();
559 const auto preparedModel =
560 PreparedModel::create(mockPreparedModel, /*executeSynchronously=*/false).value();
561 EXPECT_CALL(*mockPreparedModel, execute_1_3(_, _, _, _, _))
562 .Times(kNumberOfComputations)
563 .WillRepeatedly(Invoke(makeExecuteAsynchronously(
564 V1_3::ErrorStatus::NONE, V1_3::ErrorStatus::NONE, {}, kNoTiming)));
565
566 // create execution
567 const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
568 ASSERT_TRUE(createResult.has_value())
569 << "Failed with " << createResult.error().code << ": " << createResult.error().message;
570 ASSERT_NE(createResult.value(), nullptr);
571
572 // invoke compute repeatedly
573 for (uint32_t i = 0; i < kNumberOfComputations; i++) {
574 const auto computeResult = createResult.value()->compute({});
575 EXPECT_TRUE(computeResult.has_value()) << "Failed with " << computeResult.error().code
576 << ": " << computeResult.error().message;
577 }
578 }
579
TEST(PreparedModelTest,reusableExecuteAsyncLaunchError)580 TEST(PreparedModelTest, reusableExecuteAsyncLaunchError) {
581 // setup test
582 const auto mockPreparedModel = createMockPreparedModel();
583 const auto preparedModel =
584 PreparedModel::create(mockPreparedModel, /*executeSynchronously=*/false).value();
585 EXPECT_CALL(*mockPreparedModel, execute_1_3(_, _, _, _, _))
586 .Times(1)
587 .WillOnce(Invoke(makeExecuteAsynchronously(V1_3::ErrorStatus::GENERAL_FAILURE,
588 V1_3::ErrorStatus::GENERAL_FAILURE, {},
589 kNoTiming)));
590
591 // create execution
592 const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
593 ASSERT_TRUE(createResult.has_value())
594 << "Failed with " << createResult.error().code << ": " << createResult.error().message;
595 ASSERT_NE(createResult.value(), nullptr);
596
597 // invoke compute
598 const auto computeResult = createResult.value()->compute({});
599 ASSERT_FALSE(computeResult.has_value());
600 EXPECT_EQ(computeResult.error().code, nn::ErrorStatus::GENERAL_FAILURE);
601 }
602
TEST(PreparedModelTest,reusableExecuteAsyncReturnError)603 TEST(PreparedModelTest, reusableExecuteAsyncReturnError) {
604 // setup test
605 const auto mockPreparedModel = createMockPreparedModel();
606 const auto preparedModel =
607 PreparedModel::create(mockPreparedModel, /*executeSynchronously=*/false).value();
608 EXPECT_CALL(*mockPreparedModel, execute_1_3(_, _, _, _, _))
609 .Times(1)
610 .WillOnce(Invoke(makeExecuteAsynchronously(
611 V1_3::ErrorStatus::NONE, V1_3::ErrorStatus::GENERAL_FAILURE, {}, kNoTiming)));
612
613 // run test
614 const auto result = preparedModel->execute({}, {}, {}, {}, {}, {});
615
616 // verify result
617 ASSERT_FALSE(result.has_value());
618 EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
619 }
620
TEST(PreparedModelTest,reusableExecuteAsyncTransportFailure)621 TEST(PreparedModelTest, reusableExecuteAsyncTransportFailure) {
622 // setup test
623 const auto mockPreparedModel = createMockPreparedModel();
624 const auto preparedModel =
625 PreparedModel::create(mockPreparedModel, /*executeSynchronously=*/false).value();
626 EXPECT_CALL(*mockPreparedModel, execute_1_3(_, _, _, _, _))
627 .Times(1)
628 .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure));
629
630 // create execution
631 const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
632 ASSERT_TRUE(createResult.has_value())
633 << "Failed with " << createResult.error().code << ": " << createResult.error().message;
634 ASSERT_NE(createResult.value(), nullptr);
635
636 // invoke compute
637 const auto computeResult = createResult.value()->compute({});
638 ASSERT_FALSE(computeResult.has_value());
639 EXPECT_EQ(computeResult.error().code, nn::ErrorStatus::GENERAL_FAILURE);
640 }
641
TEST(PreparedModelTest,reusableExecuteAsyncDeadObject)642 TEST(PreparedModelTest, reusableExecuteAsyncDeadObject) {
643 // setup test
644 const auto mockPreparedModel = createMockPreparedModel();
645 const auto preparedModel =
646 PreparedModel::create(mockPreparedModel, /*executeSynchronously=*/false).value();
647 EXPECT_CALL(*mockPreparedModel, execute_1_3(_, _, _, _, _))
648 .Times(1)
649 .WillOnce(InvokeWithoutArgs(makeDeadObjectFailure));
650
651 // create execution
652 const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
653 ASSERT_TRUE(createResult.has_value())
654 << "Failed with " << createResult.error().code << ": " << createResult.error().message;
655 ASSERT_NE(createResult.value(), nullptr);
656
657 // invoke compute
658 const auto computeResult = createResult.value()->compute({});
659 ASSERT_FALSE(computeResult.has_value());
660 EXPECT_EQ(computeResult.error().code, nn::ErrorStatus::DEAD_OBJECT);
661 }
662
TEST(PreparedModelTest,reusableExecuteAsyncCrash)663 TEST(PreparedModelTest, reusableExecuteAsyncCrash) {
664 // setup test
665 const auto mockPreparedModel = createMockPreparedModel();
666 const auto preparedModel =
667 PreparedModel::create(mockPreparedModel, /*executeSynchronously=*/false).value();
668 const auto ret = [&mockPreparedModel]() -> hardware::Return<V1_3::ErrorStatus> {
669 mockPreparedModel->simulateCrash();
670 return V1_3::ErrorStatus::NONE;
671 };
672 EXPECT_CALL(*mockPreparedModel, execute_1_3(_, _, _, _, _))
673 .Times(1)
674 .WillOnce(InvokeWithoutArgs(ret));
675
676 // create execution
677 const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
678 ASSERT_TRUE(createResult.has_value())
679 << "Failed with " << createResult.error().code << ": " << createResult.error().message;
680 ASSERT_NE(createResult.value(), nullptr);
681
682 // invoke compute
683 const auto computeResult = createResult.value()->compute({});
684 ASSERT_FALSE(computeResult.has_value());
685 EXPECT_EQ(computeResult.error().code, nn::ErrorStatus::DEAD_OBJECT);
686 }
687
TEST(PreparedModelTest,reusableExecuteFenced)688 TEST(PreparedModelTest, reusableExecuteFenced) {
689 // setup call
690 const uint32_t kNumberOfComputations = 2;
691 const auto mockPreparedModel = createMockPreparedModel();
692 const auto preparedModel =
693 PreparedModel::create(mockPreparedModel, /*executeSynchronously=*/true).value();
694 const auto mockCallback = MockFencedExecutionCallback::create();
695 EXPECT_CALL(*mockCallback, getExecutionInfo(_))
696 .Times(kNumberOfComputations)
697 .WillRepeatedly(Invoke(makeExecuteFencedCallbackReturn(V1_3::ErrorStatus::NONE,
698 kNoTiming, kNoTiming)));
699 EXPECT_CALL(*mockPreparedModel, executeFenced(_, _, _, _, _, _, _))
700 .Times(kNumberOfComputations)
701 .WillRepeatedly(
702 Invoke(makeExecuteFencedReturn(V1_3::ErrorStatus::NONE, {}, mockCallback)));
703
704 // create execution
705 const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
706 ASSERT_TRUE(createResult.has_value())
707 << "Failed with " << createResult.error().code << ": " << createResult.error().message;
708 ASSERT_NE(createResult.value(), nullptr);
709
710 // invoke compute repeatedly
711 for (uint32_t i = 0; i < kNumberOfComputations; i++) {
712 const auto computeResult = createResult.value()->computeFenced({}, {}, {});
713 ASSERT_TRUE(computeResult.has_value()) << "Failed with " << computeResult.error().code
714 << ": " << computeResult.error().message;
715 const auto& [syncFence, callback] = computeResult.value();
716 EXPECT_EQ(syncFence.syncWait({}), nn::SyncFence::FenceState::SIGNALED);
717 ASSERT_NE(callback, nullptr);
718
719 // get results from callback
720 const auto callbackResult = callback();
721 ASSERT_TRUE(callbackResult.has_value()) << "Failed with " << callbackResult.error().code
722 << ": " << callbackResult.error().message;
723 }
724 }
725
TEST(PreparedModelTest,reusableExecuteFencedCallbackError)726 TEST(PreparedModelTest, reusableExecuteFencedCallbackError) {
727 // setup call
728 const auto mockPreparedModel = createMockPreparedModel();
729 const auto preparedModel =
730 PreparedModel::create(mockPreparedModel, /*executeSynchronously=*/true).value();
731 const auto mockCallback = MockFencedExecutionCallback::create();
732 EXPECT_CALL(*mockCallback, getExecutionInfo(_))
733 .Times(1)
734 .WillOnce(Invoke(makeExecuteFencedCallbackReturn(V1_3::ErrorStatus::GENERAL_FAILURE,
735 kNoTiming, kNoTiming)));
736 EXPECT_CALL(*mockPreparedModel, executeFenced(_, _, _, _, _, _, _))
737 .Times(1)
738 .WillOnce(Invoke(makeExecuteFencedReturn(V1_3::ErrorStatus::NONE, {}, mockCallback)));
739
740 // create execution
741 const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
742 ASSERT_TRUE(createResult.has_value())
743 << "Failed with " << createResult.error().code << ": " << createResult.error().message;
744 ASSERT_NE(createResult.value(), nullptr);
745
746 // invoke compute
747 const auto computeResult = createResult.value()->computeFenced({}, {}, {});
748 ASSERT_TRUE(computeResult.has_value()) << "Failed with " << computeResult.error().code << ": "
749 << computeResult.error().message;
750 const auto& [syncFence, callback] = computeResult.value();
751 EXPECT_NE(syncFence.syncWait({}), nn::SyncFence::FenceState::ACTIVE);
752 ASSERT_NE(callback, nullptr);
753
754 // verify callback failure
755 const auto callbackResult = callback();
756 ASSERT_FALSE(callbackResult.has_value());
757 EXPECT_EQ(callbackResult.error().code, nn::ErrorStatus::GENERAL_FAILURE);
758 }
759
TEST(PreparedModelTest,reusableExecuteFencedError)760 TEST(PreparedModelTest, reusableExecuteFencedError) {
761 // setup test
762 const auto mockPreparedModel = createMockPreparedModel();
763 const auto preparedModel =
764 PreparedModel::create(mockPreparedModel, /*executeSynchronously=*/true).value();
765 EXPECT_CALL(*mockPreparedModel, executeFenced(_, _, _, _, _, _, _))
766 .Times(1)
767 .WillOnce(Invoke(
768 makeExecuteFencedReturn(V1_3::ErrorStatus::GENERAL_FAILURE, {}, nullptr)));
769
770 // create execution
771 const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
772 ASSERT_TRUE(createResult.has_value())
773 << "Failed with " << createResult.error().code << ": " << createResult.error().message;
774 ASSERT_NE(createResult.value(), nullptr);
775
776 // invoke compute
777 const auto computeResult = createResult.value()->computeFenced({}, {}, {});
778 ASSERT_FALSE(computeResult.has_value());
779 EXPECT_EQ(computeResult.error().code, nn::ErrorStatus::GENERAL_FAILURE);
780 }
781
TEST(PreparedModelTest,reusableExecuteFencedTransportFailure)782 TEST(PreparedModelTest, reusableExecuteFencedTransportFailure) {
783 // setup test
784 const auto mockPreparedModel = createMockPreparedModel();
785 const auto preparedModel =
786 PreparedModel::create(mockPreparedModel, /*executeSynchronously=*/true).value();
787 EXPECT_CALL(*mockPreparedModel, executeFenced(_, _, _, _, _, _, _))
788 .Times(1)
789 .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure));
790
791 // create execution
792 const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
793 ASSERT_TRUE(createResult.has_value())
794 << "Failed with " << createResult.error().code << ": " << createResult.error().message;
795 ASSERT_NE(createResult.value(), nullptr);
796
797 // invoke compute
798 const auto computeResult = createResult.value()->computeFenced({}, {}, {});
799 ASSERT_FALSE(computeResult.has_value());
800 EXPECT_EQ(computeResult.error().code, nn::ErrorStatus::GENERAL_FAILURE);
801 }
802
TEST(PreparedModelTest,reusableExecuteFencedDeadObject)803 TEST(PreparedModelTest, reusableExecuteFencedDeadObject) {
804 // setup test
805 const auto mockPreparedModel = createMockPreparedModel();
806 const auto preparedModel =
807 PreparedModel::create(mockPreparedModel, /*executeSynchronously=*/true).value();
808 EXPECT_CALL(*mockPreparedModel, executeFenced(_, _, _, _, _, _, _))
809 .Times(1)
810 .WillOnce(InvokeWithoutArgs(makeDeadObjectFailure));
811
812 // create execution
813 const auto createResult = preparedModel->createReusableExecution({}, {}, {}, {}, {});
814 ASSERT_TRUE(createResult.has_value())
815 << "Failed with " << createResult.error().code << ": " << createResult.error().message;
816 ASSERT_NE(createResult.value(), nullptr);
817
818 // invoke compute
819 const auto computeResult = createResult.value()->computeFenced({}, {}, {});
820 ASSERT_FALSE(computeResult.has_value());
821 EXPECT_EQ(computeResult.error().code, nn::ErrorStatus::DEAD_OBJECT);
822 }
TEST(PreparedModelTest,configureExecutionBurst)823 TEST(PreparedModelTest, configureExecutionBurst) {
824 // setup test
825 const auto mockPreparedModel = MockPreparedModel::create();
826 const auto mockBurstContext = sp<MockBurstContext>::make();
827 EXPECT_CALL(*mockPreparedModel, configureExecutionBurst(_, _, _, _))
828 .Times(1)
829 .WillOnce(makeConfigureExecutionBurstReturn(V1_0::ErrorStatus::NONE, mockBurstContext));
830 const auto preparedModel =
831 PreparedModel::create(mockPreparedModel, /*executeSynchronously=*/true).value();
832
833 // run test
834 const auto result = preparedModel->configureExecutionBurst();
835
836 // verify result
837 ASSERT_TRUE(result.has_value())
838 << "Failed with " << result.error().code << ": " << result.error().message;
839 EXPECT_NE(result.value(), nullptr);
840 }
841
TEST(PreparedModelTest,configureExecutionBurstError)842 TEST(PreparedModelTest, configureExecutionBurstError) {
843 // setup test
844 const auto mockPreparedModel = MockPreparedModel::create();
845 const auto preparedModel =
846 PreparedModel::create(mockPreparedModel, /*executeSynchronously=*/true).value();
847 EXPECT_CALL(*mockPreparedModel, configureExecutionBurst(_, _, _, _))
848 .Times(1)
849 .WillOnce(
850 makeConfigureExecutionBurstReturn(V1_0::ErrorStatus::GENERAL_FAILURE, nullptr));
851
852 // run test
853 const auto result = preparedModel->configureExecutionBurst();
854
855 // verify result
856 ASSERT_FALSE(result.has_value());
857 EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
858 }
859
TEST(PreparedModelTest,configureExecutionBurstTransportFailure)860 TEST(PreparedModelTest, configureExecutionBurstTransportFailure) {
861 // setup test
862 const auto mockPreparedModel = MockPreparedModel::create();
863 const auto preparedModel =
864 PreparedModel::create(mockPreparedModel, /*executeSynchronously=*/true).value();
865 EXPECT_CALL(*mockPreparedModel, configureExecutionBurst(_, _, _, _))
866 .Times(1)
867 .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure));
868
869 // run test
870 const auto result = preparedModel->configureExecutionBurst();
871
872 // verify result
873 ASSERT_FALSE(result.has_value());
874 EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
875 }
876
TEST(PreparedModelTest,configureExecutionBurstDeadObject)877 TEST(PreparedModelTest, configureExecutionBurstDeadObject) {
878 // setup test
879 const auto mockPreparedModel = MockPreparedModel::create();
880 const auto preparedModel =
881 PreparedModel::create(mockPreparedModel, /*executeSynchronously=*/true).value();
882 EXPECT_CALL(*mockPreparedModel, configureExecutionBurst(_, _, _, _))
883 .Times(1)
884 .WillOnce(InvokeWithoutArgs(makeDeadObjectFailure));
885
886 // run test
887 const auto result = preparedModel->configureExecutionBurst();
888
889 // verify result
890 ASSERT_FALSE(result.has_value());
891 EXPECT_EQ(result.error().code, nn::ErrorStatus::DEAD_OBJECT);
892 }
893
TEST(PreparedModelTest,getUnderlyingResource)894 TEST(PreparedModelTest, getUnderlyingResource) {
895 // setup test
896 const auto mockPreparedModel = createMockPreparedModel();
897 const auto preparedModel =
898 PreparedModel::create(mockPreparedModel, /*executeSynchronously=*/true).value();
899
900 // run test
901 const auto resource = preparedModel->getUnderlyingResource();
902
903 // verify resource
904 const sp<V1_3::IPreparedModel>* maybeMock = std::any_cast<sp<V1_3::IPreparedModel>>(&resource);
905 ASSERT_NE(maybeMock, nullptr);
906 EXPECT_EQ(maybeMock->get(), mockPreparedModel.get());
907 }
908
909 } // namespace android::hardware::neuralnetworks::V1_3::utils
910