1 /* 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 #ifndef ANDROID_HARDWARE_NEURALNETWORKS_V1_2_CALLBACKS_H 18 #define ANDROID_HARDWARE_NEURALNETWORKS_V1_2_CALLBACKS_H 19 20 #include <android-base/thread_annotations.h> 21 #include <android/hardware/neuralnetworks/1.0/IExecutionCallback.h> 22 #include <android/hardware/neuralnetworks/1.0/IPreparedModelCallback.h> 23 #include <android/hardware/neuralnetworks/1.2/IExecutionCallback.h> 24 #include <android/hardware/neuralnetworks/1.2/IPreparedModelCallback.h> 25 #include <hidl/Status.h> 26 #include <condition_variable> 27 #include <mutex> 28 29 /* 30 * The Callback classes are used internally by the NeuralNetworks runtime to 31 * synchronize between different threads. An asynchronous task is launched 32 * paired with a callback object. When a client thread requires the output being 33 * generated by the asynchronous task, the client thread can wait for the result 34 * and be blocked until it has completed. Any wait may safely be called 35 * concurrently, even on the same callback object. When the asynchronous task 36 * has finished its workload, it must immediately call "notify*". If the 37 * asynchronous task has failed to launch, the function that tried to launch the 38 * asynchronous task must immediately call "notify*". This "notify*" call 39 * awakens any client threads waiting on the callback object. 40 * 41 * These classes exist to enable synchronization across HIDL. When 42 * synchronization is only required in the same process, consider using 43 * std::future, std::mutex, std::condition_variable, or std::experimental::latch 44 * instead. 45 */ 46 47 namespace android::hardware::neuralnetworks::V1_2::implementation { 48 49 /** 50 * The PreparedModelCallback class is used to receive the error status of 51 * preparing a model as well as the prepared model from a task executing 52 * asynchronously with respect to the runtime. If a calling thread calls wait 53 * or get* on a PreparedModelCallback object and the corresponding asynchronous 54 * task has not finished preparing the model, the calling thread will block 55 * until the asynchronous task has either called notify or notify_1_2. 56 * 57 * If the callback object is notified more than once, only the results of the 58 * first call to notify* are used, and the results from subsequent calls are 59 * discarded. 60 * 61 * This callback object is passed as an argument to IDevice::prepareModel*. 62 */ 63 class PreparedModelCallback : public IPreparedModelCallback { 64 public: 65 /** 66 * IPreparedModelCallback::notify marks the callback object with the return 67 * status of the asynchronous model preparation along with the prepared 68 * model, and allows all prior and future wait calls on the 69 * PreparedModelCallback object to proceed. 70 * 71 * Either IPreparedModelCallback::notify or 72 * IPreparedModelCallback::notify_1_2 must be called on a given 73 * PreparedModelCallback object. 74 * 75 * If the callback object is notified more than once, only the results of 76 * the first call to notify* are used, and the results from subsequent calls 77 * are discarded. 78 * 79 * @param status Error status returned from asynchronously preparing the 80 * model; will be: 81 * - NONE if the asynchronous preparation was successful 82 * - DEVICE_UNAVAILABLE if driver is offline or busy 83 * - GENERAL_FAILURE if there is an unspecified error 84 * - INVALID_ARGUMENT if the input model is invalid 85 * @param preparedModel Returned model that has been prepared for execution, 86 * nullptr if the model was unable to be prepared. 87 */ 88 Return<void> notify(V1_0::ErrorStatus status, 89 const sp<V1_0::IPreparedModel>& preparedModel) override; 90 91 /** 92 * IPreparedModelCallback::notify_1_2 marks the callback object with the 93 * return status of the asynchronous model preparation along with the 94 * prepared model, and allows all prior and future wait calls on the 95 * PreparedModelCallback object to proceed. 96 * 97 * Either IPreparedModelCallback::notify or 98 * IPreparedModelCallback::notify_1_2 must be called on a given 99 * PreparedModelCallback object. 100 * 101 * If the callback object is notified more than once, only the results of 102 * the first call to notify* are used, and the results from subsequent calls 103 * are discarded. 104 * 105 * @param status Error status returned from asynchronously preparing the 106 * model; will be: 107 * - NONE if the asynchronous preparation was successful 108 * - DEVICE_UNAVAILABLE if driver is offline or busy 109 * - GENERAL_FAILURE if there is an unspecified error 110 * - INVALID_ARGUMENT if the input model is invalid 111 * @param preparedModel Returned model that has been prepared for execution, 112 * nullptr if the model was unable to be prepared. 113 */ 114 Return<void> notify_1_2(V1_0::ErrorStatus status, 115 const sp<V1_2::IPreparedModel>& preparedModel) override; 116 117 /** 118 * PreparedModelCallback::wait blocks until notify* has been called on the 119 * callback object. 120 */ 121 void wait() const; 122 123 /** 124 * Retrieves the error status returned from the asynchronous task launched 125 * by IDevice::prepareModel*. If IDevice::prepareModel* has not finished 126 * asynchronously preparing the model, this call will block until the 127 * asynchronous task notifies the object. 128 * 129 * @return status Error status returned from asynchronously preparing the 130 * model; will be: 131 * - NONE if the asynchronous preparation was successful 132 * - DEVICE_UNAVAILABLE if driver is offline or busy 133 * - GENERAL_FAILURE if there is an unspecified error 134 * - INVALID_ARGUMENT if the input model is invalid 135 */ 136 V1_0::ErrorStatus getStatus() const; 137 138 /** 139 * Retrieves the model that has been prepared for execution from the 140 * asynchronous task launched by IDevice::prepareModel*. If 141 * IDevice::prepareModel* has not finished asynchronously preparing the 142 * model, this call will block until the asynchronous task notifies the 143 * object. 144 * 145 * @return preparedModel Returned model that has been prepared for 146 * execution, nullptr if the model was unable to be prepared. 147 */ 148 sp<V1_0::IPreparedModel> getPreparedModel() const; 149 150 private: 151 mutable std::mutex mMutex; 152 mutable std::condition_variable mCondition; 153 bool mNotified GUARDED_BY(mMutex) = false; 154 V1_0::ErrorStatus mErrorStatus = V1_0::ErrorStatus::GENERAL_FAILURE; 155 sp<V1_0::IPreparedModel> mPreparedModel; 156 }; 157 158 /** 159 * The ExecutionCallback class is used to receive the results of the execution 160 * from a task executing asynchronously with respect to the runtime. If a 161 * calling thread calls wait or get* on a ExecutionCallback object and the 162 * corresponding asynchronous task has not finished the execution, the calling 163 * thread will block until the asynchronous task has either called notify or 164 * notify_1_2. 165 * 166 * If the callback object is notified more than once, only the results of the 167 * first call to notify* are used, and the results from subsequent calls are 168 * discarded. 169 * 170 * This callback object is passed as an argument to IPreparedModel::execute*. 171 */ 172 class ExecutionCallback : public IExecutionCallback { 173 public: 174 /** 175 * IExecutionCallback::notify marks the callback object with the return 176 * status of the asynchronous execution that held this callback and enables 177 * all prior and future wait calls on the ExecutionCallback object to 178 * proceed. 179 * 180 * Either IExecutionCallback::notify or IExecutionCallback::notify_1_2 must 181 * be called on a given ExecutionCallback object. 182 * 183 * If the callback object is notified more than once, only the results of 184 * the first call to notify* are used, and the results from subsequent calls 185 * are discarded. 186 * 187 * @param status Error status returned from launching the asynchronous task 188 * (if the launch fails) or from the asynchronous task itself (if the 189 * launch succeeds). Must be: 190 * - NONE if the asynchronous execution was successful 191 * - DEVICE_UNAVAILABLE if driver is offline or busy 192 * - GENERAL_FAILURE if there is an unspecified error 193 * - OUTPUT_INSUFFICIENT_SIZE if provided output buffer is not large 194 * enough to store the resultant values 195 * - INVALID_ARGUMENT if the input request is invalid 196 */ 197 Return<void> notify(V1_0::ErrorStatus status) override; 198 199 /** 200 * IExecutionCallback::notify_1_2 marks the callback object with the results 201 * (error status, dynamic output shapes, and timing information) of the 202 * asynchronous execution that held this callback and enables all prior and 203 * future wait calls on the ExecutionCallback object to proceed. 204 * 205 * Either IExecutionCallback::notify or IExecutionCallback::notify_1_2 must 206 * be called on a given ExecutionCallback object. 207 * 208 * If the callback object is notified more than once, only the results of 209 * the first call to notify* are used, and the results from subsequent calls 210 * are discarded. 211 * 212 * @param status Error status returned from launching the asynchronous task 213 * (if the launch fails) or from the asynchronous task itself (if the 214 * launch succeeds). Must be: 215 * - NONE if the asynchronous execution was successful 216 * - DEVICE_UNAVAILABLE if driver is offline or busy 217 * - GENERAL_FAILURE if the asynchronous task resulted in an unspecified 218 * error 219 * - OUTPUT_INSUFFICIENT_SIZE if at least one output operand buffer is 220 * not large enough to store the corresponding output 221 * - INVALID_ARGUMENT if one of the input arguments to prepareModel is 222 * invalid 223 * @param outputShapes A list of shape information of model output operands. 224 * The index into "outputShapes" corresponds to the index of the output 225 * operand in the Request outputs vector. outputShapes must be empty 226 * unless the status is either NONE or OUTPUT_INSUFFICIENT_SIZE. 227 * @param Timing Duration of execution. Unless MeasureTiming::YES was passed 228 * when launching the execution and status is NONE, all times must be 229 * reported as UINT64_MAX. A driver may choose to report any time as 230 * UINT64_MAX, indicating that particular measurement is not available. 231 */ 232 Return<void> notify_1_2(V1_0::ErrorStatus status, const hidl_vec<OutputShape>& outputShapes, 233 const Timing& timing) override; 234 235 // An overload of the latest notify interface to hide the version from ExecutionBuilder. notify(V1_0::ErrorStatus status,const hidl_vec<OutputShape> & outputShapes,const Timing & timing)236 Return<void> notify(V1_0::ErrorStatus status, const hidl_vec<OutputShape>& outputShapes, 237 const Timing& timing) { 238 return notify_1_2(status, outputShapes, timing); 239 } 240 241 /** 242 * ExecutionCallback::wait blocks until notify* has been called on the 243 * callback object. 244 */ 245 void wait() const; 246 247 /** 248 * Retrieves the error status returned from the asynchronous task launched 249 * by either IPreparedModel::execute or IPreparedModel::execute_1_2. If 250 * IPreparedModel::execute or IPreparedModel::execute_1_2 has not finished 251 * asynchronously executing, this call will block until the asynchronous 252 * task notifies the object. 253 * 254 * @return status Error status returned from launching the asynchronous task 255 * (if the launch fails) or from the asynchronous task itself (if the 256 * launch succeeds). Must be: 257 * - NONE if the asynchronous execution was successful 258 * - DEVICE_UNAVAILABLE if driver is offline or busy 259 * - GENERAL_FAILURE if the asynchronous task resulted in an unspecified 260 * error 261 * - OUTPUT_INSUFFICIENT_SIZE if at least one output operand buffer is 262 * not large enough to store the corresponding output 263 * - INVALID_ARGUMENT if one of the input arguments to prepareModel is 264 * invalid 265 */ 266 V1_0::ErrorStatus getStatus() const; 267 268 /** 269 * Retrieves the output shapes returned from the asynchronous task launched 270 * by IPreparedModel::execute_1_2. If IPreparedModel::execute_1_2 has not 271 * finished asynchronously executing, this call will block until the 272 * asynchronous task notifies the object. 273 * 274 * If the asynchronous task was launched by IPreparedModel::execute, an 275 * empty vector will be returned. 276 * 277 * @return outputShapes A list of shape information of model output 278 * operands. The index into "outputShapes" corresponds to the index of 279 * the output operand in the Request outputs vector. outputShapes must 280 * be empty unless the status is either NONE or 281 * OUTPUT_INSUFFICIENT_SIZE. outputShaps may be empty if the status is 282 * NONE and all model output operands are fully-specified at execution 283 * time. outputShapes must have the same number of elements as the 284 * number of model output operands if the status is 285 * OUTPUT_INSUFFICIENT_SIZE, or if the status is NONE and the model has 286 * at least one output operand that is not fully-specified. 287 */ 288 const std::vector<OutputShape>& getOutputShapes() const; 289 290 /** 291 * Retrieves the duration of execution of the asynchronous task launched by 292 * IPreparedModel::execute_1_2. If IPreparedModel::execute_1_2 has not 293 * finished asynchronously executing, this call will block until the 294 * asynchronous task notifies the object. 295 * 296 * If the asynchronous task was launched by IPreparedModel::execute, every 297 * time must be UINT64_MAX. 298 * 299 * @return timing Duration of the execution. Every time must be UINT64_MAX 300 * unless the status is NONE. 301 */ 302 Timing getTiming() const; 303 304 private: 305 /* 306 * ExecutionCallback::notifyInternal stores the results of the execution 307 * (status, output shapes, and timing information) in the ExecutionCallback 308 * object before any call to wait or get* return. It then enables all prior 309 * and future wait calls on the ExecutionCallback object to proceed. 310 */ 311 void notifyInternal(V1_0::ErrorStatus errorStatus, const hidl_vec<OutputShape>& outputShapes, 312 const Timing& timing); 313 314 // members 315 mutable std::mutex mMutex; 316 mutable std::condition_variable mCondition; 317 bool mNotified GUARDED_BY(mMutex) = false; 318 V1_0::ErrorStatus mErrorStatus = V1_0::ErrorStatus::GENERAL_FAILURE; 319 std::vector<OutputShape> mOutputShapes = {}; 320 Timing mTiming = {}; 321 }; 322 323 } // namespace android::hardware::neuralnetworks::V1_2::implementation 324 325 #endif // ANDROID_HARDWARE_NEURALNETWORKS_V1_2_CALLBACKS_H 326