blob: 5062ac9a9755680be7518d05bc26372d1de4e92d [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
19#include <android/hardware/neuralnetworks/1.2/IExecutionCallback.h>
20#include <gmock/gmock.h>
21#include <gtest/gtest.h>
22#include <nnapi/IPreparedModel.h>
23#include <nnapi/TypeUtils.h>
24#include <nnapi/Types.h>
25#include <nnapi/hal/1.2/PreparedModel.h>
26
27#include <functional>
28#include <memory>
29
30namespace android::hardware::neuralnetworks::V1_2::utils {
31namespace {
32
33using ::testing::_;
34using ::testing::Invoke;
35using ::testing::InvokeWithoutArgs;
36
37const sp<V1_2::IPreparedModel> kInvalidPreparedModel;
38constexpr auto kNoTiming = V1_2::Timing{.timeOnDevice = std::numeric_limits<uint64_t>::max(),
39 .timeInDriver = std::numeric_limits<uint64_t>::max()};
40
41sp<MockPreparedModel> createMockPreparedModel() {
42 const auto mockPreparedModel = MockPreparedModel::create();
43
44 // Ensure that older calls are not used.
45 EXPECT_CALL(*mockPreparedModel, execute(_, _)).Times(0);
46
47 return mockPreparedModel;
48}
49
50auto makeExecuteSynchronously(V1_0::ErrorStatus status,
51 const std::vector<V1_2::OutputShape>& outputShapes,
52 const V1_2::Timing& timing) {
53 return [status, outputShapes, timing](const V1_0::Request& /*request*/,
54 V1_2::MeasureTiming /*measureTiming*/,
55 const V1_2::IPreparedModel::executeSynchronously_cb& cb) {
56 cb(status, outputShapes, timing);
57 return hardware::Void();
58 };
59}
60auto makeExecuteAsynchronously(V1_0::ErrorStatus launchStatus, V1_0::ErrorStatus returnStatus,
61 const std::vector<V1_2::OutputShape>& outputShapes,
62 const V1_2::Timing& timing) {
63 return [launchStatus, returnStatus, outputShapes, timing](
64 const V1_0::Request& /*request*/, V1_2::MeasureTiming /*measureTiming*/,
65 const sp<V1_2::IExecutionCallback>& cb) -> Return<V1_0::ErrorStatus> {
66 cb->notify_1_2(returnStatus, outputShapes, timing);
67 return launchStatus;
68 };
69}
70
71std::function<hardware::Status()> makeTransportFailure(status_t status) {
72 return [status] { return hardware::Status::fromStatusT(status); };
73}
74
75const auto makeGeneralTransportFailure = makeTransportFailure(NO_MEMORY);
76const auto makeDeadObjectFailure = makeTransportFailure(DEAD_OBJECT);
77
78} // namespace
79
80TEST(PreparedModelTest, invalidPreparedModel) {
81 // run test
82 const auto result = PreparedModel::create(kInvalidPreparedModel, /*executeSynchronously=*/true);
83
84 // verify result
85 ASSERT_FALSE(result.has_value());
86 EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
87}
88
89TEST(PreparedModelTest, linkToDeathError) {
90 // setup call
91 const auto mockPreparedModel = createMockPreparedModel();
92 const auto ret = []() -> Return<bool> { return false; };
93 EXPECT_CALL(*mockPreparedModel, linkToDeathRet()).Times(1).WillOnce(InvokeWithoutArgs(ret));
94
95 // run test
96 const auto result = PreparedModel::create(mockPreparedModel, /*executeSynchronously=*/true);
97
98 // verify result
99 ASSERT_FALSE(result.has_value());
100 EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
101}
102
103TEST(PreparedModelTest, linkToDeathTransportFailure) {
104 // setup call
105 const auto mockPreparedModel = createMockPreparedModel();
106 EXPECT_CALL(*mockPreparedModel, linkToDeathRet())
107 .Times(1)
108 .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure));
109
110 // run test
111 const auto result = PreparedModel::create(mockPreparedModel, /*executeSynchronously=*/true);
112
113 // verify result
114 ASSERT_FALSE(result.has_value());
115 EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
116}
117
118TEST(PreparedModelTest, linkToDeathDeadObject) {
119 // setup call
120 const auto mockPreparedModel = createMockPreparedModel();
121 EXPECT_CALL(*mockPreparedModel, linkToDeathRet())
122 .Times(1)
123 .WillOnce(InvokeWithoutArgs(makeDeadObjectFailure));
124
125 // run test
126 const auto result = PreparedModel::create(mockPreparedModel, /*executeSynchronously=*/true);
127
128 // verify result
129 ASSERT_FALSE(result.has_value());
130 EXPECT_EQ(result.error().code, nn::ErrorStatus::DEAD_OBJECT);
131}
132
133TEST(PreparedModelTest, executeSync) {
134 // setup call
135 const auto mockPreparedModel = createMockPreparedModel();
136 const auto preparedModel =
137 PreparedModel::create(mockPreparedModel, /*executeSynchronously=*/true).value();
138 EXPECT_CALL(*mockPreparedModel, executeSynchronously(_, _, _))
139 .Times(1)
140 .WillOnce(Invoke(makeExecuteSynchronously(V1_0::ErrorStatus::NONE, {}, kNoTiming)));
141
142 // run test
143 const auto result = preparedModel->execute({}, {}, {}, {});
144
145 // verify result
146 EXPECT_TRUE(result.has_value())
147 << "Failed with " << result.error().code << ": " << result.error().message;
148}
149
150TEST(PreparedModelTest, executeSyncError) {
151 // setup test
152 const auto mockPreparedModel = createMockPreparedModel();
153 const auto preparedModel =
154 PreparedModel::create(mockPreparedModel, /*executeSynchronously=*/true).value();
155 EXPECT_CALL(*mockPreparedModel, executeSynchronously(_, _, _))
156 .Times(1)
157 .WillOnce(Invoke(
158 makeExecuteSynchronously(V1_0::ErrorStatus::GENERAL_FAILURE, {}, kNoTiming)));
159
160 // run test
161 const auto result = preparedModel->execute({}, {}, {}, {});
162
163 // verify result
164 ASSERT_FALSE(result.has_value());
165 EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
166}
167
168TEST(PreparedModelTest, executeSyncTransportFailure) {
169 // setup test
170 const auto mockPreparedModel = createMockPreparedModel();
171 const auto preparedModel =
172 PreparedModel::create(mockPreparedModel, /*executeSynchronously=*/true).value();
173 EXPECT_CALL(*mockPreparedModel, executeSynchronously(_, _, _))
174 .Times(1)
175 .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure));
176
177 // run test
178 const auto result = preparedModel->execute({}, {}, {}, {});
179
180 // verify result
181 ASSERT_FALSE(result.has_value());
182 EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
183}
184
185TEST(PreparedModelTest, executeSyncDeadObject) {
186 // setup test
187 const auto mockPreparedModel = createMockPreparedModel();
188 const auto preparedModel =
189 PreparedModel::create(mockPreparedModel, /*executeSynchronously=*/true).value();
190 EXPECT_CALL(*mockPreparedModel, executeSynchronously(_, _, _))
191 .Times(1)
192 .WillOnce(InvokeWithoutArgs(makeDeadObjectFailure));
193
194 // run test
195 const auto result = preparedModel->execute({}, {}, {}, {});
196
197 // verify result
198 ASSERT_FALSE(result.has_value());
199 EXPECT_EQ(result.error().code, nn::ErrorStatus::DEAD_OBJECT);
200}
201
202TEST(PreparedModelTest, executeAsync) {
203 // setup call
204 const auto mockPreparedModel = createMockPreparedModel();
205 const auto preparedModel =
206 PreparedModel::create(mockPreparedModel, /*executeSynchronously=*/false).value();
207 EXPECT_CALL(*mockPreparedModel, execute_1_2(_, _, _))
208 .Times(1)
209 .WillOnce(Invoke(makeExecuteAsynchronously(V1_0::ErrorStatus::NONE,
210 V1_0::ErrorStatus::NONE, {}, kNoTiming)));
211
212 // run test
213 const auto result = preparedModel->execute({}, {}, {}, {});
214
215 // verify result
216 EXPECT_TRUE(result.has_value())
217 << "Failed with " << result.error().code << ": " << result.error().message;
218}
219
220TEST(PreparedModelTest, executeAsyncLaunchError) {
221 // setup test
222 const auto mockPreparedModel = createMockPreparedModel();
223 const auto preparedModel =
224 PreparedModel::create(mockPreparedModel, /*executeSynchronously=*/false).value();
225 EXPECT_CALL(*mockPreparedModel, execute_1_2(_, _, _))
226 .Times(1)
227 .WillOnce(Invoke(makeExecuteAsynchronously(V1_0::ErrorStatus::GENERAL_FAILURE,
228 V1_0::ErrorStatus::GENERAL_FAILURE, {},
229 kNoTiming)));
230
231 // run test
232 const auto result = preparedModel->execute({}, {}, {}, {});
233
234 // verify result
235 ASSERT_FALSE(result.has_value());
236 EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
237}
238
239TEST(PreparedModelTest, executeAsyncReturnError) {
240 // setup test
241 const auto mockPreparedModel = createMockPreparedModel();
242 const auto preparedModel =
243 PreparedModel::create(mockPreparedModel, /*executeSynchronously=*/false).value();
244 EXPECT_CALL(*mockPreparedModel, execute_1_2(_, _, _))
245 .Times(1)
246 .WillOnce(Invoke(makeExecuteAsynchronously(
247 V1_0::ErrorStatus::NONE, V1_0::ErrorStatus::GENERAL_FAILURE, {}, kNoTiming)));
248
249 // run test
250 const auto result = preparedModel->execute({}, {}, {}, {});
251
252 // verify result
253 ASSERT_FALSE(result.has_value());
254 EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
255}
256
257TEST(PreparedModelTest, executeAsyncTransportFailure) {
258 // setup test
259 const auto mockPreparedModel = createMockPreparedModel();
260 const auto preparedModel =
261 PreparedModel::create(mockPreparedModel, /*executeSynchronously=*/false).value();
262 EXPECT_CALL(*mockPreparedModel, execute_1_2(_, _, _))
263 .Times(1)
264 .WillOnce(InvokeWithoutArgs(makeGeneralTransportFailure));
265
266 // run test
267 const auto result = preparedModel->execute({}, {}, {}, {});
268
269 // verify result
270 ASSERT_FALSE(result.has_value());
271 EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
272}
273
274TEST(PreparedModelTest, executeAsyncDeadObject) {
275 // setup test
276 const auto mockPreparedModel = createMockPreparedModel();
277 const auto preparedModel =
278 PreparedModel::create(mockPreparedModel, /*executeSynchronously=*/false).value();
279 EXPECT_CALL(*mockPreparedModel, execute_1_2(_, _, _))
280 .Times(1)
281 .WillOnce(InvokeWithoutArgs(makeDeadObjectFailure));
282
283 // run test
284 const auto result = preparedModel->execute({}, {}, {}, {});
285
286 // verify result
287 ASSERT_FALSE(result.has_value());
288 EXPECT_EQ(result.error().code, nn::ErrorStatus::DEAD_OBJECT);
289}
290
291TEST(PreparedModelTest, executeAsyncCrash) {
292 // setup test
293 const auto mockPreparedModel = createMockPreparedModel();
294 const auto preparedModel =
295 PreparedModel::create(mockPreparedModel, /*executeSynchronously=*/false).value();
296 const auto ret = [&mockPreparedModel]() -> hardware::Return<V1_0::ErrorStatus> {
297 mockPreparedModel->simulateCrash();
298 return V1_0::ErrorStatus::NONE;
299 };
300 EXPECT_CALL(*mockPreparedModel, execute_1_2(_, _, _)).Times(1).WillOnce(InvokeWithoutArgs(ret));
301
302 // run test
303 const auto result = preparedModel->execute({}, {}, {}, {});
304
305 // verify result
306 ASSERT_FALSE(result.has_value());
307 EXPECT_EQ(result.error().code, nn::ErrorStatus::DEAD_OBJECT);
308}
309
310TEST(PreparedModelTest, executeFencedNotSupported) {
311 // setup test
312 const auto mockPreparedModel = createMockPreparedModel();
313 const auto preparedModel =
314 PreparedModel::create(mockPreparedModel, /*executeSynchronously=*/true).value();
315
316 // run test
317 const auto result = preparedModel->executeFenced({}, {}, {}, {}, {}, {});
318
319 // verify result
320 ASSERT_FALSE(result.has_value());
321 EXPECT_EQ(result.error().code, nn::ErrorStatus::GENERAL_FAILURE);
322}
323
324// TODO: test burst execution if/when it is added to nn::IPreparedModel.
325
326TEST(PreparedModelTest, getUnderlyingResource) {
327 // setup test
328 const auto mockPreparedModel = createMockPreparedModel();
329 const auto preparedModel =
330 PreparedModel::create(mockPreparedModel, /*executeSynchronously=*/true).value();
331
332 // run test
333 const auto resource = preparedModel->getUnderlyingResource();
334
335 // verify resource
336 const sp<V1_2::IPreparedModel>* maybeMock = std::any_cast<sp<V1_2::IPreparedModel>>(&resource);
337 ASSERT_NE(maybeMock, nullptr);
338 EXPECT_EQ(maybeMock->get(), mockPreparedModel.get());
339}
340
341} // namespace android::hardware::neuralnetworks::V1_2::utils