blob: db8f429f13af632d55f326569a42517d49b5e819 [file] [log] [blame]
Lev Proleevc185e882020-12-15 19:25:32 +00001/*
2 * Copyright (C) 2021 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_aidl_hal_test"
18
19#include <android/binder_auto_utils.h>
20
21#include <chrono>
22
23#include <TestHarness.h>
24#include <nnapi/hal/aidl/Utils.h>
25
26#include "Callbacks.h"
27#include "GeneratedTestHarness.h"
28#include "Utils.h"
29#include "VtsHalNeuralnetworks.h"
30
31namespace aidl::android::hardware::neuralnetworks::vts::functional {
32
33using ExecutionMutation = std::function<void(Request*)>;
34
35///////////////////////// UTILITY FUNCTIONS /////////////////////////
36
37// Primary validation function. This function will take a valid request, apply a
38// mutation to it to invalidate the request, then pass it to interface calls
39// that use the request.
40static void validate(const std::shared_ptr<IPreparedModel>& preparedModel,
41 const std::string& message, const Request& originalRequest,
42 const ExecutionMutation& mutate) {
43 Request request = utils::clone(originalRequest).value();
44 mutate(&request);
45
46 // We'd like to test both with timing requested and without timing
47 // requested. Rather than running each test both ways, we'll decide whether
48 // to request timing by hashing the message. We do not use std::hash because
49 // it is not guaranteed stable across executions.
50 char hash = 0;
51 for (auto c : message) {
52 hash ^= c;
53 };
54 bool measure = (hash & 1);
55
56 // synchronous
57 {
58 SCOPED_TRACE(message + " [executeSynchronously]");
59 ExecutionResult executionResult;
60 const auto executeStatus = preparedModel->executeSynchronously(
61 request, measure, kNoDeadline, kOmittedTimeoutDuration, &executionResult);
62 ASSERT_FALSE(executeStatus.isOk());
63 ASSERT_EQ(executeStatus.getExceptionCode(), EX_SERVICE_SPECIFIC);
64 ASSERT_EQ(static_cast<ErrorStatus>(executeStatus.getServiceSpecificError()),
65 ErrorStatus::INVALID_ARGUMENT);
66 }
67
68 // fenced
69 {
70 SCOPED_TRACE(message + " [executeFenced]");
71 ndk::ScopedFileDescriptor syncFence;
72 std::shared_ptr<IFencedExecutionCallback> callback;
73 const auto executeStatus = preparedModel->executeFenced(request, {}, false, kNoDeadline,
74 kOmittedTimeoutDuration,
75 kNoDuration, &syncFence, &callback);
76 ASSERT_FALSE(executeStatus.isOk());
77 ASSERT_EQ(executeStatus.getExceptionCode(), EX_SERVICE_SPECIFIC);
78 ASSERT_EQ(static_cast<ErrorStatus>(executeStatus.getServiceSpecificError()),
79 ErrorStatus::INVALID_ARGUMENT);
80 }
81}
82
83///////////////////////// REMOVE INPUT ////////////////////////////////////
84
85static void removeInputTest(const std::shared_ptr<IPreparedModel>& preparedModel,
86 const Request& request) {
87 for (size_t input = 0; input < request.inputs.size(); ++input) {
88 const std::string message = "removeInput: removed input " + std::to_string(input);
89 validate(preparedModel, message, request, [input](Request* request) {
90 request->inputs.erase(request->inputs.begin() + input);
91 });
92 }
93}
94
95///////////////////////// REMOVE OUTPUT ////////////////////////////////////
96
97static void removeOutputTest(const std::shared_ptr<IPreparedModel>& preparedModel,
98 const Request& request) {
99 for (size_t output = 0; output < request.outputs.size(); ++output) {
100 const std::string message = "removeOutput: removed Output " + std::to_string(output);
101 validate(preparedModel, message, request, [output](Request* request) {
102 request->outputs.erase(request->outputs.begin() + output);
103 });
104 }
105}
106
107///////////////////////////// ENTRY POINT //////////////////////////////////
108
109void validateRequest(const std::shared_ptr<IPreparedModel>& preparedModel, const Request& request) {
110 removeInputTest(preparedModel, request);
111 removeOutputTest(preparedModel, request);
112}
113
114void validateRequestFailure(const std::shared_ptr<IPreparedModel>& preparedModel,
115 const Request& request) {
116 SCOPED_TRACE("Expecting request to fail [executeSynchronously]");
117 ExecutionResult executionResult;
118 const auto executeStatus = preparedModel->executeSynchronously(
119 request, false, kNoDeadline, kOmittedTimeoutDuration, &executionResult);
120
121 ASSERT_FALSE(executeStatus.isOk());
122 ASSERT_EQ(executeStatus.getExceptionCode(), EX_SERVICE_SPECIFIC);
123 ASSERT_NE(static_cast<ErrorStatus>(executeStatus.getServiceSpecificError()), ErrorStatus::NONE);
124}
125
126} // namespace aidl::android::hardware::neuralnetworks::vts::functional