blob: d297b1a4178a204e9a5570fb0c658649de92f9ce [file] [log] [blame]
Michael Butler6e492a62020-12-10 15:38:45 -08001/*
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 "MockPreparedModel.h"
18
Michael Butler8414a6e2021-03-10 18:41:05 -080019#include "MockBurstContext.h"
20
Michael Butler6e492a62020-12-10 15:38:45 -080021#include <android/hardware/neuralnetworks/1.2/IExecutionCallback.h>
22#include <gmock/gmock.h>
23#include <gtest/gtest.h>
24#include <nnapi/IPreparedModel.h>
25#include <nnapi/TypeUtils.h>
26#include <nnapi/Types.h>
27#include <nnapi/hal/1.2/PreparedModel.h>
28
29#include <functional>
30#include <memory>
31
32namespace android::hardware::neuralnetworks::V1_2::utils {
33namespace {
34
35using ::testing::_;
36using ::testing::Invoke;
37using ::testing::InvokeWithoutArgs;
38
39const sp<V1_2::IPreparedModel> kInvalidPreparedModel;
40constexpr auto kNoTiming = V1_2::Timing{.timeOnDevice = std::numeric_limits<uint64_t>::max(),
41 .timeInDriver = std::numeric_limits<uint64_t>::max()};
42
43sp<MockPreparedModel> createMockPreparedModel() {
44 const auto mockPreparedModel = MockPreparedModel::create();
45
46 // Ensure that older calls are not used.
47 EXPECT_CALL(*mockPreparedModel, execute(_, _)).Times(0);
48
49 return mockPreparedModel;
50}
51
52auto makeExecuteSynchronously(V1_0::ErrorStatus status,
53 const std::vector<V1_2::OutputShape>& outputShapes,
54 const V1_2::Timing& timing) {
55 return [status, outputShapes, timing](const V1_0::Request& /*request*/,
56 V1_2::MeasureTiming /*measureTiming*/,
57 const V1_2::IPreparedModel::executeSynchronously_cb& cb) {
58 cb(status, outputShapes, timing);
59 return hardware::Void();
60 };
61}
62auto makeExecuteAsynchronously(V1_0::ErrorStatus launchStatus, V1_0::ErrorStatus returnStatus,
63 const std::vector<V1_2::OutputShape>& outputShapes,
64 const V1_2::Timing& timing) {
65 return [launchStatus, returnStatus, outputShapes, timing](
66 const V1_0::Request& /*request*/, V1_2::MeasureTiming /*measureTiming*/,
67 const sp<V1_2::IExecutionCallback>& cb) -> Return<V1_0::ErrorStatus> {
68 cb->notify_1_2(returnStatus, outputShapes, timing);
69 return launchStatus;
70 };
71}
Michael Butler8414a6e2021-03-10 18:41:05 -080072auto makeConfigureExecutionBurstReturn(V1_0::ErrorStatus status,
73 const sp<MockBurstContext>& burstContext) {
74 return [status, burstContext](
75 const sp<V1_2::IBurstCallback>& /*callback*/,
76 const MQDescriptorSync<V1_2::FmqRequestDatum>& /*requestChannel*/,
77 const MQDescriptorSync<V1_2::FmqResultDatum>& /*resultChannel*/,
78 V1_2::IPreparedModel::configureExecutionBurst_cb cb) -> hardware::Return<void> {
79 cb(status, burstContext);
80 return hardware::Void();
81 };
82}
Michael Butler6e492a62020-12-10 15:38:45 -080083
84std::function<hardware::Status()> makeTransportFailure(status_t status) {
85 return [status] { return hardware::Status::fromStatusT(status); };
86}
87
88const auto makeGeneralTransportFailure = makeTransportFailure(NO_MEMORY);
89const auto makeDeadObjectFailure = makeTransportFailure(DEAD_OBJECT);
90
91} // namespace
92
93TEST(PreparedModelTest, invalidPreparedModel) {
94 // run test
95 const auto result = PreparedModel::create(kInvalidPreparedModel, /*executeSynchronously=*/true);
96
97 // verify result
98 ASSERT_FALSE(result.has_value());
99 EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
100}
101
102TEST(PreparedModelTest, linkToDeathError) {
103 // setup call
104 const auto mockPreparedModel = createMockPreparedModel();
105 const auto ret = []() -> Return<bool> { return false; };
106 EXPECT_CALL(*mockPreparedModel, linkToDeathRet()).Times(1).WillOnce(InvokeWithoutArgs(ret));
107
108 // run test
109 const auto result = PreparedModel::create(mockPreparedModel, /*executeSynchronously=*/true);
110
111 // verify result
112 ASSERT_FALSE(result.has_value());
113 EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
114}
115
116TEST(PreparedModelTest, linkToDeathTransportFailure) {
117 // setup call
118 const auto mockPreparedModel = createMockPreparedModel();
119 EXPECT_CALL(*mockPreparedModel, linkToDeathRet())
120 .Times(1)
121 .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure));
122
123 // run test
124 const auto result = PreparedModel::create(mockPreparedModel, /*executeSynchronously=*/true);
125
126 // verify result
127 ASSERT_FALSE(result.has_value());
128 EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
129}
130
131TEST(PreparedModelTest, linkToDeathDeadObject) {
132 // setup call
133 const auto mockPreparedModel = createMockPreparedModel();
134 EXPECT_CALL(*mockPreparedModel, linkToDeathRet())
135 .Times(1)
136 .WillOnce(InvokeWithoutArgs(makeDeadObjectFailure));
137
138 // run test
139 const auto result = PreparedModel::create(mockPreparedModel, /*executeSynchronously=*/true);
140
141 // verify result
142 ASSERT_FALSE(result.has_value());
143 EXPECT_EQ(result.error().code, nn::ErrorStatus::DEAD_OBJECT);
144}
145
146TEST(PreparedModelTest, executeSync) {
147 // setup call
148 const auto mockPreparedModel = createMockPreparedModel();
149 const auto preparedModel =
150 PreparedModel::create(mockPreparedModel, /*executeSynchronously=*/true).value();
151 EXPECT_CALL(*mockPreparedModel, executeSynchronously(_, _, _))
152 .Times(1)
153 .WillOnce(Invoke(makeExecuteSynchronously(V1_0::ErrorStatus::NONE, {}, kNoTiming)));
154
155 // run test
156 const auto result = preparedModel->execute({}, {}, {}, {});
157
158 // verify result
159 EXPECT_TRUE(result.has_value())
160 << "Failed with " << result.error().code << ": " << result.error().message;
161}
162
163TEST(PreparedModelTest, executeSyncError) {
164 // setup test
165 const auto mockPreparedModel = createMockPreparedModel();
166 const auto preparedModel =
167 PreparedModel::create(mockPreparedModel, /*executeSynchronously=*/true).value();
168 EXPECT_CALL(*mockPreparedModel, executeSynchronously(_, _, _))
169 .Times(1)
170 .WillOnce(Invoke(
171 makeExecuteSynchronously(V1_0::ErrorStatus::GENERAL_FAILURE, {}, kNoTiming)));
172
173 // run test
174 const auto result = preparedModel->execute({}, {}, {}, {});
175
176 // verify result
177 ASSERT_FALSE(result.has_value());
178 EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
179}
180
181TEST(PreparedModelTest, executeSyncTransportFailure) {
182 // setup test
183 const auto mockPreparedModel = createMockPreparedModel();
184 const auto preparedModel =
185 PreparedModel::create(mockPreparedModel, /*executeSynchronously=*/true).value();
186 EXPECT_CALL(*mockPreparedModel, executeSynchronously(_, _, _))
187 .Times(1)
188 .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure));
189
190 // run test
191 const auto result = preparedModel->execute({}, {}, {}, {});
192
193 // verify result
194 ASSERT_FALSE(result.has_value());
195 EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
196}
197
198TEST(PreparedModelTest, executeSyncDeadObject) {
199 // setup test
200 const auto mockPreparedModel = createMockPreparedModel();
201 const auto preparedModel =
202 PreparedModel::create(mockPreparedModel, /*executeSynchronously=*/true).value();
203 EXPECT_CALL(*mockPreparedModel, executeSynchronously(_, _, _))
204 .Times(1)
205 .WillOnce(InvokeWithoutArgs(makeDeadObjectFailure));
206
207 // run test
208 const auto result = preparedModel->execute({}, {}, {}, {});
209
210 // verify result
211 ASSERT_FALSE(result.has_value());
212 EXPECT_EQ(result.error().code, nn::ErrorStatus::DEAD_OBJECT);
213}
214
215TEST(PreparedModelTest, executeAsync) {
216 // setup call
217 const auto mockPreparedModel = createMockPreparedModel();
218 const auto preparedModel =
219 PreparedModel::create(mockPreparedModel, /*executeSynchronously=*/false).value();
220 EXPECT_CALL(*mockPreparedModel, execute_1_2(_, _, _))
221 .Times(1)
222 .WillOnce(Invoke(makeExecuteAsynchronously(V1_0::ErrorStatus::NONE,
223 V1_0::ErrorStatus::NONE, {}, kNoTiming)));
224
225 // run test
226 const auto result = preparedModel->execute({}, {}, {}, {});
227
228 // verify result
229 EXPECT_TRUE(result.has_value())
230 << "Failed with " << result.error().code << ": " << result.error().message;
231}
232
233TEST(PreparedModelTest, executeAsyncLaunchError) {
234 // setup test
235 const auto mockPreparedModel = createMockPreparedModel();
236 const auto preparedModel =
237 PreparedModel::create(mockPreparedModel, /*executeSynchronously=*/false).value();
238 EXPECT_CALL(*mockPreparedModel, execute_1_2(_, _, _))
239 .Times(1)
240 .WillOnce(Invoke(makeExecuteAsynchronously(V1_0::ErrorStatus::GENERAL_FAILURE,
241 V1_0::ErrorStatus::GENERAL_FAILURE, {},
242 kNoTiming)));
243
244 // run test
245 const auto result = preparedModel->execute({}, {}, {}, {});
246
247 // verify result
248 ASSERT_FALSE(result.has_value());
249 EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
250}
251
252TEST(PreparedModelTest, executeAsyncReturnError) {
253 // setup test
254 const auto mockPreparedModel = createMockPreparedModel();
255 const auto preparedModel =
256 PreparedModel::create(mockPreparedModel, /*executeSynchronously=*/false).value();
257 EXPECT_CALL(*mockPreparedModel, execute_1_2(_, _, _))
258 .Times(1)
259 .WillOnce(Invoke(makeExecuteAsynchronously(
260 V1_0::ErrorStatus::NONE, V1_0::ErrorStatus::GENERAL_FAILURE, {}, kNoTiming)));
261
262 // run test
263 const auto result = preparedModel->execute({}, {}, {}, {});
264
265 // verify result
266 ASSERT_FALSE(result.has_value());
267 EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
268}
269
270TEST(PreparedModelTest, executeAsyncTransportFailure) {
271 // setup test
272 const auto mockPreparedModel = createMockPreparedModel();
273 const auto preparedModel =
274 PreparedModel::create(mockPreparedModel, /*executeSynchronously=*/false).value();
275 EXPECT_CALL(*mockPreparedModel, execute_1_2(_, _, _))
276 .Times(1)
277 .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure));
278
279 // run test
280 const auto result = preparedModel->execute({}, {}, {}, {});
281
282 // verify result
283 ASSERT_FALSE(result.has_value());
284 EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
285}
286
287TEST(PreparedModelTest, executeAsyncDeadObject) {
288 // setup test
289 const auto mockPreparedModel = createMockPreparedModel();
290 const auto preparedModel =
291 PreparedModel::create(mockPreparedModel, /*executeSynchronously=*/false).value();
292 EXPECT_CALL(*mockPreparedModel, execute_1_2(_, _, _))
293 .Times(1)
294 .WillOnce(InvokeWithoutArgs(makeDeadObjectFailure));
295
296 // run test
297 const auto result = preparedModel->execute({}, {}, {}, {});
298
299 // verify result
300 ASSERT_FALSE(result.has_value());
301 EXPECT_EQ(result.error().code, nn::ErrorStatus::DEAD_OBJECT);
302}
303
304TEST(PreparedModelTest, executeAsyncCrash) {
305 // setup test
306 const auto mockPreparedModel = createMockPreparedModel();
307 const auto preparedModel =
308 PreparedModel::create(mockPreparedModel, /*executeSynchronously=*/false).value();
309 const auto ret = [&mockPreparedModel]() -> hardware::Return<V1_0::ErrorStatus> {
310 mockPreparedModel->simulateCrash();
311 return V1_0::ErrorStatus::NONE;
312 };
313 EXPECT_CALL(*mockPreparedModel, execute_1_2(_, _, _)).Times(1).WillOnce(InvokeWithoutArgs(ret));
314
315 // run test
316 const auto result = preparedModel->execute({}, {}, {}, {});
317
318 // verify result
319 ASSERT_FALSE(result.has_value());
320 EXPECT_EQ(result.error().code, nn::ErrorStatus::DEAD_OBJECT);
321}
322
323TEST(PreparedModelTest, executeFencedNotSupported) {
324 // setup test
325 const auto mockPreparedModel = createMockPreparedModel();
326 const auto preparedModel =
327 PreparedModel::create(mockPreparedModel, /*executeSynchronously=*/true).value();
328
329 // run test
330 const auto result = preparedModel->executeFenced({}, {}, {}, {}, {}, {});
331
332 // verify result
333 ASSERT_FALSE(result.has_value());
334 EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
335}
336
Michael Butler8414a6e2021-03-10 18:41:05 -0800337TEST(PreparedModelTest, configureExecutionBurst) {
338 // setup test
339 const auto mockPreparedModel = MockPreparedModel::create();
340 const auto mockBurstContext = sp<MockBurstContext>::make();
341 EXPECT_CALL(*mockPreparedModel, configureExecutionBurst(_, _, _, _))
342 .Times(1)
343 .WillOnce(makeConfigureExecutionBurstReturn(V1_0::ErrorStatus::NONE, mockBurstContext));
344 const auto preparedModel =
345 PreparedModel::create(mockPreparedModel, /*executeSynchronously=*/true).value();
346
347 // run test
348 const auto result = preparedModel->configureExecutionBurst();
349
350 // verify result
351 ASSERT_TRUE(result.has_value())
352 << "Failed with " << result.error().code << ": " << result.error().message;
353 EXPECT_NE(result.value(), nullptr);
354}
355
356TEST(PreparedModelTest, configureExecutionBurstError) {
357 // setup test
358 const auto mockPreparedModel = MockPreparedModel::create();
359 const auto preparedModel =
360 PreparedModel::create(mockPreparedModel, /*executeSynchronously=*/true).value();
361 EXPECT_CALL(*mockPreparedModel, configureExecutionBurst(_, _, _, _))
362 .Times(1)
363 .WillOnce(
364 makeConfigureExecutionBurstReturn(V1_0::ErrorStatus::GENERAL_FAILURE, nullptr));
365
366 // run test
367 const auto result = preparedModel->configureExecutionBurst();
368
369 // verify result
370 ASSERT_FALSE(result.has_value());
371 EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
372}
373
374TEST(PreparedModelTest, configureExecutionBurstTransportFailure) {
375 // setup test
376 const auto mockPreparedModel = MockPreparedModel::create();
377 const auto preparedModel =
378 PreparedModel::create(mockPreparedModel, /*executeSynchronously=*/true).value();
379 EXPECT_CALL(*mockPreparedModel, configureExecutionBurst(_, _, _, _))
380 .Times(1)
381 .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure));
382
383 // run test
384 const auto result = preparedModel->configureExecutionBurst();
385
386 // verify result
387 ASSERT_FALSE(result.has_value());
388 EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
389}
390
391TEST(PreparedModelTest, configureExecutionBurstDeadObject) {
392 // setup test
393 const auto mockPreparedModel = MockPreparedModel::create();
394 const auto preparedModel =
395 PreparedModel::create(mockPreparedModel, /*executeSynchronously=*/true).value();
396 EXPECT_CALL(*mockPreparedModel, configureExecutionBurst(_, _, _, _))
397 .Times(1)
398 .WillOnce(InvokeWithoutArgs(makeDeadObjectFailure));
399
400 // run test
401 const auto result = preparedModel->configureExecutionBurst();
402
403 // verify result
404 ASSERT_FALSE(result.has_value());
405 EXPECT_EQ(result.error().code, nn::ErrorStatus::DEAD_OBJECT);
406}
Michael Butler6e492a62020-12-10 15:38:45 -0800407
408TEST(PreparedModelTest, getUnderlyingResource) {
409 // setup test
410 const auto mockPreparedModel = createMockPreparedModel();
411 const auto preparedModel =
412 PreparedModel::create(mockPreparedModel, /*executeSynchronously=*/true).value();
413
414 // run test
415 const auto resource = preparedModel->getUnderlyingResource();
416
417 // verify resource
418 const sp<V1_2::IPreparedModel>* maybeMock = std::any_cast<sp<V1_2::IPreparedModel>>(&resource);
419 ASSERT_NE(maybeMock, nullptr);
420 EXPECT_EQ(maybeMock->get(), mockPreparedModel.get());
421}
422
423} // namespace android::hardware::neuralnetworks::V1_2::utils