blob: 5de99fd0b35c57c21d7ab564645739f34659f4f5 [file] [log] [blame]
Slava Shklyaev73ee79d2019-05-14 14:15:14 +01001/*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Xusong Wang7df43062019-08-09 16:38:14 -070017#include "1.0/Utils.h"
18
19#include "MemoryUtils.h"
Slava Shklyaev73ee79d2019-05-14 14:15:14 +010020#include "TestHarness.h"
21
Xusong Wang7df43062019-08-09 16:38:14 -070022#include <android-base/logging.h>
Slava Shklyaev73ee79d2019-05-14 14:15:14 +010023#include <android/hardware/neuralnetworks/1.0/types.h>
Xusong Wang7df43062019-08-09 16:38:14 -070024#include <android/hidl/allocator/1.0/IAllocator.h>
25#include <android/hidl/memory/1.0/IMemory.h>
26#include <hidlmemory/mapping.h>
Slava Shklyaev73ee79d2019-05-14 14:15:14 +010027
Xusong Wangead950d2019-08-09 16:45:24 -070028#include <algorithm>
Slava Shklyaev73ee79d2019-05-14 14:15:14 +010029#include <vector>
30
Michael Butler62749b92019-08-26 23:55:47 -070031namespace android::hardware::neuralnetworks {
Slava Shklyaev73ee79d2019-05-14 14:15:14 +010032
Xusong Wang7df43062019-08-09 16:38:14 -070033using namespace test_helper;
Michael Butler62749b92019-08-26 23:55:47 -070034using hidl::memory::V1_0::IMemory;
35using V1_0::DataLocation;
36using V1_0::Request;
37using V1_0::RequestArgument;
Slava Shklyaev73ee79d2019-05-14 14:15:14 +010038
Xusong Wang7df43062019-08-09 16:38:14 -070039constexpr uint32_t kInputPoolIndex = 0;
40constexpr uint32_t kOutputPoolIndex = 1;
41
42Request createRequest(const TestModel& testModel) {
43 // Model inputs.
44 hidl_vec<RequestArgument> inputs(testModel.inputIndexes.size());
45 size_t inputSize = 0;
46 for (uint32_t i = 0; i < testModel.inputIndexes.size(); i++) {
47 const auto& op = testModel.operands[testModel.inputIndexes[i]];
48 if (op.data.size() == 0) {
49 // Omitted input.
50 inputs[i] = {.hasNoValue = true};
51 } else {
52 DataLocation loc = {.poolIndex = kInputPoolIndex,
53 .offset = static_cast<uint32_t>(inputSize),
54 .length = static_cast<uint32_t>(op.data.size())};
55 inputSize += op.data.alignedSize();
56 inputs[i] = {.hasNoValue = false, .location = loc, .dimensions = {}};
57 }
58 }
59
60 // Model outputs.
61 hidl_vec<RequestArgument> outputs(testModel.outputIndexes.size());
62 size_t outputSize = 0;
63 for (uint32_t i = 0; i < testModel.outputIndexes.size(); i++) {
64 const auto& op = testModel.operands[testModel.outputIndexes[i]];
Xusong Wangead950d2019-08-09 16:45:24 -070065
66 // In the case of zero-sized output, we should at least provide a one-byte buffer.
67 // This is because zero-sized tensors are only supported internally to the driver, or
68 // reported in output shapes. It is illegal for the client to pre-specify a zero-sized
69 // tensor as model output. Otherwise, we will have two semantic conflicts:
70 // - "Zero dimension" conflicts with "unspecified dimension".
71 // - "Omitted operand buffer" conflicts with "zero-sized operand buffer".
72 size_t bufferSize = std::max<size_t>(op.data.size(), 1);
73
Xusong Wang7df43062019-08-09 16:38:14 -070074 DataLocation loc = {.poolIndex = kOutputPoolIndex,
75 .offset = static_cast<uint32_t>(outputSize),
Xusong Wangead950d2019-08-09 16:45:24 -070076 .length = static_cast<uint32_t>(bufferSize)};
77 outputSize += op.data.size() == 0 ? TestBuffer::kAlignment : op.data.alignedSize();
Xusong Wang7df43062019-08-09 16:38:14 -070078 outputs[i] = {.hasNoValue = false, .location = loc, .dimensions = {}};
79 }
80
81 // Allocate memory pools.
82 hidl_vec<hidl_memory> pools = {nn::allocateSharedMemory(inputSize),
83 nn::allocateSharedMemory(outputSize)};
84 CHECK_NE(pools[kInputPoolIndex].size(), 0u);
85 CHECK_NE(pools[kOutputPoolIndex].size(), 0u);
86 sp<IMemory> inputMemory = mapMemory(pools[kInputPoolIndex]);
87 CHECK(inputMemory.get() != nullptr);
88 uint8_t* inputPtr = static_cast<uint8_t*>(static_cast<void*>(inputMemory->getPointer()));
89 CHECK(inputPtr != nullptr);
90
91 // Copy input data to the memory pool.
92 for (uint32_t i = 0; i < testModel.inputIndexes.size(); i++) {
93 const auto& op = testModel.operands[testModel.inputIndexes[i]];
94 if (op.data.size() > 0) {
95 const uint8_t* begin = op.data.get<uint8_t>();
96 const uint8_t* end = begin + op.data.size();
97 std::copy(begin, end, inputPtr + inputs[i].location.offset);
98 }
99 }
100
101 return {.inputs = std::move(inputs), .outputs = std::move(outputs), .pools = std::move(pools)};
Slava Shklyaev73ee79d2019-05-14 14:15:14 +0100102}
103
Xusong Wang7df43062019-08-09 16:38:14 -0700104std::vector<TestBuffer> getOutputBuffers(const Request& request) {
105 sp<IMemory> outputMemory = mapMemory(request.pools[kOutputPoolIndex]);
106 CHECK(outputMemory.get() != nullptr);
107 uint8_t* outputPtr = static_cast<uint8_t*>(static_cast<void*>(outputMemory->getPointer()));
108 CHECK(outputPtr != nullptr);
109
110 // Copy out output results.
111 std::vector<TestBuffer> outputBuffers;
112 for (const auto& output : request.outputs) {
113 outputBuffers.emplace_back(output.location.length, outputPtr + output.location.offset);
114 }
115
116 return outputBuffers;
Slava Shklyaev73ee79d2019-05-14 14:15:14 +0100117}
118
Michael Butler62749b92019-08-26 23:55:47 -0700119} // namespace android::hardware::neuralnetworks