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

Commit f24d64d3 authored by Xusong Wang's avatar Xusong Wang Committed by Automerger Merge Worker
Browse files

Merge "Add BLOB AHWB tests in VTS." into rvc-dev am: e71fa3a1

Change-Id: I5f0153634e43a221077fe26698bced172fc47686
parents 590ff52c e71fa3a1
Loading
Loading
Loading
Loading
+4 −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);
+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;
}

+2 −1
Original line number Diff line number Diff line
@@ -129,7 +129,8 @@ 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);
}
+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
+4 −2
Original line number Diff line number Diff line
@@ -133,7 +133,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;
@@ -151,7 +153,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);
Loading