blob: 5768e3794a41824e9c4e220f2b422d97f64898e3 [file] [log] [blame]
Xusong Wang68c32342019-10-23 10:35:07 -07001/*
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#define LOG_TAG "Callbacks"
18
19#include "1.3/Callbacks.h"
20
21#include <android-base/logging.h>
22
23#include <limits>
24
25namespace android::hardware::neuralnetworks::V1_3::implementation {
26
Michael Butler9449a282019-12-11 19:08:08 -080027using V1_2::OutputShape;
28using V1_2::Timing;
29
30constexpr Timing kNoTiming = {.timeOnDevice = std::numeric_limits<uint64_t>::max(),
31 .timeInDriver = std::numeric_limits<uint64_t>::max()};
Xusong Wang68c32342019-10-23 10:35:07 -070032
33// PreparedModelCallback methods begin here
34
Michael Butler9449a282019-12-11 19:08:08 -080035Return<void> PreparedModelCallback::notifyInternal(ErrorStatus errorStatus,
36 const sp<V1_0::IPreparedModel>& preparedModel) {
Xusong Wang68c32342019-10-23 10:35:07 -070037 {
38 std::lock_guard<std::mutex> hold(mMutex);
39
40 // quick-return if object has already been notified
41 if (mNotified) {
42 return Void();
43 }
44
45 // store results and mark as notified
46 mErrorStatus = errorStatus;
47 mPreparedModel = preparedModel;
48 mNotified = true;
49 }
50
51 mCondition.notify_all();
52 return Void();
53}
54
Michael Butler9449a282019-12-11 19:08:08 -080055Return<void> PreparedModelCallback::notify(V1_0::ErrorStatus errorStatus,
56 const sp<V1_0::IPreparedModel>& preparedModel) {
57 return notifyInternal(static_cast<ErrorStatus>(errorStatus), preparedModel);
Xusong Wang68c32342019-10-23 10:35:07 -070058}
59
Michael Butler9449a282019-12-11 19:08:08 -080060Return<void> PreparedModelCallback::notify_1_2(V1_0::ErrorStatus errorStatus,
61 const sp<V1_2::IPreparedModel>& preparedModel) {
62 return notifyInternal(static_cast<ErrorStatus>(errorStatus), preparedModel);
63}
64
65Return<void> PreparedModelCallback::notify_1_3(V1_3::ErrorStatus errorStatus,
Xusong Wang62a760c2019-10-25 12:07:17 -070066 const sp<V1_3::IPreparedModel>& preparedModel) {
Michael Butler9449a282019-12-11 19:08:08 -080067 return notifyInternal(errorStatus, preparedModel);
Xusong Wang68c32342019-10-23 10:35:07 -070068}
69
70void PreparedModelCallback::wait() const {
71 std::unique_lock<std::mutex> lock(mMutex);
72 mCondition.wait(lock, [this] { return mNotified; });
73}
74
75ErrorStatus PreparedModelCallback::getStatus() const {
76 wait();
77 return mErrorStatus;
78}
79
80sp<V1_0::IPreparedModel> PreparedModelCallback::getPreparedModel() const {
81 wait();
82 return mPreparedModel;
83}
84
Michael Butler9449a282019-12-11 19:08:08 -080085// ExecutionCallback methods begin here
86
87Return<void> ExecutionCallback::notify(V1_0::ErrorStatus errorStatus) {
88 return notifyInternal(static_cast<ErrorStatus>(errorStatus), {}, kNoTiming);
89}
90
91Return<void> ExecutionCallback::notify_1_2(V1_0::ErrorStatus errorStatus,
92 const hidl_vec<OutputShape>& outputShapes,
93 const Timing& timing) {
94 return notifyInternal(static_cast<ErrorStatus>(errorStatus), outputShapes, timing);
95}
96
97Return<void> ExecutionCallback::notify_1_3(V1_3::ErrorStatus errorStatus,
98 const hidl_vec<OutputShape>& outputShapes,
99 const Timing& timing) {
100 return notifyInternal(errorStatus, outputShapes, timing);
101}
102
103void ExecutionCallback::wait() const {
104 std::unique_lock<std::mutex> lock(mMutex);
105 mCondition.wait(lock, [this] { return mNotified; });
106}
107
108ErrorStatus ExecutionCallback::getStatus() const {
109 wait();
110 return mErrorStatus;
111}
112
113const std::vector<OutputShape>& ExecutionCallback::getOutputShapes() const {
114 wait();
115 return mOutputShapes;
116}
117
118Timing ExecutionCallback::getTiming() const {
119 wait();
120 return mTiming;
121}
122
123Return<void> ExecutionCallback::notifyInternal(ErrorStatus errorStatus,
124 hidl_vec<OutputShape> outputShapes, Timing timing) {
125 // check results
126 if (errorStatus == ErrorStatus::OUTPUT_INSUFFICIENT_SIZE) {
127 // outputShapes must not be empty if OUTPUT_INSUFFICIENT_SIZE.
128 if (outputShapes.size() == 0) {
129 LOG(ERROR) << "Notifid with empty output shape vector when OUTPUT_INSUFFICIENT_SIZE";
130 errorStatus = ErrorStatus::GENERAL_FAILURE;
131 outputShapes = {};
132 timing = kNoTiming;
133 }
134 } else if (errorStatus != ErrorStatus::NONE) {
135 // outputShapes must be empty if errorStatus is neither NONE nor OUTPUT_INSUFFICIENT_SIZE.
136 if (outputShapes.size() != 0) {
137 LOG(ERROR) << "Notified with non-empty output shape vector when error status is "
138 "neither NONE nor OUTPUT_INSUFFICIENT_SIZE";
139 errorStatus = ErrorStatus::GENERAL_FAILURE;
140 outputShapes = {};
141 timing = kNoTiming;
142 }
143 }
144
145 // store results
146 {
147 std::lock_guard<std::mutex> hold(mMutex);
148
149 // quick-return if object has already been notified
150 if (mNotified) {
151 return Void();
152 }
153
154 mErrorStatus = errorStatus;
155 mOutputShapes = std::move(outputShapes);
156 mTiming = timing;
157 mNotified = true;
158 }
159 mCondition.notify_all();
160 return Void();
161}
162
Xusong Wang68c32342019-10-23 10:35:07 -0700163} // namespace android::hardware::neuralnetworks::V1_3::implementation