diff --git a/neuralnetworks/1.0/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.0/vts/functional/ValidateRequest.cpp index 72a500783f..f0c93b7b54 100644 --- a/neuralnetworks/1.0/vts/functional/ValidateRequest.cpp +++ b/neuralnetworks/1.0/vts/functional/ValidateRequest.cpp @@ -34,7 +34,6 @@ namespace vts { namespace functional { using ::android::hardware::neuralnetworks::V1_2::implementation::ExecutionCallback; -using ::android::hardware::neuralnetworks::V1_2::implementation::PreparedModelCallback; using ::android::hidl::memory::V1_0::IMemory; using test_helper::for_all; using test_helper::MixedTyped; @@ -42,53 +41,6 @@ using test_helper::MixedTypedExample; ///////////////////////// UTILITY FUNCTIONS ///////////////////////// -static void createPreparedModel(const sp& device, const V1_0::Model& model, - sp* preparedModel) { - ASSERT_NE(nullptr, preparedModel); - - // see if service can handle model - bool fullySupportsModel = false; - Return supportedOpsLaunchStatus = device->getSupportedOperations( - model, [&fullySupportsModel](ErrorStatus status, const hidl_vec& supported) { - ASSERT_EQ(ErrorStatus::NONE, status); - ASSERT_NE(0ul, supported.size()); - fullySupportsModel = - std::all_of(supported.begin(), supported.end(), [](bool valid) { return valid; }); - }); - ASSERT_TRUE(supportedOpsLaunchStatus.isOk()); - - // launch prepare model - sp preparedModelCallback = new PreparedModelCallback(); - ASSERT_NE(nullptr, preparedModelCallback.get()); - Return prepareLaunchStatus = device->prepareModel(model, preparedModelCallback); - ASSERT_TRUE(prepareLaunchStatus.isOk()); - ASSERT_EQ(ErrorStatus::NONE, static_cast(prepareLaunchStatus)); - - // retrieve prepared model - preparedModelCallback->wait(); - ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus(); - *preparedModel = preparedModelCallback->getPreparedModel(); - - // The getSupportedOperations call returns a list of operations that are - // guaranteed not to fail if prepareModel 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 - // operation, but reports that it successfully prepared the model, the test - // can continue. - if (!fullySupportsModel && prepareReturnStatus != ErrorStatus::NONE) { - ASSERT_EQ(nullptr, preparedModel->get()); - LOG(INFO) << "NN VTS: Unable to test Request validation because vendor service cannot " - "prepare model that it does not support."; - std::cout << "[ ] Unable to test Request validation because vendor service " - "cannot prepare model that it does not support." - << std::endl; - return; - } - ASSERT_EQ(ErrorStatus::NONE, prepareReturnStatus); - ASSERT_NE(nullptr, preparedModel->get()); -} - // Primary validation function. This function will take a valid request, apply a // mutation to it to invalidate the request, then pass it to interface calls // that use the request. Note that the request here is passed by value, and any @@ -237,15 +189,8 @@ std::vector createRequests(const std::vector& exampl return requests; } -void ValidationTest::validateRequests(const V1_0::Model& model, +void ValidationTest::validateRequests(const sp& preparedModel, const std::vector& requests) { - // create IPreparedModel - sp preparedModel; - ASSERT_NO_FATAL_FAILURE(createPreparedModel(device, model, &preparedModel)); - if (preparedModel == nullptr) { - return; - } - // validate each request for (const Request& request : requests) { removeInputTest(preparedModel, request); diff --git a/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.cpp index 31638c425f..aee2f8549b 100644 --- a/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.cpp +++ b/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.cpp @@ -18,6 +18,10 @@ #include "VtsHalNeuralnetworks.h" +#include + +#include "Callbacks.h" + namespace android { namespace hardware { namespace neuralnetworks { @@ -25,6 +29,55 @@ namespace V1_0 { namespace vts { namespace functional { +using ::android::hardware::neuralnetworks::V1_2::implementation::PreparedModelCallback; + +static void createPreparedModel(const sp& device, const V1_0::Model& model, + sp* preparedModel) { + ASSERT_NE(nullptr, preparedModel); + + // see if service can handle model + bool fullySupportsModel = false; + Return supportedOpsLaunchStatus = device->getSupportedOperations( + model, [&fullySupportsModel](ErrorStatus status, const hidl_vec& supported) { + ASSERT_EQ(ErrorStatus::NONE, status); + ASSERT_NE(0ul, supported.size()); + fullySupportsModel = std::all_of(supported.begin(), supported.end(), + [](bool valid) { return valid; }); + }); + ASSERT_TRUE(supportedOpsLaunchStatus.isOk()); + + // launch prepare model + sp preparedModelCallback = new PreparedModelCallback(); + ASSERT_NE(nullptr, preparedModelCallback.get()); + Return prepareLaunchStatus = device->prepareModel(model, preparedModelCallback); + ASSERT_TRUE(prepareLaunchStatus.isOk()); + ASSERT_EQ(ErrorStatus::NONE, static_cast(prepareLaunchStatus)); + + // retrieve prepared model + preparedModelCallback->wait(); + ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus(); + *preparedModel = preparedModelCallback->getPreparedModel(); + + // The getSupportedOperations call returns a list of operations that are + // guaranteed not to fail if prepareModel 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 + // operation, but reports that it successfully prepared the model, the test + // can continue. + if (!fullySupportsModel && prepareReturnStatus != ErrorStatus::NONE) { + ASSERT_EQ(nullptr, preparedModel->get()); + LOG(INFO) << "NN VTS: Unable to test Request validation because vendor service cannot " + "prepare model that it does not support."; + std::cout << "[ ] Unable to test Request validation because vendor service " + "cannot prepare model that it does not support." + << std::endl; + return; + } + ASSERT_EQ(ErrorStatus::NONE, prepareReturnStatus); + ASSERT_NE(nullptr, preparedModel->get()); +} + // A class for test environment setup NeuralnetworksHidlEnvironment::NeuralnetworksHidlEnvironment() {} @@ -68,9 +121,17 @@ void NeuralnetworksHidlTest::TearDown() { ::testing::VtsHalHidlTargetTestBase::TearDown(); } -void ValidationTest::validateEverything(const Model& model, const std::vector& request) { +void ValidationTest::validateEverything(const Model& model, const std::vector& requests) { validateModel(model); - validateRequests(model, request); + + // create IPreparedModel + sp preparedModel; + ASSERT_NO_FATAL_FAILURE(createPreparedModel(device, model, &preparedModel)); + if (preparedModel == nullptr) { + return; + } + + validateRequests(preparedModel, requests); } } // namespace functional diff --git a/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.h b/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.h index 559d678ea1..22285be38e 100644 --- a/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.h +++ b/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.h @@ -67,7 +67,8 @@ class ValidationTest : public NeuralnetworksHidlTest { private: void validateModel(const Model& model); - void validateRequests(const Model& model, const std::vector& request); + void validateRequests(const sp& preparedModel, + const std::vector& requests); }; // Tag for the generated tests diff --git a/neuralnetworks/1.1/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.1/vts/functional/ValidateRequest.cpp index 5225bf7581..f4adbabf93 100644 --- a/neuralnetworks/1.1/vts/functional/ValidateRequest.cpp +++ b/neuralnetworks/1.1/vts/functional/ValidateRequest.cpp @@ -34,7 +34,6 @@ namespace vts { namespace functional { using ::android::hardware::neuralnetworks::V1_2::implementation::ExecutionCallback; -using ::android::hardware::neuralnetworks::V1_2::implementation::PreparedModelCallback; using ::android::hidl::memory::V1_0::IMemory; using test_helper::for_all; using test_helper::MixedTyped; @@ -42,54 +41,6 @@ using test_helper::MixedTypedExample; ///////////////////////// UTILITY FUNCTIONS ///////////////////////// -static void createPreparedModel(const sp& device, const V1_1::Model& model, - sp* preparedModel) { - ASSERT_NE(nullptr, preparedModel); - - // see if service can handle model - bool fullySupportsModel = false; - Return supportedOpsLaunchStatus = device->getSupportedOperations_1_1( - model, [&fullySupportsModel](ErrorStatus status, const hidl_vec& supported) { - ASSERT_EQ(ErrorStatus::NONE, status); - ASSERT_NE(0ul, supported.size()); - fullySupportsModel = - std::all_of(supported.begin(), supported.end(), [](bool valid) { return valid; }); - }); - ASSERT_TRUE(supportedOpsLaunchStatus.isOk()); - - // launch prepare model - sp preparedModelCallback = new PreparedModelCallback(); - ASSERT_NE(nullptr, preparedModelCallback.get()); - Return prepareLaunchStatus = device->prepareModel_1_1( - model, ExecutionPreference::FAST_SINGLE_ANSWER, preparedModelCallback); - ASSERT_TRUE(prepareLaunchStatus.isOk()); - ASSERT_EQ(ErrorStatus::NONE, static_cast(prepareLaunchStatus)); - - // retrieve prepared model - preparedModelCallback->wait(); - ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus(); - *preparedModel = preparedModelCallback->getPreparedModel(); - - // The getSupportedOperations_1_1 call returns a list of operations that are - // guaranteed not to fail if prepareModel_1_1 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 - // operation, but reports that it successfully prepared the model, the test - // can continue. - if (!fullySupportsModel && prepareReturnStatus != ErrorStatus::NONE) { - ASSERT_EQ(nullptr, preparedModel->get()); - LOG(INFO) << "NN VTS: Unable to test Request validation because vendor service cannot " - "prepare model that it does not support."; - std::cout << "[ ] Unable to test Request validation because vendor service " - "cannot prepare model that it does not support." - << std::endl; - return; - } - ASSERT_EQ(ErrorStatus::NONE, prepareReturnStatus); - ASSERT_NE(nullptr, preparedModel->get()); -} - // Primary validation function. This function will take a valid request, apply a // mutation to it to invalidate the request, then pass it to interface calls // that use the request. Note that the request here is passed by value, and any @@ -238,15 +189,8 @@ std::vector createRequests(const std::vector& exampl return requests; } -void ValidationTest::validateRequests(const V1_1::Model& model, +void ValidationTest::validateRequests(const sp& preparedModel, const std::vector& requests) { - // create IPreparedModel - sp preparedModel; - ASSERT_NO_FATAL_FAILURE(createPreparedModel(device, model, &preparedModel)); - if (preparedModel == nullptr) { - return; - } - // validate each request for (const Request& request : requests) { removeInputTest(preparedModel, request); diff --git a/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.cpp index 11fa693ddc..08069f2e7a 100644 --- a/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.cpp +++ b/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.cpp @@ -18,6 +18,10 @@ #include "VtsHalNeuralnetworks.h" +#include + +#include "Callbacks.h" + namespace android { namespace hardware { namespace neuralnetworks { @@ -25,6 +29,56 @@ namespace V1_1 { namespace vts { namespace functional { +using ::android::hardware::neuralnetworks::V1_2::implementation::PreparedModelCallback; + +static void createPreparedModel(const sp& device, const V1_1::Model& model, + sp* preparedModel) { + ASSERT_NE(nullptr, preparedModel); + + // see if service can handle model + bool fullySupportsModel = false; + Return supportedOpsLaunchStatus = device->getSupportedOperations_1_1( + model, [&fullySupportsModel](ErrorStatus status, const hidl_vec& supported) { + ASSERT_EQ(ErrorStatus::NONE, status); + ASSERT_NE(0ul, supported.size()); + fullySupportsModel = std::all_of(supported.begin(), supported.end(), + [](bool valid) { return valid; }); + }); + ASSERT_TRUE(supportedOpsLaunchStatus.isOk()); + + // launch prepare model + sp preparedModelCallback = new PreparedModelCallback(); + ASSERT_NE(nullptr, preparedModelCallback.get()); + Return prepareLaunchStatus = device->prepareModel_1_1( + model, ExecutionPreference::FAST_SINGLE_ANSWER, preparedModelCallback); + ASSERT_TRUE(prepareLaunchStatus.isOk()); + ASSERT_EQ(ErrorStatus::NONE, static_cast(prepareLaunchStatus)); + + // retrieve prepared model + preparedModelCallback->wait(); + ErrorStatus prepareReturnStatus = preparedModelCallback->getStatus(); + *preparedModel = preparedModelCallback->getPreparedModel(); + + // The getSupportedOperations_1_1 call returns a list of operations that are + // guaranteed not to fail if prepareModel_1_1 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 + // operation, but reports that it successfully prepared the model, the test + // can continue. + if (!fullySupportsModel && prepareReturnStatus != ErrorStatus::NONE) { + ASSERT_EQ(nullptr, preparedModel->get()); + LOG(INFO) << "NN VTS: Unable to test Request validation because vendor service cannot " + "prepare model that it does not support."; + std::cout << "[ ] Unable to test Request validation because vendor service " + "cannot prepare model that it does not support." + << std::endl; + return; + } + ASSERT_EQ(ErrorStatus::NONE, prepareReturnStatus); + ASSERT_NE(nullptr, preparedModel->get()); +} + // A class for test environment setup NeuralnetworksHidlEnvironment::NeuralnetworksHidlEnvironment() {} @@ -68,9 +122,17 @@ void NeuralnetworksHidlTest::TearDown() { ::testing::VtsHalHidlTargetTestBase::TearDown(); } -void ValidationTest::validateEverything(const Model& model, const std::vector& request) { +void ValidationTest::validateEverything(const Model& model, const std::vector& requests) { validateModel(model); - validateRequests(model, request); + + // create IPreparedModel + sp preparedModel; + ASSERT_NO_FATAL_FAILURE(createPreparedModel(device, model, &preparedModel)); + if (preparedModel == nullptr) { + return; + } + + validateRequests(preparedModel, requests); } } // namespace functional diff --git a/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.h b/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.h index cea2b54c2d..f3f587b866 100644 --- a/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.h +++ b/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.h @@ -76,7 +76,8 @@ class ValidationTest : public NeuralnetworksHidlTest { private: void validateModel(const Model& model); - void validateRequests(const Model& model, const std::vector& request); + void validateRequests(const sp& preparedModel, + const std::vector& requests); }; // Tag for the generated tests diff --git a/neuralnetworks/1.2/vts/functional/ValidateBurst.cpp b/neuralnetworks/1.2/vts/functional/ValidateBurst.cpp index 8bb4934833..8c6391e815 100644 --- a/neuralnetworks/1.2/vts/functional/ValidateBurst.cpp +++ b/neuralnetworks/1.2/vts/functional/ValidateBurst.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 The Android Open Source Project + * 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. @@ -39,7 +39,13 @@ using ::android::nn::RequestChannelSender; using ::android::nn::ResultChannelReceiver; using ExecutionBurstCallback = ::android::nn::ExecutionBurstController::ExecutionBurstCallback; +// This constant value represents the length of an FMQ that is large enough to +// return a result from a burst execution for all of the generated test cases. constexpr size_t kExecutionBurstChannelLength = 1024; + +// This constant value represents a length of an FMQ that is not large enough +// to return a result from a burst execution for some of the generated test +// cases. constexpr size_t kExecutionBurstChannelSmallLength = 8; ///////////////////////// UTILITY FUNCTIONS ///////////////////////// @@ -51,7 +57,8 @@ static bool badTiming(Timing timing) { static void createBurst(const sp& preparedModel, const sp& callback, std::unique_ptr* sender, std::unique_ptr* receiver, - sp* context) { + sp* context, + size_t resultChannelLength = kExecutionBurstChannelLength) { ASSERT_NE(nullptr, preparedModel.get()); ASSERT_NE(nullptr, sender); ASSERT_NE(nullptr, receiver); @@ -61,7 +68,7 @@ static void createBurst(const sp& preparedModel, const sp& preparedModel, const sp& preparedModel, - std::shared_ptr* controller, size_t resultChannelLength) { + const sp& preparedModel, size_t resultChannelLength, + std::shared_ptr* controller) { ASSERT_NE(nullptr, preparedModel.get()); ASSERT_NE(nullptr, controller); // create FMQ objects - auto [fmqRequestChannel, fmqRequestDescriptor] = - RequestChannelSender::create(kExecutionBurstChannelLength, /*blocking=*/true); - auto [fmqResultChannel, fmqResultDescriptor] = - ResultChannelReceiver::create(resultChannelLength, /*blocking=*/true); - ASSERT_NE(nullptr, fmqRequestChannel.get()); - ASSERT_NE(nullptr, fmqResultChannel.get()); - ASSERT_NE(nullptr, fmqRequestDescriptor); - ASSERT_NE(nullptr, fmqResultDescriptor); - - // configure burst + std::unique_ptr sender; + std::unique_ptr receiver; sp callback = new ExecutionBurstCallback(); - ErrorStatus errorStatus; - sp burstContext; - const Return ret = preparedModel->configureExecutionBurst( - callback, *fmqRequestDescriptor, *fmqResultDescriptor, - [&errorStatus, &burstContext](ErrorStatus status, const sp& context) { - errorStatus = status; - burstContext = context; - }); - ASSERT_TRUE(ret.isOk()); - ASSERT_EQ(ErrorStatus::NONE, errorStatus); - ASSERT_NE(nullptr, burstContext.get()); + sp context; + ASSERT_NO_FATAL_FAILURE(createBurst(preparedModel, callback, &sender, &receiver, &context, + resultChannelLength)); + ASSERT_NE(nullptr, sender.get()); + ASSERT_NE(nullptr, receiver.get()); + ASSERT_NE(nullptr, context.get()); // return values - *controller = std::make_shared( - std::move(fmqRequestChannel), std::move(fmqResultChannel), burstContext, callback); + *controller = std::make_shared(std::move(sender), std::move(receiver), + context, callback); } // Primary validation function. This function will take a valid serialized @@ -139,7 +133,7 @@ static void validate(RequestChannelSender* sender, ResultChannelReceiver* receiv SCOPED_TRACE(message); // send invalid packet - sender->sendPacket(serialized); + ASSERT_TRUE(sender->sendPacket(serialized)); // receive error auto results = receiver->getBlocking(); @@ -150,27 +144,34 @@ static void validate(RequestChannelSender* sender, ResultChannelReceiver* receiv EXPECT_TRUE(badTiming(timing)); } -static std::vector createUniqueDatum() { +// For validation, valid packet entries are mutated to invalid packet entries, +// or invalid packet entries are inserted into valid packets. This function +// creates pre-set invalid packet entries for convenience. +static std::vector createBadRequestPacketEntries() { const FmqRequestDatum::PacketInformation packetInformation = { /*.packetSize=*/10, /*.numberOfInputOperands=*/10, /*.numberOfOutputOperands=*/10, /*.numberOfPools=*/10}; const FmqRequestDatum::OperandInformation operandInformation = { /*.hasNoValue=*/false, /*.location=*/{}, /*.numberOfDimensions=*/10}; const int32_t invalidPoolIdentifier = std::numeric_limits::max(); - std::vector unique(7); - unique[0].packetInformation(packetInformation); - unique[1].inputOperandInformation(operandInformation); - unique[2].inputOperandDimensionValue(0); - unique[3].outputOperandInformation(operandInformation); - unique[4].outputOperandDimensionValue(0); - unique[5].poolIdentifier(invalidPoolIdentifier); - unique[6].measureTiming(MeasureTiming::YES); - return unique; + std::vector bad(7); + bad[0].packetInformation(packetInformation); + bad[1].inputOperandInformation(operandInformation); + bad[2].inputOperandDimensionValue(0); + bad[3].outputOperandInformation(operandInformation); + bad[4].outputOperandDimensionValue(0); + bad[5].poolIdentifier(invalidPoolIdentifier); + bad[6].measureTiming(MeasureTiming::YES); + return bad; } -static const std::vector& getUniqueDatum() { - static const std::vector unique = createUniqueDatum(); - return unique; +// For validation, valid packet entries are mutated to invalid packet entries, +// or invalid packet entries are inserted into valid packets. This function +// retrieves pre-set invalid packet entries for convenience. This function +// caches these data so they can be reused on subsequent validation checks. +static const std::vector& getBadRequestPacketEntries() { + static const std::vector bad = createBadRequestPacketEntries(); + return bad; } ///////////////////////// REMOVE DATUM //////////////////////////////////// @@ -190,7 +191,7 @@ static void removeDatumTest(RequestChannelSender* sender, ResultChannelReceiver* static void addDatumTest(RequestChannelSender* sender, ResultChannelReceiver* receiver, const std::vector& serialized) { - const std::vector& extra = getUniqueDatum(); + const std::vector& extra = getBadRequestPacketEntries(); for (size_t index = 0; index <= serialized.size(); ++index) { for (size_t type = 0; type < extra.size(); ++type) { const std::string message = "addDatum: added datum type " + std::to_string(type) + @@ -209,17 +210,17 @@ static bool interestingCase(const FmqRequestDatum& lhs, const FmqRequestDatum& r using Discriminator = FmqRequestDatum::hidl_discriminator; const bool differentValues = (lhs != rhs); - const bool sameSumType = (lhs.getDiscriminator() == rhs.getDiscriminator()); + const bool sameDiscriminator = (lhs.getDiscriminator() == rhs.getDiscriminator()); const auto discriminator = rhs.getDiscriminator(); const bool isDimensionValue = (discriminator == Discriminator::inputOperandDimensionValue || discriminator == Discriminator::outputOperandDimensionValue); - return differentValues && !(sameSumType && isDimensionValue); + return differentValues && !(sameDiscriminator && isDimensionValue); } static void mutateDatumTest(RequestChannelSender* sender, ResultChannelReceiver* receiver, const std::vector& serialized) { - const std::vector& change = getUniqueDatum(); + const std::vector& change = getBadRequestPacketEntries(); for (size_t index = 0; index < serialized.size(); ++index) { for (size_t type = 0; type < change.size(); ++type) { if (interestingCase(serialized[index], change[type])) { @@ -252,17 +253,17 @@ static void validateBurstSerialization(const sp& preparedModel, // validate each request for (const Request& request : requests) { // load memory into callback slots - std::vector keys(request.pools.size()); - for (size_t i = 0; i < keys.size(); ++i) { - keys[i] = reinterpret_cast(&request.pools[i]); - } + std::vector keys; + keys.reserve(request.pools.size()); + std::transform(request.pools.begin(), request.pools.end(), std::back_inserter(keys), + [](const auto& pool) { return reinterpret_cast(&pool); }); const std::vector slots = callback->getSlots(request.pools, keys); // ensure slot std::numeric_limits::max() doesn't exist (for // subsequent slot validation testing) - const auto maxElement = std::max_element(slots.begin(), slots.end()); - ASSERT_NE(slots.end(), maxElement); - ASSERT_NE(std::numeric_limits::max(), *maxElement); + ASSERT_TRUE(std::all_of(slots.begin(), slots.end(), [](int32_t slot) { + return slot != std::numeric_limits::max(); + })); // serialize the request const auto serialized = ::android::nn::serialize(request, MeasureTiming::YES, slots); @@ -274,18 +275,20 @@ static void validateBurstSerialization(const sp& preparedModel, } } +// This test validates that when the Result message size exceeds length of the +// result FMQ, the service instance gracefully fails and returns an error. static void validateBurstFmqLength(const sp& preparedModel, const std::vector& requests) { // create regular burst std::shared_ptr controllerRegular; - ASSERT_NO_FATAL_FAILURE(createBurstWithResultChannelLength(preparedModel, &controllerRegular, - kExecutionBurstChannelLength)); + ASSERT_NO_FATAL_FAILURE(createBurstWithResultChannelLength( + preparedModel, kExecutionBurstChannelLength, &controllerRegular)); ASSERT_NE(nullptr, controllerRegular.get()); // create burst with small output channel std::shared_ptr controllerSmall; - ASSERT_NO_FATAL_FAILURE(createBurstWithResultChannelLength(preparedModel, &controllerSmall, - kExecutionBurstChannelSmallLength)); + ASSERT_NO_FATAL_FAILURE(createBurstWithResultChannelLength( + preparedModel, kExecutionBurstChannelSmallLength, &controllerSmall)); ASSERT_NE(nullptr, controllerSmall.get()); // validate each request @@ -297,24 +300,25 @@ static void validateBurstFmqLength(const sp& preparedModel, } // collect serialized result by running regular burst - const auto [status1, outputShapes1, timing1] = + const auto [statusRegular, outputShapesRegular, timingRegular] = controllerRegular->compute(request, MeasureTiming::NO, keys); - // skip test if synchronous output isn't useful + // skip test if regular burst output isn't useful for testing a failure + // caused by having too small of a length for the result FMQ const std::vector serialized = - ::android::nn::serialize(status1, outputShapes1, timing1); - if (status1 != ErrorStatus::NONE || + ::android::nn::serialize(statusRegular, outputShapesRegular, timingRegular); + if (statusRegular != ErrorStatus::NONE || serialized.size() <= kExecutionBurstChannelSmallLength) { continue; } // by this point, execution should fail because the result channel isn't // large enough to return the serialized result - const auto [status2, outputShapes2, timing2] = + const auto [statusSmall, outputShapesSmall, timingSmall] = controllerSmall->compute(request, MeasureTiming::NO, keys); - EXPECT_NE(ErrorStatus::NONE, status2); - EXPECT_EQ(0u, outputShapes2.size()); - EXPECT_TRUE(badTiming(timing2)); + EXPECT_NE(ErrorStatus::NONE, statusSmall); + EXPECT_EQ(0u, outputShapesSmall.size()); + EXPECT_TRUE(badTiming(timingSmall)); } } diff --git a/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.cpp index 93182f1da2..4ddefe8134 100644 --- a/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.cpp +++ b/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.cpp @@ -29,7 +29,6 @@ namespace V1_2 { namespace vts { namespace functional { -using ::android::hardware::neuralnetworks::V1_2::implementation::ExecutionCallback; using ::android::hardware::neuralnetworks::V1_2::implementation::PreparedModelCallback; using HidlToken = hidl_array(Constant::BYTE_SIZE_OF_CACHE_TOKEN)>; using V1_1::ExecutionPreference; @@ -127,7 +126,7 @@ void NeuralnetworksHidlTest::TearDown() { ::testing::VtsHalHidlTargetTestBase::TearDown(); } -void ValidationTest::validateEverything(const Model& model, const std::vector& request) { +void ValidationTest::validateEverything(const Model& model, const std::vector& requests) { validateModel(model); // create IPreparedModel @@ -137,8 +136,8 @@ void ValidationTest::validateEverything(const Model& model, const std::vector getPreparedModel_1_2( diff --git a/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.h b/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.h index 36e73a4fb0..8d1acbe03e 100644 --- a/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.h +++ b/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.h @@ -72,7 +72,7 @@ class NeuralnetworksHidlTest : public ::testing::VtsHalHidlTargetTestBase { // Tag for the validation tests class ValidationTest : public NeuralnetworksHidlTest { protected: - void validateEverything(const Model& model, const std::vector& request); + void validateEverything(const Model& model, const std::vector& requests); private: void validateModel(const Model& model);