From 3fd70b020ea4393e84d4bfc1c1c35418b5a59752 Mon Sep 17 00:00:00 2001 From: Miao Wang Date: Tue, 21 Jan 2020 13:15:09 -0800 Subject: [PATCH] Update sync fence related API for NNAPI - Allow IPreparedModel::executeFenced to measure gated durations. - Allow IPreparedModel::executeFenced to specify an optional deadline and aa optional post-gate-release maximum duration. Bug: 142778241 Bug: 141363565 Test: mm Change-Id: I1687ec5543f93ed9bb5d7fcf14dbe15ed5b5cd0d --- current.txt | 6 +- .../1.3/IFencedExecutionCallback.hal | 25 ++++-- neuralnetworks/1.3/IPreparedModel.hal | 78 ++++++++++++------- neuralnetworks/1.3/types.hal | 13 ++++ .../vts/functional/GeneratedTestHarness.cpp | 37 +++++---- .../1.3/vts/functional/ValidateRequest.cpp | 2 +- .../vts/functional/VtsHalNeuralnetworks.cpp | 22 +++--- 7 files changed, 118 insertions(+), 65 deletions(-) diff --git a/current.txt b/current.txt index 75975f2626..74c0cbbb5b 100644 --- a/current.txt +++ b/current.txt @@ -665,10 +665,10 @@ a3eddd9bbdc87e8c22764070037dd1154f1cf006e6fba93364c4f85d4c134a19 android.hardwar 65c16331e57f6dd68b3971f06f78fe9e3209afb60630c31705aa355f9a52bf0d android.hardware.neuralnetworks@1.3::IBuffer d1f382d14e1384b907d5bb5780df7f01934650d556fedbed2f15a90773c657d6 android.hardware.neuralnetworks@1.3::IDevice 4167dc3ad35e9cd0d2057d4868c7675ae2c3c9d05bbd614c1f5dccfa5fd68797 android.hardware.neuralnetworks@1.3::IExecutionCallback -29e26e83399b69c7998b787bd30426dd5baa2da350effca76bbee1ba877355c9 android.hardware.neuralnetworks@1.3::IFencedExecutionCallback -384fd9fd6e4d43ea11d407e52ea81da5242c3c5f4b458b8707d8feb652a13e36 android.hardware.neuralnetworks@1.3::IPreparedModel +2fa3679ad7c94b5e88724adcd560c561041068a4ca565c63830e68101988746a android.hardware.neuralnetworks@1.3::IFencedExecutionCallback +237b23b126a66f3432658020fed78cdd06ba6297459436fe6bae0ba753370833 android.hardware.neuralnetworks@1.3::IPreparedModel 0439a1fbbec7f16e5e4c653d85ac685d51bfafbae15b8f8cca530acdd7d6a8ce android.hardware.neuralnetworks@1.3::IPreparedModelCallback -5f1a4e0c29fc686ed476f9f04eed35e4405d21288cb2746b978d6891de5cc37d android.hardware.neuralnetworks@1.3::types +3646950b10f7cacdafca13609b0e18496cea942f3bdfe920494661856eff48bb android.hardware.neuralnetworks@1.3::types 3e01d4446cd69fd1c48f8572efd97487bc179564b32bd795800b97bbe10be37b android.hardware.wifi@1.4::IWifi c67aaf26a7a40d14ea61e70e20afacbd0bb906df1704d585ac8599fbb69dd44b android.hardware.wifi.hostapd@1.2::IHostapd 11f6448d15336361180391c8ebcdfd2d7cf77b3782d577e594d583aadc9c2877 android.hardware.wifi.hostapd@1.2::types diff --git a/neuralnetworks/1.3/IFencedExecutionCallback.hal b/neuralnetworks/1.3/IFencedExecutionCallback.hal index 39076b9a16..6030809406 100644 --- a/neuralnetworks/1.3/IFencedExecutionCallback.hal +++ b/neuralnetworks/1.3/IFencedExecutionCallback.hal @@ -38,11 +38,24 @@ interface IFencedExecutionCallback { * - DEVICE_UNAVAILABLE if driver is offline or busy * - GENERAL_FAILURE if the asynchronous task resulted in an * unspecified error - * @return timing Duration of execution. Unless MeasureTiming::YES was passed when - * launching the execution and status is NONE, all times must - * be reported as UINT64_MAX. A driver may choose to report - * any time as UINT64_MAX, indicating that particular measurement is - * not available. + * - MISSED_DEADLINE_* if the deadline for executing a model + * cannot be met + * - RESOURCE_EXHAUSTED_* if the task was aborted by the + * driver + * @return timingLaunched The duration starts when executeFenced is called and ends when + * executeFenced signals the returned syncFence. + * Unless MeasureTiming::YES was passed when + * launching the execution and status is NONE, all times + * must be reported as UINT64_MAX. A driver may choose to + * report any time as UINT64_MAX, indicating that particular + * measurement is not available. + * @return timingFenced The duration starts when all waitFor sync fences have been signaled + * and ends when executeFenced signals the returned syncFence. + * Unless MeasureTiming::YES was passed when + * launching the execution and status is NONE, all times + * must be reported as UINT64_MAX. A driver may choose to + * report any time as UINT64_MAX, indicating that particular + * measurement is not available. */ - getExecutionInfo() generates (ErrorStatus status, Timing timing); + getExecutionInfo() generates (ErrorStatus status, Timing timingLaunched, Timing timingFenced); }; diff --git a/neuralnetworks/1.3/IPreparedModel.hal b/neuralnetworks/1.3/IPreparedModel.hal index f84bcf4ffc..d645de789c 100644 --- a/neuralnetworks/1.3/IPreparedModel.hal +++ b/neuralnetworks/1.3/IPreparedModel.hal @@ -21,6 +21,7 @@ import @1.2::MeasureTiming; import @1.2::OutputShape; import @1.2::Timing; import ErrorStatus; +import OptionalTimeoutDuration; import OptionalTimePoint; import Request; import IExecutionCallback; @@ -68,7 +69,7 @@ interface IPreparedModel extends @1.2::IPreparedModel { * There must be no failure unless the device itself is in a bad state. * * execute_1_3 can be called with an optional deadline. If the execution - * is not able to completed before the provided deadline, the execution + * is not able to be completed before the provided deadline, the execution * must be aborted, and either {@link * ErrorStatus::MISSED_DEADLINE_TRANSIENT} or {@link * ErrorStatus::MISSED_DEADLINE_PERSISTENT} must be returned. The error due @@ -88,7 +89,7 @@ interface IPreparedModel extends @1.2::IPreparedModel { * The duration runs from the time the driver sees the call * to the execute_1_3 function to the time the driver invokes * the callback. - * @param deadline The time by which execution must complete. If the + * @param deadline The time by which the execution must complete. If the * execution cannot be finished by the deadline, the * execution must be aborted. * @param callback A callback object used to return the error status of @@ -139,7 +140,7 @@ interface IPreparedModel extends @1.2::IPreparedModel { * in a bad state. * * executeSynchronously_1_3 can be called with an optional deadline. If the - * execution is not able to completed before the provided deadline, the + * execution is not able to be completed before the provided deadline, the * execution must be aborted, and either {@link * ErrorStatus::MISSED_DEADLINE_TRANSIENT} or {@link * ErrorStatus::MISSED_DEADLINE_PERSISTENT} must be returned. The error due @@ -159,7 +160,7 @@ interface IPreparedModel extends @1.2::IPreparedModel { * The duration runs from the time the driver sees the call * to the executeSynchronously_1_3 function to the time the driver * returns from the function. - * @param deadline The time by which execution must complete. If the + * @param deadline The time by which the execution must complete. If the * execution cannot be finished by the deadline, the * execution must be aborted. * @return status Error status of the execution, must be: @@ -194,52 +195,75 @@ interface IPreparedModel extends @1.2::IPreparedModel { * Launch a fenced asynchronous execution on a prepared model. * * The execution is performed asynchronously with respect to the caller. - * executeFenced must fully validate the request, and only accept one that is - * guaranteed to be completed, unless a hardware failure or kernel panic happens on the device. - * If there is an error during validation, executeFenced must immediately return with - * the corresponding ErrorStatus. If the request is valid and there is no error launching, - * executeFenced must dispatch an asynchronous task to perform the execution in the - * background, and immediately return with ErrorStatus::NONE, a sync_fence that will be - * signaled once the execution is completed, and a callback that can be used by the client - * to query the duration and runtime error status. If the task has finished - * before the call returns, empty handle may be returned for the sync fence. If the - * asynchronous task fails to launch, executeFenced must immediately return with - * ErrorStatus::GENERAL_FAILURE, and empty handle for the sync fence and nullptr - * for callback. The execution must wait for all the sync fences (if any) in wait_for to be - * signaled before starting the actual execution. - * - * If any of sync fences in wait_for changes to error status after the executeFenced - * call succeeds, the driver must immediately set the returned sync fence to error status. + * executeFenced must verify the inputs to the function are correct, and the usages + * of memory pools allocated by IDevice::allocate are valid. If there is an error, + * executeFenced must immediately return with the corresponding ErrorStatus, an empty + * handle for syncFence, and nullptr for callback. If the inputs to the function + * are valid and there is no error, executeFenced must dispatch an asynchronous task + * to perform the execution in the background, and immediately return with + * ErrorStatus::NONE, a sync fence that will be signaled once the execution is completed, + * and a callback that can be used by the client to query the duration and runtime error + * status. If the task has finished before the call returns, an empty handle may be returned + * for syncFence. The execution must wait for all the sync fences (if any) in waitFor + * to be signaled before starting the actual execution. * * When the asynchronous task has finished its execution, it must - * immediately signal the sync_fence created when dispatching. After - * the sync_fence is signaled, the task must not modify the content of + * immediately signal the syncFence returned from the executeFenced call. After + * the syncFence is signaled, the task must not modify the content of * any data object referenced by 'request' (described by the * {@link @1.0::DataLocation} of a {@link @1.0::RequestArgument}). * + * executeFenced can be called with an optional deadline and an optional duration. + * If the execution is not able to be completed before the provided deadline or + * within the timeout duration (measured from when all sync fences in waitFor are + * signaled), whichever comes earlier, the execution must be aborted, and either + * {@link ErrorStatus::MISSED_DEADLINE_TRANSIENT} or {@link + * ErrorStatus::MISSED_DEADLINE_PERSISTENT} must be returned. The error due + * to an abort must be sent the same way as other errors, described above. + * If the service reports that it does not support execution deadlines via + * IDevice::supportsDeadlines, and executeFenced is called with a + * deadline or duration, then the argument is invalid, and + * {@link ErrorStatus::INVALID_ARGUMENT} must be returned. + * + * If any of the sync fences in waitFor changes to error status after the executeFenced + * call succeeds, or the execution is aborted because it cannot finish before the deadline + * has been reached or the duration has elapsed, the driver must immediately set the returned + * syncFence to error status. + * * Any number of calls to the executeFenced, execute* and executeSynchronously* * functions, in any combination, may be made concurrently, even on the same * IPreparedModel object. * * @param request The input and output information on which the prepared - * model is to be executed. + * model is to be executed. The outputs in the request must have + * fully specified dimensions. * @param waitFor A vector of sync fence file descriptors. * Execution must not start until all sync fences have been signaled. * @param measure Specifies whether or not to measure duration of the execution. - * The duration runs from the time the driver sees the call - * to the executeFenced function to the time sync_fence is triggered. + * @param deadline The time by which the execution must complete. If the + * execution cannot be finished by the deadline, the + * execution must be aborted. + * @param duration The length of time within which the execution must + * complete after all sync fences in waitFor are signaled. If the + * execution cannot be finished within the duration, the execution + * must be aborted. * @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 * - INVALID_ARGUMENT if one of the input arguments is invalid, including * fences in error states. - * @return syncFence The sync fence that will be triggered when the task is completed. + * - MISSED_DEADLINE_* if the deadline for executing a model + * cannot be met + * - RESOURCE_EXHAUSTED_* if the task was aborted by the + * driver + * @return syncFence The sync fence that will be signaled when the task is completed. * The sync fence will be set to error if a critical error, * e.g. hardware failure or kernel panic, occurs when doing execution. * @return callback The IFencedExecutionCallback can be used to query information like duration * and error status when the execution is completed. */ - executeFenced(Request request, vec waitFor, MeasureTiming measure) + executeFenced(Request request, vec waitFor, MeasureTiming measure, + OptionalTimePoint deadline, OptionalTimeoutDuration duration) generates (ErrorStatus status, handle syncFence, IFencedExecutionCallback callback); }; diff --git a/neuralnetworks/1.3/types.hal b/neuralnetworks/1.3/types.hal index abc33e77d3..ed577e4d9d 100644 --- a/neuralnetworks/1.3/types.hal +++ b/neuralnetworks/1.3/types.hal @@ -5576,6 +5576,19 @@ safe_union OptionalTimePoint { uint64_t nanoseconds; }; +/** + * Optional timeout duration measured in nanoseconds. + */ +safe_union OptionalTimeoutDuration { + /** No time point provided. */ + Monostate none; + + /** + * Timeout duration measured in nanoseconds. + */ + uint64_t nanoseconds; +}; + /** * Return status of a function. */ diff --git a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp index 88837db349..8ea0b7eb47 100644 --- a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp +++ b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp @@ -80,6 +80,13 @@ enum class MemoryType { SHARED, DEVICE }; enum class IOType { INPUT, OUTPUT }; +static void waitForSyncFence(int syncFd) { + constexpr int kInfiniteTimeout = -1; + ASSERT_GT(syncFd, 0); + int r = sync_wait(syncFd, kInfiniteTimeout); + ASSERT_GE(r, 0); +} + struct TestConfig { Executor executor; MeasureTiming measureTiming; @@ -567,33 +574,29 @@ void EvaluatePreparedModel(const sp& device, const sp& case Executor::FENCED: { SCOPED_TRACE("fenced"); ErrorStatus result; - hidl_handle sync_fence_handle; - sp fenced_callback; + hidl_handle syncFenceHandle; + sp fencedCallback; Return ret = preparedModel->executeFenced( - request, {}, testConfig.measureTiming, - [&result, &sync_fence_handle, &fenced_callback]( + request, {}, testConfig.measureTiming, {}, {}, + [&result, &syncFenceHandle, &fencedCallback]( ErrorStatus error, const hidl_handle& handle, const sp& callback) { result = error; - sync_fence_handle = handle; - fenced_callback = callback; + syncFenceHandle = handle; + fencedCallback = callback; }); ASSERT_TRUE(ret.isOk()); if (result != ErrorStatus::NONE) { - ASSERT_EQ(sync_fence_handle.getNativeHandle(), nullptr); - ASSERT_EQ(fenced_callback, nullptr); + ASSERT_EQ(syncFenceHandle.getNativeHandle(), nullptr); + ASSERT_EQ(fencedCallback, nullptr); executionStatus = ErrorStatus::GENERAL_FAILURE; - } else if (sync_fence_handle.getNativeHandle()) { - constexpr int kInfiniteTimeout = -1; - int sync_fd = sync_fence_handle.getNativeHandle()->data[0]; - ASSERT_GT(sync_fd, 0); - int r = sync_wait(sync_fd, kInfiniteTimeout); - ASSERT_GE(r, 0); + } else if (syncFenceHandle.getNativeHandle()) { + waitForSyncFence(syncFenceHandle.getNativeHandle()->data[0]); } if (result == ErrorStatus::NONE) { - ASSERT_NE(fenced_callback, nullptr); - Return ret = fenced_callback->getExecutionInfo( - [&executionStatus, &timing](ErrorStatus error, Timing t) { + ASSERT_NE(fencedCallback, nullptr); + Return ret = fencedCallback->getExecutionInfo( + [&executionStatus, &timing](ErrorStatus error, Timing t, Timing) { executionStatus = error; timing = t; }); diff --git a/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp index 1ddd09c033..2fd9b647f1 100644 --- a/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp +++ b/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp @@ -143,7 +143,7 @@ static void validate(const sp& preparedModel, const std::string& { SCOPED_TRACE(message + " [executeFenced]"); Return ret = preparedModel->executeFenced( - request, {}, MeasureTiming::NO, + request, {}, MeasureTiming::NO, {}, {}, [](ErrorStatus error, const hidl_handle& handle, const sp& callback) { if (error != ErrorStatus::DEVICE_UNAVAILABLE) { diff --git a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp index c84f5b70e7..896ace65b9 100644 --- a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp +++ b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp @@ -136,17 +136,17 @@ void validateBurst(const sp& preparedModel, const V1_0::Request& // Validate sync_fence handles for dispatch with valid input void validateExecuteFenced(const sp& preparedModel, const Request& request) { SCOPED_TRACE("Expecting request to fail [executeFenced]"); - Return ret_null = - preparedModel->executeFenced(request, {hidl_handle(nullptr)}, V1_2::MeasureTiming::NO, - [](ErrorStatus error, const hidl_handle& handle, - const sp& callback) { - // TODO: fix this once sample driver impl is merged. - if (error != ErrorStatus::DEVICE_UNAVAILABLE) { - ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, error); - } - ASSERT_EQ(handle.getNativeHandle(), nullptr); - ASSERT_EQ(callback, nullptr); - }); + Return ret_null = preparedModel->executeFenced( + request, {hidl_handle(nullptr)}, V1_2::MeasureTiming::NO, {}, {}, + [](ErrorStatus error, const hidl_handle& handle, + const sp& callback) { + // TODO: fix this once sample driver impl is merged. + if (error != ErrorStatus::DEVICE_UNAVAILABLE) { + ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, error); + } + ASSERT_EQ(handle.getNativeHandle(), nullptr); + ASSERT_EQ(callback, nullptr); + }); ASSERT_TRUE(ret_null.isOk()); }