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

Commit 3acc7dc1 authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge changes I0699ed67,I58293973,I9c795dcb,I0b731d10,Ia2097345

* changes:
  Remove extra tests from NNAPI VTS validation tests
  Fix the timing initialization error for failed executeFenced case
  Add BLOB AHWB tests in VTS.
  Add fenced compute path to memory domain validation test.
  Add memory domain VTS validation tests.
parents 46aa366a b1865b65
Loading
Loading
Loading
Loading
+8 −2
Original line number Diff line number Diff line
@@ -125,7 +125,9 @@ Model createModel(const TestModel& testModel) {
// Test driver for those generated from ml/nn/runtime/test/spec
void Execute(const sp<IDevice>& device, const TestModel& testModel) {
    const Model model = createModel(testModel);
    const Request request = createRequest(testModel);

    ExecutionContext context;
    const Request request = context.createRequest(testModel);

    // Create IPreparedModel.
    sp<IPreparedModel> preparedModel;
@@ -143,7 +145,7 @@ void Execute(const sp<IDevice>& device, const TestModel& testModel) {
    ASSERT_EQ(ErrorStatus::NONE, executionCallback->getStatus());

    // Retrieve execution results.
    const std::vector<TestBuffer> outputs = getOutputBuffers(request);
    const std::vector<TestBuffer> outputs = context.getOutputBuffers(request);

    // We want "close-enough" results.
    checkResults(testModel, outputs);
@@ -158,6 +160,10 @@ std::vector<NamedModel> getNamedModels(const FilterFn& filter) {
    return TestModelManager::get().getTestModels(filter);
}

std::vector<NamedModel> getNamedModels(const FilterNameFn& filter) {
    return TestModelManager::get().getTestModels(filter);
}

std::string printGeneratedTest(const testing::TestParamInfo<GeneratedTestParam>& info) {
    const auto& [namedDevice, namedModel] = info.param;
    return gtestCompliantName(getName(namedDevice) + "_" + getName(namedModel));
+3 −0
Original line number Diff line number Diff line
@@ -37,6 +37,9 @@ class GeneratedTestBase : public testing::TestWithParam<GeneratedTestParam> {
using FilterFn = std::function<bool(const test_helper::TestModel&)>;
std::vector<NamedModel> getNamedModels(const FilterFn& filter);

using FilterNameFn = std::function<bool(const std::string&)>;
std::vector<NamedModel> getNamedModels(const FilterNameFn& filter);

std::string printGeneratedTest(const testing::TestParamInfo<GeneratedTestParam>& info);

#define INSTANTIATE_GENERATED_TEST(TestSuite, filter)                                     \
+73 −18
Original line number Diff line number Diff line
@@ -21,10 +21,13 @@

#include <android-base/logging.h>
#include <android/hardware/neuralnetworks/1.0/types.h>
#include <android/hardware_buffer.h>
#include <android/hidl/allocator/1.0/IAllocator.h>
#include <android/hidl/memory/1.0/IMemory.h>
#include <hidlmemory/mapping.h>
#include <vndk/hardware_buffer.h>

#include <gtest/gtest.h>
#include <algorithm>
#include <iostream>
#include <vector>
@@ -37,10 +40,64 @@ using V1_0::DataLocation;
using V1_0::Request;
using V1_0::RequestArgument;

constexpr uint32_t kInputPoolIndex = 0;
constexpr uint32_t kOutputPoolIndex = 1;
std::unique_ptr<TestAshmem> TestAshmem::create(uint32_t size) {
    auto ashmem = std::make_unique<TestAshmem>(size);
    return ashmem->mIsValid ? std::move(ashmem) : nullptr;
}

void TestAshmem::initialize(uint32_t size) {
    mIsValid = false;
    ASSERT_GT(size, 0);
    mHidlMemory = nn::allocateSharedMemory(size);
    ASSERT_TRUE(mHidlMemory.valid());
    mMappedMemory = mapMemory(mHidlMemory);
    ASSERT_NE(mMappedMemory, nullptr);
    mPtr = static_cast<uint8_t*>(static_cast<void*>(mMappedMemory->getPointer()));
    ASSERT_NE(mPtr, nullptr);
    mIsValid = true;
}

std::unique_ptr<TestBlobAHWB> TestBlobAHWB::create(uint32_t size) {
    auto ahwb = std::make_unique<TestBlobAHWB>(size);
    return ahwb->mIsValid ? std::move(ahwb) : nullptr;
}

void TestBlobAHWB::initialize(uint32_t size) {
    mIsValid = false;
    ASSERT_GT(size, 0);
    const auto usage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN | AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN;
    const AHardwareBuffer_Desc desc = {
            .width = size,
            .height = 1,
            .layers = 1,
            .format = AHARDWAREBUFFER_FORMAT_BLOB,
            .usage = usage,
            .stride = size,
    };
    ASSERT_EQ(AHardwareBuffer_allocate(&desc, &mAhwb), 0);
    ASSERT_NE(mAhwb, nullptr);

    void* buffer = nullptr;
    ASSERT_EQ(AHardwareBuffer_lock(mAhwb, usage, -1, nullptr, &buffer), 0);
    ASSERT_NE(buffer, nullptr);
    mPtr = static_cast<uint8_t*>(buffer);

    const native_handle_t* handle = AHardwareBuffer_getNativeHandle(mAhwb);
    ASSERT_NE(handle, nullptr);
    mHidlMemory = hidl_memory("hardware_buffer_blob", handle, desc.width);
    mIsValid = true;
}

TestBlobAHWB::~TestBlobAHWB() {
    if (mAhwb) {
        AHardwareBuffer_unlock(mAhwb, nullptr);
        AHardwareBuffer_release(mAhwb);
    }
}

Request ExecutionContext::createRequest(const TestModel& testModel, MemoryType memoryType) {
    CHECK(memoryType == MemoryType::ASHMEM || memoryType == MemoryType::BLOB_AHWB);

Request createRequest(const TestModel& testModel) {
    // Model inputs.
    hidl_vec<RequestArgument> inputs(testModel.main.inputIndexes.size());
    size_t inputSize = 0;
@@ -80,16 +137,19 @@ Request createRequest(const TestModel& testModel) {
    }

    // Allocate memory pools.
    hidl_vec<hidl_memory> pools = {nn::allocateSharedMemory(inputSize),
                                   nn::allocateSharedMemory(outputSize)};
    CHECK_NE(pools[kInputPoolIndex].size(), 0u);
    CHECK_NE(pools[kOutputPoolIndex].size(), 0u);
    sp<IMemory> inputMemory = mapMemory(pools[kInputPoolIndex]);
    CHECK(inputMemory.get() != nullptr);
    uint8_t* inputPtr = static_cast<uint8_t*>(static_cast<void*>(inputMemory->getPointer()));
    CHECK(inputPtr != nullptr);
    if (memoryType == MemoryType::ASHMEM) {
        mInputMemory = TestAshmem::create(inputSize);
        mOutputMemory = TestAshmem::create(outputSize);
    } else {
        mInputMemory = TestBlobAHWB::create(inputSize);
        mOutputMemory = TestBlobAHWB::create(outputSize);
    }
    EXPECT_NE(mInputMemory, nullptr);
    EXPECT_NE(mOutputMemory, nullptr);
    hidl_vec<hidl_memory> pools = {mInputMemory->getHidlMemory(), mOutputMemory->getHidlMemory()};

    // Copy input data to the memory pool.
    uint8_t* inputPtr = mInputMemory->getPointer();
    for (uint32_t i = 0; i < testModel.main.inputIndexes.size(); i++) {
        const auto& op = testModel.main.operands[testModel.main.inputIndexes[i]];
        if (op.data.size() > 0) {
@@ -102,18 +162,13 @@ Request createRequest(const TestModel& testModel) {
    return {.inputs = std::move(inputs), .outputs = std::move(outputs), .pools = std::move(pools)};
}

std::vector<TestBuffer> getOutputBuffers(const Request& request) {
    sp<IMemory> outputMemory = mapMemory(request.pools[kOutputPoolIndex]);
    CHECK(outputMemory.get() != nullptr);
    uint8_t* outputPtr = static_cast<uint8_t*>(static_cast<void*>(outputMemory->getPointer()));
    CHECK(outputPtr != nullptr);

std::vector<TestBuffer> ExecutionContext::getOutputBuffers(const Request& request) const {
    // Copy out output results.
    uint8_t* outputPtr = mOutputMemory->getPointer();
    std::vector<TestBuffer> outputBuffers;
    for (const auto& output : request.outputs) {
        outputBuffers.emplace_back(output.location.length, outputPtr + output.location.offset);
    }

    return outputBuffers;
}

+8 −2
Original line number Diff line number Diff line
@@ -129,11 +129,17 @@ void validateEverything(const sp<IDevice>& device, const Model& model, const Req

TEST_P(ValidationTest, Test) {
    const Model model = createModel(kTestModel);
    const Request request = createRequest(kTestModel);
    ExecutionContext context;
    const Request request = context.createRequest(kTestModel);
    ASSERT_FALSE(kTestModel.expectFailure);
    validateEverything(kDevice, model, request);
}

INSTANTIATE_GENERATED_TEST(ValidationTest, [](const test_helper::TestModel&) { return true; });
INSTANTIATE_GENERATED_TEST(ValidationTest, [](const std::string& testName) {
    // Skip validation for the "inputs_as_internal" and "all_tensors_as_inputs"
    // generated tests.
    return testName.find("inputs_as_internal") == std::string::npos &&
           testName.find("all_tensors_as_inputs") == std::string::npos;
});

}  // namespace android::hardware::neuralnetworks::V1_0::vts::functional
+69 −5
Original line number Diff line number Diff line
@@ -19,6 +19,8 @@

#include <android-base/logging.h>
#include <android/hardware/neuralnetworks/1.0/types.h>
#include <android/hardware_buffer.h>
#include <android/hidl/memory/1.0/IMemory.h>
#include <algorithm>
#include <iosfwd>
#include <string>
@@ -28,11 +30,73 @@

namespace android::hardware::neuralnetworks {

// Convenience class to manage the lifetime of memory resources.
class TestMemoryBase {
    DISALLOW_COPY_AND_ASSIGN(TestMemoryBase);

  public:
    TestMemoryBase() = default;
    virtual ~TestMemoryBase() = default;
    uint8_t* getPointer() const { return mPtr; }
    hidl_memory getHidlMemory() const { return mHidlMemory; }

  protected:
    uint8_t* mPtr = nullptr;
    hidl_memory mHidlMemory;
    bool mIsValid = false;
};

class TestAshmem : public TestMemoryBase {
  public:
    static std::unique_ptr<TestAshmem> create(uint32_t size);

    // Prefer TestAshmem::create.
    // The constructor calls initialize, which constructs the memory resources. This is a workaround
    // that gtest macros cannot be used directly in a constructor.
    TestAshmem(uint32_t size) { initialize(size); }

  private:
    void initialize(uint32_t size);
    sp<hidl::memory::V1_0::IMemory> mMappedMemory;
};

class TestBlobAHWB : public TestMemoryBase {
  public:
    static std::unique_ptr<TestBlobAHWB> create(uint32_t size);

    // Prefer TestBlobAHWB::create.
    // The constructor calls initialize, which constructs the memory resources. This is a
    // workaround that gtest macros cannot be used directly in a constructor.
    TestBlobAHWB(uint32_t size) { initialize(size); }
    ~TestBlobAHWB();

  private:
    void initialize(uint32_t size);
    AHardwareBuffer* mAhwb = nullptr;
};

enum class MemoryType { ASHMEM, BLOB_AHWB, DEVICE };

// Manages the lifetime of memory resources used in an execution.
class ExecutionContext {
    DISALLOW_COPY_AND_ASSIGN(ExecutionContext);

  public:
    static constexpr uint32_t kInputPoolIndex = 0;
    static constexpr uint32_t kOutputPoolIndex = 1;

    ExecutionContext() = default;

    // Create HIDL Request from the TestModel struct.
V1_0::Request createRequest(const test_helper::TestModel& testModel);
    V1_0::Request createRequest(const test_helper::TestModel& testModel,
                                MemoryType memoryType = MemoryType::ASHMEM);

    // After execution, copy out output results from the output memory pool.
std::vector<::test_helper::TestBuffer> getOutputBuffers(const V1_0::Request& request);
    std::vector<test_helper::TestBuffer> getOutputBuffers(const V1_0::Request& request) const;

  private:
    std::unique_ptr<TestMemoryBase> mInputMemory, mOutputMemory;
};

// Delete element from hidl_vec. hidl_vec doesn't support a "remove" operation,
// so this is efficiently accomplished by moving the element to the end and
Loading