blob: fccc61257430061fbe52a06e55b454236319e37e [file] [log] [blame]
Michael Butler616701d2020-01-07 14:52:44 -08001/*
2 * Copyright (C) 2019 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 "1.0/Utils.h"
18#include "1.3/Callbacks.h"
19#include "1.3/Utils.h"
20#include "GeneratedTestHarness.h"
21#include "Utils.h"
22
23namespace android::hardware::neuralnetworks::V1_3::vts::functional {
24
25using implementation::ExecutionCallback;
26using implementation::PreparedModelCallback;
27using test_helper::TestBuffer;
28using test_helper::TestModel;
29using V1_1::ExecutionPreference;
30using V1_2::MeasureTiming;
31using V1_2::OutputShape;
32using V1_2::Timing;
33
34using HidlToken =
35 hidl_array<uint8_t, static_cast<uint32_t>(V1_2::Constant::BYTE_SIZE_OF_CACHE_TOKEN)>;
36
37enum class DeadlineBoundType { NOW, UNLIMITED };
38constexpr std::array<DeadlineBoundType, 2> deadlineBounds = {DeadlineBoundType::NOW,
39 DeadlineBoundType::UNLIMITED};
40std::string toString(DeadlineBoundType type) {
41 switch (type) {
42 case DeadlineBoundType::NOW:
43 return "NOW";
44 case DeadlineBoundType::UNLIMITED:
45 return "UNLIMITED";
46 }
47 LOG(FATAL) << "Unrecognized DeadlineBoundType: " << static_cast<int>(type);
48 return {};
49}
50
51using Results = std::tuple<ErrorStatus, hidl_vec<OutputShape>, Timing>;
52using MaybeResults = std::optional<Results>;
53
54using ExecutionFunction =
55 std::function<MaybeResults(const sp<IPreparedModel>& preparedModel, const Request& request,
56 DeadlineBoundType deadlineBound)>;
57
58static OptionalTimePoint makeOptionalTimePoint(DeadlineBoundType deadlineBoundType) {
59 OptionalTimePoint deadline;
60 switch (deadlineBoundType) {
61 case DeadlineBoundType::NOW: {
62 const auto currentTime = std::chrono::steady_clock::now();
63 const auto currentTimeInNanoseconds =
64 std::chrono::time_point_cast<std::chrono::nanoseconds>(currentTime);
65 const uint64_t nanosecondsSinceEpoch =
66 currentTimeInNanoseconds.time_since_epoch().count();
Michael Butler6a4172c2020-02-04 16:15:04 -080067 deadline.nanosecondsSinceEpoch(nanosecondsSinceEpoch);
Michael Butler616701d2020-01-07 14:52:44 -080068 } break;
69 case DeadlineBoundType::UNLIMITED: {
Michael Butler79d6bb12020-02-12 18:54:07 -080070 const auto maxTime = std::chrono::time_point<std::chrono::steady_clock,
71 std::chrono::nanoseconds>::max();
72 const uint64_t nanosecondsSinceEpoch = maxTime.time_since_epoch().count();
73 deadline.nanosecondsSinceEpoch(nanosecondsSinceEpoch);
Michael Butler616701d2020-01-07 14:52:44 -080074 } break;
75 }
76 return deadline;
77}
78
79void runPrepareModelTest(const sp<IDevice>& device, const Model& model, Priority priority,
80 std::optional<DeadlineBoundType> deadlineBound) {
81 OptionalTimePoint deadline;
82 if (deadlineBound.has_value()) {
83 deadline = makeOptionalTimePoint(deadlineBound.value());
84 }
85
86 // see if service can handle model
87 bool fullySupportsModel = false;
88 const Return<void> supportedCall = device->getSupportedOperations_1_3(
89 model, [&fullySupportsModel](ErrorStatus status, const hidl_vec<bool>& supported) {
90 ASSERT_EQ(ErrorStatus::NONE, status);
91 ASSERT_NE(0ul, supported.size());
92 fullySupportsModel = std::all_of(supported.begin(), supported.end(),
93 [](bool valid) { return valid; });
94 });
95 ASSERT_TRUE(supportedCall.isOk());
96
97 // launch prepare model
98 const sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
99 const Return<ErrorStatus> prepareLaunchStatus = device->prepareModel_1_3(
100 model, ExecutionPreference::FAST_SINGLE_ANSWER, priority, deadline,
101 hidl_vec<hidl_handle>(), hidl_vec<hidl_handle>(), HidlToken(), preparedModelCallback);
102 ASSERT_TRUE(prepareLaunchStatus.isOk());
103 ASSERT_EQ(ErrorStatus::NONE, static_cast<ErrorStatus>(prepareLaunchStatus));
104
105 // retrieve prepared model
106 preparedModelCallback->wait();
107 const ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus();
108 const sp<V1_0::IPreparedModel> preparedModelV1_0 = preparedModelCallback->getPreparedModel();
109 const sp<IPreparedModel> preparedModel =
110 IPreparedModel::castFrom(preparedModelV1_0).withDefault(nullptr);
111
112 // The getSupportedOperations_1_3 call returns a list of operations that are
113 // guaranteed not to fail if prepareModel_1_3 is called, and
114 // 'fullySupportsModel' is true i.f.f. the entire model is guaranteed.
115 // If a driver has any doubt that it can prepare an operation, it must
116 // return false. So here, if a driver isn't sure if it can support an
117 // operation, but reports that it successfully prepared the model, the test
118 // can continue.
119 if (!fullySupportsModel && prepareReturnStatus != ErrorStatus::NONE) {
120 ASSERT_EQ(nullptr, preparedModel.get());
121 return;
122 }
123
124 // verify return status
125 if (!deadlineBound.has_value()) {
126 EXPECT_EQ(ErrorStatus::NONE, prepareReturnStatus);
127 } else {
128 switch (deadlineBound.value()) {
129 case DeadlineBoundType::NOW:
130 // If the execution was launched with a deadline of NOW, the
131 // deadline has already passed when the driver would launch the
132 // execution. In this case, the driver must return
133 // MISSED_DEADLINE_*.
134 EXPECT_TRUE(prepareReturnStatus == ErrorStatus::MISSED_DEADLINE_TRANSIENT ||
135 prepareReturnStatus == ErrorStatus::MISSED_DEADLINE_PERSISTENT);
136 break;
137 case DeadlineBoundType::UNLIMITED:
138 // If an unlimited deadline is supplied, we expect the execution to
139 // proceed normally. In this case, check it normally by breaking out
140 // of the switch statement.
141 EXPECT_EQ(ErrorStatus::NONE, prepareReturnStatus);
142 break;
143 }
144 }
145 ASSERT_EQ(prepareReturnStatus == ErrorStatus::NONE, preparedModel.get() != nullptr);
146}
147
148void runPrepareModelTests(const sp<IDevice>& device, const Model& model,
149 bool supportsPrepareModelDeadline) {
150 // test priority
151 for (auto priority : hidl_enum_range<Priority>{}) {
152 SCOPED_TRACE("priority: " + toString(priority));
153 if (priority == kDefaultPriority) continue;
154 runPrepareModelTest(device, model, priority, {});
155 }
156
157 // test deadline
158 if (supportsPrepareModelDeadline) {
159 for (auto deadlineBound : deadlineBounds) {
160 SCOPED_TRACE("deadlineBound: " + toString(deadlineBound));
161 runPrepareModelTest(device, model, kDefaultPriority, deadlineBound);
162 }
163 }
164}
165
166static MaybeResults executeAsynchronously(const sp<IPreparedModel>& preparedModel,
167 const Request& request, DeadlineBoundType deadlineBound) {
168 SCOPED_TRACE("asynchronous");
169 const MeasureTiming measure = MeasureTiming::NO;
170 const OptionalTimePoint deadline = makeOptionalTimePoint(deadlineBound);
171
172 // launch execution
173 const sp<ExecutionCallback> callback = new ExecutionCallback();
Slava Shklyaevf034bf92020-02-11 14:27:02 +0000174 Return<ErrorStatus> ret = preparedModel->execute_1_3(request, measure, deadline, {}, callback);
Michael Butler616701d2020-01-07 14:52:44 -0800175 EXPECT_TRUE(ret.isOk());
176 EXPECT_EQ(ErrorStatus::NONE, ret.withDefault(ErrorStatus::GENERAL_FAILURE));
177 if (!ret.isOk() || ret != ErrorStatus::NONE) return std::nullopt;
178
179 // retrieve execution results
180 callback->wait();
181 const ErrorStatus status = callback->getStatus();
182 hidl_vec<OutputShape> outputShapes = callback->getOutputShapes();
183 const Timing timing = callback->getTiming();
184
185 // return results
186 return Results{status, std::move(outputShapes), timing};
187}
188
189static MaybeResults executeSynchronously(const sp<IPreparedModel>& preparedModel,
190 const Request& request, DeadlineBoundType deadlineBound) {
191 SCOPED_TRACE("synchronous");
192 const MeasureTiming measure = MeasureTiming::NO;
193 const OptionalTimePoint deadline = makeOptionalTimePoint(deadlineBound);
194
195 // configure results callback
196 MaybeResults results;
197 const auto cb = [&results](const auto&... args) { *results = {args...}; };
198
199 // run execution
200 const Return<void> ret =
Slava Shklyaevf034bf92020-02-11 14:27:02 +0000201 preparedModel->executeSynchronously_1_3(request, measure, deadline, {}, cb);
Michael Butler616701d2020-01-07 14:52:44 -0800202 EXPECT_TRUE(ret.isOk());
203 if (!ret.isOk()) return std::nullopt;
204
205 // return results
206 return results;
207}
208
209void runExecutionTest(const sp<IPreparedModel>& preparedModel, const TestModel& testModel,
210 const Request& request, bool synchronous, DeadlineBoundType deadlineBound) {
211 const ExecutionFunction execute = synchronous ? executeSynchronously : executeAsynchronously;
212
213 // Perform execution and unpack results.
214 const auto results = execute(preparedModel, request, deadlineBound);
215 if (!results.has_value()) return;
216 const auto& [status, outputShapes, timing] = results.value();
217
218 // Verify no timing information was returned
219 EXPECT_EQ(UINT64_MAX, timing.timeOnDevice);
220 EXPECT_EQ(UINT64_MAX, timing.timeInDriver);
221
222 // Validate deadline information if applicable.
223 switch (deadlineBound) {
224 case DeadlineBoundType::NOW:
225 // If the execution was launched with a deadline of NOW, the
226 // deadline has already passed when the driver would launch the
227 // execution. In this case, the driver must return
228 // MISSED_DEADLINE_*.
229 ASSERT_TRUE(status == ErrorStatus::MISSED_DEADLINE_TRANSIENT ||
230 status == ErrorStatus::MISSED_DEADLINE_PERSISTENT);
231 return;
232 case DeadlineBoundType::UNLIMITED:
233 // If an unlimited deadline is supplied, we expect the execution to
234 // proceed normally. In this case, check it normally by breaking out
235 // of the switch statement.
236 ASSERT_EQ(ErrorStatus::NONE, status);
237 break;
238 }
239
240 // If the model output operands are fully specified, outputShapes must be either
241 // either empty, or have the same number of elements as the number of outputs.
Slava Shklyaev1f98e2e2020-01-31 15:14:24 +0000242 ASSERT_TRUE(outputShapes.size() == 0 ||
243 outputShapes.size() == testModel.main.outputIndexes.size());
Michael Butler616701d2020-01-07 14:52:44 -0800244
245 // Go through all outputs, check returned output shapes.
246 for (uint32_t i = 0; i < outputShapes.size(); i++) {
247 EXPECT_TRUE(outputShapes[i].isSufficient);
Slava Shklyaev1f98e2e2020-01-31 15:14:24 +0000248 const auto& expect = testModel.main.operands[testModel.main.outputIndexes[i]].dimensions;
Michael Butler616701d2020-01-07 14:52:44 -0800249 const std::vector<uint32_t> actual = outputShapes[i].dimensions;
250 EXPECT_EQ(expect, actual);
251 }
252
253 // Retrieve execution results.
254 ASSERT_TRUE(nn::compliantWithV1_0(request));
255 const V1_0::Request request10 = nn::convertToV1_0(request);
256 const std::vector<TestBuffer> outputs = getOutputBuffers(request10);
257
258 // We want "close-enough" results.
259 checkResults(testModel, outputs);
260}
261
262void runExecutionTests(const sp<IPreparedModel>& preparedModel, const TestModel& testModel,
263 const Request& request) {
264 for (bool synchronous : {false, true}) {
265 for (auto deadlineBound : deadlineBounds) {
266 runExecutionTest(preparedModel, testModel, request, synchronous, deadlineBound);
267 }
268 }
269}
270
271void runTests(const sp<IDevice>& device, const TestModel& testModel,
272 std::pair<bool, bool> supportsDeadlines) {
273 // setup
274 const auto [supportsPrepareModelDeadline, supportsExecutionDeadline] = supportsDeadlines;
275 if (!supportsPrepareModelDeadline && !supportsExecutionDeadline) return;
276 const Model model = createModel(testModel);
277
278 // run prepare model tests
279 runPrepareModelTests(device, model, supportsPrepareModelDeadline);
280
281 if (supportsExecutionDeadline) {
282 // prepare model
283 sp<IPreparedModel> preparedModel;
284 createPreparedModel(device, model, &preparedModel);
285 if (preparedModel == nullptr) return;
286
287 // run execution tests
288 const Request request = nn::convertToV1_3(createRequest(testModel));
289 runExecutionTests(preparedModel, testModel, request);
290 }
291}
292
293class DeadlineTest : public GeneratedTestBase {};
294
295TEST_P(DeadlineTest, Test) {
296 runTests(kDevice, kTestModel, mSupportsDeadlines);
297}
298
299INSTANTIATE_GENERATED_TEST(DeadlineTest,
300 [](const TestModel& testModel) { return !testModel.expectFailure; });
301
302} // namespace android::hardware::neuralnetworks::V1_3::vts::functional