1 /*
2 * Copyright (C) 2017 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
17 #include "TestMemory.h"
18
19 #include <android-base/scopeguard.h>
20 #include <gtest/gtest.h>
21 #include <sys/mman.h>
22 #include <sys/types.h>
23 #include <unistd.h>
24
25 #include "TestNeuralNetworksWrapper.h"
26 #include "TmpDirectoryUtils.h"
27
28 #ifdef __ANDROID__
29 #include <android/hardware_buffer.h>
30 #endif // __ANDROID__
31
32 using WrapperCompilation = ::android::nn::test_wrapper::Compilation;
33 using WrapperExecution = ::android::nn::test_wrapper::Execution;
34 using WrapperMemory = ::android::nn::test_wrapper::Memory;
35 using WrapperModel = ::android::nn::test_wrapper::Model;
36 using WrapperOperandType = ::android::nn::test_wrapper::OperandType;
37 using WrapperResult = ::android::nn::test_wrapper::Result;
38 using WrapperType = ::android::nn::test_wrapper::Type;
39
40 namespace {
41
42 // Tests the various ways to pass weights and input/output data.
43 class MemoryTest : public ::testing::Test {
44 protected:
SetUp()45 void SetUp() override {}
46 };
47
TEST_F(MemoryTest,TestFd)48 TEST_F(MemoryTest, TestFd) {
49 // Create a file that contains matrix2 and matrix3.
50 char path[] = NN_TMP_DIR "/TestMemoryXXXXXX";
51 int fd = mkstemp(path);
52 const uint32_t offsetForMatrix2 = 20;
53 const uint32_t offsetForMatrix3 = 200;
54 static_assert(offsetForMatrix2 + sizeof(matrix2) < offsetForMatrix3, "matrices overlap");
55 lseek(fd, offsetForMatrix2, SEEK_SET);
56 EXPECT_EQ(write(fd, matrix2, sizeof(matrix2)), static_cast<ssize_t>(sizeof(matrix2)));
57 lseek(fd, offsetForMatrix3, SEEK_SET);
58 EXPECT_EQ(write(fd, matrix3, sizeof(matrix3)), static_cast<ssize_t>(sizeof(matrix3)));
59 fsync(fd);
60
61 WrapperMemory weights(offsetForMatrix3 + sizeof(matrix3), PROT_READ, fd, 0);
62 ASSERT_TRUE(weights.isValid());
63
64 WrapperModel model;
65 WrapperOperandType matrixType(WrapperType::TENSOR_FLOAT32, {3, 4});
66 WrapperOperandType scalarType(WrapperType::INT32, {});
67 int32_t activation(0);
68 auto a = model.addOperand(&matrixType);
69 auto b = model.addOperand(&matrixType);
70 auto c = model.addOperand(&matrixType);
71 auto d = model.addOperand(&matrixType);
72 auto e = model.addOperand(&matrixType);
73 auto f = model.addOperand(&scalarType);
74
75 model.setOperandValueFromMemory(e, &weights, offsetForMatrix2, sizeof(Matrix3x4));
76 model.setOperandValueFromMemory(a, &weights, offsetForMatrix3, sizeof(Matrix3x4));
77 model.setOperandValue(f, &activation, sizeof(activation));
78 model.addOperation(ANEURALNETWORKS_ADD, {a, c, f}, {b});
79 model.addOperation(ANEURALNETWORKS_ADD, {b, e, f}, {d});
80 model.identifyInputsAndOutputs({c}, {d});
81 ASSERT_TRUE(model.isValid());
82 model.finish();
83
84 // Test the three node model.
85 Matrix3x4 actual;
86 memset(&actual, 0, sizeof(actual));
87 WrapperCompilation compilation2(&model);
88 ASSERT_EQ(compilation2.finish(), WrapperResult::NO_ERROR);
89 WrapperExecution execution2(&compilation2);
90 ASSERT_EQ(execution2.setInput(0, matrix1, sizeof(Matrix3x4)), WrapperResult::NO_ERROR);
91 ASSERT_EQ(execution2.setOutput(0, actual, sizeof(Matrix3x4)), WrapperResult::NO_ERROR);
92 ASSERT_EQ(execution2.compute(), WrapperResult::NO_ERROR);
93 ASSERT_EQ(CompareMatrices(expected3, actual), 0);
94
95 close(fd);
96 unlink(path);
97 }
98
99 // Hardware buffers are an Android concept, which aren't necessarily
100 // available on other platforms such as ChromeOS, which also build NNAPI.
101 #if defined(__ANDROID__)
TEST_F(MemoryTest,TestAHardwareBuffer)102 TEST_F(MemoryTest, TestAHardwareBuffer) {
103 const uint32_t offsetForMatrix2 = 20;
104 const uint32_t offsetForMatrix3 = 200;
105
106 AHardwareBuffer_Desc desc{
107 .width = offsetForMatrix3 + sizeof(matrix3),
108 .height = 1,
109 .layers = 1,
110 .format = AHARDWAREBUFFER_FORMAT_BLOB,
111 .usage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN | AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN,
112 };
113 AHardwareBuffer* buffer = nullptr;
114 ASSERT_EQ(AHardwareBuffer_allocate(&desc, &buffer), 0);
115 auto allocateGuard =
116 android::base::make_scope_guard([buffer]() { AHardwareBuffer_release(buffer); });
117
118 void* bufferPtr = nullptr;
119 ASSERT_EQ(AHardwareBuffer_lock(buffer, desc.usage, -1, NULL, &bufferPtr), 0);
120 memcpy((uint8_t*)bufferPtr + offsetForMatrix2, matrix2, sizeof(matrix2));
121 memcpy((uint8_t*)bufferPtr + offsetForMatrix3, matrix3, sizeof(matrix3));
122 ASSERT_EQ(AHardwareBuffer_unlock(buffer, nullptr), 0);
123
124 WrapperMemory weights(buffer);
125 ASSERT_TRUE(weights.isValid());
126
127 WrapperModel model;
128 WrapperOperandType matrixType(WrapperType::TENSOR_FLOAT32, {3, 4});
129 WrapperOperandType scalarType(WrapperType::INT32, {});
130 int32_t activation(0);
131 auto a = model.addOperand(&matrixType);
132 auto b = model.addOperand(&matrixType);
133 auto c = model.addOperand(&matrixType);
134 auto d = model.addOperand(&matrixType);
135 auto e = model.addOperand(&matrixType);
136 auto f = model.addOperand(&scalarType);
137
138 model.setOperandValueFromMemory(e, &weights, offsetForMatrix2, sizeof(Matrix3x4));
139 model.setOperandValueFromMemory(a, &weights, offsetForMatrix3, sizeof(Matrix3x4));
140 model.setOperandValue(f, &activation, sizeof(activation));
141 model.addOperation(ANEURALNETWORKS_ADD, {a, c, f}, {b});
142 model.addOperation(ANEURALNETWORKS_ADD, {b, e, f}, {d});
143 model.identifyInputsAndOutputs({c}, {d});
144 ASSERT_TRUE(model.isValid());
145 model.finish();
146
147 // Test the three node model.
148 Matrix3x4 actual;
149 memset(&actual, 0, sizeof(actual));
150 WrapperCompilation compilation2(&model);
151 ASSERT_EQ(compilation2.finish(), WrapperResult::NO_ERROR);
152 WrapperExecution execution2(&compilation2);
153 ASSERT_EQ(execution2.setInput(0, matrix1, sizeof(Matrix3x4)), WrapperResult::NO_ERROR);
154 ASSERT_EQ(execution2.setOutput(0, actual, sizeof(Matrix3x4)), WrapperResult::NO_ERROR);
155 ASSERT_EQ(execution2.compute(), WrapperResult::NO_ERROR);
156 ASSERT_EQ(CompareMatrices(expected3, actual), 0);
157 }
158 #endif
159
160 } // end namespace
161