1 /*
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 
17 #ifndef ANDROID_HARDWARE_NEURALNETWORKS_V1_0_UTILS_H
18 #define ANDROID_HARDWARE_NEURALNETWORKS_V1_0_UTILS_H
19 
20 #include <android-base/logging.h>
21 #include <android/hardware/neuralnetworks/1.0/types.h>
22 #include <android/hardware_buffer.h>
23 #include <android/hidl/memory/1.0/IMemory.h>
24 #include <gtest/gtest.h>
25 #include <algorithm>
26 #include <iosfwd>
27 #include <string>
28 #include <utility>
29 #include <vector>
30 #include "TestHarness.h"
31 
32 namespace android::hardware::neuralnetworks {
33 
34 // Convenience class to manage the lifetime of memory resources.
35 class TestMemoryBase {
36     DISALLOW_COPY_AND_ASSIGN(TestMemoryBase);
37 
38   public:
39     TestMemoryBase() = default;
40     virtual ~TestMemoryBase() = default;
getPointer()41     uint8_t* getPointer() const { return mPtr; }
getHidlMemory()42     hidl_memory getHidlMemory() const { return mHidlMemory; }
43 
44   protected:
45     uint8_t* mPtr = nullptr;
46     hidl_memory mHidlMemory;
47     bool mIsValid = false;
48 };
49 
50 class TestAshmem : public TestMemoryBase {
51   public:
52     static std::unique_ptr<TestAshmem> create(uint32_t size);
53 
54     // Prefer TestAshmem::create.
55     // The constructor calls initialize, which constructs the memory resources. This is a workaround
56     // that gtest macros cannot be used directly in a constructor.
TestAshmem(uint32_t size)57     TestAshmem(uint32_t size) { initialize(size); }
58 
59   private:
60     void initialize(uint32_t size);
61     sp<hidl::memory::V1_0::IMemory> mMappedMemory;
62 };
63 
64 class TestBlobAHWB : public TestMemoryBase {
65   public:
66     static std::unique_ptr<TestBlobAHWB> create(uint32_t size);
67 
68     // Prefer TestBlobAHWB::create.
69     // The constructor calls initialize, which constructs the memory resources. This is a
70     // workaround that gtest macros cannot be used directly in a constructor.
TestBlobAHWB(uint32_t size)71     TestBlobAHWB(uint32_t size) { initialize(size); }
72     ~TestBlobAHWB();
73 
74   private:
75     void initialize(uint32_t size);
76     AHardwareBuffer* mAhwb = nullptr;
77 };
78 
79 enum class MemoryType { ASHMEM, BLOB_AHWB, DEVICE };
80 
81 // Manages the lifetime of memory resources used in an execution.
82 class ExecutionContext {
83     DISALLOW_COPY_AND_ASSIGN(ExecutionContext);
84 
85   public:
86     static constexpr uint32_t kInputPoolIndex = 0;
87     static constexpr uint32_t kOutputPoolIndex = 1;
88 
89     ExecutionContext() = default;
90 
91     // Create HIDL Request from the TestModel struct.
92     V1_0::Request createRequest(const test_helper::TestModel& testModel,
93                                 MemoryType memoryType = MemoryType::ASHMEM);
94 
95     // After execution, copy out output results from the output memory pool.
96     std::vector<test_helper::TestBuffer> getOutputBuffers(const V1_0::Request& request) const;
97 
98   private:
99     std::unique_ptr<TestMemoryBase> mInputMemory, mOutputMemory;
100 };
101 
102 // Delete element from hidl_vec. hidl_vec doesn't support a "remove" operation,
103 // so this is efficiently accomplished by moving the element to the end and
104 // resizing the hidl_vec to one less.
105 template <typename Type>
hidl_vec_removeAt(hidl_vec<Type> * vec,uint32_t index)106 inline void hidl_vec_removeAt(hidl_vec<Type>* vec, uint32_t index) {
107     CHECK(vec != nullptr);
108     std::rotate(vec->begin() + index, vec->begin() + index + 1, vec->end());
109     vec->resize(vec->size() - 1);
110 }
111 
112 // Assumes there is exactly one instance of the value in the vector.
113 template <typename Type>
hidl_vec_remove(hidl_vec<Type> * vec,const Type & val)114 inline void hidl_vec_remove(hidl_vec<Type>* vec, const Type& val) {
115     CHECK(vec != nullptr);
116     auto where = std::find(vec->begin(), vec->end(), val);
117     ASSERT_NE(where, vec->end());
118     hidl_vec_removeAt(vec, where - vec->begin());
119 }
120 
121 template <typename Type>
hidl_vec_push_back(hidl_vec<Type> * vec,const Type & value)122 inline uint32_t hidl_vec_push_back(hidl_vec<Type>* vec, const Type& value) {
123     CHECK(vec != nullptr);
124     const uint32_t index = vec->size();
125     vec->resize(index + 1);
126     (*vec)[index] = value;
127     return index;
128 }
129 
130 // Returns the amount of space needed to store a value of the specified type.
131 //
132 // Aborts if the specified type is an extension type or OEM type.
133 uint32_t sizeOfData(V1_0::OperandType type);
134 
135 // Returns the amount of space needed to store a value of the dimensions and
136 // type of this operand. For a non-extension, non-OEM tensor with unspecified
137 // rank or at least one unspecified dimension, returns zero.
138 //
139 // Aborts if the specified type is an extension type or OEM type.
140 uint32_t sizeOfData(const V1_0::Operand& operand);
141 
142 template <typename Type>
143 using Named = std::pair<std::string, Type>;
144 
145 template <typename Type>
getName(const Named<Type> & namedData)146 const std::string& getName(const Named<Type>& namedData) {
147     return namedData.first;
148 }
149 
150 template <typename Type>
getData(const Named<Type> & namedData)151 const Type& getData(const Named<Type>& namedData) {
152     return namedData.second;
153 }
154 
155 std::string gtestCompliantName(std::string name);
156 
157 }  // namespace android::hardware::neuralnetworks
158 
159 namespace android::hardware::neuralnetworks::V1_0 {
160 
161 // pretty-print values for error messages
162 ::std::ostream& operator<<(::std::ostream& os, ErrorStatus errorStatus);
163 ::std::ostream& operator<<(::std::ostream& os, DeviceStatus deviceStatus);
164 
165 }  // namespace android::hardware::neuralnetworks::V1_0
166 
167 #endif  // ANDROID_HARDWARE_NEURALNETWORKS_V1_0_UTILS_H
168