mirror of
https://github.com/Evolution-X/hardware_interfaces
synced 2026-02-01 11:36:00 +00:00
Merge changes from topics "aosp-nnapi-1.3-operations", "aosp-nnapi-async-cmdqueue"
* changes: Fix the NNAPI vts tests about validateExecuteFenced Add VTS tests for NNAPI IPreparedModel::executeFenced Support sync fence in NNAPI Add FILL and RANK ops Add ELU and HARD_SWISH NNAPI: Regenerate types.hal to sync with types.spec
This commit is contained in:
@@ -625,9 +625,10 @@ ac429fca0da4ce91218768ec31b64ded88251f8a26d8c4f27c06abdc5b1926d9 android.hardwar
|
||||
65c16331e57f6dd68b3971f06f78fe9e3209afb60630c31705aa355f9a52bf0d android.hardware.neuralnetworks@1.3::IBuffer
|
||||
d1f382d14e1384b907d5bb5780df7f01934650d556fedbed2f15a90773c657d6 android.hardware.neuralnetworks@1.3::IDevice
|
||||
4167dc3ad35e9cd0d2057d4868c7675ae2c3c9d05bbd614c1f5dccfa5fd68797 android.hardware.neuralnetworks@1.3::IExecutionCallback
|
||||
7d23020248194abbee8091cc624f39a5a6d7ccba338b172d5d2d3df0cceffbee android.hardware.neuralnetworks@1.3::IPreparedModel
|
||||
29e26e83399b69c7998b787bd30426dd5baa2da350effca76bbee1ba877355c9 android.hardware.neuralnetworks@1.3::IFencedExecutionCallback
|
||||
384fd9fd6e4d43ea11d407e52ea81da5242c3c5f4b458b8707d8feb652a13e36 android.hardware.neuralnetworks@1.3::IPreparedModel
|
||||
0439a1fbbec7f16e5e4c653d85ac685d51bfafbae15b8f8cca530acdd7d6a8ce android.hardware.neuralnetworks@1.3::IPreparedModelCallback
|
||||
ee65638f8af3f9f4f222e7208eaa9f1f8e7f8e0a21545846ba67d0e27624efa1 android.hardware.neuralnetworks@1.3::types
|
||||
5f1a4e0c29fc686ed476f9f04eed35e4405d21288cb2746b978d6891de5cc37d android.hardware.neuralnetworks@1.3::types
|
||||
3e01d4446cd69fd1c48f8572efd97487bc179564b32bd795800b97bbe10be37b android.hardware.wifi@1.4::IWifi
|
||||
a64467bae843569f0d465c5be7f0c7a5b987985b55a3ef4794dd5afc68538650 android.hardware.wifi.supplicant@1.3::ISupplicant
|
||||
44445b8a03d7b9e68b2fbd954672c18a8fce9e32851b0692f4f4ab3407f86ecb android.hardware.wifi.supplicant@1.3::ISupplicantStaIface
|
||||
|
||||
@@ -11,6 +11,7 @@ hidl_interface {
|
||||
"IBuffer.hal",
|
||||
"IDevice.hal",
|
||||
"IExecutionCallback.hal",
|
||||
"IFencedExecutionCallback.hal",
|
||||
"IPreparedModel.hal",
|
||||
"IPreparedModelCallback.hal",
|
||||
],
|
||||
|
||||
48
neuralnetworks/1.3/IFencedExecutionCallback.hal
Normal file
48
neuralnetworks/1.3/IFencedExecutionCallback.hal
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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.3;
|
||||
|
||||
import @1.2::Timing;
|
||||
import ErrorStatus;
|
||||
|
||||
/**
|
||||
* IFencedExecutionCallback can be used to query the error status result
|
||||
* and duration information from an IPreparedModel::executeFenced call.
|
||||
*/
|
||||
interface IFencedExecutionCallback {
|
||||
|
||||
/**
|
||||
* The getExecutionInfo method is used by the clients to query error status
|
||||
* result and duration information. The method must only be called after the actual
|
||||
* evaluation has finished or resulted in an runtime error, as indicated by the status
|
||||
* of the sync fence returned by the IPreparedModel::executeFenced call, otherwise
|
||||
* GENERAL_FAILURE must be returned.
|
||||
*
|
||||
* @return status Error status returned from the asynchronously dispatched execution
|
||||
* 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
|
||||
* @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.
|
||||
*/
|
||||
getExecutionInfo() generates (ErrorStatus status, Timing timing);
|
||||
};
|
||||
@@ -24,6 +24,7 @@ import ErrorStatus;
|
||||
import OptionalTimePoint;
|
||||
import Request;
|
||||
import IExecutionCallback;
|
||||
import IFencedExecutionCallback;
|
||||
|
||||
/**
|
||||
* IPreparedModel describes a model that has been prepared for execution and
|
||||
@@ -91,7 +92,8 @@ interface IPreparedModel extends @1.2::IPreparedModel {
|
||||
* execution cannot be finished by the deadline, the
|
||||
* execution must be aborted.
|
||||
* @param callback A callback object used to return the error status of
|
||||
* the execution. The callback object's notify function must
|
||||
* the execution, shape information of model output operands, and
|
||||
* duration of 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:
|
||||
@@ -187,4 +189,57 @@ interface IPreparedModel extends @1.2::IPreparedModel {
|
||||
OptionalTimePoint deadline)
|
||||
generates (ErrorStatus status, vec<OutputShape> outputShapes,
|
||||
Timing timing);
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* 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
|
||||
* any data object referenced by 'request' (described by the
|
||||
* {@link @1.0::DataLocation} of a {@link @1.0::RequestArgument}).
|
||||
*
|
||||
* 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.
|
||||
* @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.
|
||||
* @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.
|
||||
* 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<handle> waitFor, MeasureTiming measure)
|
||||
generates (ErrorStatus status, handle syncFence, IFencedExecutionCallback callback);
|
||||
};
|
||||
|
||||
@@ -1415,6 +1415,7 @@ enum OperationType : int32_t {
|
||||
* * {@link OperandType::TENSOR_FLOAT32}
|
||||
* * {@link OperandType::TENSOR_QUANT8_ASYMM}
|
||||
* * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
|
||||
* * {@link OperandType::TENSOR_INT32} (since HAL version 1.3)
|
||||
*
|
||||
* Supported tensor rank: up to 4
|
||||
*
|
||||
@@ -1425,6 +1426,8 @@ enum OperationType : int32_t {
|
||||
* * 2: An {@link OperandType::INT32} scalar, and has to be one of the
|
||||
* {@link FusedActivationFunc} values. Specifies the activation to
|
||||
* invoke on the result.
|
||||
* For a {@link OperandType::TENSOR_INT32} tensor,
|
||||
* the {@link FusedActivationFunc} must be "NONE".
|
||||
*
|
||||
* Outputs:
|
||||
* * 0: The product, a tensor of the same {@link OperandType} as input0.
|
||||
@@ -1905,6 +1908,11 @@ enum OperationType : int32_t {
|
||||
* dimensions. The output is the result of dividing the first input tensor
|
||||
* by the second, optionally modified by an activation function.
|
||||
*
|
||||
* For inputs of {@link OperandType::TENSOR_INT32}, performs
|
||||
* "floor division" ("//" in Python). For example,
|
||||
* 5 // 2 = 2
|
||||
* -5 // 2 = -3
|
||||
*
|
||||
* Two dimensions are compatible when:
|
||||
* 1. they are equal, or
|
||||
* 2. one of them is 1
|
||||
@@ -1925,6 +1933,7 @@ enum OperationType : int32_t {
|
||||
* Supported tensor {@link OperandType}:
|
||||
* * {@link OperandType::TENSOR_FLOAT16} (since HAL version 1.2)
|
||||
* * {@link OperandType::TENSOR_FLOAT32}
|
||||
* * {@link OperandType::TENSOR_INT32} (since HAL version 1.3)
|
||||
*
|
||||
* Supported tensor rank: up to 4
|
||||
*
|
||||
@@ -1935,6 +1944,8 @@ enum OperationType : int32_t {
|
||||
* * 2: An {@link OperandType::INT32} scalar, and has to be one of the
|
||||
* {@link FusedActivationFunc} values. Specifies the activation to
|
||||
* invoke on the result.
|
||||
* For a {@link OperandType::TENSOR_INT32} tensor,
|
||||
* the {@link FusedActivationFunc} must be "NONE".
|
||||
*
|
||||
* Outputs:
|
||||
* * 0: A tensor of the same {@link OperandType} as input0.
|
||||
@@ -2186,6 +2197,7 @@ enum OperationType : int32_t {
|
||||
* * {@link OperandType::TENSOR_FLOAT32}
|
||||
* * {@link OperandType::TENSOR_QUANT8_ASYMM} (since HAL version 1.2)
|
||||
* * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} (since HAL version 1.3)
|
||||
* * {@link OperandType::TENSOR_INT32} (since HAL version 1.3)
|
||||
*
|
||||
* Supported tensor rank: up to 4
|
||||
*
|
||||
@@ -2196,6 +2208,8 @@ enum OperationType : int32_t {
|
||||
* * 2: An {@link OperandType::INT32} scalar, and has to be one of the
|
||||
* {@link FusedActivationFunc} values. Specifies the activation to
|
||||
* invoke on the result.
|
||||
* For a {@link OperandType::TENSOR_INT32} tensor,
|
||||
* the {@link FusedActivationFunc} must be "NONE".
|
||||
*
|
||||
* Outputs:
|
||||
* * 0: A tensor of the same {@link OperandType} as input0.
|
||||
@@ -2242,6 +2256,7 @@ enum OperationType : int32_t {
|
||||
* Supported tensor {@link OperandType}:
|
||||
* * {@link OperandType::TENSOR_FLOAT16}
|
||||
* * {@link OperandType::TENSOR_FLOAT32}
|
||||
* * {@link OperandType::TENSOR_INT32} (since HAL version 1.3)
|
||||
*
|
||||
* Supported tensor rank: from 1.
|
||||
*
|
||||
@@ -4971,6 +4986,106 @@ enum OperationType : int32_t {
|
||||
*/
|
||||
WHILE = 97,
|
||||
|
||||
/**
|
||||
* Computes exponential linear activation on the input tensor element-wise.
|
||||
*
|
||||
* The output is calculated using the following formula:
|
||||
*
|
||||
* ELU(x) = max(0, x) + min(0, alpha * (exp(x) - 1))
|
||||
*
|
||||
* Supported tensor {@link OperandType}:
|
||||
* * {@link OperandType::TENSOR_FLOAT16}
|
||||
* * {@link OperandType::TENSOR_FLOAT32}
|
||||
*
|
||||
* Inputs:
|
||||
* * 0: A tensor, specifying the input. May be zero-sized.
|
||||
* * 1: A scalar, specifying the alpha parameter.
|
||||
* For input tensor of {@link OperandType::TENSOR_FLOAT16},
|
||||
* the alpha value must be of {@link OperandType::FLOAT16}.
|
||||
* For input tensor of {@link OperandType::TENSOR_FLOAT32},
|
||||
* the alpha value must be of {@link OperandType::FLOAT32}.
|
||||
*
|
||||
* Outputs:
|
||||
* * 0: The output tensor of same shape and type as input0.
|
||||
*/
|
||||
ELU = 98,
|
||||
|
||||
/**
|
||||
* Computes hard-swish activation on the input tensor element-wise.
|
||||
*
|
||||
* Hard swish activation is introduced in
|
||||
* https://arxiv.org/pdf/1905.02244.pdf
|
||||
*
|
||||
* The output is calculated using the following formula:
|
||||
*
|
||||
* h-swish(x) = x * max(0, min(6, (x + 3))) / 6
|
||||
|
||||
* Supported tensor {@link OperandType}:
|
||||
* * {@link OperandType::TENSOR_FLOAT16}
|
||||
* * {@link OperandType::TENSOR_FLOAT32}
|
||||
* * {@link OperandType::TENSOR_QUANT8_ASYMM}
|
||||
* * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED}
|
||||
*
|
||||
* Inputs:
|
||||
* * 0: A tensor, specifying the input. May be zero-sized.
|
||||
*
|
||||
* Outputs:
|
||||
* * 0: The output tensor of same shape and type as input0.
|
||||
* Scale and zero point of this tensor may be different from the input
|
||||
* tensor's parameters.
|
||||
*/
|
||||
HARD_SWISH = 99,
|
||||
|
||||
/**
|
||||
* Creates a tensor filled with a scalar value.
|
||||
*
|
||||
* Supported output tensor {@link OperandType}:
|
||||
* * {@link OperandType::TENSOR_FLOAT16}
|
||||
* * {@link OperandType::TENSOR_FLOAT32}
|
||||
* * {@link OperandType::TENSOR_INT32}
|
||||
*
|
||||
* Inputs:
|
||||
* * 0: A 1-D tensor, specifying the desired output tensor shape.
|
||||
* * 1: A scalar, specifying the value to fill the output tensors with.
|
||||
* For output tensor of {@link OperandType::TENSOR_FLOAT16},
|
||||
* the scalar must be of {@link OperandType::FLOAT16}.
|
||||
* For output tensor of {@link OperandType::TENSOR_FLOAT32},
|
||||
* the scalar must be of {@link OperandType::FLOAT32}.
|
||||
* For output tensor of {@link OperandType::TENSOR_INT32},
|
||||
* the scalar must be of {@link OperandType::INT32}.
|
||||
*
|
||||
* Outputs:
|
||||
* * 0: The output tensor.
|
||||
*/
|
||||
FILL = 100,
|
||||
|
||||
/**
|
||||
* Returns the rank of a tensor.
|
||||
*
|
||||
* The rank of a tensor is the number of dimensions in it. Also known as
|
||||
* "order", "degree", "ndims".
|
||||
*
|
||||
* Supported tensor {@link OperandType}:
|
||||
* * {@link OperandType::TENSOR_FLOAT16}
|
||||
* * {@link OperandType::TENSOR_FLOAT32}
|
||||
* * {@link OperandType::TENSOR_INT32}
|
||||
* * {@link OperandType::TENSOR_QUANT8_ASYMM}
|
||||
* * {@link OperandType::TENSOR_QUANT16_SYMM}
|
||||
* * {@link OperandType::TENSOR_BOOL8}
|
||||
* * {@link OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL}
|
||||
* * {@link OperandType::TENSOR_QUANT16_ASYMM}
|
||||
* * {@link OperandType::TENSOR_QUANT8_SYMM}
|
||||
* * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED}
|
||||
*
|
||||
* Inputs:
|
||||
* * 0: The input tensor.
|
||||
*
|
||||
* Outputs:
|
||||
* * 0: A scalar of {@link OperandType::INT32}, specifying the rank
|
||||
* of the input tensor.
|
||||
*/
|
||||
RANK = 101,
|
||||
|
||||
/**
|
||||
* DEPRECATED. Since NNAPI 1.2, extensions are the preferred alternative to
|
||||
* OEM operation and data types.
|
||||
@@ -4993,7 +5108,7 @@ enum OperationType : int32_t {
|
||||
enum OperationTypeRange : uint32_t {
|
||||
BASE_MIN = 0,
|
||||
FUNDAMENTAL_MIN = 0,
|
||||
FUNDAMENTAL_MAX = 97,
|
||||
FUNDAMENTAL_MAX = 101,
|
||||
OEM_MIN = 10000,
|
||||
OEM_MAX = 10000,
|
||||
BASE_MAX = 0xFFFF,
|
||||
|
||||
@@ -65,6 +65,7 @@ cc_test {
|
||||
"libhidlmemory",
|
||||
"libneuralnetworks_generated_test_harness",
|
||||
"libneuralnetworks_utils",
|
||||
"libsync",
|
||||
],
|
||||
whole_static_libs: [
|
||||
"neuralnetworks_generated_V1_0_example",
|
||||
|
||||
@@ -29,11 +29,13 @@
|
||||
#include <android/hardware/neuralnetworks/1.2/IPreparedModelCallback.h>
|
||||
#include <android/hardware/neuralnetworks/1.2/types.h>
|
||||
#include <android/hardware/neuralnetworks/1.3/IDevice.h>
|
||||
#include <android/hardware/neuralnetworks/1.3/IFencedExecutionCallback.h>
|
||||
#include <android/hardware/neuralnetworks/1.3/IPreparedModel.h>
|
||||
#include <android/hardware/neuralnetworks/1.3/IPreparedModelCallback.h>
|
||||
#include <android/hardware/neuralnetworks/1.3/types.h>
|
||||
#include <android/hidl/allocator/1.0/IAllocator.h>
|
||||
#include <android/hidl/memory/1.0/IMemory.h>
|
||||
#include <android/sync.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include <hidlmemory/mapping.h>
|
||||
|
||||
@@ -70,7 +72,7 @@ using HidlToken = hidl_array<uint8_t, static_cast<uint32_t>(Constant::BYTE_SIZE_
|
||||
|
||||
namespace {
|
||||
|
||||
enum class Executor { ASYNC, SYNC, BURST };
|
||||
enum class Executor { ASYNC, SYNC, BURST, FENCED };
|
||||
|
||||
enum class OutputType { FULLY_SPECIFIED, UNSPECIFIED, INSUFFICIENT };
|
||||
|
||||
@@ -562,9 +564,48 @@ void EvaluatePreparedModel(const sp<IDevice>& device, const sp<IPreparedModel>&
|
||||
|
||||
break;
|
||||
}
|
||||
case Executor::FENCED: {
|
||||
SCOPED_TRACE("fenced");
|
||||
ErrorStatus result;
|
||||
hidl_handle sync_fence_handle;
|
||||
sp<IFencedExecutionCallback> fenced_callback;
|
||||
Return<void> ret = preparedModel->executeFenced(
|
||||
request, {}, testConfig.measureTiming,
|
||||
[&result, &sync_fence_handle, &fenced_callback](
|
||||
ErrorStatus error, const hidl_handle& handle,
|
||||
const sp<IFencedExecutionCallback>& callback) {
|
||||
result = error;
|
||||
sync_fence_handle = handle;
|
||||
fenced_callback = callback;
|
||||
});
|
||||
ASSERT_TRUE(ret.isOk());
|
||||
if (result != ErrorStatus::NONE) {
|
||||
ASSERT_EQ(sync_fence_handle.getNativeHandle(), nullptr);
|
||||
ASSERT_EQ(fenced_callback, 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);
|
||||
}
|
||||
if (result == ErrorStatus::NONE) {
|
||||
ASSERT_NE(fenced_callback, nullptr);
|
||||
Return<void> ret = fenced_callback->getExecutionInfo(
|
||||
[&executionStatus, &timing](ErrorStatus error, Timing t) {
|
||||
executionStatus = error;
|
||||
timing = t;
|
||||
});
|
||||
ASSERT_TRUE(ret.isOk());
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (testConfig.outputType != OutputType::FULLY_SPECIFIED &&
|
||||
// The driver is allowed to reject executeFenced, and if they do, we should skip.
|
||||
if ((testConfig.outputType != OutputType::FULLY_SPECIFIED ||
|
||||
testConfig.executor == Executor::FENCED) &&
|
||||
executionStatus == ErrorStatus::GENERAL_FAILURE) {
|
||||
if (skipped != nullptr) {
|
||||
*skipped = true;
|
||||
@@ -648,6 +689,11 @@ void EvaluatePreparedModel(const sp<IDevice>& device, const sp<IPreparedModel>&
|
||||
executorList = {Executor::ASYNC, Executor::SYNC};
|
||||
memoryType = MemoryType::DEVICE;
|
||||
} break;
|
||||
case TestKind::FENCED_COMPUTE: {
|
||||
outputTypesList = {OutputType::FULLY_SPECIFIED};
|
||||
measureTimingList = {MeasureTiming::NO, MeasureTiming::YES};
|
||||
executorList = {Executor::FENCED};
|
||||
} break;
|
||||
case TestKind::QUANTIZATION_COUPLING: {
|
||||
LOG(FATAL) << "Wrong TestKind for EvaluatePreparedModel";
|
||||
return;
|
||||
@@ -671,7 +717,8 @@ void EvaluatePreparedCoupledModels(const sp<IDevice>& device,
|
||||
const TestModel& coupledModel) {
|
||||
const std::vector<OutputType> outputTypesList = {OutputType::FULLY_SPECIFIED};
|
||||
const std::vector<MeasureTiming> measureTimingList = {MeasureTiming::NO, MeasureTiming::YES};
|
||||
const std::vector<Executor> executorList = {Executor::ASYNC, Executor::SYNC, Executor::BURST};
|
||||
const std::vector<Executor> executorList = {Executor::ASYNC, Executor::SYNC, Executor::BURST,
|
||||
Executor::FENCED};
|
||||
|
||||
for (const OutputType outputType : outputTypesList) {
|
||||
for (const MeasureTiming measureTiming : measureTimingList) {
|
||||
@@ -708,7 +755,8 @@ void Execute(const sp<IDevice>& device, const TestModel& testModel, TestKind tes
|
||||
switch (testKind) {
|
||||
case TestKind::GENERAL:
|
||||
case TestKind::DYNAMIC_SHAPE:
|
||||
case TestKind::MEMORY_DOMAIN: {
|
||||
case TestKind::MEMORY_DOMAIN:
|
||||
case TestKind::FENCED_COMPUTE: {
|
||||
createPreparedModel(device, model, &preparedModel);
|
||||
if (preparedModel == nullptr) return;
|
||||
EvaluatePreparedModel(device, preparedModel, testModel, testKind);
|
||||
@@ -771,6 +819,9 @@ class DynamicOutputShapeTest : public GeneratedTest {};
|
||||
// Tag for the memory domain tests
|
||||
class MemoryDomainTest : public GeneratedTest {};
|
||||
|
||||
// Tag for the fenced compute tests
|
||||
class FencedComputeTest : public GeneratedTest {};
|
||||
|
||||
// Tag for the dynamic output shape tests
|
||||
class QuantizationCouplingTest : public GeneratedTest {};
|
||||
|
||||
@@ -786,6 +837,10 @@ TEST_P(MemoryDomainTest, Test) {
|
||||
Execute(kDevice, kTestModel, /*testKind=*/TestKind::MEMORY_DOMAIN);
|
||||
}
|
||||
|
||||
TEST_P(FencedComputeTest, Test) {
|
||||
Execute(kDevice, kTestModel, /*testKind=*/TestKind::FENCED_COMPUTE);
|
||||
}
|
||||
|
||||
TEST_P(QuantizationCouplingTest, Test) {
|
||||
Execute(kDevice, kTestModel, /*testKind=*/TestKind::QUANTIZATION_COUPLING);
|
||||
}
|
||||
@@ -793,12 +848,16 @@ TEST_P(QuantizationCouplingTest, Test) {
|
||||
INSTANTIATE_GENERATED_TEST(GeneratedTest,
|
||||
[](const TestModel& testModel) { return !testModel.expectFailure; });
|
||||
|
||||
INSTANTIATE_GENERATED_TEST(DynamicOutputShapeTest,
|
||||
[](const TestModel& testModel) { return !testModel.expectFailure; });
|
||||
INSTANTIATE_GENERATED_TEST(DynamicOutputShapeTest, [](const TestModel& testModel) {
|
||||
return !testModel.expectFailure && !testModel.hasScalarOutputs();
|
||||
});
|
||||
|
||||
INSTANTIATE_GENERATED_TEST(MemoryDomainTest,
|
||||
[](const TestModel& testModel) { return !testModel.expectFailure; });
|
||||
|
||||
INSTANTIATE_GENERATED_TEST(FencedComputeTest,
|
||||
[](const TestModel& testModel) { return !testModel.expectFailure; });
|
||||
|
||||
INSTANTIATE_GENERATED_TEST(QuantizationCouplingTest, [](const TestModel& testModel) {
|
||||
return testModel.hasQuant8CoupledOperands() && testModel.operations.size() == 1;
|
||||
});
|
||||
|
||||
@@ -65,6 +65,8 @@ enum class TestKind {
|
||||
DYNAMIC_SHAPE,
|
||||
// Same as GENERAL but use device memories for inputs and outputs
|
||||
MEMORY_DOMAIN,
|
||||
// Same as GENERAL but use executeFenced for exeuction
|
||||
FENCED_COMPUTE,
|
||||
// Tests if quantized model with TENSOR_QUANT8_ASYMM produces the same result
|
||||
// (OK/SKIPPED/FAILED) as the model with all such tensors converted to
|
||||
// TENSOR_QUANT8_ASYMM_SIGNED.
|
||||
|
||||
@@ -337,6 +337,7 @@ static bool mutateOperationOperandTypeSkip(size_t operand, OperandType type, con
|
||||
// - TRANSPOSE_CONV_2D filter type (arg 1) can be QUANT8_ASYMM or QUANT8_SYMM_PER_CHANNEL
|
||||
// - AXIS_ALIGNED_BBOX_TRANSFORM bounding boxes (arg 1) can be of
|
||||
// TENSOR_QUANT8_ASYMM or TENSOR_QUANT8_ASYMM_SIGNED.
|
||||
// - RANK's input can have any TENSOR_* type.
|
||||
switch (operation.type) {
|
||||
case OperationType::LSH_PROJECTION: {
|
||||
if (operand == operation.inputs[1]) {
|
||||
@@ -399,6 +400,20 @@ static bool mutateOperationOperandTypeSkip(size_t operand, OperandType type, con
|
||||
return true;
|
||||
}
|
||||
} break;
|
||||
case OperationType::RANK: {
|
||||
if (operand == operation.inputs[0] &&
|
||||
(type == OperandType::TENSOR_FLOAT16 || type == OperandType::TENSOR_FLOAT32 ||
|
||||
type == OperandType::TENSOR_INT32 ||
|
||||
type == OperandType::TENSOR_QUANT8_ASYMM ||
|
||||
type == OperandType::TENSOR_QUANT16_SYMM ||
|
||||
type == OperandType::TENSOR_BOOL8 ||
|
||||
type == OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL ||
|
||||
type == OperandType::TENSOR_QUANT16_ASYMM ||
|
||||
type == OperandType::TENSOR_QUANT8_SYMM ||
|
||||
type == OperandType::TENSOR_QUANT8_ASYMM_SIGNED)) {
|
||||
return true;
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -16,7 +16,9 @@
|
||||
|
||||
#define LOG_TAG "neuralnetworks_hidl_hal_test"
|
||||
|
||||
#include <android/hardware/neuralnetworks/1.3/IFencedExecutionCallback.h>
|
||||
#include <chrono>
|
||||
|
||||
#include "1.0/Utils.h"
|
||||
#include "1.3/Callbacks.h"
|
||||
#include "ExecutionBurstController.h"
|
||||
@@ -136,6 +138,22 @@ static void validate(const sp<IPreparedModel>& preparedModel, const std::string&
|
||||
burst->freeMemory(keys.front());
|
||||
}
|
||||
}
|
||||
|
||||
// dispatch
|
||||
{
|
||||
SCOPED_TRACE(message + " [executeFenced]");
|
||||
Return<void> ret = preparedModel->executeFenced(
|
||||
request, {}, MeasureTiming::NO,
|
||||
[](ErrorStatus error, const hidl_handle& handle,
|
||||
const sp<IFencedExecutionCallback>& callback) {
|
||||
if (error != ErrorStatus::DEVICE_UNAVAILABLE) {
|
||||
ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, error);
|
||||
}
|
||||
ASSERT_EQ(handle.getNativeHandle(), nullptr);
|
||||
ASSERT_EQ(callback, nullptr);
|
||||
});
|
||||
ASSERT_TRUE(ret.isOk());
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////// REMOVE INPUT ////////////////////////////////////
|
||||
|
||||
@@ -133,6 +133,23 @@ void validateRequestFailure(const sp<IPreparedModel>& preparedModel, const Reque
|
||||
// Forward declaration from ValidateBurst.cpp
|
||||
void validateBurst(const sp<IPreparedModel>& preparedModel, const V1_0::Request& request);
|
||||
|
||||
// Validate sync_fence handles for dispatch with valid input
|
||||
void validateExecuteFenced(const sp<IPreparedModel>& preparedModel, const Request& request) {
|
||||
SCOPED_TRACE("Expecting request to fail [executeFenced]");
|
||||
Return<void> ret_null =
|
||||
preparedModel->executeFenced(request, {hidl_handle(nullptr)}, V1_2::MeasureTiming::NO,
|
||||
[](ErrorStatus error, const hidl_handle& handle,
|
||||
const sp<IFencedExecutionCallback>& 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());
|
||||
}
|
||||
|
||||
void validateEverything(const sp<IDevice>& device, const Model& model, const Request& request,
|
||||
std::pair<bool, bool> supportsDeadlines) {
|
||||
const auto [prepareModelDeadlineSupported, executionDeadlineSupported] = supportsDeadlines;
|
||||
@@ -144,6 +161,7 @@ void validateEverything(const sp<IDevice>& device, const Model& model, const Req
|
||||
if (preparedModel == nullptr) return;
|
||||
|
||||
validateRequest(preparedModel, request, executionDeadlineSupported);
|
||||
validateExecuteFenced(preparedModel, request);
|
||||
|
||||
// TODO(butlermichael): Check if we need to test burst in V1_3 if the interface remains V1_2.
|
||||
ASSERT_TRUE(nn::compliantWithV1_0(request));
|
||||
|
||||
Reference in New Issue
Block a user