Home | History | Annotate | Download | only in functional
      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_0_CALLBACKS_H
     18 #define ANDROID_HARDWARE_NEURALNETWORKS_V1_0_CALLBACKS_H
     19 
     20 #include <android/hardware/neuralnetworks/1.0/IExecutionCallback.h>
     21 #include <android/hardware/neuralnetworks/1.0/IPreparedModelCallback.h>
     22 #include <android/hardware/neuralnetworks/1.2/IExecutionCallback.h>
     23 #include <android/hardware/neuralnetworks/1.2/IPreparedModelCallback.h>
     24 #include <hidl/MQDescriptor.h>
     25 #include <hidl/Status.h>
     26 #include <chrono>
     27 #include <condition_variable>
     28 #include <functional>
     29 #include <mutex>
     30 #include <thread>
     31 
     32 namespace android {
     33 namespace hardware {
     34 namespace neuralnetworks {
     35 namespace V1_2 {
     36 namespace implementation {
     37 
     38 using V1_0::ErrorStatus;
     39 
     40 /**
     41  * The CallbackBase class is used internally by the NeuralNetworks runtime to
     42  * synchronize between different threads. An asynchronous task is launched
     43  * paired with a callback object. When a client thread requires the output being
     44  * generated by the asynchronous task, the client thread can wait for the result
     45  * and be blocked until it has completed or a timeout condition has been
     46  * reached. Any wait* may safely be called concurrently, even on the same
     47  * callback object. When the asynchronous task has finished its workload, it
     48  * must immediately call "notify". If the asynchronous task has failed to launch,
     49  * the function that tried to launch the asynchronous task must immediately call
     50  * "notify". This "notify" call awakens any client threads waiting on the
     51  * callback object.
     52  *
     53  * The CallbackBase class implements some of the base synchronization common to
     54  * both PrepareModelCallback and ExecutionCallback. For consistency, any HIDL
     55  * callback class must inherit from CallbackBase as well as the HIDL callback
     56  * interface it implements.
     57  *
     58  * This class exists to enable synchronization across HIDL. When synchronization
     59  * is only required in the same process, consider using std::future, std::mutex,
     60  * std::condition_variable, or std::experimental::latch instead.
     61  */
     62 class CallbackBase {
     63  public:
     64     CallbackBase();
     65     ~CallbackBase();
     66 
     67     /**
     68      * CallbackBase::wait blocks until notify has been called on the callback
     69      * object.
     70      */
     71     void wait();
     72 
     73     /**
     74      * CallbackBase::wait_for blocks until notify has been called on the
     75      * callback object or the time duration from the time the wait_for function
     76      * was called has expired, whichever comes first.
     77      *
     78      * @return Status std::cv_status::no_timeout if the callback was notified
     79      *                before the time duration expired, std::cv_status::timeout
     80      *                otherwise.
     81      */
     82     template<class Rep, class Period>
     83     std::cv_status wait_for(const std::chrono::duration<Rep,Period>& timeout_duration);
     84 
     85     /**
     86      * CallbackBase::on_finish binds a function to the callback object. This
     87      * bound function will be executed when CallbackBase::notify is called,
     88      * before any calls to wait* return. (Note that CallbackBase::wait_for can
     89      * return std::cv_status::timeout before CallbackBase::notify is called for
     90      * the first time, and hence before the bound function is executed.)
     91      *
     92      * The bound function must not synchronize with or otherwise access the
     93      * callback object it is bound to, as this could cause a deadlock.
     94      *
     95      * CallbackBase::on_finish can be called at most once on a given callback
     96      * object, and the call to CallbackBase::on_finish must finish before
     97      * CallbackBase::notify is called.
     98      *
     99      * @param post_work Function to be invoked the first time
    100      *                  CallbackBase::notify is called. Must have a target --
    101      *                  i.e., must not compare equal to nullptr. post_work
    102      *                  returns true if it successfully completes, false if it
    103      *                  fails.
    104      * @return bool True if the function was successfully bound, false if
    105      *              unsuccessful.
    106      *
    107      * TODO: Why does the return value of the callback matter?
    108      */
    109     bool on_finish(std::function<bool(void)> post_work);
    110 
    111     /**
    112      * CallbackBase::bind_thread binds a thread to the event for later use by
    113      * CallbackBase::join_thread.
    114      *
    115      * The thread must be passed using std::move.
    116      *
    117      * Once a thread is bound with CallbackBase::bind_thread, the client code
    118      * should ensure that one of the following occurs before the event is
    119      * destroyed:
    120      * - CallbackBase::join_thread has been called.
    121      * - CallbackBase::wait has been called.
    122      * - CallbackBase::wait_for has been called and returned other than
    123      *   std::cv_status::no_timeout.
    124      *
    125      * The bound thread shall not call any CallbackBase method with the
    126      * exception of CallbackBase::notify, which it must call when the thread has
    127      * finished its computation.
    128      *
    129      * CallbackBase::bind_thread can be called at most once on a given callback
    130      * object.
    131      *
    132      * @param asyncThread Thread to be bound to the callback object. The thread
    133      *                    object must represent a thread of execution -- i.e.,
    134      *                    asyncThread.joinable() must be true.
    135      * @return bool True if successful, false if thread was not properly bound.
    136      */
    137     bool bind_thread(std::thread&& asyncThread);
    138 
    139     /**
    140      * CallbackBase::join_thread ensures that the thread (if any) bound to this
    141      * event with CallbackBase::bind_thread has fully finished and cleaned its
    142      * resources. It is legal to call this function multiple times, concurrently
    143      * or sequentially.
    144      */
    145     void join_thread();
    146 
    147  protected:
    148     /**
    149      * CallbackBase::notify enables all prior and future wait* calls on the
    150      * callback object to proceed. The call to CallbackBase::notify happens
    151      * before any wait* calls on this callback object return (except in the case
    152      * of wait_for timing out). The asynchronous call the callback object is
    153      * paired with must ensure that any update to state that should be visible
    154      * to the caller of wait* happens before the call to CallbackBase::notify.
    155      *
    156      * CallbackBase::notify must be called exactly once on a given callback
    157      * object.
    158      */
    159     void notify();
    160 
    161  private:
    162     // Same as CallbackBase::join_thread but assumes we already hold a lock on
    163     // mMutex.
    164     void join_thread_locked();
    165 
    166     bool                      mNotified;
    167     std::mutex                mMutex;
    168     std::condition_variable   mCondition;
    169     std::function<bool(void)> mPostWork;
    170     std::thread               mThread;
    171 };
    172 
    173 /**
    174  * The PreparedModelCallback class is used to receive the error status of
    175  * preparing a model as well as the prepared model from a task executing
    176  * asynchronously with respect to the runtime. If a calling thread calls wait*
    177  * or get* on a PreparedModelCallback object and the corresponding asynchronous
    178  * task has not finished preparing the model, the calling thread will block
    179  * until the asynchronous task has either called notify or notify_1_2. For more
    180  * information on the synchronization behavior, refer to the CallbackBase class.
    181  *
    182  * This class inherits the basic blocking and signaling calls from
    183  * CallbackBase, and implements the HIDL notify and notify_1_2 calls from
    184  * IPreparedModelCallback. This callback object is passed as an argument to
    185  * IDevice::prepareModel.
    186  */
    187 class PreparedModelCallback : public CallbackBase, public IPreparedModelCallback {
    188  public:
    189     PreparedModelCallback();
    190     ~PreparedModelCallback() override;
    191 
    192     /**
    193      * IPreparedModelCallback::notify and IPreparedModelCallback::notify_1_2
    194      * mark the callback object with the return status of the asynchronous
    195      * model preparation along with the prepared model, and call
    196      * CallbackBase::notify, enabling all prior and future wait* calls on the
    197      * PreparedModelCallback object to proceed. For more information on the
    198      * synchronization behavior, refer to the CallbackBase class.
    199      *
    200      * Either IPreparedModelCallback::notify or IPreparedModelCallback::notify_1_2
    201      * must be called exactly once on a given PreparedModelCallback object.
    202      *
    203      * @param status Error status returned from asynchronously preparing the
    204      *               model; will be:
    205      *               - NONE if the asynchronous preparation was successful
    206      *               - DEVICE_UNAVAILABLE if driver is offline or busy
    207      *               - GENERAL_FAILURE if there is an unspecified error
    208      *               - INVALID_ARGUMENT if the input model is invalid
    209      * @param preparedModel Returned model that has been prepared for execution,
    210      *                      nullptr if the model was unable to be prepared.
    211      */
    212     Return<void> notify(ErrorStatus status, const sp<V1_0::IPreparedModel>& preparedModel) override;
    213     Return<void> notify_1_2(ErrorStatus status,
    214                             const sp<V1_2::IPreparedModel>& preparedModel) override;
    215 
    216     /**
    217      * Retrieves the error status returned from the asynchronous task launched
    218      * by IDevice::prepareModel. If IDevice::prepareModel has not finished
    219      * asynchronously preparing the model, this call will block until the
    220      * asynchronous task notifies the object.
    221      *
    222      * @return status Error status returned from asynchronously preparing the
    223      *                model; will be:
    224      *                - NONE if the asynchronous preparation was successful
    225      *                - DEVICE_UNAVAILABLE if driver is offline or busy
    226      *                - GENERAL_FAILURE if there is an unspecified error
    227      *                - INVALID_ARGUMENT if the input model is invalid
    228      */
    229     ErrorStatus getStatus();
    230 
    231     /**
    232      * Retrieves the model that has been prepared for execution from the
    233      * asynchronous task launched by IDevice::prepareModel. If
    234      * IDevice::prepareModel has not finished asynchronously preparing the
    235      * model, this call will block until the asynchronous task notifies the
    236      * object.
    237      *
    238      * @return preparedModel Returned model that has been prepared for
    239      *                       execution, nullptr if the model was unable to be
    240      *                       prepared.
    241      */
    242     sp<V1_0::IPreparedModel> getPreparedModel();
    243 
    244    private:
    245     ErrorStatus        mErrorStatus;
    246     sp<V1_0::IPreparedModel> mPreparedModel;
    247 };
    248 
    249 /**
    250  * The ExecutionCallback class is used to receive the error status of the
    251  * execution from a task executing asynchronously with respect to the runtime.
    252  * If a calling thread calls wait* or get* on a PreparedModelCallback object and
    253  * the corresponding asynchronous task has not finished the execution, the
    254  * calling thread will block until the asynchronous task has either called notify
    255  * or notify_1_2. For more information on the synchronization behavior, refer to
    256  * the CallbackBase class.
    257  *
    258  * This class inherits the basic blocking and signaling calls from
    259  * CallbackBase, and implements the HIDL notify and notify_1_2 calls from
    260  * IExecutionCallback. This callback object is passed as an argument to
    261  * IPreparedModel::execute.
    262  */
    263 class ExecutionCallback : public CallbackBase,  public IExecutionCallback {
    264  public:
    265     ExecutionCallback();
    266     ~ExecutionCallback() override;
    267 
    268     /**
    269      * IExecutionCallback::notify and IExecutionCallback::notify_1_2 mark the
    270      * callback object with the return status of the asynchronous execution that
    271      * held this callback and enable all prior and future wait* calls on the
    272      * ExecutionCallback object to proceed. For more information on the
    273      * synchronization behavior, refer to the CallbackBase class.
    274      *
    275      * Either IExecutionCallback::notify or IExecutionCallback::notify_1_2 must
    276      * be called exactly once on a given ExecutionCallback object.
    277      *
    278      * @param status Error status returned from launching the asynchronous task
    279      *               (if the launch fails) or from the asynchronous task itself
    280      *               (if the launch succeeds). Must be:
    281      *               - NONE if the asynchronous execution was successful
    282      *               - DEVICE_UNAVAILABLE if driver is offline or busy
    283      *               - GENERAL_FAILURE if there is an unspecified error
    284      *               - OUTPUT_INSUFFICIENT_SIZE if provided output buffer is
    285      *                 not large enough to store the resultant values
    286      *               - INVALID_ARGUMENT if the input request is invalid
    287      */
    288     Return<void> notify(ErrorStatus status) override;
    289 
    290     /**
    291      * Similar to IExecutionCallback::notify, but for V1_2::IPreparedModel to
    292      * also notify output shapes along with error status.
    293      *
    294      * @param status Error status returned from launching the asynchronous task
    295      *               (if the launch fails) or from the asynchronous task itself
    296      *               (if the launch succeeds). Must be:
    297      *               - NONE if the asynchronous execution was successful
    298      *               - DEVICE_UNAVAILABLE if driver is offline or busy
    299      *               - GENERAL_FAILURE if the asynchronous task resulted in an
    300      *                 unspecified error
    301      *               - OUTPUT_INSUFFICIENT_SIZE if at least one output
    302      *                 operand buffer is not large enough to store the
    303      *                 corresponding output
    304      *               - INVALID_ARGUMENT if one of the input arguments to
    305      *                 prepareModel is invalid
    306      * @param outputShapes A list of shape information of model output operands.
    307      *                     The index into "outputShapes" corresponds to the index
    308      *                     of the output operand in the Request outputs vector.
    309      *                     outputShapes must be empty unless the status is either
    310      *                     NONE or OUTPUT_INSUFFICIENT_SIZE.
    311      * @return Timing Duration of execution. Unless MeasureTiming::YES was passed when
    312      *                launching the execution and status is NONE, all times must
    313      *                be reported as UINT64_MAX. A driver may choose to report
    314      *                any time as UINT64_MAX, indicating that particular measurement is
    315      *                not available.
    316      */
    317     Return<void> notify_1_2(ErrorStatus status, const hidl_vec<OutputShape>& outputShapes,
    318                             const Timing& timing) override;
    319 
    320     // An overload of the latest notify interface to hide the version from ExecutionBuilder.
    321     Return<void> notify(ErrorStatus status, const hidl_vec<OutputShape>& outputShapes,
    322                         const Timing& timing) {
    323         return notify_1_2(status, outputShapes, timing);
    324     }
    325 
    326     /**
    327      * Retrieves the error status returned from the asynchronous task launched
    328      * by either IPreparedModel::execute or IPreparedModel::execute_1_2. If
    329      * IPreparedModel::execute or IPreparedModel::execute_1_2 has not finished
    330      * asynchronously executing, this call will block until the asynchronous task
    331      * notifies the object.
    332      *
    333      * @return status Error status returned from launching the asynchronous task
    334      *                (if the launch fails) or from the asynchronous task itself
    335      *                (if the launch succeeds). Must be:
    336      *                - NONE if the asynchronous execution was successful
    337      *                - DEVICE_UNAVAILABLE if driver is offline or busy
    338      *                - GENERAL_FAILURE if the asynchronous task resulted in an
    339      *                  unspecified error
    340      *                - OUTPUT_INSUFFICIENT_SIZE if at least one output
    341      *                  operand buffer is not large enough to store the
    342      *                  corresponding output
    343      *                - INVALID_ARGUMENT if one of the input arguments to
    344      *                  prepareModel is invalid
    345      */
    346     ErrorStatus getStatus();
    347 
    348     /**
    349      * Retrieves the output shapes returned from the asynchronous task launched
    350      * by IPreparedModel::execute_1_2. If IPreparedModel::execute_1_2 has not finished
    351      * asynchronously executing, this call will block until the asynchronous task
    352      * notifies the object.
    353      *
    354      * If the asynchronous task was launched by IPreparedModel::execute, an empty vector
    355      * will be returned.
    356      *
    357      * @return outputShapes A list of shape information of model output operands.
    358      *                      The index into "outputShapes" corresponds to the index
    359      *                      of the output operand in the Request outputs vector.
    360      *                      outputShapes must be empty unless the status is either
    361      *                      NONE or OUTPUT_INSUFFICIENT_SIZE.
    362      */
    363     const std::vector<OutputShape>& getOutputShapes();
    364 
    365     /**
    366      * Retrieves the duration of execution ofthe asynchronous task launched
    367      * by IPreparedModel::execute_1_2. If IPreparedModel::execute_1_2 has not finished
    368      * asynchronously executing, this call will block until the asynchronous task
    369      * notifies the object.
    370      *
    371      * If the asynchronous task was launched by IPreparedModel::execute, every time
    372      * must be UINT64_MAX.
    373      *
    374      * @return timing Duration of the execution. Every time must be UINT64_MAX unless
    375      *                the status is NONE.
    376      */
    377     Timing getTiming();
    378 
    379    private:
    380     ErrorStatus mErrorStatus = ErrorStatus::GENERAL_FAILURE;
    381     std::vector<OutputShape> mOutputShapes = {};
    382     Timing mTiming = {};
    383 };
    384 
    385 
    386 // template function implementation(s) below this point
    387 
    388 template<class Rep, class Period>
    389 std::cv_status CallbackBase::wait_for(const std::chrono::duration<Rep,Period>& timeout_duration) {
    390     std::unique_lock<std::mutex> lock(mMutex);
    391     std::cv_status status = mCondition.wait_for(lock, timeout_duration, [this]{return mNotified;});
    392     if (status != std::cv_status::timeout) {
    393         join_thread_locked();
    394     }
    395     return status;
    396 }
    397 
    398 }  // namespace implementation
    399 }  // namespace V1_2
    400 }  // namespace neuralnetworks
    401 }  // namespace hardware
    402 }  // namespace android
    403 
    404 #endif  // ANDROID_HARDWARE_NEURALNETWORKS_V1_0_CALLBACKS_H
    405