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

Commit 2c4e0232 authored by Miao Wang's avatar Miao Wang
Browse files

Add VTS tests for NNAPI IPreparedModel::executeFenced

  - Validation tests
  - Generated tests to exercise executeFenced path

Bug: 142778241
Test: mm
Change-Id: I509f0b5713fc86885d597940aae5ade0502c97ad
parent 90cf3dd3
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -65,6 +65,7 @@ cc_test {
        "libhidlmemory",
        "libneuralnetworks_generated_test_harness",
        "libneuralnetworks_utils",
        "libsync",
    ],
    whole_static_libs: [
        "neuralnetworks_generated_V1_0_example",
+43 −3
Original line number Diff line number Diff line
@@ -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,6 +564,43 @@ 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 &&
@@ -635,7 +674,7 @@ void EvaluatePreparedModel(const sp<IDevice>& device, const sp<IPreparedModel>&
        case TestKind::GENERAL: {
            outputTypesList = {OutputType::FULLY_SPECIFIED};
            measureTimingList = {MeasureTiming::NO, MeasureTiming::YES};
            executorList = {Executor::ASYNC, Executor::SYNC, Executor::BURST};
            executorList = {Executor::ASYNC, Executor::SYNC, Executor::BURST, Executor::FENCED};
        } break;
        case TestKind::DYNAMIC_SHAPE: {
            outputTypesList = {OutputType::UNSPECIFIED, OutputType::INSUFFICIENT};
@@ -671,7 +710,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) {
+18 −0
Original line number Diff line number Diff line
@@ -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 ////////////////////////////////////
+30 −0
Original line number Diff line number Diff line
@@ -133,6 +133,35 @@ 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) {
                                             ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, error);
                                             ASSERT_EQ(handle.getNativeHandle(), nullptr);
                                             ASSERT_EQ(callback, nullptr);
                                         });
    ASSERT_TRUE(ret_null.isOk());

    native_handle_t* nativeHandle = native_handle_create(1, 0);
    ASSERT_NE(nullptr, nativeHandle);
    nativeHandle->data[0] = -1;
    hidl_handle hidlHandle;
    hidlHandle.setTo(nativeHandle, /*shouldOwn=*/true);
    Return<void> ret_invalid =
            preparedModel->executeFenced(request, {hidlHandle}, V1_2::MeasureTiming::NO,
                                         [](ErrorStatus error, const hidl_handle& handle,
                                            const sp<IFencedExecutionCallback>& callback) {
                                             ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, error);
                                             ASSERT_EQ(handle.getNativeHandle(), nullptr);
                                             ASSERT_EQ(callback, nullptr);
                                         });
    ASSERT_TRUE(ret_invalid.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 +173,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));