1 /*
2  * Copyright (C) 2020 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_INTERFACES_NEURALNETWORKS_UTILS_COMMON_COMMON_UTILS_H
18 #define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_COMMON_COMMON_UTILS_H
19 
20 #include <cutils/native_handle.h>
21 #include <hidl/HidlSupport.h>
22 #include <nnapi/Result.h>
23 #include <nnapi/SharedMemory.h>
24 #include <nnapi/Types.h>
25 #include <functional>
26 #include <vector>
27 
28 // Shorthands
29 namespace android::hardware::neuralnetworks {
30 namespace hal = ::android::hardware::neuralnetworks;
31 }  // namespace android::hardware::neuralnetworks
32 
33 // Shorthands
34 namespace aidl::android::hardware::neuralnetworks {
35 namespace aidl_hal = ::aidl::android::hardware::neuralnetworks;
36 namespace hal = ::android::hardware::neuralnetworks;
37 namespace nn = ::android::nn;
38 }  // namespace aidl::android::hardware::neuralnetworks
39 
40 // Shorthands
41 namespace android::nn {
42 namespace hal = ::android::hardware::neuralnetworks;
43 namespace aidl_hal = ::aidl::android::hardware::neuralnetworks;
44 }  // namespace android::nn
45 
46 namespace android::hardware::neuralnetworks::utils {
47 
48 nn::Capabilities::OperandPerformanceTable makeQuantized8PerformanceConsistentWithP(
49         const nn::Capabilities::PerformanceInfo& float32Performance,
50         const nn::Capabilities::PerformanceInfo& quantized8Performance);
51 
52 // Indicates if the object contains no pointer-based data that could be relocated to shared memory.
53 bool hasNoPointerData(const nn::Model& model);
54 bool hasNoPointerData(const nn::Request& request);
55 
56 // Relocate pointer-based data to shared memory. If `model` has no Operand::LifeTime::POINTER data,
57 // the function returns with a reference to `model`. If `model` has Operand::LifeTime::POINTER data,
58 // the model is copied to `maybeModelInSharedOut` with the POINTER data relocated to a memory pool,
59 // and the function returns with a reference to `*maybeModelInSharedOut`.
60 nn::GeneralResult<std::reference_wrapper<const nn::Model>> flushDataFromPointerToShared(
61         const nn::Model* model, std::optional<nn::Model>* maybeModelInSharedOut);
62 
63 // Record a relocation mapping between pointer-based data and shared memory.
64 // Only two specializations of this template may exist:
65 // - RelocationInfo<const void*> for request inputs
66 // - RelocationInfo<void*> for request outputs
67 template <typename PointerType>
68 struct RelocationInfo {
69     PointerType data;
70     size_t length;
71     size_t offset;
72 };
73 using InputRelocationInfo = RelocationInfo<const void*>;
74 using OutputRelocationInfo = RelocationInfo<void*>;
75 
76 // Keep track of the relocation mapping between pointer-based data and shared memory pool,
77 // and provide method to copy the data between pointers and the shared memory pool.
78 // Only two specializations of this template may exist:
79 // - RelocationTracker<InputRelocationInfo> for request inputs
80 // - RelocationTracker<OutputRelocationInfo> for request outputs
81 template <typename RelocationInfoType>
82 class RelocationTracker {
83   public:
create(std::vector<RelocationInfoType> relocationInfos,nn::SharedMemory memory)84     static nn::GeneralResult<std::unique_ptr<RelocationTracker>> create(
85             std::vector<RelocationInfoType> relocationInfos, nn::SharedMemory memory) {
86         auto mapping = NN_TRY(map(memory));
87         return std::make_unique<RelocationTracker<RelocationInfoType>>(
88                 std::move(relocationInfos), std::move(memory), std::move(mapping));
89     }
90 
RelocationTracker(std::vector<RelocationInfoType> relocationInfos,nn::SharedMemory memory,nn::Mapping mapping)91     RelocationTracker(std::vector<RelocationInfoType> relocationInfos, nn::SharedMemory memory,
92                       nn::Mapping mapping)
93         : kRelocationInfos(std::move(relocationInfos)),
94           kMemory(std::move(memory)),
95           kMapping(std::move(mapping)) {}
96 
97     // Specializations defined in CommonUtils.cpp.
98     // For InputRelocationTracker, this method will copy pointer data to the shared memory pool.
99     // For OutputRelocationTracker, this method will copy shared memory data to the pointers.
100     void flush() const;
101 
102   private:
103     const std::vector<RelocationInfoType> kRelocationInfos;
104     const nn::SharedMemory kMemory;
105     const nn::Mapping kMapping;
106 };
107 using InputRelocationTracker = RelocationTracker<InputRelocationInfo>;
108 using OutputRelocationTracker = RelocationTracker<OutputRelocationInfo>;
109 
110 struct RequestRelocation {
111     std::unique_ptr<InputRelocationTracker> input;
112     std::unique_ptr<OutputRelocationTracker> output;
113 };
114 
115 // Relocate pointer-based data to shared memory. If `request` has no
116 // Request::Argument::LifeTime::POINTER data, the function returns with a reference to `request`. If
117 // `request` has Request::Argument::LifeTime::POINTER data, the request is copied to
118 // `maybeRequestInSharedOut` with the POINTER data relocated to a memory pool, and the function
119 // returns with a reference to `*maybeRequestInSharedOut`. The `relocationOut` will be set to track
120 // the input and output relocations.
121 //
122 // Unlike `flushDataFromPointerToShared`, this method will not copy the input pointer data to the
123 // shared memory pool. Use `relocationOut` to flush the input or output data after the call.
124 nn::GeneralResult<std::reference_wrapper<const nn::Request>> convertRequestFromPointerToShared(
125         const nn::Request* request, uint32_t alignment, uint32_t padding,
126         std::optional<nn::Request>* maybeRequestInSharedOut, RequestRelocation* relocationOut);
127 
128 nn::GeneralResult<std::vector<uint32_t>> countNumberOfConsumers(
129         size_t numberOfOperands, const std::vector<nn::Operation>& operations);
130 
131 nn::GeneralResult<hidl_memory> createHidlMemoryFromSharedMemory(const nn::SharedMemory& memory);
132 nn::GeneralResult<nn::SharedMemory> createSharedMemoryFromHidlMemory(const hidl_memory& memory);
133 
134 nn::GeneralResult<hidl_handle> hidlHandleFromSharedHandle(const nn::Handle& handle);
135 nn::GeneralResult<nn::Handle> sharedHandleFromNativeHandle(const native_handle_t* handle);
136 
137 nn::GeneralResult<hidl_vec<hidl_handle>> convertSyncFences(
138         const std::vector<nn::SyncFence>& fences);
139 
140 }  // namespace android::hardware::neuralnetworks::utils
141 
142 #endif  // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_COMMON_COMMON_UTILS_H
143