blob: 2ef1e8f6bd1ce74e3a3f2ad4284ec38920af1828 [file] [log] [blame]
Michael Butler95899b32020-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
Michael Butlerff7d6c52020-02-13 16:37:22 -080037enum class DeadlineBoundType { NOW, UNLIMITED, SHORT };
38constexpr std::array<DeadlineBoundType, 3> deadlineBounds = {
39 DeadlineBoundType::NOW, DeadlineBoundType::UNLIMITED, DeadlineBoundType::SHORT};
Michael Butler95899b32020-01-07 14:52:44 -080040std::string toString(DeadlineBoundType type) {
41 switch (type) {
42 case DeadlineBoundType::NOW:
43 return "NOW";
44 case DeadlineBoundType::UNLIMITED:
45 return "UNLIMITED";
Michael Butlerff7d6c52020-02-13 16:37:22 -080046 case DeadlineBoundType::SHORT:
47 return "SHORT";
Michael Butler95899b32020-01-07 14:52:44 -080048 }
49 LOG(FATAL) << "Unrecognized DeadlineBoundType: " << static_cast<int>(type);
50 return {};
51}
52
Michael Butlerff7d6c52020-02-13 16:37:22 -080053constexpr auto kShortDuration = std::chrono::milliseconds{5};
54
Michael Butler95899b32020-01-07 14:52:44 -080055using Results = std::tuple<ErrorStatus, hidl_vec<OutputShape>, Timing>;
56using MaybeResults = std::optional<Results>;
57
58using ExecutionFunction =
59 std::function<MaybeResults(const sp<IPreparedModel>& preparedModel, const Request& request,
Michael Butlerff7d6c52020-02-13 16:37:22 -080060 const OptionalTimePoint& deadline)>;
Michael Butler95899b32020-01-07 14:52:44 -080061
Michael Butlerff7d6c52020-02-13 16:37:22 -080062static OptionalTimePoint makeDeadline(DeadlineBoundType deadlineBoundType) {
63 const auto getNanosecondsSinceEpoch = [](const auto& time) -> uint64_t {
64 const auto timeSinceEpoch = time.time_since_epoch();
65 return std::chrono::duration_cast<std::chrono::nanoseconds>(timeSinceEpoch).count();
66 };
67
68 std::chrono::steady_clock::time_point timePoint;
Michael Butler95899b32020-01-07 14:52:44 -080069 switch (deadlineBoundType) {
Michael Butlerff7d6c52020-02-13 16:37:22 -080070 case DeadlineBoundType::NOW:
71 timePoint = std::chrono::steady_clock::now();
72 break;
73 case DeadlineBoundType::UNLIMITED:
74 timePoint = std::chrono::steady_clock::time_point::max();
75 break;
76 case DeadlineBoundType::SHORT:
77 timePoint = std::chrono::steady_clock::now() + kShortDuration;
78 break;
Michael Butler95899b32020-01-07 14:52:44 -080079 }
Michael Butlerff7d6c52020-02-13 16:37:22 -080080
81 OptionalTimePoint deadline;
82 deadline.nanosecondsSinceEpoch(getNanosecondsSinceEpoch(timePoint));
Michael Butler95899b32020-01-07 14:52:44 -080083 return deadline;
84}
85
86void runPrepareModelTest(const sp<IDevice>& device, const Model& model, Priority priority,
87 std::optional<DeadlineBoundType> deadlineBound) {
88 OptionalTimePoint deadline;
89 if (deadlineBound.has_value()) {
Michael Butlerff7d6c52020-02-13 16:37:22 -080090 deadline = makeDeadline(deadlineBound.value());
Michael Butler95899b32020-01-07 14:52:44 -080091 }
92
93 // see if service can handle model
94 bool fullySupportsModel = false;
95 const Return<void> supportedCall = device->getSupportedOperations_1_3(
96 model, [&fullySupportsModel](ErrorStatus status, const hidl_vec<bool>& supported) {
97 ASSERT_EQ(ErrorStatus::NONE, status);
98 ASSERT_NE(0ul, supported.size());
99 fullySupportsModel = std::all_of(supported.begin(), supported.end(),
100 [](bool valid) { return valid; });
101 });
102 ASSERT_TRUE(supportedCall.isOk());
103
104 // launch prepare model
105 const sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
106 const Return<ErrorStatus> prepareLaunchStatus = device->prepareModel_1_3(
107 model, ExecutionPreference::FAST_SINGLE_ANSWER, priority, deadline,
108 hidl_vec<hidl_handle>(), hidl_vec<hidl_handle>(), HidlToken(), preparedModelCallback);
109 ASSERT_TRUE(prepareLaunchStatus.isOk());
110 ASSERT_EQ(ErrorStatus::NONE, static_cast<ErrorStatus>(prepareLaunchStatus));
111
112 // retrieve prepared model
113 preparedModelCallback->wait();
114 const ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus();
115 const sp<V1_0::IPreparedModel> preparedModelV1_0 = preparedModelCallback->getPreparedModel();
116 const sp<IPreparedModel> preparedModel =
117 IPreparedModel::castFrom(preparedModelV1_0).withDefault(nullptr);
118
119 // The getSupportedOperations_1_3 call returns a list of operations that are
120 // guaranteed not to fail if prepareModel_1_3 is called, and
121 // 'fullySupportsModel' is true i.f.f. the entire model is guaranteed.
122 // If a driver has any doubt that it can prepare an operation, it must
123 // return false. So here, if a driver isn't sure if it can support an
124 // operation, but reports that it successfully prepared the model, the test
125 // can continue.
126 if (!fullySupportsModel && prepareReturnStatus != ErrorStatus::NONE) {
127 ASSERT_EQ(nullptr, preparedModel.get());
128 return;
129 }
130
131 // verify return status
132 if (!deadlineBound.has_value()) {
133 EXPECT_EQ(ErrorStatus::NONE, prepareReturnStatus);
134 } else {
135 switch (deadlineBound.value()) {
136 case DeadlineBoundType::NOW:
Michael Butler5c40bcc2020-02-18 18:38:37 -0800137 case DeadlineBoundType::SHORT:
138 // Either the driver successfully completed the task or it
139 // aborted and returned MISSED_DEADLINE_*.
Michael Butlerff7d6c52020-02-13 16:37:22 -0800140 EXPECT_TRUE(prepareReturnStatus == ErrorStatus::NONE ||
141 prepareReturnStatus == ErrorStatus::MISSED_DEADLINE_TRANSIENT ||
Michael Butler95899b32020-01-07 14:52:44 -0800142 prepareReturnStatus == ErrorStatus::MISSED_DEADLINE_PERSISTENT);
143 break;
144 case DeadlineBoundType::UNLIMITED:
145 // If an unlimited deadline is supplied, we expect the execution to
146 // proceed normally. In this case, check it normally by breaking out
147 // of the switch statement.
148 EXPECT_EQ(ErrorStatus::NONE, prepareReturnStatus);
149 break;
150 }
151 }
152 ASSERT_EQ(prepareReturnStatus == ErrorStatus::NONE, preparedModel.get() != nullptr);
153}
154
Michael Butlerff7d6c52020-02-13 16:37:22 -0800155void runPrepareModelTests(const sp<IDevice>& device, const Model& model) {
Michael Butler95899b32020-01-07 14:52:44 -0800156 // test priority
157 for (auto priority : hidl_enum_range<Priority>{}) {
158 SCOPED_TRACE("priority: " + toString(priority));
159 if (priority == kDefaultPriority) continue;
160 runPrepareModelTest(device, model, priority, {});
161 }
162
163 // test deadline
Michael Butlerff7d6c52020-02-13 16:37:22 -0800164 for (auto deadlineBound : deadlineBounds) {
165 SCOPED_TRACE("deadlineBound: " + toString(deadlineBound));
166 runPrepareModelTest(device, model, kDefaultPriority, deadlineBound);
Michael Butler95899b32020-01-07 14:52:44 -0800167 }
168}
169
170static MaybeResults executeAsynchronously(const sp<IPreparedModel>& preparedModel,
Michael Butlerff7d6c52020-02-13 16:37:22 -0800171 const Request& request,
172 const OptionalTimePoint& deadline) {
Michael Butler95899b32020-01-07 14:52:44 -0800173 SCOPED_TRACE("asynchronous");
174 const MeasureTiming measure = MeasureTiming::NO;
Michael Butler95899b32020-01-07 14:52:44 -0800175
176 // launch execution
177 const sp<ExecutionCallback> callback = new ExecutionCallback();
Slava Shklyaeva96ab742020-02-11 14:27:02 +0000178 Return<ErrorStatus> ret = preparedModel->execute_1_3(request, measure, deadline, {}, callback);
Michael Butler95899b32020-01-07 14:52:44 -0800179 EXPECT_TRUE(ret.isOk());
180 EXPECT_EQ(ErrorStatus::NONE, ret.withDefault(ErrorStatus::GENERAL_FAILURE));
181 if (!ret.isOk() || ret != ErrorStatus::NONE) return std::nullopt;
182
183 // retrieve execution results
184 callback->wait();
185 const ErrorStatus status = callback->getStatus();
186 hidl_vec<OutputShape> outputShapes = callback->getOutputShapes();
187 const Timing timing = callback->getTiming();
188
189 // return results
190 return Results{status, std::move(outputShapes), timing};
191}
192
193static MaybeResults executeSynchronously(const sp<IPreparedModel>& preparedModel,
Michael Butlerff7d6c52020-02-13 16:37:22 -0800194 const Request& request,
195 const OptionalTimePoint& deadline) {
Michael Butler95899b32020-01-07 14:52:44 -0800196 SCOPED_TRACE("synchronous");
197 const MeasureTiming measure = MeasureTiming::NO;
Michael Butler95899b32020-01-07 14:52:44 -0800198
199 // configure results callback
200 MaybeResults results;
Michael Butler5c40bcc2020-02-18 18:38:37 -0800201 const auto cb = [&results](ErrorStatus status, const hidl_vec<OutputShape>& outputShapes,
202 const Timing& timing) {
203 results.emplace(status, outputShapes, timing);
204 };
Michael Butler95899b32020-01-07 14:52:44 -0800205
206 // run execution
207 const Return<void> ret =
Slava Shklyaeva96ab742020-02-11 14:27:02 +0000208 preparedModel->executeSynchronously_1_3(request, measure, deadline, {}, cb);
Michael Butler95899b32020-01-07 14:52:44 -0800209 EXPECT_TRUE(ret.isOk());
210 if (!ret.isOk()) return std::nullopt;
211
212 // return results
213 return results;
214}
215
216void runExecutionTest(const sp<IPreparedModel>& preparedModel, const TestModel& testModel,
Xusong Wang75e63ad2020-02-25 11:43:10 -0800217 const Request& request, const ExecutionContext& context, bool synchronous,
218 DeadlineBoundType deadlineBound) {
Michael Butler95899b32020-01-07 14:52:44 -0800219 const ExecutionFunction execute = synchronous ? executeSynchronously : executeAsynchronously;
Michael Butlerff7d6c52020-02-13 16:37:22 -0800220 const auto deadline = makeDeadline(deadlineBound);
Michael Butler95899b32020-01-07 14:52:44 -0800221
222 // Perform execution and unpack results.
Michael Butlerff7d6c52020-02-13 16:37:22 -0800223 const auto results = execute(preparedModel, request, deadline);
Michael Butler95899b32020-01-07 14:52:44 -0800224 if (!results.has_value()) return;
225 const auto& [status, outputShapes, timing] = results.value();
226
227 // Verify no timing information was returned
228 EXPECT_EQ(UINT64_MAX, timing.timeOnDevice);
229 EXPECT_EQ(UINT64_MAX, timing.timeInDriver);
230
231 // Validate deadline information if applicable.
232 switch (deadlineBound) {
233 case DeadlineBoundType::NOW:
Michael Butler5c40bcc2020-02-18 18:38:37 -0800234 case DeadlineBoundType::SHORT:
235 // Either the driver successfully completed the task or it
236 // aborted and returned MISSED_DEADLINE_*.
Michael Butlerff7d6c52020-02-13 16:37:22 -0800237 ASSERT_TRUE(status == ErrorStatus::NONE ||
238 status == ErrorStatus::MISSED_DEADLINE_TRANSIENT ||
Michael Butler95899b32020-01-07 14:52:44 -0800239 status == ErrorStatus::MISSED_DEADLINE_PERSISTENT);
Michael Butler5c40bcc2020-02-18 18:38:37 -0800240 break;
Michael Butler95899b32020-01-07 14:52:44 -0800241 case DeadlineBoundType::UNLIMITED:
242 // If an unlimited deadline is supplied, we expect the execution to
243 // proceed normally. In this case, check it normally by breaking out
244 // of the switch statement.
245 ASSERT_EQ(ErrorStatus::NONE, status);
246 break;
247 }
248
249 // If the model output operands are fully specified, outputShapes must be either
250 // either empty, or have the same number of elements as the number of outputs.
Slava Shklyaev0fff59b2020-01-31 15:14:24 +0000251 ASSERT_TRUE(outputShapes.size() == 0 ||
252 outputShapes.size() == testModel.main.outputIndexes.size());
Michael Butler95899b32020-01-07 14:52:44 -0800253
254 // Go through all outputs, check returned output shapes.
255 for (uint32_t i = 0; i < outputShapes.size(); i++) {
256 EXPECT_TRUE(outputShapes[i].isSufficient);
Slava Shklyaev0fff59b2020-01-31 15:14:24 +0000257 const auto& expect = testModel.main.operands[testModel.main.outputIndexes[i]].dimensions;
Michael Butler95899b32020-01-07 14:52:44 -0800258 const std::vector<uint32_t> actual = outputShapes[i].dimensions;
259 EXPECT_EQ(expect, actual);
260 }
261
262 // Retrieve execution results.
263 ASSERT_TRUE(nn::compliantWithV1_0(request));
264 const V1_0::Request request10 = nn::convertToV1_0(request);
Xusong Wang75e63ad2020-02-25 11:43:10 -0800265 const std::vector<TestBuffer> outputs = context.getOutputBuffers(request10);
Michael Butler95899b32020-01-07 14:52:44 -0800266
267 // We want "close-enough" results.
Michael Butler5c40bcc2020-02-18 18:38:37 -0800268 if (status == ErrorStatus::NONE) {
269 checkResults(testModel, outputs);
270 }
Michael Butler95899b32020-01-07 14:52:44 -0800271}
272
273void runExecutionTests(const sp<IPreparedModel>& preparedModel, const TestModel& testModel,
Xusong Wang75e63ad2020-02-25 11:43:10 -0800274 const Request& request, const ExecutionContext& context) {
Michael Butler95899b32020-01-07 14:52:44 -0800275 for (bool synchronous : {false, true}) {
276 for (auto deadlineBound : deadlineBounds) {
Xusong Wang75e63ad2020-02-25 11:43:10 -0800277 runExecutionTest(preparedModel, testModel, request, context, synchronous,
278 deadlineBound);
Michael Butler95899b32020-01-07 14:52:44 -0800279 }
280 }
281}
282
Michael Butlerff7d6c52020-02-13 16:37:22 -0800283void runTests(const sp<IDevice>& device, const TestModel& testModel) {
Michael Butler95899b32020-01-07 14:52:44 -0800284 // setup
Michael Butler95899b32020-01-07 14:52:44 -0800285 const Model model = createModel(testModel);
286
287 // run prepare model tests
Michael Butlerff7d6c52020-02-13 16:37:22 -0800288 runPrepareModelTests(device, model);
Michael Butler95899b32020-01-07 14:52:44 -0800289
Michael Butlerff7d6c52020-02-13 16:37:22 -0800290 // prepare model
291 sp<IPreparedModel> preparedModel;
292 createPreparedModel(device, model, &preparedModel);
293 if (preparedModel == nullptr) return;
Michael Butler95899b32020-01-07 14:52:44 -0800294
Michael Butlerff7d6c52020-02-13 16:37:22 -0800295 // run execution tests
Xusong Wang75e63ad2020-02-25 11:43:10 -0800296 ExecutionContext context;
297 const Request request = nn::convertToV1_3(context.createRequest(testModel));
298 runExecutionTests(preparedModel, testModel, request, context);
Michael Butler95899b32020-01-07 14:52:44 -0800299}
300
301class DeadlineTest : public GeneratedTestBase {};
302
303TEST_P(DeadlineTest, Test) {
Michael Butlerff7d6c52020-02-13 16:37:22 -0800304 runTests(kDevice, kTestModel);
Michael Butler95899b32020-01-07 14:52:44 -0800305}
306
307INSTANTIATE_GENERATED_TEST(DeadlineTest,
308 [](const TestModel& testModel) { return !testModel.expectFailure; });
309
310} // namespace android::hardware::neuralnetworks::V1_3::vts::functional