diff options
author | Lev Proleev <levp@google.com> | 2019-10-10 13:54:38 +0000 |
---|---|---|
committer | Lev Proleev <levp@google.com> | 2019-10-10 13:54:38 +0000 |
commit | 64f9eb4bd5cbc9bf8e3feff3618ca7681fb8b401 (patch) | |
tree | ef505a75d7b5e37851f22454dde9acaf20cddd87 /neuralnetworks/1.3 | |
parent | 543606fb92143dea42c83cb1d08c559957772178 (diff) | |
download | platform_hardware_interfaces-64f9eb4bd5cbc9bf8e3feff3618ca7681fb8b401.tar.gz platform_hardware_interfaces-64f9eb4bd5cbc9bf8e3feff3618ca7681fb8b401.tar.bz2 platform_hardware_interfaces-64f9eb4bd5cbc9bf8e3feff3618ca7681fb8b401.zip |
Revert "Modify NNAPI VTS tests to run on version 1.3"
This reverts commit 543606fb92143dea42c83cb1d08c559957772178.
Reason for revert: the topic breaks git_qt-dev-plus-aosp
Change-Id: I74859bae687d65d344ed7edc617e1a7d086960a1
Diffstat (limited to 'neuralnetworks/1.3')
13 files changed, 576 insertions, 152 deletions
diff --git a/neuralnetworks/1.3/vts/functional/Android.bp b/neuralnetworks/1.3/vts/functional/Android.bp deleted file mode 100644 index 90ce852e3e..0000000000 --- a/neuralnetworks/1.3/vts/functional/Android.bp +++ /dev/null @@ -1,58 +0,0 @@ -// -// Copyright (C) 2019 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. -// - -cc_test { - name: "VtsHalNeuralNetworksV1_3TargetTest", - defaults: ["VtsHalTargetTestDefaults"], - srcs: [ - "BasicTests.cpp", - "CompilationCachingTests.cpp", - "GeneratedTestHarness.cpp", - "TestAssertions.cpp", - "ValidateBurst.cpp", - "ValidateModel.cpp", - "ValidateRequest.cpp", - "VtsHalNeuralnetworks.cpp", - ], - shared_libs: [ - "libfmq", - "libnativewindow", - ], - static_libs: [ - "android.hardware.neuralnetworks@1.0", - "android.hardware.neuralnetworks@1.1", - "android.hardware.neuralnetworks@1.2", - "android.hardware.neuralnetworks@1.3", - "android.hidl.allocator@1.0", - "android.hidl.memory@1.0", - "libgmock", - "libhidlmemory", - "libneuralnetworks_generated_test_harness", - "libneuralnetworks_utils", - "VtsHalNeuralNetworksV1_0_utils", - "VtsHalNeuralNetworksV1_2Callbacks", - ], - whole_static_libs: [ - "neuralnetworks_generated_V1_0_example", - "neuralnetworks_generated_V1_1_example", - "neuralnetworks_generated_V1_2_example", - "neuralnetworks_generated_V1_3_example", - ], - header_libs: [ - "libneuralnetworks_headers", - ], - test_suites: ["general-tests"], -} diff --git a/neuralnetworks/1.3/vts/functional/BasicTests.cpp b/neuralnetworks/1.3/vts/functional/BasicTests.cpp index b64dc2f61b..8e82c5376e 100644 --- a/neuralnetworks/1.3/vts/functional/BasicTests.cpp +++ b/neuralnetworks/1.3/vts/functional/BasicTests.cpp @@ -18,14 +18,11 @@ #include "VtsHalNeuralnetworks.h" -namespace android::hardware::neuralnetworks::V1_3::vts::functional { +namespace android::hardware::neuralnetworks::V1_2::vts::functional { using V1_0::DeviceStatus; using V1_0::ErrorStatus; using V1_0::PerformanceInfo; -using V1_2::Constant; -using V1_2::DeviceType; -using V1_2::Extension; // create device test TEST_P(NeuralnetworksHidlTest, CreateDevice) {} @@ -40,7 +37,7 @@ TEST_P(NeuralnetworksHidlTest, StatusTest) { // initialization TEST_P(NeuralnetworksHidlTest, GetCapabilitiesTest) { using OperandPerformance = Capabilities::OperandPerformance; - Return<void> ret = kDevice->getCapabilities_1_3([](ErrorStatus status, + Return<void> ret = kDevice->getCapabilities_1_2([](ErrorStatus status, const Capabilities& capabilities) { EXPECT_EQ(ErrorStatus::NONE, status); @@ -61,4 +58,57 @@ TEST_P(NeuralnetworksHidlTest, GetCapabilitiesTest) { }); EXPECT_TRUE(ret.isOk()); } -} // namespace android::hardware::neuralnetworks::V1_3::vts::functional + +// device version test +TEST_P(NeuralnetworksHidlTest, GetDeviceVersionStringTest) { + Return<void> ret = + kDevice->getVersionString([](ErrorStatus status, const hidl_string& version) { + EXPECT_EQ(ErrorStatus::NONE, status); + EXPECT_LT(0, version.size()); + }); + EXPECT_TRUE(ret.isOk()); +} + +// device type test +TEST_P(NeuralnetworksHidlTest, GetDeviceTypeTest) { + Return<void> ret = kDevice->getType([](ErrorStatus status, DeviceType type) { + EXPECT_EQ(ErrorStatus::NONE, status); + EXPECT_TRUE(type == DeviceType::OTHER || type == DeviceType::CPU || + type == DeviceType::GPU || type == DeviceType::ACCELERATOR); + }); + EXPECT_TRUE(ret.isOk()); +} + +// device supported extensions test +TEST_P(NeuralnetworksHidlTest, GetDeviceSupportedExtensionsTest) { + Return<void> ret = kDevice->getSupportedExtensions( + [](ErrorStatus status, const hidl_vec<Extension>& extensions) { + EXPECT_EQ(ErrorStatus::NONE, status); + for (auto& extension : extensions) { + std::string extensionName = extension.name; + EXPECT_FALSE(extensionName.empty()); + for (char c : extensionName) { + EXPECT_TRUE(('a' <= c && c <= 'z') || ('0' <= c && c <= '9') || c == '_' || + c == '.') + << "Extension name contains an illegal character: " << c; + } + EXPECT_NE(extensionName.find('.'), std::string::npos) + << "Extension name must start with the reverse domain name of the " + "vendor"; + } + }); + EXPECT_TRUE(ret.isOk()); +} + +// getNumberOfCacheFilesNeeded test +TEST_P(NeuralnetworksHidlTest, getNumberOfCacheFilesNeeded) { + Return<void> ret = kDevice->getNumberOfCacheFilesNeeded( + [](ErrorStatus status, uint32_t numModelCache, uint32_t numDataCache) { + EXPECT_EQ(ErrorStatus::NONE, status); + EXPECT_LE(numModelCache, + static_cast<uint32_t>(Constant::MAX_NUMBER_OF_CACHE_FILES)); + EXPECT_LE(numDataCache, static_cast<uint32_t>(Constant::MAX_NUMBER_OF_CACHE_FILES)); + }); + EXPECT_TRUE(ret.isOk()); +} +} // namespace android::hardware::neuralnetworks::V1_2::vts::functional diff --git a/neuralnetworks/1.3/vts/functional/Callbacks.cpp b/neuralnetworks/1.3/vts/functional/Callbacks.cpp new file mode 100644 index 0000000000..3972ad6ff2 --- /dev/null +++ b/neuralnetworks/1.3/vts/functional/Callbacks.cpp @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2019 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. + */ + +#define LOG_TAG "Callbacks" + +#include "1.2/Callbacks.h" + +#include <android-base/logging.h> + +#include <limits> + +namespace android::hardware::neuralnetworks::V1_2::implementation { + +using V1_0::ErrorStatus; + +constexpr Timing kNoTiming = {.timeOnDevice = std::numeric_limits<uint64_t>::max(), + .timeInDriver = std::numeric_limits<uint64_t>::max()}; + +// PreparedModelCallback methods begin here + +Return<void> PreparedModelCallback::notify(ErrorStatus errorStatus, + const sp<V1_0::IPreparedModel>& preparedModel) { + { + std::lock_guard<std::mutex> hold(mMutex); + + // quick-return if object has already been notified + if (mNotified) { + return Void(); + } + + // store results and mark as notified + mErrorStatus = errorStatus; + mPreparedModel = preparedModel; + mNotified = true; + } + + mCondition.notify_all(); + return Void(); +} + +Return<void> PreparedModelCallback::notify_1_2(ErrorStatus errorStatus, + const sp<V1_2::IPreparedModel>& preparedModel) { + return notify(errorStatus, preparedModel); +} + +void PreparedModelCallback::wait() const { + std::unique_lock<std::mutex> lock(mMutex); + mCondition.wait(lock, [this] { return mNotified; }); +} + +ErrorStatus PreparedModelCallback::getStatus() const { + wait(); + return mErrorStatus; +} + +sp<V1_0::IPreparedModel> PreparedModelCallback::getPreparedModel() const { + wait(); + return mPreparedModel; +} + +// ExecutionCallback methods begin here + +Return<void> ExecutionCallback::notify(ErrorStatus errorStatus) { + notifyInternal(errorStatus, {}, kNoTiming); + return Void(); +} + +Return<void> ExecutionCallback::notify_1_2(ErrorStatus errorStatus, + const hidl_vec<OutputShape>& outputShapes, + const Timing& timing) { + if (errorStatus == ErrorStatus::OUTPUT_INSUFFICIENT_SIZE) { + // outputShapes must not be empty if OUTPUT_INSUFFICIENT_SIZE. + if (outputShapes.size() == 0) { + LOG(ERROR) << "Notified with empty output shape vector when OUTPUT_INSUFFICIENT_SIZE"; + notifyInternal(ErrorStatus::GENERAL_FAILURE, {}, kNoTiming); + return Void(); + } + } else if (errorStatus != ErrorStatus::NONE) { + // outputShapes must be empty if errorStatus is neither NONE nor OUTPUT_INSUFFICIENT_SIZE. + if (outputShapes.size() != 0) { + LOG(ERROR) << "Notified with non-empty output shape vector when error status is " + "neither NONE nor OUTPUT_INSUFFICIENT_SIZE"; + notifyInternal(ErrorStatus::GENERAL_FAILURE, {}, kNoTiming); + return Void(); + } + } + notifyInternal(errorStatus, outputShapes, timing); + return Void(); +} + +void ExecutionCallback::wait() const { + std::unique_lock<std::mutex> lock(mMutex); + mCondition.wait(lock, [this] { return mNotified; }); +} + +ErrorStatus ExecutionCallback::getStatus() const { + wait(); + return mErrorStatus; +} + +const std::vector<OutputShape>& ExecutionCallback::getOutputShapes() const { + wait(); + return mOutputShapes; +} + +Timing ExecutionCallback::getTiming() const { + wait(); + return mTiming; +} + +void ExecutionCallback::notifyInternal(ErrorStatus errorStatus, + const hidl_vec<OutputShape>& outputShapes, + const Timing& timing) { + { + std::lock_guard<std::mutex> hold(mMutex); + + // quick-return if object has already been notified + if (mNotified) { + return; + } + + mErrorStatus = errorStatus; + mOutputShapes = outputShapes; + mTiming = timing; + mNotified = true; + } + mCondition.notify_all(); +} + +} // namespace android::hardware::neuralnetworks::V1_2::implementation diff --git a/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp b/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp index 0ac4738fff..2130a76b75 100644 --- a/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp +++ b/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp @@ -45,15 +45,12 @@ namespace generated_tests::mobilenet_quantized { const test_helper::TestModel& get_test_model(); } // namespace generated_tests::mobilenet_quantized -namespace android::hardware::neuralnetworks::V1_3::vts::functional { +namespace android::hardware::neuralnetworks::V1_2::vts::functional { using namespace test_helper; +using implementation::PreparedModelCallback; using V1_0::ErrorStatus; using V1_1::ExecutionPreference; -using V1_2::Constant; -using V1_2::IPreparedModel; -using V1_2::OperationType; -using V1_2::implementation::PreparedModelCallback; namespace float32_model { @@ -305,7 +302,7 @@ class CompilationCachingTestBase : public testing::Test { // See if the service can handle the model. bool isModelFullySupported(const Model& model) { bool fullySupportsModel = false; - Return<void> supportedCall = kDevice->getSupportedOperations_1_3( + Return<void> supportedCall = kDevice->getSupportedOperations_1_2( model, [&fullySupportsModel, &model](ErrorStatus status, const hidl_vec<bool>& supported) { ASSERT_EQ(ErrorStatus::NONE, status); @@ -326,7 +323,7 @@ class CompilationCachingTestBase : public testing::Test { sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback(); hidl_array<uint8_t, sizeof(mToken)> cacheToken(mToken); Return<ErrorStatus> prepareLaunchStatus = - kDevice->prepareModel_1_3(model, ExecutionPreference::FAST_SINGLE_ANSWER, + kDevice->prepareModel_1_2(model, ExecutionPreference::FAST_SINGLE_ANSWER, modelCache, dataCache, cacheToken, preparedModelCallback); ASSERT_TRUE(prepareLaunchStatus.isOk()); ASSERT_EQ(static_cast<ErrorStatus>(prepareLaunchStatus), ErrorStatus::NONE); @@ -1374,4 +1371,4 @@ INSTANTIATE_TEST_CASE_P(TestCompilationCaching, CompilationCachingSecurityTest, testing::Range(0U, 10U)), printCompilationCachingSecurityTest); -} // namespace android::hardware::neuralnetworks::V1_3::vts::functional +} // namespace android::hardware::neuralnetworks::V1_2::vts::functional diff --git a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp index 16a7d70fb5..2beec983e0 100644 --- a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp +++ b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp @@ -27,9 +27,6 @@ #include <android/hardware/neuralnetworks/1.2/IExecutionCallback.h> #include <android/hardware/neuralnetworks/1.2/IPreparedModel.h> #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/types.h> #include <android/hidl/allocator/1.0/IAllocator.h> #include <android/hidl/memory/1.0/IMemory.h> #include <hidlmemory/mapping.h> @@ -47,24 +44,17 @@ #include "Utils.h" #include "VtsHalNeuralnetworks.h" -namespace android::hardware::neuralnetworks::V1_3::vts::functional { +namespace android::hardware::neuralnetworks::V1_2::vts::functional { using namespace test_helper; using hidl::memory::V1_0::IMemory; +using implementation::ExecutionCallback; +using implementation::PreparedModelCallback; using V1_0::DataLocation; using V1_0::ErrorStatus; using V1_0::OperandLifeTime; using V1_0::Request; using V1_1::ExecutionPreference; -using V1_2::Constant; -using V1_2::IPreparedModel; -using V1_2::MeasureTiming; -using V1_2::OperationType; -using V1_2::OutputShape; -using V1_2::SymmPerChannelQuantParams; -using V1_2::Timing; -using V1_2::implementation::ExecutionCallback; -using V1_2::implementation::PreparedModelCallback; using HidlToken = hidl_array<uint8_t, static_cast<uint32_t>(Constant::BYTE_SIZE_OF_CACHE_TOKEN)>; enum class OutputType { FULLY_SPECIFIED, UNSPECIFIED, INSUFFICIENT }; @@ -415,4 +405,4 @@ INSTANTIATE_GENERATED_TEST(GeneratedTest, INSTANTIATE_GENERATED_TEST(DynamicOutputShapeTest, [](const TestModel& testModel) { return !testModel.expectFailure; }); -} // namespace android::hardware::neuralnetworks::V1_3::vts::functional +} // namespace android::hardware::neuralnetworks::V1_2::vts::functional diff --git a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h index b9277cfd4a..dfc980c169 100644 --- a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h +++ b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h @@ -14,19 +14,19 @@ * limitations under the License. */ -#ifndef ANDROID_HARDWARE_NEURALNETWORKS_V1_3_GENERATED_TEST_HARNESS_H -#define ANDROID_HARDWARE_NEURALNETWORKS_V1_3_GENERATED_TEST_HARNESS_H +#ifndef ANDROID_HARDWARE_NEURALNETWORKS_V1_2_GENERATED_TEST_HARNESS_H +#define ANDROID_HARDWARE_NEURALNETWORKS_V1_2_GENERATED_TEST_HARNESS_H +#include <android/hardware/neuralnetworks/1.2/IDevice.h> #include <android/hardware/neuralnetworks/1.2/IPreparedModel.h> -#include <android/hardware/neuralnetworks/1.3/IDevice.h> -#include <android/hardware/neuralnetworks/1.3/types.h> +#include <android/hardware/neuralnetworks/1.2/types.h> #include <functional> #include <vector> #include "1.0/Utils.h" #include "TestHarness.h" #include "VtsHalNeuralnetworks.h" -namespace android::hardware::neuralnetworks::V1_3::vts::functional { +namespace android::hardware::neuralnetworks::V1_2::vts::functional { using NamedModel = Named<const test_helper::TestModel*>; using GeneratedTestParam = std::tuple<NamedDevice, NamedModel>; @@ -55,12 +55,11 @@ class ValidationTest : public GeneratedTestBase {}; Model createModel(const test_helper::TestModel& testModel); -void PrepareModel(const sp<IDevice>& device, const Model& model, - sp<V1_2::IPreparedModel>* preparedModel); +void PrepareModel(const sp<IDevice>& device, const Model& model, sp<IPreparedModel>* preparedModel); -void EvaluatePreparedModel(const sp<V1_2::IPreparedModel>& preparedModel, +void EvaluatePreparedModel(const sp<IPreparedModel>& preparedModel, const test_helper::TestModel& testModel, bool testDynamicOutputShape); -} // namespace android::hardware::neuralnetworks::V1_3::vts::functional +} // namespace android::hardware::neuralnetworks::V1_2::vts::functional -#endif // ANDROID_HARDWARE_NEURALNETWORKS_V1_3_GENERATED_TEST_HARNESS_H +#endif // ANDROID_HARDWARE_NEURALNETWORKS_V1_2_GENERATED_TEST_HARNESS_H diff --git a/neuralnetworks/1.3/vts/functional/TestAssertions.cpp b/neuralnetworks/1.3/vts/functional/TestAssertions.cpp index 7361078eca..a0aa3c37d1 100644 --- a/neuralnetworks/1.3/vts/functional/TestAssertions.cpp +++ b/neuralnetworks/1.3/vts/functional/TestAssertions.cpp @@ -14,10 +14,10 @@ * limitations under the License. */ -#include <android/hardware/neuralnetworks/1.3/types.h> +#include <android/hardware/neuralnetworks/1.2/types.h> #include "TestHarness.h" -namespace android::hardware::neuralnetworks::V1_3 { +namespace android::hardware::neuralnetworks::V1_2 { // Make sure that the HIDL enums are compatible with the values defined in // frameworks/ml/nn/tools/test_generator/test_harness/include/TestHarness.h. @@ -25,8 +25,6 @@ using namespace test_helper; #define CHECK_TEST_ENUM(EnumType, enumValue) \ static_assert(static_cast<EnumType>(Test##EnumType::enumValue) == EnumType::enumValue) -using V1_2::OperationType; - CHECK_TEST_ENUM(OperandType, FLOAT32); CHECK_TEST_ENUM(OperandType, INT32); CHECK_TEST_ENUM(OperandType, UINT32); @@ -41,7 +39,6 @@ CHECK_TEST_ENUM(OperandType, FLOAT16); CHECK_TEST_ENUM(OperandType, TENSOR_QUANT8_SYMM_PER_CHANNEL); CHECK_TEST_ENUM(OperandType, TENSOR_QUANT16_ASYMM); CHECK_TEST_ENUM(OperandType, TENSOR_QUANT8_SYMM); -CHECK_TEST_ENUM(OperandType, TENSOR_QUANT8_ASYMM_SIGNED); CHECK_TEST_ENUM(OperationType, ADD); CHECK_TEST_ENUM(OperationType, AVERAGE_POOL_2D); @@ -141,4 +138,4 @@ CHECK_TEST_ENUM(OperationType, RESIZE_NEAREST_NEIGHBOR); #undef CHECK_TEST_ENUM -} // namespace android::hardware::neuralnetworks::V1_3 +} // namespace android::hardware::neuralnetworks::V1_2 diff --git a/neuralnetworks/1.3/vts/functional/ValidateBurst.cpp b/neuralnetworks/1.3/vts/functional/ValidateBurst.cpp index 95f9f427b2..1d4493d208 100644 --- a/neuralnetworks/1.3/vts/functional/ValidateBurst.cpp +++ b/neuralnetworks/1.3/vts/functional/ValidateBurst.cpp @@ -28,20 +28,13 @@ #include <android-base/logging.h> #include <cstring> -namespace android::hardware::neuralnetworks::V1_3::vts::functional { +namespace android::hardware::neuralnetworks::V1_2::vts::functional { using nn::ExecutionBurstController; using nn::RequestChannelSender; using nn::ResultChannelReceiver; using V1_0::ErrorStatus; using V1_0::Request; -using V1_2::FmqRequestDatum; -using V1_2::FmqResultDatum; -using V1_2::IBurstCallback; -using V1_2::IBurstContext; -using V1_2::IPreparedModel; -using V1_2::MeasureTiming; -using V1_2::Timing; using ExecutionBurstCallback = ExecutionBurstController::ExecutionBurstCallback; // This constant value represents the length of an FMQ that is large enough to @@ -404,4 +397,4 @@ void validateBurst(const sp<IPreparedModel>& preparedModel, const Request& reque ASSERT_NO_FATAL_FAILURE(validateBurstSanitized(preparedModel, request)); } -} // namespace android::hardware::neuralnetworks::V1_3::vts::functional +} // namespace android::hardware::neuralnetworks::V1_2::vts::functional diff --git a/neuralnetworks/1.3/vts/functional/ValidateModel.cpp b/neuralnetworks/1.3/vts/functional/ValidateModel.cpp index 44b32a9fec..30530beacc 100644 --- a/neuralnetworks/1.3/vts/functional/ValidateModel.cpp +++ b/neuralnetworks/1.3/vts/functional/ValidateModel.cpp @@ -21,26 +21,21 @@ #include "GeneratedTestHarness.h" #include "VtsHalNeuralnetworks.h" -namespace android::hardware::neuralnetworks::V1_3::vts::functional { +namespace android::hardware::neuralnetworks::V1_2::vts::functional { +using implementation::PreparedModelCallback; using V1_0::ErrorStatus; using V1_0::OperandLifeTime; using V1_1::ExecutionPreference; -using V1_2::IPreparedModel; -using V1_2::OperationType; -using V1_2::OperationTypeRange; -using V1_2::SymmPerChannelQuantParams; -using V1_2::implementation::PreparedModelCallback; -using HidlToken = - hidl_array<uint8_t, static_cast<uint32_t>(V1_2::Constant::BYTE_SIZE_OF_CACHE_TOKEN)>; +using HidlToken = hidl_array<uint8_t, static_cast<uint32_t>(Constant::BYTE_SIZE_OF_CACHE_TOKEN)>; ///////////////////////// UTILITY FUNCTIONS ///////////////////////// static void validateGetSupportedOperations(const sp<IDevice>& device, const std::string& message, const Model& model) { - SCOPED_TRACE(message + " [getSupportedOperations_1_3]"); + SCOPED_TRACE(message + " [getSupportedOperations_1_2]"); - Return<void> ret = device->getSupportedOperations_1_3( + Return<void> ret = device->getSupportedOperations_1_2( model, [&](ErrorStatus status, const hidl_vec<bool>&) { EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, status); }); @@ -49,11 +44,11 @@ static void validateGetSupportedOperations(const sp<IDevice>& device, const std: static void validatePrepareModel(const sp<IDevice>& device, const std::string& message, const Model& model, ExecutionPreference preference) { - SCOPED_TRACE(message + " [prepareModel_1_3]"); + SCOPED_TRACE(message + " [prepareModel_1_2]"); sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback(); Return<ErrorStatus> prepareLaunchStatus = - device->prepareModel_1_3(model, preference, hidl_vec<hidl_handle>(), + device->prepareModel_1_2(model, preference, hidl_vec<hidl_handle>(), hidl_vec<hidl_handle>(), HidlToken(), preparedModelCallback); ASSERT_TRUE(prepareLaunchStatus.isOk()); ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, static_cast<ErrorStatus>(prepareLaunchStatus)); @@ -715,4 +710,4 @@ void validateModel(const sp<IDevice>& device, const Model& model) { mutateExecutionPreferenceTest(device, model); } -} // namespace android::hardware::neuralnetworks::V1_3::vts::functional +} // namespace android::hardware::neuralnetworks::V1_2::vts::functional diff --git a/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp index 612212382c..f25ee62617 100644 --- a/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp +++ b/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp @@ -24,15 +24,11 @@ #include "Utils.h" #include "VtsHalNeuralnetworks.h" -namespace android::hardware::neuralnetworks::V1_3::vts::functional { +namespace android::hardware::neuralnetworks::V1_2::vts::functional { +using implementation::ExecutionCallback; using V1_0::ErrorStatus; using V1_0::Request; -using V1_2::IPreparedModel; -using V1_2::MeasureTiming; -using V1_2::OutputShape; -using V1_2::Timing; -using V1_2::implementation::ExecutionCallback; ///////////////////////// UTILITY FUNCTIONS ///////////////////////// @@ -169,4 +165,4 @@ void validateRequestFailure(const sp<IPreparedModel>& preparedModel, const Reque ASSERT_TRUE(executeStatus.isOk()); } -} // namespace android::hardware::neuralnetworks::V1_3::vts::functional +} // namespace android::hardware::neuralnetworks::V1_2::vts::functional diff --git a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp index 4f0e150b32..4fbd0e270f 100644 --- a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp +++ b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp @@ -26,15 +26,13 @@ #include "GeneratedTestHarness.h" #include "TestHarness.h" -namespace android::hardware::neuralnetworks::V1_3::vts::functional { +namespace android::hardware::neuralnetworks::V1_2::vts::functional { -using HidlToken = - hidl_array<uint8_t, static_cast<uint32_t>(V1_2::Constant::BYTE_SIZE_OF_CACHE_TOKEN)>; +using implementation::PreparedModelCallback; +using HidlToken = hidl_array<uint8_t, static_cast<uint32_t>(Constant::BYTE_SIZE_OF_CACHE_TOKEN)>; using V1_0::ErrorStatus; using V1_0::Request; using V1_1::ExecutionPreference; -using V1_2::IPreparedModel; -using V1_2::implementation::PreparedModelCallback; // internal helper function void createPreparedModel(const sp<IDevice>& device, const Model& model, @@ -44,7 +42,7 @@ void createPreparedModel(const sp<IDevice>& device, const Model& model, // see if service can handle model bool fullySupportsModel = false; - const Return<void> supportedCall = device->getSupportedOperations_1_3( + const Return<void> supportedCall = device->getSupportedOperations_1_2( model, [&fullySupportsModel](ErrorStatus status, const hidl_vec<bool>& supported) { ASSERT_EQ(ErrorStatus::NONE, status); ASSERT_NE(0ul, supported.size()); @@ -55,7 +53,7 @@ void createPreparedModel(const sp<IDevice>& device, const Model& model, // launch prepare model const sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback(); - const Return<ErrorStatus> prepareLaunchStatus = device->prepareModel_1_3( + const Return<ErrorStatus> prepareLaunchStatus = device->prepareModel_1_2( model, ExecutionPreference::FAST_SINGLE_ANSWER, hidl_vec<hidl_handle>(), hidl_vec<hidl_handle>(), HidlToken(), preparedModelCallback); ASSERT_TRUE(prepareLaunchStatus.isOk()); @@ -66,8 +64,8 @@ void createPreparedModel(const sp<IDevice>& device, const Model& model, const ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus(); *preparedModel = getPreparedModel_1_2(preparedModelCallback); - // The getSupportedOperations_1_3 call returns a list of operations that are - // guaranteed not to fail if prepareModel_1_3 is called, and + // The getSupportedOperations_1_2 call returns a list of operations that are + // guaranteed not to fail if prepareModel_1_2 is called, and // 'fullySupportsModel' is true i.f.f. the entire model is guaranteed. // If a driver has any doubt that it can prepare an operation, it must // return false. So here, if a driver isn't sure if it can support an @@ -165,9 +163,9 @@ TEST_P(ValidationTest, Test) { INSTANTIATE_GENERATED_TEST(ValidationTest, [](const test_helper::TestModel&) { return true; }); -sp<IPreparedModel> getPreparedModel_1_2(const sp<PreparedModelCallback>& callback) { +sp<IPreparedModel> getPreparedModel_1_2(const sp<implementation::PreparedModelCallback>& callback) { sp<V1_0::IPreparedModel> preparedModelV1_0 = callback->getPreparedModel(); return IPreparedModel::castFrom(preparedModelV1_0).withDefault(nullptr); } -} // namespace android::hardware::neuralnetworks::V1_3::vts::functional +} // namespace android::hardware::neuralnetworks::V1_2::vts::functional diff --git a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.h b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.h index fc654ce8f0..d01336eccd 100644 --- a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.h +++ b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.h @@ -14,17 +14,17 @@ * limitations under the License. */ -#ifndef ANDROID_HARDWARE_NEURALNETWORKS_V1_3_VTS_HAL_NEURALNETWORKS_H -#define ANDROID_HARDWARE_NEURALNETWORKS_V1_3_VTS_HAL_NEURALNETWORKS_H +#ifndef ANDROID_HARDWARE_NEURALNETWORKS_V1_2_VTS_HAL_NEURALNETWORKS_H +#define ANDROID_HARDWARE_NEURALNETWORKS_V1_2_VTS_HAL_NEURALNETWORKS_H +#include <android/hardware/neuralnetworks/1.2/IDevice.h> #include <android/hardware/neuralnetworks/1.2/IPreparedModel.h> -#include <android/hardware/neuralnetworks/1.3/IDevice.h> -#include <android/hardware/neuralnetworks/1.3/types.h> +#include <android/hardware/neuralnetworks/1.2/types.h> #include <gtest/gtest.h> #include "1.0/Utils.h" #include "1.2/Callbacks.h" -namespace android::hardware::neuralnetworks::V1_3::vts::functional { +namespace android::hardware::neuralnetworks::V1_2::vts::functional { using NamedDevice = Named<sp<IDevice>>; using NeuralnetworksHidlTestParam = NamedDevice; @@ -47,12 +47,11 @@ std::string printNeuralnetworksHidlTest( // Create an IPreparedModel object. If the model cannot be prepared, // "preparedModel" will be nullptr instead. void createPreparedModel(const sp<IDevice>& device, const Model& model, - sp<V1_2::IPreparedModel>* preparedModel); + sp<IPreparedModel>* preparedModel); // Utility function to get PreparedModel from callback and downcast to V1_2. -sp<V1_2::IPreparedModel> getPreparedModel_1_2( - const sp<V1_2::implementation::PreparedModelCallback>& callback); +sp<IPreparedModel> getPreparedModel_1_2(const sp<implementation::PreparedModelCallback>& callback); -} // namespace android::hardware::neuralnetworks::V1_3::vts::functional +} // namespace android::hardware::neuralnetworks::V1_2::vts::functional -#endif // ANDROID_HARDWARE_NEURALNETWORKS_V1_3_VTS_HAL_NEURALNETWORKS_H +#endif // ANDROID_HARDWARE_NEURALNETWORKS_V1_2_VTS_HAL_NEURALNETWORKS_H diff --git a/neuralnetworks/1.3/vts/functional/include/1.2/Callbacks.h b/neuralnetworks/1.3/vts/functional/include/1.2/Callbacks.h new file mode 100644 index 0000000000..bf4792cc6b --- /dev/null +++ b/neuralnetworks/1.3/vts/functional/include/1.2/Callbacks.h @@ -0,0 +1,325 @@ +/* + * Copyright (C) 2018 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. + */ + +#ifndef ANDROID_HARDWARE_NEURALNETWORKS_V1_2_CALLBACKS_H +#define ANDROID_HARDWARE_NEURALNETWORKS_V1_2_CALLBACKS_H + +#include <android-base/thread_annotations.h> +#include <android/hardware/neuralnetworks/1.0/IExecutionCallback.h> +#include <android/hardware/neuralnetworks/1.0/IPreparedModelCallback.h> +#include <android/hardware/neuralnetworks/1.2/IExecutionCallback.h> +#include <android/hardware/neuralnetworks/1.2/IPreparedModelCallback.h> +#include <hidl/Status.h> +#include <condition_variable> +#include <mutex> + +/* + * The Callback classes are used internally by the NeuralNetworks runtime to + * synchronize between different threads. An asynchronous task is launched + * paired with a callback object. When a client thread requires the output being + * generated by the asynchronous task, the client thread can wait for the result + * and be blocked until it has completed. Any wait may safely be called + * concurrently, even on the same callback object. When the asynchronous task + * has finished its workload, it must immediately call "notify*". If the + * asynchronous task has failed to launch, the function that tried to launch the + * asynchronous task must immediately call "notify*". This "notify*" call + * awakens any client threads waiting on the callback object. + * + * These classes exist to enable synchronization across HIDL. When + * synchronization is only required in the same process, consider using + * std::future, std::mutex, std::condition_variable, or std::experimental::latch + * instead. + */ + +namespace android::hardware::neuralnetworks::V1_2::implementation { + +/** + * The PreparedModelCallback class is used to receive the error status of + * preparing a model as well as the prepared model from a task executing + * asynchronously with respect to the runtime. If a calling thread calls wait + * or get* on a PreparedModelCallback object and the corresponding asynchronous + * task has not finished preparing the model, the calling thread will block + * until the asynchronous task has either called notify or notify_1_2. + * + * If the callback object is notified more than once, only the results of the + * first call to notify* are used, and the results from subsequent calls are + * discarded. + * + * This callback object is passed as an argument to IDevice::prepareModel*. + */ +class PreparedModelCallback : public IPreparedModelCallback { + public: + /** + * IPreparedModelCallback::notify marks the callback object with the return + * status of the asynchronous model preparation along with the prepared + * model, and allows all prior and future wait calls on the + * PreparedModelCallback object to proceed. + * + * Either IPreparedModelCallback::notify or + * IPreparedModelCallback::notify_1_2 must be called on a given + * PreparedModelCallback object. + * + * If the callback object is notified more than once, only the results of + * the first call to notify* are used, and the results from subsequent calls + * are discarded. + * + * @param status Error status returned from asynchronously preparing the + * model; will be: + * - NONE if the asynchronous preparation was successful + * - DEVICE_UNAVAILABLE if driver is offline or busy + * - GENERAL_FAILURE if there is an unspecified error + * - INVALID_ARGUMENT if the input model is invalid + * @param preparedModel Returned model that has been prepared for execution, + * nullptr if the model was unable to be prepared. + */ + Return<void> notify(V1_0::ErrorStatus status, + const sp<V1_0::IPreparedModel>& preparedModel) override; + + /** + * IPreparedModelCallback::notify_1_2 marks the callback object with the + * return status of the asynchronous model preparation along with the + * prepared model, and allows all prior and future wait calls on the + * PreparedModelCallback object to proceed. + * + * Either IPreparedModelCallback::notify or + * IPreparedModelCallback::notify_1_2 must be called on a given + * PreparedModelCallback object. + * + * If the callback object is notified more than once, only the results of + * the first call to notify* are used, and the results from subsequent calls + * are discarded. + * + * @param status Error status returned from asynchronously preparing the + * model; will be: + * - NONE if the asynchronous preparation was successful + * - DEVICE_UNAVAILABLE if driver is offline or busy + * - GENERAL_FAILURE if there is an unspecified error + * - INVALID_ARGUMENT if the input model is invalid + * @param preparedModel Returned model that has been prepared for execution, + * nullptr if the model was unable to be prepared. + */ + Return<void> notify_1_2(V1_0::ErrorStatus status, + const sp<V1_2::IPreparedModel>& preparedModel) override; + + /** + * PreparedModelCallback::wait blocks until notify* has been called on the + * callback object. + */ + void wait() const; + + /** + * Retrieves the error status returned from the asynchronous task launched + * by IDevice::prepareModel*. If IDevice::prepareModel* has not finished + * asynchronously preparing the model, this call will block until the + * asynchronous task notifies the object. + * + * @return status Error status returned from asynchronously preparing the + * model; will be: + * - NONE if the asynchronous preparation was successful + * - DEVICE_UNAVAILABLE if driver is offline or busy + * - GENERAL_FAILURE if there is an unspecified error + * - INVALID_ARGUMENT if the input model is invalid + */ + V1_0::ErrorStatus getStatus() const; + + /** + * Retrieves the model that has been prepared for execution from the + * asynchronous task launched by IDevice::prepareModel*. If + * IDevice::prepareModel* has not finished asynchronously preparing the + * model, this call will block until the asynchronous task notifies the + * object. + * + * @return preparedModel Returned model that has been prepared for + * execution, nullptr if the model was unable to be prepared. + */ + sp<V1_0::IPreparedModel> getPreparedModel() const; + + private: + mutable std::mutex mMutex; + mutable std::condition_variable mCondition; + bool mNotified GUARDED_BY(mMutex) = false; + V1_0::ErrorStatus mErrorStatus = V1_0::ErrorStatus::GENERAL_FAILURE; + sp<V1_0::IPreparedModel> mPreparedModel; +}; + +/** + * The ExecutionCallback class is used to receive the results of the execution + * from a task executing asynchronously with respect to the runtime. If a + * calling thread calls wait or get* on a ExecutionCallback object and the + * corresponding asynchronous task has not finished the execution, the calling + * thread will block until the asynchronous task has either called notify or + * notify_1_2. + * + * If the callback object is notified more than once, only the results of the + * first call to notify* are used, and the results from subsequent calls are + * discarded. + * + * This callback object is passed as an argument to IPreparedModel::execute*. + */ +class ExecutionCallback : public IExecutionCallback { + public: + /** + * IExecutionCallback::notify marks the callback object with the return + * status of the asynchronous execution that held this callback and enables + * all prior and future wait calls on the ExecutionCallback object to + * proceed. + * + * Either IExecutionCallback::notify or IExecutionCallback::notify_1_2 must + * be called on a given ExecutionCallback object. + * + * If the callback object is notified more than once, only the results of + * the first call to notify* are used, and the results from subsequent calls + * are discarded. + * + * @param status 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 there is an unspecified error + * - OUTPUT_INSUFFICIENT_SIZE if provided output buffer is not large + * enough to store the resultant values + * - INVALID_ARGUMENT if the input request is invalid + */ + Return<void> notify(V1_0::ErrorStatus status) override; + + /** + * IExecutionCallback::notify_1_2 marks the callback object with the results + * (error status, dynamic output shapes, and timing information) of the + * asynchronous execution that held this callback and enables all prior and + * future wait calls on the ExecutionCallback object to proceed. + * + * Either IExecutionCallback::notify or IExecutionCallback::notify_1_2 must + * be called on a given ExecutionCallback object. + * + * If the callback object is notified more than once, only the results of + * the first call to notify* are used, and the results from subsequent calls + * are discarded. + * + * @param status 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 at least one output operand buffer is + * not large enough to store the corresponding output + * - INVALID_ARGUMENT if one of the input arguments to prepareModel is + * invalid + * @param outputShapes A list of shape information of model output operands. + * The index into "outputShapes" corresponds to the index of the output + * operand in the Request outputs vector. outputShapes must be empty + * unless the status is either NONE or OUTPUT_INSUFFICIENT_SIZE. + * @param 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. + */ + Return<void> notify_1_2(V1_0::ErrorStatus status, const hidl_vec<OutputShape>& outputShapes, + const Timing& timing) override; + + // An overload of the latest notify interface to hide the version from ExecutionBuilder. + Return<void> notify(V1_0::ErrorStatus status, const hidl_vec<OutputShape>& outputShapes, + const Timing& timing) { + return notify_1_2(status, outputShapes, timing); + } + + /** + * ExecutionCallback::wait blocks until notify* has been called on the + * callback object. + */ + void wait() const; + + /** + * Retrieves the error status returned from the asynchronous task launched + * by either IPreparedModel::execute or IPreparedModel::execute_1_2. If + * IPreparedModel::execute or IPreparedModel::execute_1_2 has not finished + * asynchronously executing, this call will block until the asynchronous + * task notifies the object. + * + * @return status 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 at least one output operand buffer is + * not large enough to store the corresponding output + * - INVALID_ARGUMENT if one of the input arguments to prepareModel is + * invalid + */ + V1_0::ErrorStatus getStatus() const; + + /** + * Retrieves the output shapes returned from the asynchronous task launched + * by IPreparedModel::execute_1_2. If IPreparedModel::execute_1_2 has not + * finished asynchronously executing, this call will block until the + * asynchronous task notifies the object. + * + * If the asynchronous task was launched by IPreparedModel::execute, an + * empty vector will be returned. + * + * @return outputShapes A list of shape information of model output + * operands. The index into "outputShapes" corresponds to the index of + * the output operand in the Request outputs vector. outputShapes must + * be empty unless the status is either NONE or + * OUTPUT_INSUFFICIENT_SIZE. outputShaps may be empty if the status is + * NONE and all model output operands are fully-specified at execution + * time. outputShapes must have the same number of elements as the + * number of model output operands if the status is + * OUTPUT_INSUFFICIENT_SIZE, or if the status is NONE and the model has + * at least one output operand that is not fully-specified. + */ + const std::vector<OutputShape>& getOutputShapes() const; + + /** + * Retrieves the duration of execution of the asynchronous task launched by + * IPreparedModel::execute_1_2. If IPreparedModel::execute_1_2 has not + * finished asynchronously executing, this call will block until the + * asynchronous task notifies the object. + * + * If the asynchronous task was launched by IPreparedModel::execute, every + * time must be UINT64_MAX. + * + * @return timing Duration of the execution. Every time must be UINT64_MAX + * unless the status is NONE. + */ + Timing getTiming() const; + + private: + /* + * ExecutionCallback::notifyInternal stores the results of the execution + * (status, output shapes, and timing information) in the ExecutionCallback + * object before any call to wait or get* return. It then enables all prior + * and future wait calls on the ExecutionCallback object to proceed. + */ + void notifyInternal(V1_0::ErrorStatus errorStatus, const hidl_vec<OutputShape>& outputShapes, + const Timing& timing); + + // members + mutable std::mutex mMutex; + mutable std::condition_variable mCondition; + bool mNotified GUARDED_BY(mMutex) = false; + V1_0::ErrorStatus mErrorStatus = V1_0::ErrorStatus::GENERAL_FAILURE; + std::vector<OutputShape> mOutputShapes = {}; + Timing mTiming = {}; +}; + +} // namespace android::hardware::neuralnetworks::V1_2::implementation + +#endif // ANDROID_HARDWARE_NEURALNETWORKS_V1_2_CALLBACKS_H |