Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit cf22a57c authored by Michael Butler's avatar Michael Butler Committed by Steven Moreland
Browse files

NNAPI HAL: Change IEvent to explicit callbacks

IEvent was a synchronization primitive which caused some confusion
in the interface. Originally the event object was paired with an
asynchronous task, and the asynchronous task would signal this event
when the corresponding output was ready to be used.

In the case of IDevice::prepareModel, the function call would return an
IPreparedModel object that was not guaranteed to be prepared until the
runtime had returned from waiting on the corresponding event object.
The event object has been changed to two explicit callbacks--
IPreparedModelCallback and IExecutionCallback. Now,
IDevice::prepareModel no longer returns an unfinished IPreparedModel;
instead, it will pass the IPreparedModel object to the runtime through
IPreparedModelCallback::notify. When the runtime retreives the
IPreparedModel object, the asynchronous task has already finished
preparing the model.

The two callbacks are used for different purposes. Each has its own
version of notify to pass the data back to the runtime:
* IPreparedModelCallback::notify(ErrorStatus, IPreparedModel)
* IExecutionCallback::notify(ErrorStatus)

Bug: 63905942
Test: mm, vts, ml/nn/runtime/tests
Change-Id: I0c88cd262ba762e0af15e9da31ebe813a5d150b2
parent 7e028640
Loading
Loading
Loading
Loading
+14 −7
Original line number Diff line number Diff line
@@ -5,8 +5,9 @@ filegroup {
    srcs: [
        "types.hal",
        "IDevice.hal",
        "IEvent.hal",
        "IExecutionCallback.hal",
        "IPreparedModel.hal",
        "IPreparedModelCallback.hal",
    ],
}

@@ -20,8 +21,9 @@ genrule {
    out: [
        "android/hardware/neuralnetworks/1.0/types.cpp",
        "android/hardware/neuralnetworks/1.0/DeviceAll.cpp",
        "android/hardware/neuralnetworks/1.0/EventAll.cpp",
        "android/hardware/neuralnetworks/1.0/ExecutionCallbackAll.cpp",
        "android/hardware/neuralnetworks/1.0/PreparedModelAll.cpp",
        "android/hardware/neuralnetworks/1.0/PreparedModelCallbackAll.cpp",
    ],
}

@@ -40,16 +42,21 @@ genrule {
        "android/hardware/neuralnetworks/1.0/BnHwDevice.h",
        "android/hardware/neuralnetworks/1.0/BpHwDevice.h",
        "android/hardware/neuralnetworks/1.0/BsDevice.h",
        "android/hardware/neuralnetworks/1.0/IEvent.h",
        "android/hardware/neuralnetworks/1.0/IHwEvent.h",
        "android/hardware/neuralnetworks/1.0/BnHwEvent.h",
        "android/hardware/neuralnetworks/1.0/BpHwEvent.h",
        "android/hardware/neuralnetworks/1.0/BsEvent.h",
        "android/hardware/neuralnetworks/1.0/IExecutionCallback.h",
        "android/hardware/neuralnetworks/1.0/IHwExecutionCallback.h",
        "android/hardware/neuralnetworks/1.0/BnHwExecutionCallback.h",
        "android/hardware/neuralnetworks/1.0/BpHwExecutionCallback.h",
        "android/hardware/neuralnetworks/1.0/BsExecutionCallback.h",
        "android/hardware/neuralnetworks/1.0/IPreparedModel.h",
        "android/hardware/neuralnetworks/1.0/IHwPreparedModel.h",
        "android/hardware/neuralnetworks/1.0/BnHwPreparedModel.h",
        "android/hardware/neuralnetworks/1.0/BpHwPreparedModel.h",
        "android/hardware/neuralnetworks/1.0/BsPreparedModel.h",
        "android/hardware/neuralnetworks/1.0/IPreparedModelCallback.h",
        "android/hardware/neuralnetworks/1.0/IHwPreparedModelCallback.h",
        "android/hardware/neuralnetworks/1.0/BnHwPreparedModelCallback.h",
        "android/hardware/neuralnetworks/1.0/BpHwPreparedModelCallback.h",
        "android/hardware/neuralnetworks/1.0/BsPreparedModelCallback.h",
    ],
}

+47 −18
Original line number Diff line number Diff line
@@ -16,8 +16,7 @@

package android.hardware.neuralnetworks@1.0;

import IEvent;
import IPreparedModel;
import IPreparedModelCallback;

/**
 * This interface represents a device driver.
@@ -37,10 +36,9 @@ interface IDevice {
    /**
     * Gets the supported operations in a model.
     *
     * getSupportedSubgraph provides a more nuanced indication on whether a
     * model is able to be compiled by the driver. Having the entire model
     * allows for additional information such as tensor shapes to inputs or
     * tensor strides, information which is not known in "initialize".
     * getSupportedSubgraph indicates which operations of a model are fully
     * supported by the vendor driver. If an operation may not be supported for
     * any reason, getSupportedOperations must return false for that operation.
     *
     * @param model A model whose operations--and their corresponding
     *              operands--are to be verified by the driver.
@@ -48,7 +46,7 @@ interface IDevice {
     *                - NONE if successful
     *                - DEVICE_UNAVAILABLE if driver is offline or busy
     *                - GENERAL_FAILURE if there is an unspecified error
     *                - INVALID_ARGUMENT when provided model is invalid
     *                - INVALID_ARGUMENT if provided model is invalid
     * @return supportedOperations A list of supported operations, where true
     *                             indicates the operation is supported and
     *                             false indicates the operation is not
@@ -60,29 +58,60 @@ interface IDevice {
                generates (ErrorStatus status, vec<bool> supportedOperations);

    /**
     * Prepares a model for execution.
     * Creates a prepared model for execution.
     *
     * prepareModel is used to make any necessary transformations or alternative
     * representations to a model for execution, possible including
     * representations to a model for execution, possiblly including
     * transformations on the constant data, optimization on the model's graph,
     * or compilation into the device's native binary format.
     * or compilation into the device's native binary format. The model itself
     * is not changed.
     *
     * The model is prepared asynchronously with respect to the caller. The
     * prepareModel function must verify the inputs to the prepareModel function
     * are correct. If there is an error, prepareModel must immediately invoke
     * the callback with the appropriate ErrorStatus value and nullptr for the
     * IPreparedModel, then return with the same ErrorStatus. If the inputs to
     * the prepareModel function are valid and there is no error, prepareModel
     * must launch an asynchronous task to prepare the model in the background,
     * and immediately return from prepareModel with ErrorStatus::NONE. If the
     * asynchronous task fails to launch, prepareModel must immediately invoke
     * the callback with ErrorStatus::GENERAL_FAILURE and nullptr for the
     * IPreparedModel, then return with ErrorStatus::GENERAL_FAILURE.
     *
     * When the asynchronous task has finished preparing the model, it must
     * immediately invoke the callback function provided as an input to
     * prepareModel. If the model was prepared successfully, the callback object
     * must be invoked with an error status of ErrorStatus::NONE and the
     * produced IPreparedModel object. If an error occurred preparing the model,
     * the callback object must be invoked with the appropriate ErrorStatus
     * value and nullptr for the IPreparedModel.
     *
     * The only information that may be unknown to the model at this stage is
     * the shape of the tensors, which may only be known at execution time.
     * the shape of the tensors, which may only be known at execution time. As
     * such, some driver services may return partially prepared models, where
     * the prepared model can only be finished when it is paired with a set of
     * inputs to the model. Note that the same prepared model object can be
     * used with different shapes of inputs on different (possibly concurrent)
     * executions.
     *
     * Multiple threads can call prepareModel on the same model concurrently.
     *
     * @param model The model to be prepared for execution.
     * @param event A synchronization callback that must be signaled once the
     *              execution has finished.
     * @return status Error status of the call, must be:
     * @param callback A callback object used to return the error status of
     *                 preparing the model for execution and the prepared model
     *                 if successful, nullptr otherwise. The callback object's
     *                 notify function must be called exactly once, even if the
     *                 model could not be prepared.
     * @return status Error status of launching a task which prepares the model
     *                in the background; must be:
     *                - NONE if preparation task is successfully launched
     *                - DEVICE_UNAVAILABLE if driver is offline or busy
     *                - GENERAL_FAILURE if there is an unspecified error
     *                - INVALID_ARGUMENT when one of the input arguments is
     *                - INVALID_ARGUMENT if one of the input arguments is
     *                  invalid
     * @return preparedModel A handle to the resultant prepared model.
     */
    prepareModel(Model model, IEvent event)
      generates (ErrorStatus status, IPreparedModel preparedModel);
    prepareModel(Model model, IPreparedModelCallback callback)
      generates (ErrorStatus status);

    /**
     * Returns the current status of a driver.
+44 −0
Original line number Diff line number Diff line
@@ -17,29 +17,28 @@
package android.hardware.neuralnetworks@1.0;

/**
 * The IEvent interface is a callback object passed by the
 * Neuralnetworks runtime to the vendor service. It is used as a
 * synchronization primitive between one or more runtime threads and a
 * single asynchronous vendor thread.  An event object is passed as an
 * argument to a HIDL call that is expected to take a non-trivial
 * amount of time. When the asynchronous execution thread has
 * completed its computation, it must call "notify" on the event to
 * indicate to the Neuralnetworks runtime whether the computation was
 * successful or not, and that the corresponding output is ready to be
 * consumed if the execution was successful.
 * IExecutionCallback must be used to return the error status result from an
 * execution asynchronously launched from IPreparedModel::execute.
 */
interface IEvent {
interface IExecutionCallback {

    /**
     * IEvent::notify is called by the server thread (i.e., the thread doing
     * the work) to mark the event as completed so that any threads requiring
     * the corresponding output can continue executing.
     * notify must be invoked immediately after the asynchronous task has
     * finished performing the execution. notify must be provided with the
     * ErrorStatus resulting from the execution. If the asynchronous task
     * is not launched, notify must be invoked with the appropriate error.
     *
     * @param status Error status returned from the asynchronous task, must be:
     *               - NONE if asynchronous task was successful
     * @return param Error status returned from launching the asynchronous task
     *               (if the launch fails) or from the asynchronous task itself
     *               (if the launch succeeds). Must be:
     *               - NONE if the asynchronous execution was successful
     *               - DEVICE_UNAVAILABLE if driver is offline or busy
     *               - GENERAL_FAILURE if the asynchronous task resulted in an
     *                 unspecified error
     *               - OUTPUT_INSUFFICIENT_SIZE if provided output buffer is
     *                 not large enough to store the resultant values
     *               - INVALID_ARGUMENT if one of the input arguments to
     *                 prepareModel is invalid
     */
    oneway notify(ErrorStatus status);
};
+26 −12
Original line number Diff line number Diff line
@@ -16,7 +16,7 @@

package android.hardware.neuralnetworks@1.0;

import IEvent;
import IExecutionCallback;

/**
 * IPreparedModel describes a model that has been prepared for execution and
@@ -24,28 +24,42 @@ import IEvent;
 */
interface IPreparedModel {
    /**
     * Spawns an asynchronous execution on a prepared model.
     * Launches an asynchronous execution on a prepared model.
     *
     * Executions are asynchronous with respect to the Neuralnetworks runtime.
     * To support this, IPreparedModel::execute must spawn a new task and return
     * whether the task was successfully launched. The asynchronous task which
     * performs the execution must call event's IEvent::notify with the status
     * of the execution immediately after the execution has finished.
     * The execution is performed asynchronously with respect to the caller.
     * execute must verify the inputs to the function are correct. If there is
     * an error, execute must immediately invoke the callback with the
     * appropriate ErrorStatus value, then return with the same ErrorStatus. If
     * the inputs to the function are valid and there is no error, execute must
     * launch an asynchronous task to perform the execution in the background,
     * and immediately return with ErrorStatus::NONE. If the asynchronous task
     * fails to launch, execute must immediately invoke the callback with
     * ErrorStatus::GENERAL_FAILURE, then return with
     * ErrorStatus::GENERAL_FAILURE.
     *
     * Multiple threads can call this execute function concurrently.
     * When the asynchronous task has finished its execution, it must
     * immediately invoke the callback object provided as an input to the
     * execute function. This callback must be provided with the ErrorStatus of
     * the execution.
     *
     * Multiple threads can call the execute function on the same IPreparedModel
     * object concurrently with different requests.
     *
     * @param request The input and output information on which the prepared
     *                model is to be executed.
     * @param event A callback used for synchronization that must be signaled
     *              once the execution has finished.
     * @param callback A callback object used to return the error status of
     *                 the execution. The callback object's notify function must
     *                 be called exactly once, even if the execution was
     *                 unsuccessful.
     * @return status Error status of the call, must be:
     *                - NONE if task is successfully launched
     *                - DEVICE_UNAVAILABLE if driver is offline or busy
     *                - GENERAL_FAILURE if there is an unspecified error
     *                - OUTPUT_INSUFFICIENT_SIZE if provided output buffer is
     *                  not large enough to store the resultant values
     *                - INVALID_ARGUMENT when one of the input arguments is
     *                - INVALID_ARGUMENT if one of the input arguments is
     *                  invalid
     */
    execute(Request request, IEvent event) generates (ErrorStatus status);
    execute(Request request, IExecutionCallback callback)
        generates (ErrorStatus status);
};
+53 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.hardware.neuralnetworks@1.0;

import IPreparedModel;

/**
 * IPreparedModelCallback must be used to return a prepared model produced by an
 * asynchronous task launched from IDevice::prepareModel.
 */
interface IPreparedModelCallback {

    /**
     * notify must be invoked immediately after the asynchronous task holding
     * this callback has finished preparing the model. If the model was
     * successfully prepared, notify must be invoked with ErrorStatus::NONE and
     * the prepared model. If the model was not able to be successfully
     * prepared, notify must be invoked with the appropriate ErrorStatus and
     * nullptr as the IPreparedModel. If the asynchronous task holding this
     * callback fails to launch or if the model provided to
     * IDevice::prepareModel is invalid, notify must be invoked with the
     * appropriate error as well as nullptr for the IPreparedModel.
     *
     * @param status Error status returned from the asynchronous model
     *               preparation task; must be:
     *               - NONE if the asynchronous task successfully prepared the
     *                 model
     *               - DEVICE_UNAVAILABLE if driver is offline or busy
     *               - GENERAL_FAILURE if the asynchronous task resulted in an
     *                 unspecified error
     *               - INVALID_ARGUMENT if one of the input arguments to
     *                 prepareModel is invalid
     * @param preparedModel A model that has been asynchronously prepared for
     *                      execution. If the model was unable to be prepared
     *                      due to an error, nullptr must be passed in place of
     *                      the IPreparedModel object.
     */
    oneway notify(ErrorStatus status, IPreparedModel preparedModel);
};
Loading