blob: 49b9b0bcc3d79dd9fc38705b7646bdc7bfed200c [file] [log] [blame]
Michael Butler4b276a72020-08-06 23:22:35 -07001/*
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 "PreparedModel.h"
18
19#include "Callbacks.h"
20#include "Conversions.h"
21#include "Utils.h"
22
23#include <android/hardware/neuralnetworks/1.0/types.h>
24#include <android/hardware/neuralnetworks/1.1/types.h>
25#include <android/hardware/neuralnetworks/1.2/types.h>
26#include <android/hardware/neuralnetworks/1.3/IPreparedModel.h>
27#include <android/hardware/neuralnetworks/1.3/types.h>
28#include <nnapi/IPreparedModel.h>
29#include <nnapi/Result.h>
Michael Butler6547b2a2020-11-22 19:36:30 -080030#include <nnapi/TypeUtils.h>
Michael Butler4b276a72020-08-06 23:22:35 -070031#include <nnapi/Types.h>
32#include <nnapi/hal/1.2/Conversions.h>
33#include <nnapi/hal/CommonUtils.h>
34#include <nnapi/hal/HandleError.h>
35#include <nnapi/hal/ProtectCallback.h>
36
37#include <memory>
38#include <tuple>
39#include <utility>
40#include <vector>
41
42namespace android::hardware::neuralnetworks::V1_3::utils {
43namespace {
44
45nn::GeneralResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>>
46convertExecutionResultsHelper(const hidl_vec<V1_2::OutputShape>& outputShapes,
47 const V1_2::Timing& timing) {
Michael Butler6547b2a2020-11-22 19:36:30 -080048 return std::make_pair(NN_TRY(nn::convert(outputShapes)), NN_TRY(nn::convert(timing)));
Michael Butler4b276a72020-08-06 23:22:35 -070049}
50
51nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> convertExecutionResults(
52 const hidl_vec<V1_2::OutputShape>& outputShapes, const V1_2::Timing& timing) {
53 return hal::utils::makeExecutionFailure(convertExecutionResultsHelper(outputShapes, timing));
54}
55
Michael Butler4b276a72020-08-06 23:22:35 -070056nn::GeneralResult<std::pair<nn::Timing, nn::Timing>> convertFencedExecutionCallbackResults(
57 const V1_2::Timing& timingLaunched, const V1_2::Timing& timingFenced) {
Michael Butler6547b2a2020-11-22 19:36:30 -080058 return std::make_pair(NN_TRY(nn::convert(timingLaunched)), NN_TRY(nn::convert(timingFenced)));
Michael Butler4b276a72020-08-06 23:22:35 -070059}
60
61nn::GeneralResult<std::pair<nn::SyncFence, nn::ExecuteFencedInfoCallback>>
62convertExecuteFencedResults(const hidl_handle& syncFence,
63 const sp<IFencedExecutionCallback>& callback) {
64 auto resultSyncFence = nn::SyncFence::createAsSignaled();
65 if (syncFence.getNativeHandle() != nullptr) {
Michael Butler6547b2a2020-11-22 19:36:30 -080066 auto sharedHandle = NN_TRY(nn::convert(syncFence));
Michael Butler4b276a72020-08-06 23:22:35 -070067 resultSyncFence = NN_TRY(hal::utils::makeGeneralFailure(
Michael Butler6547b2a2020-11-22 19:36:30 -080068 nn::SyncFence::create(std::move(sharedHandle)), nn::ErrorStatus::GENERAL_FAILURE));
Michael Butler4b276a72020-08-06 23:22:35 -070069 }
70
71 if (callback == nullptr) {
72 return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE) << "callback is null";
73 }
74
75 // Create callback which can be used to retrieve the execution error status and timings.
76 nn::ExecuteFencedInfoCallback resultCallback =
77 [callback]() -> nn::GeneralResult<std::pair<nn::Timing, nn::Timing>> {
78 nn::GeneralResult<std::pair<nn::Timing, nn::Timing>> result =
79 NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE) << "uninitialized";
80 auto cb = [&result](ErrorStatus status, const V1_2::Timing& timingLaunched,
81 const V1_2::Timing& timingFenced) {
82 if (status != ErrorStatus::NONE) {
Michael Butler6547b2a2020-11-22 19:36:30 -080083 const auto canonical =
84 nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
Michael Butler4b276a72020-08-06 23:22:35 -070085 result = NN_ERROR(canonical) << "getExecutionInfo failed with " << toString(status);
86 } else {
87 result = convertFencedExecutionCallbackResults(timingLaunched, timingFenced);
88 }
89 };
90
91 const auto ret = callback->getExecutionInfo(cb);
Michael Butlercca3e202020-11-22 20:25:34 -080092 HANDLE_TRANSPORT_FAILURE(ret);
Michael Butler4b276a72020-08-06 23:22:35 -070093
94 return result;
95 };
96
97 return std::make_pair(std::move(resultSyncFence), std::move(resultCallback));
98}
99
100} // namespace
101
102nn::GeneralResult<std::shared_ptr<const PreparedModel>> PreparedModel::create(
103 sp<V1_3::IPreparedModel> preparedModel) {
104 if (preparedModel == nullptr) {
105 return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT)
106 << "V1_3::utils::PreparedModel::create must have non-null preparedModel";
107 }
108
109 auto deathHandler = NN_TRY(hal::utils::DeathHandler::create(preparedModel));
110 return std::make_shared<const PreparedModel>(PrivateConstructorTag{}, std::move(preparedModel),
111 std::move(deathHandler));
112}
113
114PreparedModel::PreparedModel(PrivateConstructorTag /*tag*/, sp<V1_3::IPreparedModel> preparedModel,
115 hal::utils::DeathHandler deathHandler)
116 : kPreparedModel(std::move(preparedModel)), kDeathHandler(std::move(deathHandler)) {}
117
118nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>>
119PreparedModel::executeSynchronously(const Request& request, V1_2::MeasureTiming measure,
120 const OptionalTimePoint& deadline,
121 const OptionalTimeoutDuration& loopTimeoutDuration) const {
122 nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> result =
123 NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE) << "uninitialized";
124 const auto cb = [&result](ErrorStatus status, const hidl_vec<V1_2::OutputShape>& outputShapes,
125 const V1_2::Timing& timing) {
126 if (status != ErrorStatus::NONE) {
Michael Butler6547b2a2020-11-22 19:36:30 -0800127 const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
Michael Butler4b276a72020-08-06 23:22:35 -0700128 result = NN_ERROR(canonical) << "executeSynchronously failed with " << toString(status);
129 } else {
130 result = convertExecutionResults(outputShapes, timing);
131 }
132 };
133
134 const auto ret = kPreparedModel->executeSynchronously_1_3(request, measure, deadline,
135 loopTimeoutDuration, cb);
Michael Butlercca3e202020-11-22 20:25:34 -0800136 HANDLE_TRANSPORT_FAILURE(ret);
Michael Butler4b276a72020-08-06 23:22:35 -0700137
138 return result;
139}
140
141nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>>
142PreparedModel::executeAsynchronously(const Request& request, V1_2::MeasureTiming measure,
143 const OptionalTimePoint& deadline,
144 const OptionalTimeoutDuration& loopTimeoutDuration) const {
145 const auto cb = sp<ExecutionCallback>::make();
146 const auto scoped = kDeathHandler.protectCallback(cb.get());
147
148 const auto ret =
149 kPreparedModel->execute_1_3(request, measure, deadline, loopTimeoutDuration, cb);
Michael Butlercca3e202020-11-22 20:25:34 -0800150 const auto status = HANDLE_TRANSPORT_FAILURE(ret);
Michael Butler4b276a72020-08-06 23:22:35 -0700151 if (status != ErrorStatus::NONE) {
Michael Butler6547b2a2020-11-22 19:36:30 -0800152 const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
Michael Butler4b276a72020-08-06 23:22:35 -0700153 return NN_ERROR(canonical) << "executeAsynchronously failed with " << toString(status);
154 }
155
156 return cb->get();
157}
158
159nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> PreparedModel::execute(
160 const nn::Request& request, nn::MeasureTiming measure,
161 const nn::OptionalTimePoint& deadline,
162 const nn::OptionalTimeoutDuration& loopTimeoutDuration) const {
163 // Ensure that request is ready for IPC.
164 std::optional<nn::Request> maybeRequestInShared;
165 const nn::Request& requestInShared = NN_TRY(hal::utils::makeExecutionFailure(
166 hal::utils::flushDataFromPointerToShared(&request, &maybeRequestInShared)));
167
168 const auto hidlRequest = NN_TRY(hal::utils::makeExecutionFailure(convert(requestInShared)));
169 const auto hidlMeasure =
170 NN_TRY(hal::utils::makeExecutionFailure(V1_2::utils::convert(measure)));
171 const auto hidlDeadline = NN_TRY(hal::utils::makeExecutionFailure(convert(deadline)));
172 const auto hidlLoopTimeoutDuration =
173 NN_TRY(hal::utils::makeExecutionFailure(convert(loopTimeoutDuration)));
174
175 nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> result =
176 NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE) << "uninitialized";
177 const bool preferSynchronous = true;
178
179 // Execute synchronously if allowed.
180 if (preferSynchronous) {
181 result = executeSynchronously(hidlRequest, hidlMeasure, hidlDeadline,
182 hidlLoopTimeoutDuration);
183 }
184
185 // Run asymchronous execution if execution has not already completed.
186 if (!result.has_value()) {
187 result = executeAsynchronously(hidlRequest, hidlMeasure, hidlDeadline,
188 hidlLoopTimeoutDuration);
189 }
190
191 // Flush output buffers if suxcessful execution.
192 if (result.has_value()) {
193 NN_TRY(hal::utils::makeExecutionFailure(
194 hal::utils::unflushDataFromSharedToPointer(request, maybeRequestInShared)));
195 }
196
197 return result;
198}
199
200nn::GeneralResult<std::pair<nn::SyncFence, nn::ExecuteFencedInfoCallback>>
201PreparedModel::executeFenced(const nn::Request& request, const std::vector<nn::SyncFence>& waitFor,
202 nn::MeasureTiming measure, const nn::OptionalTimePoint& deadline,
203 const nn::OptionalTimeoutDuration& loopTimeoutDuration,
204 const nn::OptionalTimeoutDuration& timeoutDurationAfterFence) const {
205 // Ensure that request is ready for IPC.
206 std::optional<nn::Request> maybeRequestInShared;
207 const nn::Request& requestInShared =
208 NN_TRY(hal::utils::flushDataFromPointerToShared(&request, &maybeRequestInShared));
209
210 const auto hidlRequest = NN_TRY(convert(requestInShared));
Slava Shklyaev49817a02020-10-27 18:44:01 +0000211 const auto hidlWaitFor = NN_TRY(hal::utils::convertSyncFences(waitFor));
Michael Butler4b276a72020-08-06 23:22:35 -0700212 const auto hidlMeasure = NN_TRY(V1_2::utils::convert(measure));
213 const auto hidlDeadline = NN_TRY(convert(deadline));
214 const auto hidlLoopTimeoutDuration = NN_TRY(convert(loopTimeoutDuration));
215 const auto hidlTimeoutDurationAfterFence = NN_TRY(convert(timeoutDurationAfterFence));
216
217 nn::GeneralResult<std::pair<nn::SyncFence, nn::ExecuteFencedInfoCallback>> result =
218 NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE) << "uninitialized";
219 auto cb = [&result](ErrorStatus status, const hidl_handle& syncFence,
220 const sp<IFencedExecutionCallback>& callback) {
221 if (status != ErrorStatus::NONE) {
Michael Butler6547b2a2020-11-22 19:36:30 -0800222 const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
Michael Butler4b276a72020-08-06 23:22:35 -0700223 result = NN_ERROR(canonical) << "executeFenced failed with " << toString(status);
224 } else {
225 result = convertExecuteFencedResults(syncFence, callback);
226 }
227 };
228
229 const auto ret = kPreparedModel->executeFenced(hidlRequest, hidlWaitFor, hidlMeasure,
230 hidlDeadline, hidlLoopTimeoutDuration,
231 hidlTimeoutDurationAfterFence, cb);
Michael Butlercca3e202020-11-22 20:25:34 -0800232 HANDLE_TRANSPORT_FAILURE(ret);
Michael Butler4b276a72020-08-06 23:22:35 -0700233 auto [syncFence, callback] = NN_TRY(std::move(result));
234
235 // If executeFenced required the request memory to be moved into shared memory, block here until
236 // the fenced execution has completed and flush the memory back.
237 if (maybeRequestInShared.has_value()) {
238 const auto state = syncFence.syncWait({});
239 if (state != nn::SyncFence::FenceState::SIGNALED) {
240 return NN_ERROR() << "syncWait failed with " << state;
241 }
242 NN_TRY(hal::utils::unflushDataFromSharedToPointer(request, maybeRequestInShared));
243 }
244
245 return std::make_pair(std::move(syncFence), std::move(callback));
246}
247
248std::any PreparedModel::getUnderlyingResource() const {
249 sp<V1_3::IPreparedModel> resource = kPreparedModel;
250 return resource;
251}
252
253} // namespace android::hardware::neuralnetworks::V1_3::utils