blob: 3972ad6ff2e4c799417c9f2effeaf1ea31b32b8e [file] [log] [blame]
Slava Shklyaev73ee79d2019-05-14 14:15:14 +01001/*
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
Michael Butler051cf392019-07-16 16:52:06 -070017#define LOG_TAG "Callbacks"
18
Slava Shklyaev73ee79d2019-05-14 14:15:14 +010019#include "1.2/Callbacks.h"
Michael Butler051cf392019-07-16 16:52:06 -070020
Slava Shklyaev73ee79d2019-05-14 14:15:14 +010021#include <android-base/logging.h>
22
Michael Butler051cf392019-07-16 16:52:06 -070023#include <limits>
Slava Shklyaev73ee79d2019-05-14 14:15:14 +010024
Michael Butler051cf392019-07-16 16:52:06 -070025namespace android::hardware::neuralnetworks::V1_2::implementation {
Slava Shklyaev73ee79d2019-05-14 14:15:14 +010026
Michael Butler62749b92019-08-26 23:55:47 -070027using V1_0::ErrorStatus;
28
Michael Butler051cf392019-07-16 16:52:06 -070029constexpr Timing kNoTiming = {.timeOnDevice = std::numeric_limits<uint64_t>::max(),
30 .timeInDriver = std::numeric_limits<uint64_t>::max()};
Slava Shklyaev73ee79d2019-05-14 14:15:14 +010031
Michael Butler051cf392019-07-16 16:52:06 -070032// PreparedModelCallback methods begin here
Slava Shklyaev73ee79d2019-05-14 14:15:14 +010033
34Return<void> PreparedModelCallback::notify(ErrorStatus errorStatus,
35 const sp<V1_0::IPreparedModel>& preparedModel) {
Michael Butler051cf392019-07-16 16:52:06 -070036 {
37 std::lock_guard<std::mutex> hold(mMutex);
38
39 // quick-return if object has already been notified
40 if (mNotified) {
41 return Void();
42 }
43
44 // store results and mark as notified
45 mErrorStatus = errorStatus;
46 mPreparedModel = preparedModel;
47 mNotified = true;
48 }
49
50 mCondition.notify_all();
Slava Shklyaev73ee79d2019-05-14 14:15:14 +010051 return Void();
52}
53
54Return<void> PreparedModelCallback::notify_1_2(ErrorStatus errorStatus,
55 const sp<V1_2::IPreparedModel>& preparedModel) {
Michael Butler051cf392019-07-16 16:52:06 -070056 return notify(errorStatus, preparedModel);
Slava Shklyaev73ee79d2019-05-14 14:15:14 +010057}
58
Michael Butler051cf392019-07-16 16:52:06 -070059void PreparedModelCallback::wait() const {
60 std::unique_lock<std::mutex> lock(mMutex);
61 mCondition.wait(lock, [this] { return mNotified; });
62}
63
64ErrorStatus PreparedModelCallback::getStatus() const {
Slava Shklyaev73ee79d2019-05-14 14:15:14 +010065 wait();
66 return mErrorStatus;
67}
68
Michael Butler051cf392019-07-16 16:52:06 -070069sp<V1_0::IPreparedModel> PreparedModelCallback::getPreparedModel() const {
Slava Shklyaev73ee79d2019-05-14 14:15:14 +010070 wait();
71 return mPreparedModel;
72}
73
Michael Butler051cf392019-07-16 16:52:06 -070074// ExecutionCallback methods begin here
Slava Shklyaev73ee79d2019-05-14 14:15:14 +010075
76Return<void> ExecutionCallback::notify(ErrorStatus errorStatus) {
Michael Butler051cf392019-07-16 16:52:06 -070077 notifyInternal(errorStatus, {}, kNoTiming);
Slava Shklyaev73ee79d2019-05-14 14:15:14 +010078 return Void();
79}
80
81Return<void> ExecutionCallback::notify_1_2(ErrorStatus errorStatus,
82 const hidl_vec<OutputShape>& outputShapes,
83 const Timing& timing) {
Michael Butler051cf392019-07-16 16:52:06 -070084 if (errorStatus == ErrorStatus::OUTPUT_INSUFFICIENT_SIZE) {
85 // outputShapes must not be empty if OUTPUT_INSUFFICIENT_SIZE.
86 if (outputShapes.size() == 0) {
87 LOG(ERROR) << "Notified with empty output shape vector when OUTPUT_INSUFFICIENT_SIZE";
88 notifyInternal(ErrorStatus::GENERAL_FAILURE, {}, kNoTiming);
89 return Void();
90 }
91 } else if (errorStatus != ErrorStatus::NONE) {
92 // outputShapes must be empty if errorStatus is neither NONE nor OUTPUT_INSUFFICIENT_SIZE.
93 if (outputShapes.size() != 0) {
94 LOG(ERROR) << "Notified with non-empty output shape vector when error status is "
95 "neither NONE nor OUTPUT_INSUFFICIENT_SIZE";
96 notifyInternal(ErrorStatus::GENERAL_FAILURE, {}, kNoTiming);
97 return Void();
98 }
99 }
100 notifyInternal(errorStatus, outputShapes, timing);
Slava Shklyaev73ee79d2019-05-14 14:15:14 +0100101 return Void();
102}
103
Michael Butler051cf392019-07-16 16:52:06 -0700104void ExecutionCallback::wait() const {
105 std::unique_lock<std::mutex> lock(mMutex);
106 mCondition.wait(lock, [this] { return mNotified; });
107}
108
109ErrorStatus ExecutionCallback::getStatus() const {
Slava Shklyaev73ee79d2019-05-14 14:15:14 +0100110 wait();
111 return mErrorStatus;
112}
113
Michael Butler051cf392019-07-16 16:52:06 -0700114const std::vector<OutputShape>& ExecutionCallback::getOutputShapes() const {
Slava Shklyaev73ee79d2019-05-14 14:15:14 +0100115 wait();
116 return mOutputShapes;
117}
118
Michael Butler051cf392019-07-16 16:52:06 -0700119Timing ExecutionCallback::getTiming() const {
Slava Shklyaev73ee79d2019-05-14 14:15:14 +0100120 wait();
121 return mTiming;
122}
123
Michael Butler051cf392019-07-16 16:52:06 -0700124void ExecutionCallback::notifyInternal(ErrorStatus errorStatus,
125 const hidl_vec<OutputShape>& outputShapes,
126 const Timing& timing) {
127 {
128 std::lock_guard<std::mutex> hold(mMutex);
129
130 // quick-return if object has already been notified
131 if (mNotified) {
132 return;
133 }
134
135 mErrorStatus = errorStatus;
136 mOutputShapes = outputShapes;
137 mTiming = timing;
138 mNotified = true;
139 }
140 mCondition.notify_all();
141}
142
143} // namespace android::hardware::neuralnetworks::V1_2::implementation