blob: 5aa27516db0f52e7c3a3aa6fa30ca712011d685b [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
31namespace android {
32namespace hardware {
33namespace neuralnetworks {
34
Xusong Wang7df43062019-08-09 16:38:14 -070035using namespace test_helper;
36using ::android::hardware::neuralnetworks::V1_0::DataLocation;
37using ::android::hardware::neuralnetworks::V1_0::Request;
Slava Shklyaev73ee79d2019-05-14 14:15:14 +010038using ::android::hardware::neuralnetworks::V1_0::RequestArgument;
Xusong Wang7df43062019-08-09 16:38:14 -070039using ::android::hidl::memory::V1_0::IMemory;
Slava Shklyaev73ee79d2019-05-14 14:15:14 +010040
Xusong Wang7df43062019-08-09 16:38:14 -070041constexpr uint32_t kInputPoolIndex = 0;
42constexpr uint32_t kOutputPoolIndex = 1;
43
44Request createRequest(const TestModel& testModel) {
45 // Model inputs.
46 hidl_vec<RequestArgument> inputs(testModel.inputIndexes.size());
47 size_t inputSize = 0;
48 for (uint32_t i = 0; i < testModel.inputIndexes.size(); i++) {
49 const auto& op = testModel.operands[testModel.inputIndexes[i]];
50 if (op.data.size() == 0) {
51 // Omitted input.
52 inputs[i] = {.hasNoValue = true};
53 } else {
54 DataLocation loc = {.poolIndex = kInputPoolIndex,
55 .offset = static_cast<uint32_t>(inputSize),
56 .length = static_cast<uint32_t>(op.data.size())};
57 inputSize += op.data.alignedSize();
58 inputs[i] = {.hasNoValue = false, .location = loc, .dimensions = {}};
59 }
60 }
61
62 // Model outputs.
63 hidl_vec<RequestArgument> outputs(testModel.outputIndexes.size());
64 size_t outputSize = 0;
65 for (uint32_t i = 0; i < testModel.outputIndexes.size(); i++) {
66 const auto& op = testModel.operands[testModel.outputIndexes[i]];
Xusong Wangead950d2019-08-09 16:45:24 -070067
68 // In the case of zero-sized output, we should at least provide a one-byte buffer.
69 // This is because zero-sized tensors are only supported internally to the driver, or
70 // reported in output shapes. It is illegal for the client to pre-specify a zero-sized
71 // tensor as model output. Otherwise, we will have two semantic conflicts:
72 // - "Zero dimension" conflicts with "unspecified dimension".
73 // - "Omitted operand buffer" conflicts with "zero-sized operand buffer".
74 size_t bufferSize = std::max<size_t>(op.data.size(), 1);
75
Xusong Wang7df43062019-08-09 16:38:14 -070076 DataLocation loc = {.poolIndex = kOutputPoolIndex,
77 .offset = static_cast<uint32_t>(outputSize),
Xusong Wangead950d2019-08-09 16:45:24 -070078 .length = static_cast<uint32_t>(bufferSize)};
79 outputSize += op.data.size() == 0 ? TestBuffer::kAlignment : op.data.alignedSize();
Xusong Wang7df43062019-08-09 16:38:14 -070080 outputs[i] = {.hasNoValue = false, .location = loc, .dimensions = {}};
81 }
82
83 // Allocate memory pools.
84 hidl_vec<hidl_memory> pools = {nn::allocateSharedMemory(inputSize),
85 nn::allocateSharedMemory(outputSize)};
86 CHECK_NE(pools[kInputPoolIndex].size(), 0u);
87 CHECK_NE(pools[kOutputPoolIndex].size(), 0u);
88 sp<IMemory> inputMemory = mapMemory(pools[kInputPoolIndex]);
89 CHECK(inputMemory.get() != nullptr);
90 uint8_t* inputPtr = static_cast<uint8_t*>(static_cast<void*>(inputMemory->getPointer()));
91 CHECK(inputPtr != nullptr);
92
93 // Copy input data to the memory pool.
94 for (uint32_t i = 0; i < testModel.inputIndexes.size(); i++) {
95 const auto& op = testModel.operands[testModel.inputIndexes[i]];
96 if (op.data.size() > 0) {
97 const uint8_t* begin = op.data.get<uint8_t>();
98 const uint8_t* end = begin + op.data.size();
99 std::copy(begin, end, inputPtr + inputs[i].location.offset);
100 }
101 }
102
103 return {.inputs = std::move(inputs), .outputs = std::move(outputs), .pools = std::move(pools)};
Slava Shklyaev73ee79d2019-05-14 14:15:14 +0100104}
105
Xusong Wang7df43062019-08-09 16:38:14 -0700106std::vector<TestBuffer> getOutputBuffers(const Request& request) {
107 sp<IMemory> outputMemory = mapMemory(request.pools[kOutputPoolIndex]);
108 CHECK(outputMemory.get() != nullptr);
109 uint8_t* outputPtr = static_cast<uint8_t*>(static_cast<void*>(outputMemory->getPointer()));
110 CHECK(outputPtr != nullptr);
111
112 // Copy out output results.
113 std::vector<TestBuffer> outputBuffers;
114 for (const auto& output : request.outputs) {
115 outputBuffers.emplace_back(output.location.length, outputPtr + output.location.offset);
116 }
117
118 return outputBuffers;
Slava Shklyaev73ee79d2019-05-14 14:15:14 +0100119}
120
121} // namespace neuralnetworks
122} // namespace hardware
123} // namespace android