blob: 20f4fe2c00370ca8eb6ea24cc0d6c254d126bee8 [file] [log] [blame]
Lev Proleev3b13b552019-08-30 11:35:34 +01001/*
2 * Copyright (C) 2018 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#define LOG_TAG "neuralnetworks_hidl_hal_test"
18
Miao Wang2c4e0232019-12-26 18:03:56 -080019#include <android/hardware/neuralnetworks/1.3/IFencedExecutionCallback.h>
Michael Butler57568872019-07-25 17:22:11 -070020#include <chrono>
Miao Wang2c4e0232019-12-26 18:03:56 -080021
Lev Proleev3b13b552019-08-30 11:35:34 +010022#include "1.0/Utils.h"
Michael Butler9449a282019-12-11 19:08:08 -080023#include "1.3/Callbacks.h"
Lev Proleev3b13b552019-08-30 11:35:34 +010024#include "ExecutionBurstController.h"
25#include "GeneratedTestHarness.h"
26#include "TestHarness.h"
27#include "Utils.h"
28#include "VtsHalNeuralnetworks.h"
29
Lev Proleevb49dadf2019-08-30 11:57:18 +010030namespace android::hardware::neuralnetworks::V1_3::vts::functional {
Lev Proleev3b13b552019-08-30 11:35:34 +010031
Michael Butler9449a282019-12-11 19:08:08 -080032using implementation::ExecutionCallback;
Lev Proleevb49dadf2019-08-30 11:57:18 +010033using V1_2::MeasureTiming;
34using V1_2::OutputShape;
35using V1_2::Timing;
Lev Proleev3b13b552019-08-30 11:35:34 +010036
37///////////////////////// UTILITY FUNCTIONS /////////////////////////
38
39static bool badTiming(Timing timing) {
40 return timing.timeOnDevice == UINT64_MAX && timing.timeInDriver == UINT64_MAX;
41}
42
43// Primary validation function. This function will take a valid request, apply a
44// mutation to it to invalidate the request, then pass it to interface calls
45// that use the request. Note that the request here is passed by value, and any
46// mutation to the request does not leave this function.
47static void validate(const sp<IPreparedModel>& preparedModel, const std::string& message,
Michael Butler616701d2020-01-07 14:52:44 -080048 Request request, const std::function<void(Request*)>& mutation,
49 bool testDeadline = false) {
Lev Proleev3b13b552019-08-30 11:35:34 +010050 mutation(&request);
51
52 // We'd like to test both with timing requested and without timing
53 // requested. Rather than running each test both ways, we'll decide whether
54 // to request timing by hashing the message. We do not use std::hash because
55 // it is not guaranteed stable across executions.
56 char hash = 0;
57 for (auto c : message) {
58 hash ^= c;
59 };
60 MeasureTiming measure = (hash & 1) ? MeasureTiming::YES : MeasureTiming::NO;
61
Michael Butler616701d2020-01-07 14:52:44 -080062 OptionalTimePoint deadline;
63 if (testDeadline) {
Michael Butler6a4172c2020-02-04 16:15:04 -080064 deadline.nanosecondsSinceEpoch(std::numeric_limits<uint64_t>::max());
Michael Butler616701d2020-01-07 14:52:44 -080065 }
66
Lev Proleev3b13b552019-08-30 11:35:34 +010067 // asynchronous
68 {
Xusong Wang62a760c2019-10-25 12:07:17 -070069 SCOPED_TRACE(message + " [execute_1_3]");
Lev Proleev3b13b552019-08-30 11:35:34 +010070
71 sp<ExecutionCallback> executionCallback = new ExecutionCallback();
72 Return<ErrorStatus> executeLaunchStatus =
Slava Shklyaevf034bf92020-02-11 14:27:02 +000073 preparedModel->execute_1_3(request, measure, deadline, {}, executionCallback);
Lev Proleev3b13b552019-08-30 11:35:34 +010074 ASSERT_TRUE(executeLaunchStatus.isOk());
75 ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, static_cast<ErrorStatus>(executeLaunchStatus));
76
77 executionCallback->wait();
78 ErrorStatus executionReturnStatus = executionCallback->getStatus();
79 const auto& outputShapes = executionCallback->getOutputShapes();
80 Timing timing = executionCallback->getTiming();
81 ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, executionReturnStatus);
82 ASSERT_EQ(outputShapes.size(), 0);
83 ASSERT_TRUE(badTiming(timing));
84 }
85
86 // synchronous
87 {
Xusong Wangebd88ba2019-10-28 11:11:19 -070088 SCOPED_TRACE(message + " [executeSynchronously_1_3]");
Lev Proleev3b13b552019-08-30 11:35:34 +010089
Xusong Wangebd88ba2019-10-28 11:11:19 -070090 Return<void> executeStatus = preparedModel->executeSynchronously_1_3(
Slava Shklyaevf034bf92020-02-11 14:27:02 +000091 request, measure, deadline, {},
Lev Proleev3b13b552019-08-30 11:35:34 +010092 [](ErrorStatus error, const hidl_vec<OutputShape>& outputShapes,
93 const Timing& timing) {
94 ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, error);
95 EXPECT_EQ(outputShapes.size(), 0);
96 EXPECT_TRUE(badTiming(timing));
97 });
98 ASSERT_TRUE(executeStatus.isOk());
99 }
100
101 // burst
Xusong Wang931d5a12019-11-27 12:46:48 -0800102 // TODO(butlermichael): Check if we need to test burst in V1_3 if the interface remains V1_2.
Michael Butler616701d2020-01-07 14:52:44 -0800103 if (!testDeadline) {
Lev Proleev3b13b552019-08-30 11:35:34 +0100104 SCOPED_TRACE(message + " [burst]");
105
Xusong Wang931d5a12019-11-27 12:46:48 -0800106 ASSERT_TRUE(nn::compliantWithV1_0(request));
107 V1_0::Request request10 = nn::convertToV1_0(request);
108
Lev Proleev3b13b552019-08-30 11:35:34 +0100109 // create burst
110 std::shared_ptr<::android::nn::ExecutionBurstController> burst =
Michael Butler57568872019-07-25 17:22:11 -0700111 android::nn::ExecutionBurstController::create(preparedModel,
112 std::chrono::microseconds{0});
Lev Proleev3b13b552019-08-30 11:35:34 +0100113 ASSERT_NE(nullptr, burst.get());
114
115 // create memory keys
Xusong Wang931d5a12019-11-27 12:46:48 -0800116 std::vector<intptr_t> keys(request10.pools.size());
Lev Proleev3b13b552019-08-30 11:35:34 +0100117 for (size_t i = 0; i < keys.size(); ++i) {
Xusong Wang931d5a12019-11-27 12:46:48 -0800118 keys[i] = reinterpret_cast<intptr_t>(&request10.pools[i]);
Lev Proleev3b13b552019-08-30 11:35:34 +0100119 }
120
121 // execute and verify
Xusong Wang931d5a12019-11-27 12:46:48 -0800122 const auto [n, outputShapes, timing, fallback] = burst->compute(request10, measure, keys);
Michael Butler57568872019-07-25 17:22:11 -0700123 const ErrorStatus status = nn::convertResultCodeToErrorStatus(n);
124 EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, status);
Lev Proleev3b13b552019-08-30 11:35:34 +0100125 EXPECT_EQ(outputShapes.size(), 0);
126 EXPECT_TRUE(badTiming(timing));
Michael Butler57568872019-07-25 17:22:11 -0700127 EXPECT_FALSE(fallback);
Lev Proleev3b13b552019-08-30 11:35:34 +0100128
129 // additional burst testing
Xusong Wang931d5a12019-11-27 12:46:48 -0800130 if (request10.pools.size() > 0) {
Lev Proleev3b13b552019-08-30 11:35:34 +0100131 // valid free
132 burst->freeMemory(keys.front());
133
134 // negative test: invalid free of unknown (blank) memory
135 burst->freeMemory(intptr_t{});
136
137 // negative test: double free of memory
138 burst->freeMemory(keys.front());
139 }
140 }
Miao Wang2c4e0232019-12-26 18:03:56 -0800141
142 // dispatch
143 {
144 SCOPED_TRACE(message + " [executeFenced]");
Miao Wang15a25f62020-02-06 15:36:41 -0800145 Return<void> ret =
Slava Shklyaevf034bf92020-02-11 14:27:02 +0000146 preparedModel->executeFenced(request, {}, MeasureTiming::NO, deadline, {}, {},
Miao Wang15a25f62020-02-06 15:36:41 -0800147 [](ErrorStatus error, const hidl_handle& handle,
148 const sp<IFencedExecutionCallback>& callback) {
149 ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, error);
150 ASSERT_EQ(handle.getNativeHandle(), nullptr);
151 ASSERT_EQ(callback, nullptr);
152 });
Miao Wang2c4e0232019-12-26 18:03:56 -0800153 ASSERT_TRUE(ret.isOk());
154 }
Lev Proleev3b13b552019-08-30 11:35:34 +0100155}
156
157///////////////////////// REMOVE INPUT ////////////////////////////////////
158
159static void removeInputTest(const sp<IPreparedModel>& preparedModel, const Request& request) {
160 for (size_t input = 0; input < request.inputs.size(); ++input) {
161 const std::string message = "removeInput: removed input " + std::to_string(input);
162 validate(preparedModel, message, request,
163 [input](Request* request) { hidl_vec_removeAt(&request->inputs, input); });
164 }
165}
166
167///////////////////////// REMOVE OUTPUT ////////////////////////////////////
168
169static void removeOutputTest(const sp<IPreparedModel>& preparedModel, const Request& request) {
170 for (size_t output = 0; output < request.outputs.size(); ++output) {
171 const std::string message = "removeOutput: removed Output " + std::to_string(output);
172 validate(preparedModel, message, request,
173 [output](Request* request) { hidl_vec_removeAt(&request->outputs, output); });
174 }
175}
176
Michael Butler616701d2020-01-07 14:52:44 -0800177///////////////////////// DEADLINE ////////////////////////////////////
178
179static void deadlineTest(const sp<IPreparedModel>& preparedModel, const Request& request) {
180 const std::string message = "deadlineTest: deadline not supported";
181 const auto noop = [](Request*) {};
182 validate(preparedModel, message, request, noop, /*testDeadline=*/true);
183}
184
Lev Proleev3b13b552019-08-30 11:35:34 +0100185///////////////////////////// ENTRY POINT //////////////////////////////////
186
Michael Butler616701d2020-01-07 14:52:44 -0800187void validateRequest(const sp<IPreparedModel>& preparedModel, const Request& request,
188 bool executionDeadlineSupported) {
Lev Proleev3b13b552019-08-30 11:35:34 +0100189 removeInputTest(preparedModel, request);
190 removeOutputTest(preparedModel, request);
Michael Butler616701d2020-01-07 14:52:44 -0800191 if (!executionDeadlineSupported) {
192 deadlineTest(preparedModel, request);
193 }
Lev Proleev3b13b552019-08-30 11:35:34 +0100194}
195
196void validateRequestFailure(const sp<IPreparedModel>& preparedModel, const Request& request) {
Xusong Wangebd88ba2019-10-28 11:11:19 -0700197 SCOPED_TRACE("Expecting request to fail [executeSynchronously_1_3]");
198 Return<void> executeStatus = preparedModel->executeSynchronously_1_3(
Slava Shklyaevf034bf92020-02-11 14:27:02 +0000199 request, MeasureTiming::NO, {}, {},
Lev Proleev3b13b552019-08-30 11:35:34 +0100200 [](ErrorStatus error, const hidl_vec<OutputShape>& outputShapes, const Timing& timing) {
201 ASSERT_NE(ErrorStatus::NONE, error);
202 EXPECT_EQ(outputShapes.size(), 0);
203 EXPECT_TRUE(badTiming(timing));
204 });
205 ASSERT_TRUE(executeStatus.isOk());
206}
207
Lev Proleevb49dadf2019-08-30 11:57:18 +0100208} // namespace android::hardware::neuralnetworks::V1_3::vts::functional