• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 // This file contains pre-canonical-types utility code and does not includes HAL
17 // utilities. LegacyHalUtils.h is a superset of these utilities that includes
18 // HAL utilities.
19 
20 #ifndef ANDROID_FRAMEWORKS_ML_NN_COMMON_LEGACY_UTILS_H
21 #define ANDROID_FRAMEWORKS_ML_NN_COMMON_LEGACY_UTILS_H
22 
23 #include <android-base/logging.h>
24 #include <nnapi/TypeUtils.h>
25 #include <nnapi/Types.h>
26 
27 #include <string>
28 #include <tuple>
29 #include <utility>
30 #include <vector>
31 
32 #include "NeuralNetworks.h"
33 #include "OperationResolver.h"
34 #include "nnapi/TypeUtils.h"
35 #include "nnapi/Types.h"
36 
37 namespace android {
38 namespace nn {
39 
40 // The number of data types (OperandCode) defined in NeuralNetworks.h.
41 const int kNumberOfDataTypes = 16;
42 
43 // The number of operation types (OperationCode) defined in NeuralNetworks.h.
44 const int kNumberOfOperationTypes = 102;
45 static_assert(kNumberOfOperationTypes == BuiltinOperationResolver::kNumberOfOperationTypes);
46 
47 // The number of execution preferences defined in NeuralNetworks.h.
48 const int kNumberOfPreferences = 3;
49 
50 // The number of data types (OperandCode) defined in NeuralNetworksOEM.h.
51 const int kNumberOfDataTypesOEM = 2;
52 
53 // The number of operation types (OperationCode) defined in NeuralNetworksOEM.h.
54 const int kNumberOfOperationTypesOEM = 1;
55 
56 // The lowest number assigned to any OEM Code in NeuralNetworksOEM.h.
57 const int kOEMCodeBase = 10000;
58 
59 /* IMPORTANT: if you change the following list, don't
60  * forget to update the corresponding 'tags' table in
61  * the initVlogMask() function implemented in Utils.cpp.
62  */
63 enum VLogFlags { MODEL = 0, COMPILATION, EXECUTION, CPUEXE, MANAGER, DRIVER, MEMORY };
64 
65 #define VLOG_IS_ON(TAG) ((vLogMask & (1 << (TAG))) != 0)
66 
67 #define VLOG(TAG)                 \
68     if (LIKELY(!VLOG_IS_ON(TAG))) \
69         ;                         \
70     else                          \
71         LOG(INFO)
72 
73 extern int vLogMask;
74 void initVLogMask();
75 
76 #ifdef NN_DEBUGGABLE
77 #define SHOW_IF_DEBUG(msg) msg
78 #else
79 #define SHOW_IF_DEBUG(msg) ""
80 #endif
81 
82 // DEPRECATED(b/118737105). Use CHECK.
83 #define nnAssert(v) CHECK(v)
84 
85 #define NN_RETURN_IF_ERROR(expr)                      \
86     do {                                              \
87         int _errorCode = (expr);                      \
88         if (_errorCode != ANEURALNETWORKS_NO_ERROR) { \
89             return _errorCode;                        \
90         }                                             \
91     } while (0)
92 
93 // Make a Duration from a duration in nanoseconds. If the value exceeds the max duration, return the
94 // maximum expressible duration.
95 Duration makeTimeoutDuration(uint64_t nanoseconds);
96 
97 // Make a Duration from a duration in nanoseconds. If the value exceeds the max duration, return the
98 // maximum expressible duration. If nanoseconds == -1, the duration is omitted. Precondition:
99 // nanoseconds >= -1
100 OptionalDuration makeTimeoutDuration(int64_t nanoseconds);
101 
102 // Make a deadline from a duration. If the sum of the current time and the
103 // duration exceeds the max time, return a time point holding the maximum
104 // expressible time.
105 TimePoint makeDeadline(Duration duration);
106 
makeDeadline(uint64_t duration)107 inline TimePoint makeDeadline(uint64_t duration) {
108     return makeDeadline(makeTimeoutDuration(duration));
109 }
110 
111 // Convenience function. If the duration is provided, this function creates a
112 // deadline using makeDeadline. If the duration is not provided, this function
113 // returns std::nullopt.
makeDeadline(OptionalDuration duration)114 inline OptionalTimePoint makeDeadline(OptionalDuration duration) {
115     return duration.has_value() ? std::make_optional(makeDeadline(*duration)) : OptionalTimePoint{};
116 }
makeDeadline(std::optional<uint64_t> duration)117 inline OptionalTimePoint makeDeadline(std::optional<uint64_t> duration) {
118     return duration.has_value() ? std::make_optional(makeDeadline(*duration)) : OptionalTimePoint{};
119 }
makeDeadline(int64_t duration)120 inline OptionalTimePoint makeDeadline(int64_t duration) {
121     return makeDeadline(makeTimeoutDuration(duration));
122 }
123 
124 // Returns true if the deadline has passed. Returns false if either the deadline
125 // has not been exceeded or if the deadline is not present.
126 bool hasDeadlinePassed(const OptionalTimePoint& deadline);
127 
128 // Returns true if an operand type is an extension type.
129 bool isExtensionOperandType(OperandType type);
130 
131 // Returns true if an operation type is an extension type.
132 bool isExtensionOperationType(OperationType type);
133 
134 // Returns the amount of space needed to store a value of the specified
135 // dimensions and type. For a tensor with unspecified rank or at least one
136 // unspecified dimension, returns zero.
137 //
138 // Aborts if the specified type is an extension type.
139 // Aborts if the size would overflow the return type.
140 //
141 // See also TypeManager::getSizeOfData(OperandType, const std::vector<uint32_t>&).
142 uint32_t nonExtensionOperandSizeOfData(OperandType type, const std::vector<uint32_t>& dimensions);
143 
144 // Returns the amount of space needed to store a value of the dimensions and
145 // type of this operand. For a tensor with unspecified rank or at least one
146 // unspecified dimension, returns zero.
147 //
148 // Aborts if the specified type is an extension type.
149 // Aborts if the size would overflow the return type.
150 //
151 // See also TypeManager::getSizeOfData(const Operand&).
nonExtensionOperandSizeOfData(const Operand & operand)152 inline uint32_t nonExtensionOperandSizeOfData(const Operand& operand) {
153     return nonExtensionOperandSizeOfData(operand.type, operand.dimensions);
154 }
155 
156 // Returns the amount of space needed to store a value of the specified
157 // dimensions and element size. For a tensor with unspecified rank or at least
158 // one unspecified dimension, returns zero.
159 //
160 // Aborts if the size would overflow the return type.
161 //
162 // See also TypeManager::getSizeOfData(const Operand&).
163 uint32_t sizeOfTensorData(uint32_t sizeOfElement, const std::vector<uint32_t>& dimensions);
164 
165 // Returns true if the amount of space needed to store a value of the specified
166 // dimensions and element size overflows the uint32_t type.
167 //
168 // Aborts if the specified type is an extension type.
169 //
170 // See also TypeManager::sizeOfDataOverflowsUInt32(OperandType, const std::vector<uint32_t>&).
171 bool nonExtensionOperandSizeOfDataOverflowsUInt32(OperandType type,
172                                                   const std::vector<uint32_t>& dimensions);
173 
174 // Returns true if the amount of space needed to store a value of the specified
175 // dimensions and element size overflows the uint32_t type.
176 //
177 // See also TypeManager::sizeOfDataOverflowsUInt32(OperandType, const std::vector<uint32_t>&).
178 bool sizeOfTensorDataOverflowsUInt32(uint32_t elementSize, const std::vector<uint32_t>& dimensions);
179 
180 // Returns true if a non-extension operand type is a scalar type.
181 //
182 // Aborts if the specified type is an extension type.
183 //
184 // See also TypeManager::isTensorType(OperandType).
185 bool nonExtensionOperandTypeIsScalar(int type);
186 
187 // Whether an operand of tensor type has unspecified dimensions.
188 //
189 // Undefined behavior if the operand type is a scalar type.
190 bool tensorHasUnspecifiedDimensions(int type, const uint32_t* dim, uint32_t dimCount);
191 bool tensorHasUnspecifiedDimensions(OperandType type, const std::vector<uint32_t>& dimensions);
192 bool tensorHasUnspecifiedDimensions(OperandType type, const Dimensions& dimensions);
193 bool tensorHasUnspecifiedDimensions(const Operand& operand);
194 bool tensorHasUnspecifiedDimensions(const ANeuralNetworksOperandType* type);
195 
196 // Returns the number of padding bytes needed to align data starting at `index` with `length` number
197 // of bytes such that `index` + returned number of padding bytes is aligned. Refer to
198 // `getAlignmentForLength` for more information on alignment (such as what the current alignments
199 // are for different data lengths).
200 uint32_t alignBytesNeeded(uint32_t index, size_t length);
201 
202 // Does a detailed LOG(INFO) of the model
203 void logModelToInfo(const Model& model);
204 
toString(uint32_t obj)205 inline std::string toString(uint32_t obj) {
206     return std::to_string(obj);
207 }
208 
209 template <typename Type>
toString(const std::vector<Type> & range)210 std::string toString(const std::vector<Type>& range) {
211     std::string os = "[";
212     for (size_t i = 0; i < range.size(); ++i) {
213         os += (i == 0 ? "" : ", ") + toString(range[i]);
214     }
215     return os += "]";
216 }
217 
218 template <typename A, typename B>
toString(const std::pair<A,B> & pair)219 std::string toString(const std::pair<A, B>& pair) {
220     std::ostringstream oss;
221     oss << "(" << pair.first << ", " << pair.second << ")";
222     return oss.str();
223 }
224 
validCode(uint32_t codeCount,uint32_t codeCountOEM,uint32_t code)225 inline bool validCode(uint32_t codeCount, uint32_t codeCountOEM, uint32_t code) {
226     return (code < codeCount) || (code >= kOEMCodeBase && (code - kOEMCodeBase) < codeCountOEM);
227 }
228 
229 // Validates an operand type.
230 //
231 // extensionOperandTypeInfo must be nullptr iff the type is not an extension type.
232 //
233 // If allowPartial is true, the dimensions may be underspecified.
234 int validateOperandType(const ANeuralNetworksOperandType& type,
235                         const Extension::OperandTypeInformation* const extensionOperandTypeInfo,
236                         const char* tag, bool allowPartial);
237 int validateOperandList(uint32_t count, const uint32_t* list, uint32_t operandCount,
238                         const char* tag);
239 
240 // A set of functions to help validate models containing IF or WHILE operations.
241 struct SubgraphValidationHelper {
242     // Checks if a given operand is a SUBGRAPH operand with a valid offset.
243     std::function<bool(const Operand&)> isValidSubgraphReference;
244     // Gets the input count of a subgraph referenced by a given operand.
245     std::function<uint32_t(const Operand&)> getSubgraphInputCount;
246     // Gets the output count of a subgraph referenced by a given operand.
247     std::function<uint32_t(const Operand&)> getSubgraphOutputCount;
248     // Gets the specified input operand of a subgraph referenced by a given operand.
249     std::function<const Operand*(const Operand&, uint32_t)> getSubgraphInputOperand;
250     // Gets the specified output operand of a subgraph referenced by a given operand.
251     std::function<const Operand*(const Operand&, uint32_t)> getSubgraphOutputOperand;
252     // Whether control flow operations with inner or outer input or output
253     // operands of unknown size are allowed.
254     bool allowControlFlowOperationWithOperandOfUnknownSize;
255 };
256 
257 // Returns ANEURALNETWORKS_NO_ERROR if the corresponding operation is defined and can handle the
258 // provided operand types in the given HAL version, otherwise returns ANEURALNETWORKS_BAD_DATA.
259 // The last argument is only used for validating IF and WHILE operations.
260 int validateOperation(ANeuralNetworksOperationType opType, uint32_t inputCount,
261                       const uint32_t* inputIndexes, uint32_t outputCount,
262                       const uint32_t* outputIndexes, const std::vector<Operand>& operands,
263                       HalVersion halVersion, const SubgraphValidationHelper& helper);
264 
getSizeFromInts(int lower,int higher)265 inline size_t getSizeFromInts(int lower, int higher) {
266     return (uint32_t)(lower) + ((uint64_t)(uint32_t)(higher) << 32);
267 }
268 
269 // Convert ANEURALNETWORKS_* result code to ErrorStatus.
270 // Not guaranteed to be a 1-to-1 mapping.
271 ErrorStatus convertResultCodeToErrorStatus(int resultCode);
272 
273 // Convert ErrorStatus to ANEURALNETWORKS_* result code.
274 // Not guaranteed to be a 1-to-1 mapping.
275 int convertErrorStatusToResultCode(ErrorStatus status);
276 
277 // Convert execution results to runtime format. Additionally checks that the
278 // returned results abide by the HAL specification, and logs an error if the
279 // result violates the specification.
280 std::tuple<int, std::vector<OutputShape>, Timing> getExecutionResult(
281         ErrorStatus status, std::vector<OutputShape> outputShapes, Timing timing);
282 
convertToCanonicalPriority(int32_t priority)283 constexpr Priority convertToCanonicalPriority(int32_t priority) {
284     switch (priority) {
285         case ANEURALNETWORKS_PRIORITY_LOW:
286             return Priority::LOW;
287         case ANEURALNETWORKS_PRIORITY_MEDIUM:
288             return Priority::MEDIUM;
289         case ANEURALNETWORKS_PRIORITY_HIGH:
290             return Priority::HIGH;
291     }
292     LOG(FATAL) << "unrecognized priority: " << priority;
293     return {};
294 }
295 
296 // The function syncWait() has the same semantics as the system function
297 // ::sync_wait(), except that the syncWait() return value is semantically
298 // richer.  The timeout parameter is in msecs.
299 enum class FenceState {
300     ACTIVE,    // fence has not been signaled
301     SIGNALED,  // fence has been signaled
302     ERROR,     // fence has been placed in the error state
303     UNKNOWN,   // either bad argument passed to syncWait(), or internal error
304 };
305 FenceState syncWait(int fd, int timeout);
306 
307 #ifdef NN_DEBUGGABLE
308 uint32_t getProp(const char* str, uint32_t defaultValue = 0);
309 #endif  // NN_DEBUGGABLE
310 
311 struct ApiVersion {
312     Version canonical;
313     int64_t featureLevel;
314 };
315 
316 constexpr auto kHalVersionV1_0ToApi = ApiVersion{.canonical = Version::ANDROID_OC_MR1,
317                                                  .featureLevel = ANEURALNETWORKS_FEATURE_LEVEL_1};
318 constexpr auto kHalVersionV1_1ToApi = ApiVersion{.canonical = Version::ANDROID_P,
319                                                  .featureLevel = ANEURALNETWORKS_FEATURE_LEVEL_2};
320 constexpr auto kHalVersionV1_2ToApi = ApiVersion{.canonical = Version::ANDROID_Q,
321                                                  .featureLevel = ANEURALNETWORKS_FEATURE_LEVEL_3};
322 constexpr auto kHalVersionV1_3ToApi = ApiVersion{.canonical = Version::ANDROID_R,
323                                                  .featureLevel = ANEURALNETWORKS_FEATURE_LEVEL_4};
324 }  // namespace nn
325 }  // namespace android
326 
327 #endif  // ANDROID_FRAMEWORKS_ML_NN_COMMON_LEGACY_UTILS_H
328